/src/uWebSockets/src/HttpRouter.h
Line | Count | Source |
1 | | /* |
2 | | * Authored by Alex Hultman, 2018-2020. |
3 | | * Intellectual property of third-party. |
4 | | |
5 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
6 | | * you may not use this file except in compliance with the License. |
7 | | * You may obtain a copy of the License at |
8 | | |
9 | | * http://www.apache.org/licenses/LICENSE-2.0 |
10 | | |
11 | | * Unless required by applicable law or agreed to in writing, software |
12 | | * distributed under the License is distributed on an "AS IS" BASIS, |
13 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
14 | | * See the License for the specific language governing permissions and |
15 | | * limitations under the License. |
16 | | */ |
17 | | |
18 | | #ifndef UWS_HTTPROUTER_HPP |
19 | | #define UWS_HTTPROUTER_HPP |
20 | | |
21 | | #include <map> |
22 | | #include <vector> |
23 | | #include <cstring> |
24 | | #include <string_view> |
25 | | #include <string> |
26 | | #include <algorithm> |
27 | | #include <memory> |
28 | | #include <utility> |
29 | | |
30 | | #include <iostream> |
31 | | |
32 | | #include "MoveOnlyFunction.h" |
33 | | |
34 | | namespace uWS { |
35 | | |
36 | | template <class USERDATA> |
37 | | struct HttpRouter { |
38 | | static constexpr std::string_view ANY_METHOD_TOKEN = "*"; |
39 | | static const uint32_t HIGH_PRIORITY = 0xd0000000, MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000; |
40 | | |
41 | | private: |
42 | | USERDATA userData; |
43 | | static const unsigned int MAX_URL_SEGMENTS = 100; |
44 | | |
45 | | /* Handler ids are 32-bit */ |
46 | | static const uint32_t HANDLER_MASK = 0x0fffffff; |
47 | | |
48 | | /* List of handlers */ |
49 | | std::vector<MoveOnlyFunction<bool(HttpRouter *)>> handlers; |
50 | | |
51 | | /* Current URL cache */ |
52 | | std::string_view currentUrl; |
53 | | std::string_view urlSegmentVector[MAX_URL_SEGMENTS]; |
54 | | int urlSegmentTop; |
55 | | |
56 | | /* The matching tree */ |
57 | | struct Node { |
58 | | std::string name; |
59 | | std::vector<std::unique_ptr<Node>> children; |
60 | | std::vector<uint32_t> handlers; |
61 | | bool isHighPriority; |
62 | | |
63 | 173k | Node(std::string name) : name(name) {}uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node::Node(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 63 | 31.3k | Node(std::string name) : name(name) {} |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node::Node(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 63 | 142k | Node(std::string name) : name(name) {} |
uWS::HttpRouter<StaticData::RouterData>::Node::Node(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >) Line | Count | Source | 63 | 44 | Node(std::string name) : name(name) {} |
|
64 | | } root = {"rootNode"}; |
65 | | |
66 | | /* Sort wildcards after alphanum */ |
67 | 43.0k | int lexicalOrder(std::string &name) { |
68 | 43.0k | if (!name.length()) { |
69 | 0 | return 2; |
70 | 0 | } |
71 | 43.0k | if (name[0] == ':') { |
72 | 7.07k | return 1; |
73 | 7.07k | } |
74 | 35.9k | if (name[0] == '*') { |
75 | 21.5k | return 0; |
76 | 21.5k | } |
77 | 14.4k | return 2; |
78 | 35.9k | } Unexecuted instantiation: uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::lexicalOrder(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::lexicalOrder(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Line | Count | Source | 67 | 43.0k | int lexicalOrder(std::string &name) { | 68 | 43.0k | if (!name.length()) { | 69 | 0 | return 2; | 70 | 0 | } | 71 | 43.0k | if (name[0] == ':') { | 72 | 7.06k | return 1; | 73 | 7.06k | } | 74 | 35.9k | if (name[0] == '*') { | 75 | 21.5k | return 0; | 76 | 21.5k | } | 77 | 14.4k | return 2; | 78 | 35.9k | } |
uWS::HttpRouter<StaticData::RouterData>::lexicalOrder(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) Line | Count | Source | 67 | 24 | int lexicalOrder(std::string &name) { | 68 | 24 | if (!name.length()) { | 69 | 0 | return 2; | 70 | 0 | } | 71 | 24 | if (name[0] == ':') { | 72 | 8 | return 1; | 73 | 8 | } | 74 | 16 | if (name[0] == '*') { | 75 | 8 | return 0; | 76 | 8 | } | 77 | 8 | return 2; | 78 | 16 | } |
|
79 | | |
80 | | /* Advance from parent to child, adding child if necessary */ |
81 | 202k | Node *getNode(Node *parent, std::string child, bool isHighPriority) { |
82 | 202k | for (std::unique_ptr<Node> &node : parent->children) { |
83 | 142k | if (node->name == child && node->isHighPriority == isHighPriority) { |
84 | 53.3k | return node.get(); |
85 | 53.3k | } |
86 | 142k | } |
87 | | |
88 | | /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */ |
89 | 148k | std::unique_ptr<Node> newNode(new Node(child)); |
90 | 148k | newNode->isHighPriority = isHighPriority; |
91 | 148k | return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { |
92 | | |
93 | 67.5k | if (a->isHighPriority != b->isHighPriority) { |
94 | 14.1k | return a->isHighPriority; |
95 | 14.1k | } |
96 | | |
97 | 53.3k | return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); |
98 | 67.5k | }), std::move(newNode))->get(); auto uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::getNode(uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool)::{lambda(auto:1&, auto:2&)#1}::operator()<std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node> > const, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node> >(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node> > const&, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node>&) constLine | Count | Source | 91 | 6.26k | return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { | 92 | | | 93 | 6.26k | if (a->isHighPriority != b->isHighPriority) { | 94 | 0 | return a->isHighPriority; | 95 | 0 | } | 96 | | | 97 | 6.26k | return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); | 98 | 6.26k | }), std::move(newNode))->get(); |
auto uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::getNode(uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool)::{lambda(auto:1&, auto:2&)#1}::operator()<std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node> > const, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node> >(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node> > const&, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node>&) constLine | Count | Source | 91 | 61.2k | return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { | 92 | | | 93 | 61.2k | if (a->isHighPriority != b->isHighPriority) { | 94 | 14.1k | return a->isHighPriority; | 95 | 14.1k | } | 96 | | | 97 | 47.1k | return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); | 98 | 61.2k | }), std::move(newNode))->get(); |
auto uWS::HttpRouter<StaticData::RouterData>::getNode(uWS::HttpRouter<StaticData::RouterData>::Node*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool)::{lambda(auto:1&, auto:2&)#1}::operator()<std::__1::unique_ptr<uWS::HttpRouter<StaticData::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<StaticData::RouterData>::Node> > const, std::__1::default_delete<uWS::HttpRouter<StaticData::RouterData>::Node> >(std::__1::unique_ptr<uWS::HttpRouter<StaticData::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<StaticData::RouterData>::Node> > const&, std::__1::default_delete<uWS::HttpRouter<StaticData::RouterData>::Node>&) constLine | Count | Source | 91 | 20 | return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { | 92 | | | 93 | 20 | if (a->isHighPriority != b->isHighPriority) { | 94 | 0 | return a->isHighPriority; | 95 | 0 | } | 96 | | | 97 | 20 | return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); | 98 | 20 | }), std::move(newNode))->get(); |
|
99 | 202k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::getNode(uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool) Line | Count | Source | 81 | 31.3k | Node *getNode(Node *parent, std::string child, bool isHighPriority) { | 82 | 31.3k | for (std::unique_ptr<Node> &node : parent->children) { | 83 | 12.5k | if (node->name == child && node->isHighPriority == isHighPriority) { | 84 | 6.26k | return node.get(); | 85 | 6.26k | } | 86 | 12.5k | } | 87 | | | 88 | | /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */ | 89 | 25.0k | std::unique_ptr<Node> newNode(new Node(child)); | 90 | 25.0k | newNode->isHighPriority = isHighPriority; | 91 | 25.0k | return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { | 92 | | | 93 | 25.0k | if (a->isHighPriority != b->isHighPriority) { | 94 | 25.0k | return a->isHighPriority; | 95 | 25.0k | } | 96 | | | 97 | 25.0k | return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); | 98 | 25.0k | }), std::move(newNode))->get(); | 99 | 31.3k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::getNode(uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool) Line | Count | Source | 81 | 170k | Node *getNode(Node *parent, std::string child, bool isHighPriority) { | 82 | 170k | for (std::unique_ptr<Node> &node : parent->children) { | 83 | 129k | if (node->name == child && node->isHighPriority == isHighPriority) { | 84 | 47.1k | return node.get(); | 85 | 47.1k | } | 86 | 129k | } | 87 | | | 88 | | /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */ | 89 | 123k | std::unique_ptr<Node> newNode(new Node(child)); | 90 | 123k | newNode->isHighPriority = isHighPriority; | 91 | 123k | return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { | 92 | | | 93 | 123k | if (a->isHighPriority != b->isHighPriority) { | 94 | 123k | return a->isHighPriority; | 95 | 123k | } | 96 | | | 97 | 123k | return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); | 98 | 123k | }), std::move(newNode))->get(); | 99 | 170k | } |
uWS::HttpRouter<StaticData::RouterData>::getNode(uWS::HttpRouter<StaticData::RouterData>::Node*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, bool) Line | Count | Source | 81 | 48 | Node *getNode(Node *parent, std::string child, bool isHighPriority) { | 82 | 48 | for (std::unique_ptr<Node> &node : parent->children) { | 83 | 32 | if (node->name == child && node->isHighPriority == isHighPriority) { | 84 | 8 | return node.get(); | 85 | 8 | } | 86 | 32 | } | 87 | | | 88 | | /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */ | 89 | 40 | std::unique_ptr<Node> newNode(new Node(child)); | 90 | 40 | newNode->isHighPriority = isHighPriority; | 91 | 40 | return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) { | 92 | | | 93 | 40 | if (a->isHighPriority != b->isHighPriority) { | 94 | 40 | return a->isHighPriority; | 95 | 40 | } | 96 | | | 97 | 40 | return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name)); | 98 | 40 | }), std::move(newNode))->get(); | 99 | 48 | } |
|
100 | | |
101 | | /* Basically a pre-allocated stack */ |
102 | | struct RouteParameters { |
103 | | friend struct HttpRouter; |
104 | | private: |
105 | | std::string_view params[MAX_URL_SEGMENTS]; |
106 | | int paramsTop; |
107 | | |
108 | 502k | void reset() { |
109 | 502k | paramsTop = -1; |
110 | 502k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::RouteParameters::reset() Line | Count | Source | 108 | 126k | void reset() { | 109 | 126k | paramsTop = -1; | 110 | 126k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::RouteParameters::reset() Line | Count | Source | 108 | 354k | void reset() { | 109 | 354k | paramsTop = -1; | 110 | 354k | } |
uWS::HttpRouter<StaticData::RouterData>::RouteParameters::reset() Line | Count | Source | 108 | 22.0k | void reset() { | 109 | 22.0k | paramsTop = -1; | 110 | 22.0k | } |
|
111 | | |
112 | 25.9k | void push(std::string_view param) { |
113 | | /* We check these bounds indirectly via the urlSegments limit */ |
114 | 25.9k | params[++paramsTop] = param; |
115 | 25.9k | } Unexecuted instantiation: uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::RouteParameters::push(std::__1::basic_string_view<char, std::__1::char_traits<char> >) uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::RouteParameters::push(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 112 | 5.54k | void push(std::string_view param) { | 113 | | /* We check these bounds indirectly via the urlSegments limit */ | 114 | 5.54k | params[++paramsTop] = param; | 115 | 5.54k | } |
uWS::HttpRouter<StaticData::RouterData>::RouteParameters::push(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 112 | 20.4k | void push(std::string_view param) { | 113 | | /* We check these bounds indirectly via the urlSegments limit */ | 114 | 20.4k | params[++paramsTop] = param; | 115 | 20.4k | } |
|
116 | | |
117 | 3.33k | void pop() { |
118 | | /* Same here, we cannot pop outside */ |
119 | 3.33k | paramsTop--; |
120 | 3.33k | } Unexecuted instantiation: uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::RouteParameters::pop() uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::RouteParameters::pop() Line | Count | Source | 117 | 3.19k | void pop() { | 118 | | /* Same here, we cannot pop outside */ | 119 | 3.19k | paramsTop--; | 120 | 3.19k | } |
uWS::HttpRouter<StaticData::RouterData>::RouteParameters::pop() Line | Count | Source | 117 | 133 | void pop() { | 118 | | /* Same here, we cannot pop outside */ | 119 | 133 | paramsTop--; | 120 | 133 | } |
|
121 | | } routeParameters; |
122 | | |
123 | | /* Set URL for router. Will reset any URL cache */ |
124 | 641k | inline void setUrl(std::string_view url) { |
125 | | |
126 | | /* Todo: URL may also start with "http://domain/" or "*", not only "/" */ |
127 | | |
128 | | /* We expect to stand on a slash */ |
129 | 641k | currentUrl = url; |
130 | 641k | urlSegmentTop = -1; |
131 | 641k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::setUrl(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 124 | 144k | inline void setUrl(std::string_view url) { | 125 | | | 126 | | /* Todo: URL may also start with "http://domain/" or "*", not only "/" */ | 127 | | | 128 | | /* We expect to stand on a slash */ | 129 | 144k | currentUrl = url; | 130 | 144k | urlSegmentTop = -1; | 131 | 144k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::setUrl(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 124 | 473k | inline void setUrl(std::string_view url) { | 125 | | | 126 | | /* Todo: URL may also start with "http://domain/" or "*", not only "/" */ | 127 | | | 128 | | /* We expect to stand on a slash */ | 129 | 473k | currentUrl = url; | 130 | 473k | urlSegmentTop = -1; | 131 | 473k | } |
uWS::HttpRouter<StaticData::RouterData>::setUrl(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 124 | 22.0k | inline void setUrl(std::string_view url) { | 125 | | | 126 | | /* Todo: URL may also start with "http://domain/" or "*", not only "/" */ | 127 | | | 128 | | /* We expect to stand on a slash */ | 129 | 22.0k | currentUrl = url; | 130 | 22.0k | urlSegmentTop = -1; | 131 | 22.0k | } |
|
132 | | |
133 | | /* Lazily parse or read from cache */ |
134 | 1.13M | inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) { |
135 | 1.13M | if (urlSegment > urlSegmentTop) { |
136 | | /* Signal as STOP when we have no more URL or stack space */ |
137 | 978k | if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) { |
138 | 314k | return {{}, true}; |
139 | 314k | } |
140 | | |
141 | | /* We always stand on a slash here, so step over it */ |
142 | 663k | currentUrl.remove_prefix(1); |
143 | | |
144 | 663k | auto segmentLength = currentUrl.find('/'); |
145 | 663k | if (segmentLength == std::string::npos) { |
146 | 627k | segmentLength = currentUrl.length(); |
147 | | |
148 | | /* Push to url segment vector */ |
149 | 627k | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); |
150 | 627k | urlSegmentTop++; |
151 | | |
152 | | /* Update currentUrl */ |
153 | 627k | currentUrl = currentUrl.substr(segmentLength); |
154 | 627k | } else { |
155 | | /* Push to url segment vector */ |
156 | 36.0k | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); |
157 | 36.0k | urlSegmentTop++; |
158 | | |
159 | | /* Update currentUrl */ |
160 | 36.0k | currentUrl = currentUrl.substr(segmentLength); |
161 | 36.0k | } |
162 | 663k | } |
163 | | /* In any case we return it */ |
164 | 822k | return {urlSegmentVector[urlSegment], false}; |
165 | 1.13M | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::getUrlSegment(int) Line | Count | Source | 134 | 180k | inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) { | 135 | 180k | if (urlSegment > urlSegmentTop) { | 136 | | /* Signal as STOP when we have no more URL or stack space */ | 137 | 157k | if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) { | 138 | 12.5k | return {{}, true}; | 139 | 12.5k | } | 140 | | | 141 | | /* We always stand on a slash here, so step over it */ | 142 | 144k | currentUrl.remove_prefix(1); | 143 | | | 144 | 144k | auto segmentLength = currentUrl.find('/'); | 145 | 144k | if (segmentLength == std::string::npos) { | 146 | 144k | segmentLength = currentUrl.length(); | 147 | | | 148 | | /* Push to url segment vector */ | 149 | 144k | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); | 150 | 144k | urlSegmentTop++; | 151 | | | 152 | | /* Update currentUrl */ | 153 | 144k | currentUrl = currentUrl.substr(segmentLength); | 154 | 144k | } else { | 155 | | /* Push to url segment vector */ | 156 | 402 | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); | 157 | 402 | urlSegmentTop++; | 158 | | | 159 | | /* Update currentUrl */ | 160 | 402 | currentUrl = currentUrl.substr(segmentLength); | 161 | 402 | } | 162 | 144k | } | 163 | | /* In any case we return it */ | 164 | 168k | return {urlSegmentVector[urlSegment], false}; | 165 | 180k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::getUrlSegment(int) Line | Count | Source | 134 | 901k | inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) { | 135 | 901k | if (urlSegment > urlSegmentTop) { | 136 | | /* Signal as STOP when we have no more URL or stack space */ | 137 | 767k | if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) { | 138 | 283k | return {{}, true}; | 139 | 283k | } | 140 | | | 141 | | /* We always stand on a slash here, so step over it */ | 142 | 484k | currentUrl.remove_prefix(1); | 143 | | | 144 | 484k | auto segmentLength = currentUrl.find('/'); | 145 | 484k | if (segmentLength == std::string::npos) { | 146 | 461k | segmentLength = currentUrl.length(); | 147 | | | 148 | | /* Push to url segment vector */ | 149 | 461k | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); | 150 | 461k | urlSegmentTop++; | 151 | | | 152 | | /* Update currentUrl */ | 153 | 461k | currentUrl = currentUrl.substr(segmentLength); | 154 | 461k | } else { | 155 | | /* Push to url segment vector */ | 156 | 22.7k | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); | 157 | 22.7k | urlSegmentTop++; | 158 | | | 159 | | /* Update currentUrl */ | 160 | 22.7k | currentUrl = currentUrl.substr(segmentLength); | 161 | 22.7k | } | 162 | 484k | } | 163 | | /* In any case we return it */ | 164 | 618k | return {urlSegmentVector[urlSegment], false}; | 165 | 901k | } |
uWS::HttpRouter<StaticData::RouterData>::getUrlSegment(int) Line | Count | Source | 134 | 55.0k | inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) { | 135 | 55.0k | if (urlSegment > urlSegmentTop) { | 136 | | /* Signal as STOP when we have no more URL or stack space */ | 137 | 53.2k | if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) { | 138 | 18.8k | return {{}, true}; | 139 | 18.8k | } | 140 | | | 141 | | /* We always stand on a slash here, so step over it */ | 142 | 34.3k | currentUrl.remove_prefix(1); | 143 | | | 144 | 34.3k | auto segmentLength = currentUrl.find('/'); | 145 | 34.3k | if (segmentLength == std::string::npos) { | 146 | 21.4k | segmentLength = currentUrl.length(); | 147 | | | 148 | | /* Push to url segment vector */ | 149 | 21.4k | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); | 150 | 21.4k | urlSegmentTop++; | 151 | | | 152 | | /* Update currentUrl */ | 153 | 21.4k | currentUrl = currentUrl.substr(segmentLength); | 154 | 21.4k | } else { | 155 | | /* Push to url segment vector */ | 156 | 12.8k | urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength); | 157 | 12.8k | urlSegmentTop++; | 158 | | | 159 | | /* Update currentUrl */ | 160 | 12.8k | currentUrl = currentUrl.substr(segmentLength); | 161 | 12.8k | } | 162 | 34.3k | } | 163 | | /* In any case we return it */ | 164 | 36.2k | return {urlSegmentVector[urlSegment], false}; | 165 | 55.0k | } |
|
166 | | |
167 | | /* Executes as many handlers it can */ |
168 | 761k | bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) { |
169 | | |
170 | 761k | auto [segment, isStop] = getUrlSegment(urlSegment); |
171 | | |
172 | | /* If we are on STOP, return where we may stand */ |
173 | 761k | if (isStop) { |
174 | | /* We have reached accross the entire URL with no stoppage, execute */ |
175 | 229k | for (uint32_t handler : parent->handlers) { |
176 | 226k | if (handlers[handler & HANDLER_MASK](this)) { |
177 | 223k | return true; |
178 | 223k | } |
179 | 226k | } |
180 | | /* We reached the end, so go back */ |
181 | 6.10k | return false; |
182 | 229k | } |
183 | | |
184 | 635k | for (auto &p : parent->children) { |
185 | 635k | if (p->name.length() && p->name[0] == '*') { |
186 | | /* Wildcard match (can be seen as a shortcut) */ |
187 | 299k | for (uint32_t handler : p->handlers) { |
188 | 299k | if (handlers[handler & HANDLER_MASK](this)) { |
189 | 277k | return true; |
190 | 277k | } |
191 | 299k | } |
192 | 336k | } else if (p->name.length() && p->name[0] == ':' && segment.length()) { |
193 | | /* Parameter match */ |
194 | 25.9k | routeParameters.push(segment); |
195 | 25.9k | if (executeHandlers(p.get(), urlSegment + 1, userData)) { |
196 | 22.6k | return true; |
197 | 22.6k | } |
198 | 3.33k | routeParameters.pop(); |
199 | 310k | } else if (p->name == segment) { |
200 | | /* Static match */ |
201 | 221k | if (executeHandlers(p.get(), urlSegment + 1, userData)) { |
202 | 215k | return true; |
203 | 215k | } |
204 | 221k | } |
205 | 635k | } |
206 | 15.7k | return false; |
207 | 531k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::executeHandlers(uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node*, int, uWS::HttpContextData<true>::RouterData&) Line | Count | Source | 168 | 130k | bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) { | 169 | | | 170 | 130k | auto [segment, isStop] = getUrlSegment(urlSegment); | 171 | | | 172 | | /* If we are on STOP, return where we may stand */ | 173 | 130k | if (isStop) { | 174 | | /* We have reached accross the entire URL with no stoppage, execute */ | 175 | 0 | for (uint32_t handler : parent->handlers) { | 176 | 0 | if (handlers[handler & HANDLER_MASK](this)) { | 177 | 0 | return true; | 178 | 0 | } | 179 | 0 | } | 180 | | /* We reached the end, so go back */ | 181 | 0 | return false; | 182 | 0 | } | 183 | | | 184 | 130k | for (auto &p : parent->children) { | 185 | 130k | if (p->name.length() && p->name[0] == '*') { | 186 | | /* Wildcard match (can be seen as a shortcut) */ | 187 | 130k | for (uint32_t handler : p->handlers) { | 188 | 130k | if (handlers[handler & HANDLER_MASK](this)) { | 189 | 126k | return true; | 190 | 126k | } | 191 | 130k | } | 192 | 130k | } else if (p->name.length() && p->name[0] == ':' && segment.length()) { | 193 | | /* Parameter match */ | 194 | 0 | routeParameters.push(segment); | 195 | 0 | if (executeHandlers(p.get(), urlSegment + 1, userData)) { | 196 | 0 | return true; | 197 | 0 | } | 198 | 0 | routeParameters.pop(); | 199 | 0 | } else if (p->name == segment) { | 200 | | /* Static match */ | 201 | 0 | if (executeHandlers(p.get(), urlSegment + 1, userData)) { | 202 | 0 | return true; | 203 | 0 | } | 204 | 0 | } | 205 | 130k | } | 206 | 4.50k | return false; | 207 | 130k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::executeHandlers(uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node*, int, uWS::HttpContextData<false>::RouterData&) Line | Count | Source | 168 | 575k | bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) { | 169 | | | 170 | 575k | auto [segment, isStop] = getUrlSegment(urlSegment); | 171 | | | 172 | | /* If we are on STOP, return where we may stand */ | 173 | 575k | if (isStop) { | 174 | | /* We have reached accross the entire URL with no stoppage, execute */ | 175 | 210k | for (uint32_t handler : parent->handlers) { | 176 | 207k | if (handlers[handler & HANDLER_MASK](this)) { | 177 | 204k | return true; | 178 | 204k | } | 179 | 207k | } | 180 | | /* We reached the end, so go back */ | 181 | 6.00k | return false; | 182 | 210k | } | 183 | | | 184 | 463k | for (auto &p : parent->children) { | 185 | 463k | if (p->name.length() && p->name[0] == '*') { | 186 | | /* Wildcard match (can be seen as a shortcut) */ | 187 | 166k | for (uint32_t handler : p->handlers) { | 188 | 166k | if (handlers[handler & HANDLER_MASK](this)) { | 189 | 149k | return true; | 190 | 149k | } | 191 | 166k | } | 192 | 296k | } else if (p->name.length() && p->name[0] == ':' && segment.length()) { | 193 | | /* Parameter match */ | 194 | 5.54k | routeParameters.push(segment); | 195 | 5.54k | if (executeHandlers(p.get(), urlSegment + 1, userData)) { | 196 | 2.34k | return true; | 197 | 2.34k | } | 198 | 3.19k | routeParameters.pop(); | 199 | 291k | } else if (p->name == segment) { | 200 | | /* Static match */ | 201 | 208k | if (executeHandlers(p.get(), urlSegment + 1, userData)) { | 202 | 204k | return true; | 203 | 204k | } | 204 | 208k | } | 205 | 463k | } | 206 | 8.23k | return false; | 207 | 364k | } |
uWS::HttpRouter<StaticData::RouterData>::executeHandlers(uWS::HttpRouter<StaticData::RouterData>::Node*, int, StaticData::RouterData&) Line | Count | Source | 168 | 54.9k | bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) { | 169 | | | 170 | 54.9k | auto [segment, isStop] = getUrlSegment(urlSegment); | 171 | | | 172 | | /* If we are on STOP, return where we may stand */ | 173 | 54.9k | if (isStop) { | 174 | | /* We have reached accross the entire URL with no stoppage, execute */ | 175 | 18.8k | for (uint32_t handler : parent->handlers) { | 176 | 18.7k | if (handlers[handler & HANDLER_MASK](this)) { | 177 | 18.7k | return true; | 178 | 18.7k | } | 179 | 18.7k | } | 180 | | /* We reached the end, so go back */ | 181 | 99 | return false; | 182 | 18.8k | } | 183 | | | 184 | 41.5k | for (auto &p : parent->children) { | 185 | 41.5k | if (p->name.length() && p->name[0] == '*') { | 186 | | /* Wildcard match (can be seen as a shortcut) */ | 187 | 2.23k | for (uint32_t handler : p->handlers) { | 188 | 2.23k | if (handlers[handler & HANDLER_MASK](this)) { | 189 | 2.10k | return true; | 190 | 2.10k | } | 191 | 2.23k | } | 192 | 39.3k | } else if (p->name.length() && p->name[0] == ':' && segment.length()) { | 193 | | /* Parameter match */ | 194 | 20.4k | routeParameters.push(segment); | 195 | 20.4k | if (executeHandlers(p.get(), urlSegment + 1, userData)) { | 196 | 20.2k | return true; | 197 | 20.2k | } | 198 | 133 | routeParameters.pop(); | 199 | 18.8k | } else if (p->name == segment) { | 200 | | /* Static match */ | 201 | 12.3k | if (executeHandlers(p.get(), urlSegment + 1, userData)) { | 202 | 10.7k | return true; | 203 | 10.7k | } | 204 | 12.3k | } | 205 | 41.5k | } | 206 | 3.05k | return false; | 207 | 36.1k | } |
|
208 | | |
209 | | /* Scans for one matching handler, returning the handler and its priority or UINT32_MAX for not found */ |
210 | 85.2k | uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) { |
211 | 106k | for (std::unique_ptr<Node> &node : root.children) { |
212 | 106k | if (method == node->name) { |
213 | 53.3k | setUrl(pattern); |
214 | 53.3k | Node *n = node.get(); |
215 | 53.3k | for (int i = 0; !getUrlSegment(i).second; i++) { |
216 | | /* Go to next segment or quit */ |
217 | 53.3k | std::string segment = std::string(getUrlSegment(i).first); |
218 | 53.3k | Node *next = nullptr; |
219 | 53.3k | for (std::unique_ptr<Node> &child : n->children) { |
220 | 35.6k | if (((segment.length() && child->name.length() && segment[0] == ':' && child->name[0] == ':') || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) { |
221 | 0 | next = child.get(); |
222 | 0 | break; |
223 | 0 | } |
224 | 35.6k | } |
225 | 53.3k | if (!next) { |
226 | 53.3k | return UINT32_MAX; |
227 | 53.3k | } |
228 | 0 | n = next; |
229 | 0 | } |
230 | | /* Seek for a priority match in the found node */ |
231 | 0 | for (unsigned int i = 0; i < n->handlers.size(); i++) { |
232 | 0 | if ((n->handlers[i] & ~HANDLER_MASK) == priority) { |
233 | 0 | return n->handlers[i]; |
234 | 0 | } |
235 | 0 | } |
236 | 0 | return UINT32_MAX; |
237 | 0 | } |
238 | 106k | } |
239 | 31.8k | return UINT32_MAX; |
240 | 85.2k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::findHandler(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int) Line | Count | Source | 210 | 12.5k | uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) { | 211 | 12.5k | for (std::unique_ptr<Node> &node : root.children) { | 212 | 12.5k | if (method == node->name) { | 213 | 6.26k | setUrl(pattern); | 214 | 6.26k | Node *n = node.get(); | 215 | 6.26k | for (int i = 0; !getUrlSegment(i).second; i++) { | 216 | | /* Go to next segment or quit */ | 217 | 6.26k | std::string segment = std::string(getUrlSegment(i).first); | 218 | 6.26k | Node *next = nullptr; | 219 | 6.26k | for (std::unique_ptr<Node> &child : n->children) { | 220 | 0 | if (((segment.length() && child->name.length() && segment[0] == ':' && child->name[0] == ':') || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) { | 221 | 0 | next = child.get(); | 222 | 0 | break; | 223 | 0 | } | 224 | 0 | } | 225 | 6.26k | if (!next) { | 226 | 6.26k | return UINT32_MAX; | 227 | 6.26k | } | 228 | 0 | n = next; | 229 | 0 | } | 230 | | /* Seek for a priority match in the found node */ | 231 | 0 | for (unsigned int i = 0; i < n->handlers.size(); i++) { | 232 | 0 | if ((n->handlers[i] & ~HANDLER_MASK) == priority) { | 233 | 0 | return n->handlers[i]; | 234 | 0 | } | 235 | 0 | } | 236 | 0 | return UINT32_MAX; | 237 | 0 | } | 238 | 12.5k | } | 239 | 6.26k | return UINT32_MAX; | 240 | 12.5k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::findHandler(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int) Line | Count | Source | 210 | 72.6k | uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) { | 211 | 93.8k | for (std::unique_ptr<Node> &node : root.children) { | 212 | 93.8k | if (method == node->name) { | 213 | 47.1k | setUrl(pattern); | 214 | 47.1k | Node *n = node.get(); | 215 | 47.1k | for (int i = 0; !getUrlSegment(i).second; i++) { | 216 | | /* Go to next segment or quit */ | 217 | 47.1k | std::string segment = std::string(getUrlSegment(i).first); | 218 | 47.1k | Node *next = nullptr; | 219 | 47.1k | for (std::unique_ptr<Node> &child : n->children) { | 220 | 35.6k | if (((segment.length() && child->name.length() && segment[0] == ':' && child->name[0] == ':') || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) { | 221 | 0 | next = child.get(); | 222 | 0 | break; | 223 | 0 | } | 224 | 35.6k | } | 225 | 47.1k | if (!next) { | 226 | 47.1k | return UINT32_MAX; | 227 | 47.1k | } | 228 | 0 | n = next; | 229 | 0 | } | 230 | | /* Seek for a priority match in the found node */ | 231 | 0 | for (unsigned int i = 0; i < n->handlers.size(); i++) { | 232 | 0 | if ((n->handlers[i] & ~HANDLER_MASK) == priority) { | 233 | 0 | return n->handlers[i]; | 234 | 0 | } | 235 | 0 | } | 236 | 0 | return UINT32_MAX; | 237 | 0 | } | 238 | 93.8k | } | 239 | 25.5k | return UINT32_MAX; | 240 | 72.6k | } |
uWS::HttpRouter<StaticData::RouterData>::findHandler(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int) Line | Count | Source | 210 | 16 | uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) { | 211 | 20 | for (std::unique_ptr<Node> &node : root.children) { | 212 | 20 | if (method == node->name) { | 213 | 8 | setUrl(pattern); | 214 | 8 | Node *n = node.get(); | 215 | 8 | for (int i = 0; !getUrlSegment(i).second; i++) { | 216 | | /* Go to next segment or quit */ | 217 | 8 | std::string segment = std::string(getUrlSegment(i).first); | 218 | 8 | Node *next = nullptr; | 219 | 12 | for (std::unique_ptr<Node> &child : n->children) { | 220 | 12 | if (((segment.length() && child->name.length() && segment[0] == ':' && child->name[0] == ':') || child->name == segment) && child->isHighPriority == (priority == HIGH_PRIORITY)) { | 221 | 0 | next = child.get(); | 222 | 0 | break; | 223 | 0 | } | 224 | 12 | } | 225 | 8 | if (!next) { | 226 | 8 | return UINT32_MAX; | 227 | 8 | } | 228 | 0 | n = next; | 229 | 0 | } | 230 | | /* Seek for a priority match in the found node */ | 231 | 0 | for (unsigned int i = 0; i < n->handlers.size(); i++) { | 232 | 0 | if ((n->handlers[i] & ~HANDLER_MASK) == priority) { | 233 | 0 | return n->handlers[i]; | 234 | 0 | } | 235 | 0 | } | 236 | 0 | return UINT32_MAX; | 237 | 0 | } | 238 | 20 | } | 239 | 8 | return UINT32_MAX; | 240 | 16 | } |
|
241 | | |
242 | | public: |
243 | 24.7k | HttpRouter() { |
244 | | /* Always have ANY route */ |
245 | 24.7k | getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false); |
246 | 24.7k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::HttpRouter() Line | Count | Source | 243 | 6.26k | HttpRouter() { | 244 | | /* Always have ANY route */ | 245 | 6.26k | getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false); | 246 | 6.26k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::HttpRouter() Line | Count | Source | 243 | 18.5k | HttpRouter() { | 244 | | /* Always have ANY route */ | 245 | 18.5k | getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false); | 246 | 18.5k | } |
uWS::HttpRouter<StaticData::RouterData>::HttpRouter() Line | Count | Source | 243 | 4 | HttpRouter() { | 244 | | /* Always have ANY route */ | 245 | 4 | getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false); | 246 | 4 | } |
|
247 | | |
248 | 525k | std::pair<int, std::string_view *> getParameters() { |
249 | 525k | return {routeParameters.paramsTop, routeParameters.params}; |
250 | 525k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::getParameters() Line | Count | Source | 248 | 130k | std::pair<int, std::string_view *> getParameters() { | 249 | 130k | return {routeParameters.paramsTop, routeParameters.params}; | 250 | 130k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::getParameters() Line | Count | Source | 248 | 374k | std::pair<int, std::string_view *> getParameters() { | 249 | 374k | return {routeParameters.paramsTop, routeParameters.params}; | 250 | 374k | } |
uWS::HttpRouter<StaticData::RouterData>::getParameters() Line | Count | Source | 248 | 20.9k | std::pair<int, std::string_view *> getParameters() { | 249 | 20.9k | return {routeParameters.paramsTop, routeParameters.params}; | 250 | 20.9k | } |
|
251 | | |
252 | 1.00M | USERDATA &getUserData() { |
253 | 1.00M | return userData; |
254 | 1.00M | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::getUserData() Line | Count | Source | 252 | 256k | USERDATA &getUserData() { | 253 | 256k | return userData; | 254 | 256k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::getUserData() Line | Count | Source | 252 | 728k | USERDATA &getUserData() { | 253 | 728k | return userData; | 254 | 728k | } |
uWS::HttpRouter<StaticData::RouterData>::getUserData() Line | Count | Source | 252 | 22.0k | USERDATA &getUserData() { | 253 | 22.0k | return userData; | 254 | 22.0k | } |
|
255 | | |
256 | | /* Fast path */ |
257 | 502k | bool route(std::string_view method, std::string_view url) { |
258 | | /* Reset url parsing cache */ |
259 | 502k | setUrl(url); |
260 | 502k | routeParameters.reset(); |
261 | | |
262 | | /* Begin by finding the method node */ |
263 | 603k | for (auto &p : root.children) { |
264 | 603k | if (p->name == method) { |
265 | | /* Then route the url */ |
266 | 422k | if (executeHandlers(p.get(), 0, userData)) { |
267 | 410k | return true; |
268 | 410k | } else { |
269 | 11.7k | break; |
270 | 11.7k | } |
271 | 422k | } |
272 | 603k | } |
273 | | |
274 | | /* Always test any route last (this check should not be necessary if we always have at least one handler) */ |
275 | 91.5k | if (root.children.empty()) [[unlikely]] { |
276 | 0 | return false; |
277 | 0 | } |
278 | 91.5k | return executeHandlers(root.children.back().get(), 0, userData); |
279 | 91.5k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::route(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 257 | 126k | bool route(std::string_view method, std::string_view url) { | 258 | | /* Reset url parsing cache */ | 259 | 126k | setUrl(url); | 260 | 126k | routeParameters.reset(); | 261 | | | 262 | | /* Begin by finding the method node */ | 263 | 151k | for (auto &p : root.children) { | 264 | 151k | if (p->name == method) { | 265 | | /* Then route the url */ | 266 | 100k | if (executeHandlers(p.get(), 0, userData)) { | 267 | 96.1k | return true; | 268 | 96.1k | } else { | 269 | 4.50k | break; | 270 | 4.50k | } | 271 | 100k | } | 272 | 151k | } | 273 | | | 274 | | /* Always test any route last (this check should not be necessary if we always have at least one handler) */ | 275 | 30.0k | if (root.children.empty()) [[unlikely]] { | 276 | 0 | return false; | 277 | 0 | } | 278 | 30.0k | return executeHandlers(root.children.back().get(), 0, userData); | 279 | 30.0k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::route(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 257 | 354k | bool route(std::string_view method, std::string_view url) { | 258 | | /* Reset url parsing cache */ | 259 | 354k | setUrl(url); | 260 | 354k | routeParameters.reset(); | 261 | | | 262 | | /* Begin by finding the method node */ | 263 | 425k | for (auto &p : root.children) { | 264 | 425k | if (p->name == method) { | 265 | | /* Then route the url */ | 266 | 301k | if (executeHandlers(p.get(), 0, userData)) { | 267 | 293k | return true; | 268 | 293k | } else { | 269 | 7.15k | break; | 270 | 7.15k | } | 271 | 301k | } | 272 | 425k | } | 273 | | | 274 | | /* Always test any route last (this check should not be necessary if we always have at least one handler) */ | 275 | 60.2k | if (root.children.empty()) [[unlikely]] { | 276 | 0 | return false; | 277 | 0 | } | 278 | 60.2k | return executeHandlers(root.children.back().get(), 0, userData); | 279 | 60.2k | } |
uWS::HttpRouter<StaticData::RouterData>::route(std::__1::basic_string_view<char, std::__1::char_traits<char> >, std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 257 | 22.0k | bool route(std::string_view method, std::string_view url) { | 258 | | /* Reset url parsing cache */ | 259 | 22.0k | setUrl(url); | 260 | 22.0k | routeParameters.reset(); | 261 | | | 262 | | /* Begin by finding the method node */ | 263 | 26.3k | for (auto &p : root.children) { | 264 | 26.3k | if (p->name == method) { | 265 | | /* Then route the url */ | 266 | 20.9k | if (executeHandlers(p.get(), 0, userData)) { | 267 | 20.8k | return true; | 268 | 20.8k | } else { | 269 | 139 | break; | 270 | 139 | } | 271 | 20.9k | } | 272 | 26.3k | } | 273 | | | 274 | | /* Always test any route last (this check should not be necessary if we always have at least one handler) */ | 275 | 1.21k | if (root.children.empty()) [[unlikely]] { | 276 | 0 | return false; | 277 | 0 | } | 278 | 1.21k | return executeHandlers(root.children.back().get(), 0, userData); | 279 | 1.21k | } |
|
280 | | |
281 | | /* Adds the corresponding entires in matching tree and handler list */ |
282 | 85.2k | void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) { |
283 | | /* First remove existing handler */ |
284 | 85.2k | remove(methods[0], pattern, priority); |
285 | | |
286 | 85.2k | for (std::string method : methods) { |
287 | | /* Lookup method */ |
288 | 85.2k | Node *node = getNode(&root, method, false); |
289 | | /* Iterate over all segments */ |
290 | 85.2k | setUrl(pattern); |
291 | 177k | for (int i = 0; !getUrlSegment(i).second; i++) { |
292 | 92.3k | std::string strippedSegment(getUrlSegment(i).first); |
293 | 92.3k | if (strippedSegment.length() && strippedSegment[0] == ':') { |
294 | | /* Parameter routes must be named only : */ |
295 | 7.08k | strippedSegment = ":"; |
296 | 7.08k | } |
297 | 92.3k | node = getNode(node, strippedSegment, priority == HIGH_PRIORITY); |
298 | 92.3k | } |
299 | | /* Insert handler in order sorted by priority (most significant 1 byte) */ |
300 | 85.2k | node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size())); |
301 | 85.2k | } |
302 | | |
303 | | /* Alloate this handler */ |
304 | 85.2k | handlers.emplace_back(std::move(handler)); |
305 | | |
306 | | /* ANY method must be last, GET must be first */ |
307 | 88.7k | std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { |
308 | 88.7k | if (a->name == "GET" && b->name != "GET") { |
309 | 24.7k | return true; |
310 | 63.9k | } else if (b->name == "GET" && a->name != "GET") { |
311 | 42.7k | return false; |
312 | 42.7k | } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) { |
313 | 14.1k | return false; |
314 | 14.1k | } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) { |
315 | 7.07k | return true; |
316 | 7.07k | } else { |
317 | 12 | return a->name < b->name; |
318 | 12 | } |
319 | 88.7k | }); auto uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::add(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ofats::any_invocable<bool (uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>*)>&&, unsigned int)::{lambda(auto:1 const&, auto:2 const&)#1}::operator()<std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node, std::__1::default_delete<std::__1::unique_ptr> >, std::__1::default_delete<std::__1::unique_ptr> >(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node, std::__1::default_delete<std::__1::unique_ptr> > const&, std::__1::default_delete<std::__1::unique_ptr> const&) constLine | Count | Source | 307 | 6.26k | std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { | 308 | 6.26k | if (a->name == "GET" && b->name != "GET") { | 309 | 6.26k | return true; | 310 | 6.26k | } else if (b->name == "GET" && a->name != "GET") { | 311 | 0 | return false; | 312 | 0 | } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) { | 313 | 0 | return false; | 314 | 0 | } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) { | 315 | 0 | return true; | 316 | 0 | } else { | 317 | 0 | return a->name < b->name; | 318 | 0 | } | 319 | 6.26k | }); |
auto uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::add(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ofats::any_invocable<bool (uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>*)>&&, unsigned int)::{lambda(auto:1 const&, auto:2 const&)#1}::operator()<std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node, std::__1::default_delete<std::__1::unique_ptr> >, std::__1::default_delete<std::__1::unique_ptr> >(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node, std::__1::default_delete<std::__1::unique_ptr> > const&, std::__1::default_delete<std::__1::unique_ptr> const&) constLine | Count | Source | 307 | 82.4k | std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { | 308 | 82.4k | if (a->name == "GET" && b->name != "GET") { | 309 | 18.5k | return true; | 310 | 63.9k | } else if (b->name == "GET" && a->name != "GET") { | 311 | 42.7k | return false; | 312 | 42.7k | } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) { | 313 | 14.1k | return false; | 314 | 14.1k | } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) { | 315 | 7.06k | return true; | 316 | 7.06k | } else { | 317 | 0 | return a->name < b->name; | 318 | 0 | } | 319 | 82.4k | }); |
auto uWS::HttpRouter<StaticData::RouterData>::add(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ofats::any_invocable<bool (uWS::HttpRouter<StaticData::RouterData>*)>&&, unsigned int)::{lambda(auto:1 const&, auto:2 const&)#1}::operator()<std::__1::unique_ptr<uWS::HttpRouter<StaticData::RouterData>::Node, std::__1::default_delete<std::__1::unique_ptr> >, std::__1::default_delete<std::__1::unique_ptr> >(std::__1::unique_ptr<uWS::HttpRouter<StaticData::RouterData>::Node, std::__1::default_delete<std::__1::unique_ptr> > const&, std::__1::default_delete<std::__1::unique_ptr> const&) constLine | Count | Source | 307 | 32 | std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { | 308 | 32 | if (a->name == "GET" && b->name != "GET") { | 309 | 0 | return true; | 310 | 32 | } else if (b->name == "GET" && a->name != "GET") { | 311 | 0 | return false; | 312 | 32 | } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) { | 313 | 12 | return false; | 314 | 20 | } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) { | 315 | 8 | return true; | 316 | 12 | } else { | 317 | 12 | return a->name < b->name; | 318 | 12 | } | 319 | 32 | }); |
|
320 | 85.2k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::add(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ofats::any_invocable<bool (uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>*)>&&, unsigned int) Line | Count | Source | 282 | 12.5k | void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) { | 283 | | /* First remove existing handler */ | 284 | 12.5k | remove(methods[0], pattern, priority); | 285 | | | 286 | 12.5k | for (std::string method : methods) { | 287 | | /* Lookup method */ | 288 | 12.5k | Node *node = getNode(&root, method, false); | 289 | | /* Iterate over all segments */ | 290 | 12.5k | setUrl(pattern); | 291 | 25.0k | for (int i = 0; !getUrlSegment(i).second; i++) { | 292 | 12.5k | std::string strippedSegment(getUrlSegment(i).first); | 293 | 12.5k | if (strippedSegment.length() && strippedSegment[0] == ':') { | 294 | | /* Parameter routes must be named only : */ | 295 | 0 | strippedSegment = ":"; | 296 | 0 | } | 297 | 12.5k | node = getNode(node, strippedSegment, priority == HIGH_PRIORITY); | 298 | 12.5k | } | 299 | | /* Insert handler in order sorted by priority (most significant 1 byte) */ | 300 | 12.5k | node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size())); | 301 | 12.5k | } | 302 | | | 303 | | /* Alloate this handler */ | 304 | 12.5k | handlers.emplace_back(std::move(handler)); | 305 | | | 306 | | /* ANY method must be last, GET must be first */ | 307 | 12.5k | std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { | 308 | 12.5k | if (a->name == "GET" && b->name != "GET") { | 309 | 12.5k | return true; | 310 | 12.5k | } else if (b->name == "GET" && a->name != "GET") { | 311 | 12.5k | return false; | 312 | 12.5k | } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) { | 313 | 12.5k | return false; | 314 | 12.5k | } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) { | 315 | 12.5k | return true; | 316 | 12.5k | } else { | 317 | 12.5k | return a->name < b->name; | 318 | 12.5k | } | 319 | 12.5k | }); | 320 | 12.5k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::add(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ofats::any_invocable<bool (uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>*)>&&, unsigned int) Line | Count | Source | 282 | 72.6k | void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) { | 283 | | /* First remove existing handler */ | 284 | 72.6k | remove(methods[0], pattern, priority); | 285 | | | 286 | 72.6k | for (std::string method : methods) { | 287 | | /* Lookup method */ | 288 | 72.6k | Node *node = getNode(&root, method, false); | 289 | | /* Iterate over all segments */ | 290 | 72.6k | setUrl(pattern); | 291 | 152k | for (int i = 0; !getUrlSegment(i).second; i++) { | 292 | 79.7k | std::string strippedSegment(getUrlSegment(i).first); | 293 | 79.7k | if (strippedSegment.length() && strippedSegment[0] == ':') { | 294 | | /* Parameter routes must be named only : */ | 295 | 7.06k | strippedSegment = ":"; | 296 | 7.06k | } | 297 | 79.7k | node = getNode(node, strippedSegment, priority == HIGH_PRIORITY); | 298 | 79.7k | } | 299 | | /* Insert handler in order sorted by priority (most significant 1 byte) */ | 300 | 72.6k | node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size())); | 301 | 72.6k | } | 302 | | | 303 | | /* Alloate this handler */ | 304 | 72.6k | handlers.emplace_back(std::move(handler)); | 305 | | | 306 | | /* ANY method must be last, GET must be first */ | 307 | 72.6k | std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { | 308 | 72.6k | if (a->name == "GET" && b->name != "GET") { | 309 | 72.6k | return true; | 310 | 72.6k | } else if (b->name == "GET" && a->name != "GET") { | 311 | 72.6k | return false; | 312 | 72.6k | } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) { | 313 | 72.6k | return false; | 314 | 72.6k | } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) { | 315 | 72.6k | return true; | 316 | 72.6k | } else { | 317 | 72.6k | return a->name < b->name; | 318 | 72.6k | } | 319 | 72.6k | }); | 320 | 72.6k | } |
uWS::HttpRouter<StaticData::RouterData>::add(std::__1::vector<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, ofats::any_invocable<bool (uWS::HttpRouter<StaticData::RouterData>*)>&&, unsigned int) Line | Count | Source | 282 | 16 | void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) { | 283 | | /* First remove existing handler */ | 284 | 16 | remove(methods[0], pattern, priority); | 285 | | | 286 | 16 | for (std::string method : methods) { | 287 | | /* Lookup method */ | 288 | 16 | Node *node = getNode(&root, method, false); | 289 | | /* Iterate over all segments */ | 290 | 16 | setUrl(pattern); | 291 | 44 | for (int i = 0; !getUrlSegment(i).second; i++) { | 292 | 28 | std::string strippedSegment(getUrlSegment(i).first); | 293 | 28 | if (strippedSegment.length() && strippedSegment[0] == ':') { | 294 | | /* Parameter routes must be named only : */ | 295 | 16 | strippedSegment = ":"; | 296 | 16 | } | 297 | 28 | node = getNode(node, strippedSegment, priority == HIGH_PRIORITY); | 298 | 28 | } | 299 | | /* Insert handler in order sorted by priority (most significant 1 byte) */ | 300 | 16 | node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size())); | 301 | 16 | } | 302 | | | 303 | | /* Alloate this handler */ | 304 | 16 | handlers.emplace_back(std::move(handler)); | 305 | | | 306 | | /* ANY method must be last, GET must be first */ | 307 | 16 | std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) { | 308 | 16 | if (a->name == "GET" && b->name != "GET") { | 309 | 16 | return true; | 310 | 16 | } else if (b->name == "GET" && a->name != "GET") { | 311 | 16 | return false; | 312 | 16 | } else if (a->name == ANY_METHOD_TOKEN && b->name != ANY_METHOD_TOKEN) { | 313 | 16 | return false; | 314 | 16 | } else if (b->name == ANY_METHOD_TOKEN && a->name != ANY_METHOD_TOKEN) { | 315 | 16 | return true; | 316 | 16 | } else { | 317 | 16 | return a->name < b->name; | 318 | 16 | } | 319 | 16 | }); | 320 | 16 | } |
|
321 | | |
322 | 0 | bool cullNode(Node *parent, Node *node, uint32_t handler) { |
323 | | /* For all children */ |
324 | 0 | for (unsigned int i = 0; i < node->children.size(); ) { |
325 | | /* Optimization todo: only enter those with same isHighPrioirty */ |
326 | | /* Enter child so we get depth first */ |
327 | 0 | if (!cullNode(node, node->children[i].get(), handler)) { |
328 | | /* Only increase if this node was not removed */ |
329 | 0 | i++; |
330 | 0 | } |
331 | 0 | } |
332 | | |
333 | | /* Cull this node (but skip the root node) */ |
334 | 0 | if (parent /*&& parent != &root*/) { |
335 | | /* Scan for equal (remove), greater (lower by 1) */ |
336 | 0 | for (auto it = node->handlers.begin(); it != node->handlers.end(); ) { |
337 | 0 | if ((*it & HANDLER_MASK) > (handler & HANDLER_MASK)) { |
338 | 0 | *it = ((*it & HANDLER_MASK) - 1) | (*it & ~HANDLER_MASK); |
339 | 0 | } else if (*it == handler) { |
340 | 0 | it = node->handlers.erase(it); |
341 | 0 | continue; |
342 | 0 | } |
343 | 0 | it++; |
344 | 0 | } |
345 | | |
346 | | /* If we have no children and no handlers, remove us from the parent->children list */ |
347 | 0 | if (!node->handlers.size() && !node->children.size()) { |
348 | 0 | parent->children.erase(std::find_if(parent->children.begin(), parent->children.end(), [node](const std::unique_ptr<Node> &a) { |
349 | 0 | return a.get() == node; |
350 | 0 | })); Unexecuted instantiation: uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::cullNode(uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node*, uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node*, unsigned int)::{lambda(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node> > const&)#1}::operator()(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node> > const&) constUnexecuted instantiation: uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::cullNode(uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node*, uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node*, unsigned int)::{lambda(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node> > const&)#1}::operator()(std::__1::unique_ptr<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node> > const&) constUnexecuted instantiation: uWS::HttpRouter<StaticData::RouterData>::cullNode(uWS::HttpRouter<StaticData::RouterData>::Node*, uWS::HttpRouter<StaticData::RouterData>::Node*, unsigned int)::{lambda(std::__1::unique_ptr<uWS::HttpRouter<StaticData::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<StaticData::RouterData>::Node> > const&)#1}::operator()(std::__1::unique_ptr<uWS::HttpRouter<StaticData::RouterData>::Node, std::__1::default_delete<uWS::HttpRouter<StaticData::RouterData>::Node> > const&) const |
351 | | /* Returning true means we removed node from parent */ |
352 | 0 | return true; |
353 | 0 | } |
354 | 0 | } |
355 | | |
356 | 0 | return false; |
357 | 0 | } Unexecuted instantiation: uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::cullNode(uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node*, uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::Node*, unsigned int) Unexecuted instantiation: uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::cullNode(uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node*, uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::Node*, unsigned int) Unexecuted instantiation: uWS::HttpRouter<StaticData::RouterData>::cullNode(uWS::HttpRouter<StaticData::RouterData>::Node*, uWS::HttpRouter<StaticData::RouterData>::Node*, unsigned int) |
358 | | |
359 | | /* Removes ALL routes with the same handler as can be found with the given parameters. |
360 | | * Removing a wildcard is done by removing ONE OF the methods the wildcard would match with. |
361 | | * Example: If wildcard includes POST, GET, PUT, you can remove ALL THREE by removing GET. */ |
362 | 85.2k | bool remove(std::string method, std::string pattern, uint32_t priority) { |
363 | 85.2k | uint32_t handler = findHandler(method, pattern, priority); |
364 | 85.2k | if (handler == UINT32_MAX) { |
365 | | /* Not found or already removed, do nothing */ |
366 | 85.2k | return false; |
367 | 85.2k | } |
368 | | |
369 | | /* Cull the entire tree */ |
370 | | /* For all nodes in depth first tree traveral; |
371 | | * if node contains handler - remove the handler - |
372 | | * if node holds no handlers after removal, remove the node and return */ |
373 | 0 | cullNode(nullptr, &root, handler); |
374 | | |
375 | | /* Now remove the actual handler */ |
376 | 0 | handlers.erase(handlers.begin() + (handler & HANDLER_MASK)); |
377 | |
|
378 | 0 | return true; |
379 | 85.2k | } uWS::HttpRouter<uWS::HttpContextData<true>::RouterData>::remove(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int) Line | Count | Source | 362 | 12.5k | bool remove(std::string method, std::string pattern, uint32_t priority) { | 363 | 12.5k | uint32_t handler = findHandler(method, pattern, priority); | 364 | 12.5k | if (handler == UINT32_MAX) { | 365 | | /* Not found or already removed, do nothing */ | 366 | 12.5k | return false; | 367 | 12.5k | } | 368 | | | 369 | | /* Cull the entire tree */ | 370 | | /* For all nodes in depth first tree traveral; | 371 | | * if node contains handler - remove the handler - | 372 | | * if node holds no handlers after removal, remove the node and return */ | 373 | 0 | cullNode(nullptr, &root, handler); | 374 | | | 375 | | /* Now remove the actual handler */ | 376 | 0 | handlers.erase(handlers.begin() + (handler & HANDLER_MASK)); | 377 | |
| 378 | 0 | return true; | 379 | 12.5k | } |
uWS::HttpRouter<uWS::HttpContextData<false>::RouterData>::remove(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int) Line | Count | Source | 362 | 72.6k | bool remove(std::string method, std::string pattern, uint32_t priority) { | 363 | 72.6k | uint32_t handler = findHandler(method, pattern, priority); | 364 | 72.6k | if (handler == UINT32_MAX) { | 365 | | /* Not found or already removed, do nothing */ | 366 | 72.6k | return false; | 367 | 72.6k | } | 368 | | | 369 | | /* Cull the entire tree */ | 370 | | /* For all nodes in depth first tree traveral; | 371 | | * if node contains handler - remove the handler - | 372 | | * if node holds no handlers after removal, remove the node and return */ | 373 | 0 | cullNode(nullptr, &root, handler); | 374 | | | 375 | | /* Now remove the actual handler */ | 376 | 0 | handlers.erase(handlers.begin() + (handler & HANDLER_MASK)); | 377 | |
| 378 | 0 | return true; | 379 | 72.6k | } |
uWS::HttpRouter<StaticData::RouterData>::remove(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, unsigned int) Line | Count | Source | 362 | 16 | bool remove(std::string method, std::string pattern, uint32_t priority) { | 363 | 16 | uint32_t handler = findHandler(method, pattern, priority); | 364 | 16 | if (handler == UINT32_MAX) { | 365 | | /* Not found or already removed, do nothing */ | 366 | 16 | return false; | 367 | 16 | } | 368 | | | 369 | | /* Cull the entire tree */ | 370 | | /* For all nodes in depth first tree traveral; | 371 | | * if node contains handler - remove the handler - | 372 | | * if node holds no handlers after removal, remove the node and return */ | 373 | 0 | cullNode(nullptr, &root, handler); | 374 | | | 375 | | /* Now remove the actual handler */ | 376 | 0 | handlers.erase(handlers.begin() + (handler & HANDLER_MASK)); | 377 | |
| 378 | 0 | return true; | 379 | 16 | } |
|
380 | | }; |
381 | | |
382 | | } |
383 | | |
384 | | #endif // UWS_HTTPROUTER_HPP |