| 660 | await self.middleware_stack(scope, receive, send) |
| 661 | |
| 662 | async def app(self, scope: Scope, receive: Receive, send: Send) -> None: |
| 663 | assert scope[class="st">"type"] in (class="st">"http", class="st">"websocket", class="st">"lifespan") |
| 664 | |
| 665 | if class="st">"router" not in scope: |
| 666 | scope[class="st">"router"] = self |
| 667 | |
| 668 | if scope[class="st">"type"] == class="st">"lifespan": |
| 669 | await self.lifespan(scope, receive, send) |
| 670 | return |
| 671 | |
| 672 | partial = None |
| 673 | |
| 674 | for route in self.routes: |
| 675 | class="cm"># Determine if any route matches the incoming scope, |
| 676 | class="cm"># and hand over to the matching route if found. |
| 677 | match, child_scope = route.matches(scope) |
| 678 | if match == Match.FULL: |
| 679 | scope.update(child_scope) |
| 680 | await route.handle(scope, receive, send) |
| 681 | return |
| 682 | elif match == Match.PARTIAL and partial is None: |
| 683 | partial = route |
| 684 | partial_scope = child_scope |
| 685 | |
| 686 | if partial is not None: |
| 687 | class="cm"># Handle partial matches. These are cases where an endpoint is |
| 688 | class="cm"># able to handle the request, but is not a preferred option. |
| 689 | class="cm"># We use this in particular to deal with class="st">"405 Method Not Allowed". |
| 690 | scope.update(partial_scope) |
| 691 | await partial.handle(scope, receive, send) |
| 692 | return |
| 693 | |
| 694 | route_path = get_route_path(scope) |
| 695 | if scope[class="st">"type"] == class="st">"http" and self.redirect_slashes and route_path != class="st">"/": |
| 696 | redirect_scope = dict(scope) |
| 697 | if route_path.endswith(class="st">"/"): |
| 698 | redirect_scope[class="st">"path"] = redirect_scope[class="st">"path"].rstrip(class="st">"/") |
| 699 | else: |
| 700 | redirect_scope[class="st">"path"] = redirect_scope[class="st">"path"] + class="st">"/" |
| 701 | |
| 702 | for route in self.routes: |
| 703 | match, child_scope = route.matches(redirect_scope) |
| 704 | if match != Match.NONE: |
| 705 | redirect_url = URL(scope=redirect_scope) |
| 706 | response = RedirectResponse(url=str(redirect_url)) |
| 707 | await response(scope, receive, send) |
| 708 | return |
| 709 | |
| 710 | await self.default(scope, receive, send) |
| 711 | |
| 712 | def __eq__(self, other: Any) -> bool: |
| 713 | return isinstance(other, Router) and self.routes == other.routes |