Route looks up a handler registered for method and path. It also parses URL for path parameters and loads them into context. For performance: - Get context from `Echo#AcquireContext()` - Reset it `Context#Reset()` - Return it `Echo#ReleaseContext()`.
(c *Context)
| 786 | // - Reset it `Context#Reset()` |
| 787 | // - Return it `Echo#ReleaseContext()`. |
| 788 | func (r *DefaultRouter) Route(c *Context) HandlerFunc { |
| 789 | pathValues := c.PathValues() |
| 790 | if cap(pathValues) < r.maxPathParamsLength { |
| 791 | pathValues = make(PathValues, 0, r.maxPathParamsLength) |
| 792 | } else { |
| 793 | pathValues = pathValues[0:cap(pathValues)] // resize slice to maximum capacity so we can index set values |
| 794 | } |
| 795 | |
| 796 | req := c.Request() |
| 797 | path := req.URL.Path |
| 798 | if !r.useEscapedPathForRouting && req.URL.RawPath != "" { |
| 799 | // Difference between URL.RawPath and URL.Path is: |
| 800 | // * URL.Path is where request path is stored. Value is stored in decoded form: /%47%6f%2f becomes /Go/. |
| 801 | // * URL.RawPath is an optional field which only gets set if the default encoding is different from Path. |
| 802 | path = req.URL.RawPath |
| 803 | } |
| 804 | var ( |
| 805 | currentNode = r.tree // root as current node |
| 806 | previousBestMatchNode *node |
| 807 | matchedRouteMethod *routeMethod |
| 808 | // search stores the remaining path to check for match. By each iteration we move from start of path to end of the path |
| 809 | // and search value gets shorter and shorter. |
| 810 | search = path |
| 811 | searchIndex = 0 |
| 812 | paramIndex int // Param counter |
| 813 | ) |
| 814 | |
| 815 | // Backtracking is needed when a dead end (leaf node) is reached in the router tree. |
| 816 | // To backtrack the current node will be changed to the parent node and the next kind for the |
| 817 | // router logic will be returned based on fromKind or kind of the dead end node (static > param > any). |
| 818 | // For example if there is no static node match we should check parent next sibling by kind (param). |
| 819 | // Backtracking itself does not check if there is a next sibling, this is done by the router logic. |
| 820 | backtrackToNextNodeKind := func(fromKind kind) (nextNodeKind kind, valid bool) { |
| 821 | previous := currentNode |
| 822 | currentNode = previous.parent |
| 823 | valid = currentNode != nil |
| 824 | |
| 825 | // Next node type by priority |
| 826 | if previous.kind == anyKind { |
| 827 | nextNodeKind = staticKind |
| 828 | } else { |
| 829 | nextNodeKind = previous.kind + 1 |
| 830 | } |
| 831 | |
| 832 | if fromKind == staticKind { |
| 833 | // when backtracking is done from static kind block we did not change search so nothing to restore |
| 834 | return |
| 835 | } |
| 836 | |
| 837 | // restore search to value it was before we move to current node we are backtracking from. |
| 838 | if previous.kind == staticKind { |
| 839 | searchIndex -= len(previous.prefix) |
| 840 | } else { |
| 841 | paramIndex-- |
| 842 | // for param/any node.prefix value is always `:` so we can not deduce searchIndex from that and must use pValue |
| 843 | // for that index as it would also contain part of path we cut off before moving into node we are backtracking from |
| 844 | searchIndex -= len(pathValues[paramIndex].Value) |
| 845 | pathValues[paramIndex].Value = "" |
nothing calls this directly
no test coverage detected