opal-up 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -18,14 +18,14 @@
18
18
  #ifndef UWS_HTTPROUTER_HPP
19
19
  #define UWS_HTTPROUTER_HPP
20
20
 
21
- #include <map>
22
- #include <vector>
23
- #include <cstring>
24
- #include <string_view>
25
- #include <string>
26
21
  #include <algorithm>
22
+ #include <cstring>
23
+ #include <map>
27
24
  #include <memory>
25
+ #include <string>
26
+ #include <string_view>
28
27
  #include <utility>
28
+ #include <vector>
29
29
 
30
30
  #include <iostream>
31
31
 
@@ -33,348 +33,366 @@
33
33
 
34
34
  namespace uWS {
35
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;
36
+ template <class USERDATA> struct HttpRouter {
37
+ static constexpr std::string_view ANY_METHOD_TOKEN = "*";
38
+ static const uint32_t HIGH_PRIORITY = 0xd0000000,
39
+ MEDIUM_PRIORITY = 0xe0000000, LOW_PRIORITY = 0xf0000000;
40
40
 
41
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
- Node(std::string name) : name(name) {}
64
- } root = {"rootNode"};
65
-
66
- /* Sort wildcards after alphanum */
67
- int lexicalOrder(std::string &name) {
68
- if (!name.length()) {
69
- return 2;
70
- }
71
- if (name[0] == ':') {
72
- return 1;
73
- }
74
- if (name[0] == '*') {
75
- return 0;
76
- }
77
- return 2;
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
+ Node(std::string name) : name(name) {}
64
+ } root = {"rootNode"};
65
+
66
+ /* Sort wildcards after alphanum */
67
+ int lexicalOrder(std::string &name) {
68
+ if (!name.length()) {
69
+ return 2;
78
70
  }
79
-
80
- /* Advance from parent to child, adding child if necessary */
81
- Node *getNode(Node *parent, std::string child, bool isHighPriority) {
82
- for (std::unique_ptr<Node> &node : parent->children) {
83
- if (node->name == child && node->isHighPriority == isHighPriority) {
84
- return node.get();
85
- }
86
- }
87
-
88
- /* Insert sorted, but keep order if parent is root (we sort methods by priority elsewhere) */
89
- std::unique_ptr<Node> newNode(new Node(child));
90
- newNode->isHighPriority = isHighPriority;
91
- return parent->children.emplace(std::upper_bound(parent->children.begin(), parent->children.end(), newNode, [parent, this](auto &a, auto &b) {
92
-
93
- if (a->isHighPriority != b->isHighPriority) {
94
- return a->isHighPriority;
95
- }
96
-
97
- return b->name.length() && (parent != &root) && (lexicalOrder(b->name) < lexicalOrder(a->name));
98
- }), std::move(newNode))->get();
71
+ if (name[0] == ':') {
72
+ return 1;
99
73
  }
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
- void reset() {
109
- paramsTop = -1;
110
- }
111
-
112
- void push(std::string_view param) {
113
- /* We check these bounds indirectly via the urlSegments limit */
114
- params[++paramsTop] = param;
115
- }
116
-
117
- void pop() {
118
- /* Same here, we cannot pop outside */
119
- paramsTop--;
120
- }
121
- } routeParameters;
122
-
123
- /* Set URL for router. Will reset any URL cache */
124
- 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
- currentUrl = url;
130
- urlSegmentTop = -1;
74
+ if (name[0] == '*') {
75
+ return 0;
76
+ }
77
+ return 2;
78
+ }
79
+
80
+ /* Advance from parent to child, adding child if necessary */
81
+ Node *getNode(Node *parent, std::string child, bool isHighPriority) {
82
+ for (std::unique_ptr<Node> &node : parent->children) {
83
+ if (node->name == child && node->isHighPriority == isHighPriority) {
84
+ return node.get();
85
+ }
131
86
  }
132
87
 
133
- /* Lazily parse or read from cache */
134
- inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {
135
- if (urlSegment > urlSegmentTop) {
136
- /* Signal as STOP when we have no more URL or stack space */
137
- if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) {
138
- return {{}, true};
139
- }
140
-
141
- /* We always stand on a slash here, so step over it */
142
- currentUrl.remove_prefix(1);
88
+ /* Insert sorted, but keep order if parent is root (we sort methods by
89
+ * priority elsewhere) */
90
+ std::unique_ptr<Node> newNode(new Node(child));
91
+ newNode->isHighPriority = isHighPriority;
92
+ return parent->children
93
+ .emplace(std::upper_bound(
94
+ parent->children.begin(), parent->children.end(), newNode,
95
+ [parent, this](auto &a, auto &b) {
96
+ if (a->isHighPriority != b->isHighPriority) {
97
+ return a->isHighPriority;
98
+ }
99
+
100
+ return b->name.length() && (parent != &root) &&
101
+ (lexicalOrder(b->name) < lexicalOrder(a->name));
102
+ }),
103
+ std::move(newNode))
104
+ ->get();
105
+ }
106
+
107
+ /* Basically a pre-allocated stack */
108
+ struct RouteParameters {
109
+ friend struct HttpRouter;
110
+
111
+ private:
112
+ std::string_view params[MAX_URL_SEGMENTS];
113
+ int paramsTop;
114
+
115
+ void reset() { paramsTop = -1; }
116
+
117
+ void push(std::string_view param) {
118
+ /* We check these bounds indirectly via the urlSegments limit */
119
+ params[++paramsTop] = param;
120
+ }
143
121
 
144
- auto segmentLength = currentUrl.find('/');
145
- if (segmentLength == std::string::npos) {
146
- segmentLength = currentUrl.length();
122
+ void pop() {
123
+ /* Same here, we cannot pop outside */
124
+ paramsTop--;
125
+ }
126
+ } routeParameters;
127
+
128
+ /* Set URL for router. Will reset any URL cache */
129
+ inline void setUrl(std::string_view url) {
130
+
131
+ /* Todo: URL may also start with "http://domain/" or "*", not only "/" */
132
+
133
+ /* We expect to stand on a slash */
134
+ currentUrl = url;
135
+ urlSegmentTop = -1;
136
+ }
137
+
138
+ /* Lazily parse or read from cache */
139
+ inline std::pair<std::string_view, bool> getUrlSegment(int urlSegment) {
140
+ if (urlSegment > urlSegmentTop) {
141
+ /* Signal as STOP when we have no more URL or stack space */
142
+ if (!currentUrl.length() || urlSegment > int(MAX_URL_SEGMENTS - 1)) {
143
+ return {{}, true};
144
+ }
145
+
146
+ /* We always stand on a slash here, so step over it */
147
+ currentUrl.remove_prefix(1);
148
+
149
+ auto segmentLength = currentUrl.find('/');
150
+ if (segmentLength == std::string::npos) {
151
+ segmentLength = currentUrl.length();
152
+
153
+ /* Push to url segment vector */
154
+ urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
155
+ urlSegmentTop++;
156
+
157
+ /* Update currentUrl */
158
+ currentUrl = currentUrl.substr(segmentLength);
159
+ } else {
160
+ /* Push to url segment vector */
161
+ urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
162
+ urlSegmentTop++;
163
+
164
+ /* Update currentUrl */
165
+ currentUrl = currentUrl.substr(segmentLength);
166
+ }
167
+ }
168
+ /* In any case we return it */
169
+ return {urlSegmentVector[urlSegment], false};
170
+ }
147
171
 
148
- /* Push to url segment vector */
149
- urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
150
- urlSegmentTop++;
172
+ /* Executes as many handlers it can */
173
+ bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) {
151
174
 
152
- /* Update currentUrl */
153
- currentUrl = currentUrl.substr(segmentLength);
154
- } else {
155
- /* Push to url segment vector */
156
- urlSegmentVector[urlSegment] = currentUrl.substr(0, segmentLength);
157
- urlSegmentTop++;
175
+ auto [segment, isStop] = getUrlSegment(urlSegment);
158
176
 
159
- /* Update currentUrl */
160
- currentUrl = currentUrl.substr(segmentLength);
161
- }
177
+ /* If we are on STOP, return where we may stand */
178
+ if (isStop) {
179
+ /* We have reached accross the entire URL with no stoppage, execute */
180
+ for (uint32_t handler : parent->handlers) {
181
+ if (handlers[handler & HANDLER_MASK](this)) {
182
+ return true;
162
183
  }
163
- /* In any case we return it */
164
- return {urlSegmentVector[urlSegment], false};
184
+ }
185
+ /* We reached the end, so go back */
186
+ return false;
165
187
  }
166
188
 
167
- /* Executes as many handlers it can */
168
- bool executeHandlers(Node *parent, int urlSegment, USERDATA &userData) {
169
-
170
- auto [segment, isStop] = getUrlSegment(urlSegment);
171
-
172
- /* If we are on STOP, return where we may stand */
173
- if (isStop) {
174
- /* We have reached accross the entire URL with no stoppage, execute */
175
- for (uint32_t handler : parent->handlers) {
176
- if (handlers[handler & HANDLER_MASK](this)) {
177
- return true;
178
- }
179
- }
180
- /* We reached the end, so go back */
181
- return false;
189
+ for (auto &p : parent->children) {
190
+ if (p->name.length() && p->name[0] == '*') {
191
+ /* Wildcard match (can be seen as a shortcut) */
192
+ for (uint32_t handler : p->handlers) {
193
+ if (handlers[handler & HANDLER_MASK](this)) {
194
+ return true;
195
+ }
182
196
  }
183
-
184
- for (auto &p : parent->children) {
185
- if (p->name.length() && p->name[0] == '*') {
186
- /* Wildcard match (can be seen as a shortcut) */
187
- for (uint32_t handler : p->handlers) {
188
- if (handlers[handler & HANDLER_MASK](this)) {
189
- return true;
190
- }
191
- }
192
- } else if (p->name.length() && p->name[0] == ':' && segment.length()) {
193
- /* Parameter match */
194
- routeParameters.push(segment);
195
- if (executeHandlers(p.get(), urlSegment + 1, userData)) {
196
- return true;
197
- }
198
- routeParameters.pop();
199
- } else if (p->name == segment) {
200
- /* Static match */
201
- if (executeHandlers(p.get(), urlSegment + 1, userData)) {
202
- return true;
203
- }
204
- }
197
+ } else if (p->name.length() && p->name[0] == ':' && segment.length()) {
198
+ /* Parameter match */
199
+ routeParameters.push(segment);
200
+ if (executeHandlers(p.get(), urlSegment + 1, userData)) {
201
+ return true;
202
+ }
203
+ routeParameters.pop();
204
+ } else if (p->name == segment) {
205
+ /* Static match */
206
+ if (executeHandlers(p.get(), urlSegment + 1, userData)) {
207
+ return true;
205
208
  }
206
- return false;
209
+ }
207
210
  }
208
-
209
- /* Scans for one matching handler, returning the handler and its priority or UINT32_MAX for not found */
210
- uint32_t findHandler(std::string method, std::string pattern, uint32_t priority) {
211
- for (std::unique_ptr<Node> &node : root.children) {
212
- if (method == node->name) {
213
- setUrl(pattern);
214
- Node *n = node.get();
215
- for (int i = 0; !getUrlSegment(i).second; i++) {
216
- /* Go to next segment or quit */
217
- std::string segment = std::string(getUrlSegment(i).first);
218
- Node *next = nullptr;
219
- for (std::unique_ptr<Node> &child : n->children) {
220
- if (child->name == segment && child->isHighPriority == (priority == HIGH_PRIORITY)) {
221
- next = child.get();
222
- break;
223
- }
224
- }
225
- if (!next) {
226
- return UINT32_MAX;
227
- }
228
- n = next;
229
- }
230
- /* Seek for a priority match in the found node */
231
- for (unsigned int i = 0; i < n->handlers.size(); i++) {
232
- if ((n->handlers[i] & ~HANDLER_MASK) == priority) {
233
- return n->handlers[i];
234
- }
235
- }
236
- return UINT32_MAX;
211
+ return false;
212
+ }
213
+
214
+ /* Scans for one matching handler, returning the handler and its priority or
215
+ * UINT32_MAX for not found */
216
+ uint32_t findHandler(std::string method, std::string pattern,
217
+ uint32_t priority) {
218
+ for (std::unique_ptr<Node> &node : root.children) {
219
+ if (method == node->name) {
220
+ setUrl(pattern);
221
+ Node *n = node.get();
222
+ for (int i = 0; !getUrlSegment(i).second; i++) {
223
+ /* Go to next segment or quit */
224
+ std::string segment = std::string(getUrlSegment(i).first);
225
+ Node *next = nullptr;
226
+ for (std::unique_ptr<Node> &child : n->children) {
227
+ if (child->name == segment &&
228
+ child->isHighPriority == (priority == HIGH_PRIORITY)) {
229
+ next = child.get();
230
+ break;
237
231
  }
232
+ }
233
+ if (!next) {
234
+ return UINT32_MAX;
235
+ }
236
+ n = next;
237
+ }
238
+ /* Seek for a priority match in the found node */
239
+ for (unsigned int i = 0; i < n->handlers.size(); i++) {
240
+ if ((n->handlers[i] & ~HANDLER_MASK) == priority) {
241
+ return n->handlers[i];
242
+ }
238
243
  }
239
244
  return UINT32_MAX;
245
+ }
240
246
  }
247
+ return UINT32_MAX;
248
+ }
241
249
 
242
250
  public:
243
- HttpRouter() {
244
- /* Always have ANY route */
245
- getNode(&root, std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()), false);
246
- }
247
-
248
- std::pair<int, std::string_view *> getParameters() {
249
- return {routeParameters.paramsTop, routeParameters.params};
251
+ HttpRouter() {
252
+ /* Always have ANY route */
253
+ getNode(&root,
254
+ std::string(ANY_METHOD_TOKEN.data(), ANY_METHOD_TOKEN.length()),
255
+ false);
256
+ }
257
+
258
+ std::pair<int, std::string_view *> getParameters() {
259
+ return {routeParameters.paramsTop, routeParameters.params};
260
+ }
261
+
262
+ USERDATA &getUserData() { return userData; }
263
+
264
+ /* Fast path */
265
+ bool route(std::string_view method, std::string_view url) {
266
+ /* Reset url parsing cache */
267
+ setUrl(url);
268
+ routeParameters.reset();
269
+
270
+ /* Begin by finding the method node */
271
+ for (auto &p : root.children) {
272
+ if (p->name == method) {
273
+ /* Then route the url */
274
+ if (executeHandlers(p.get(), 0, userData)) {
275
+ return true;
276
+ } else {
277
+ break;
278
+ }
279
+ }
250
280
  }
251
281
 
252
- USERDATA &getUserData() {
253
- return userData;
282
+ /* Always test any route last */
283
+ return executeHandlers(root.children.back().get(), 0, userData);
284
+ }
285
+
286
+ /* Adds the corresponding entires in matching tree and handler list */
287
+ void add(std::vector<std::string> methods, std::string pattern,
288
+ MoveOnlyFunction<bool(HttpRouter *)> &&handler,
289
+ uint32_t priority = MEDIUM_PRIORITY) {
290
+ /* First remove existing handler */
291
+ remove(methods[0], pattern, priority);
292
+
293
+ for (std::string method : methods) {
294
+ /* Lookup method */
295
+ Node *node = getNode(&root, method, false);
296
+ /* Iterate over all segments */
297
+ setUrl(pattern);
298
+ for (int i = 0; !getUrlSegment(i).second; i++) {
299
+ std::string strippedSegment(getUrlSegment(i).first);
300
+ if (strippedSegment.length() && strippedSegment[0] == ':') {
301
+ /* Parameter routes must be named only : */
302
+ strippedSegment = ":";
303
+ }
304
+ node = getNode(node, strippedSegment, priority == HIGH_PRIORITY);
305
+ }
306
+ /* Insert handler in order sorted by priority (most significant 1 byte) */
307
+ node->handlers.insert(
308
+ std::upper_bound(node->handlers.begin(), node->handlers.end(),
309
+ (uint32_t)(priority | handlers.size())),
310
+ (uint32_t)(priority | handlers.size()));
254
311
  }
255
312
 
256
- /* Fast path */
257
- bool route(std::string_view method, std::string_view url) {
258
- /* Reset url parsing cache */
259
- setUrl(url);
260
- routeParameters.reset();
261
-
262
- /* Begin by finding the method node */
263
- for (auto &p : root.children) {
264
- if (p->name == method) {
265
- /* Then route the url */
266
- if (executeHandlers(p.get(), 0, userData)) {
267
- return true;
313
+ /* Alloate this handler */
314
+ handlers.emplace_back(std::move(handler));
315
+
316
+ /* ANY method must be last, GET must be first */
317
+ std::sort(root.children.begin(), root.children.end(),
318
+ [](const auto &a, const auto &b) {
319
+ /* Assuming the list of methods is unique, non-repeating */
320
+ if (a->name == "GET") {
321
+ return true;
322
+ } else if (b->name == "GET") {
323
+ return false;
324
+ } else if (a->name == ANY_METHOD_TOKEN) {
325
+ return false;
326
+ } else if (b->name == ANY_METHOD_TOKEN) {
327
+ return true;
268
328
  } else {
269
- break;
329
+ return a->name < b->name;
270
330
  }
271
- }
272
- }
273
-
274
- /* Always test any route last */
275
- return executeHandlers(root.children.back().get(), 0, userData);
331
+ });
332
+ }
333
+
334
+ bool cullNode(Node *parent, Node *node, uint32_t handler) {
335
+ /* For all children */
336
+ for (unsigned int i = 0; i < node->children.size();) {
337
+ /* Optimization todo: only enter those with same isHighPrioirty */
338
+ /* Enter child so we get depth first */
339
+ if (!cullNode(node, node->children[i].get(), handler)) {
340
+ /* Only increase if this node was not removed */
341
+ i++;
342
+ }
276
343
  }
277
344
 
278
- /* Adds the corresponding entires in matching tree and handler list */
279
- void add(std::vector<std::string> methods, std::string pattern, MoveOnlyFunction<bool(HttpRouter *)> &&handler, uint32_t priority = MEDIUM_PRIORITY) {
280
- /* First remove existing handler */
281
- remove(methods[0], pattern, priority);
282
-
283
- for (std::string method : methods) {
284
- /* Lookup method */
285
- Node *node = getNode(&root, method, false);
286
- /* Iterate over all segments */
287
- setUrl(pattern);
288
- for (int i = 0; !getUrlSegment(i).second; i++) {
289
- std::string strippedSegment(getUrlSegment(i).first);
290
- if (strippedSegment.length() && strippedSegment[0] == ':') {
291
- /* Parameter routes must be named only : */
292
- strippedSegment = ":";
293
- }
294
- node = getNode(node, strippedSegment, priority == HIGH_PRIORITY);
295
- }
296
- /* Insert handler in order sorted by priority (most significant 1 byte) */
297
- node->handlers.insert(std::upper_bound(node->handlers.begin(), node->handlers.end(), (uint32_t) (priority | handlers.size())), (uint32_t) (priority | handlers.size()));
345
+ /* Cull this node (but skip the root node) */
346
+ if (parent /*&& parent != &root*/) {
347
+ /* Scan for equal (remove), greater (lower by 1) */
348
+ for (auto it = node->handlers.begin(); it != node->handlers.end();) {
349
+ if ((*it & HANDLER_MASK) > (handler & HANDLER_MASK)) {
350
+ *it = ((*it & HANDLER_MASK) - 1) | (*it & ~HANDLER_MASK);
351
+ } else if (*it == handler) {
352
+ it = node->handlers.erase(it);
353
+ continue;
298
354
  }
299
-
300
- /* Alloate this handler */
301
- handlers.emplace_back(std::move(handler));
302
-
303
- /* ANY method must be last, GET must be first */
304
- std::sort(root.children.begin(), root.children.end(), [](const auto &a, const auto &b) {
305
- /* Assuming the list of methods is unique, non-repeating */
306
- if (a->name == "GET") {
307
- return true;
308
- } else if (b->name == "GET") {
309
- return false;
310
- } else if (a->name == ANY_METHOD_TOKEN) {
311
- return false;
312
- } else if (b->name == ANY_METHOD_TOKEN) {
313
- return true;
314
- } else {
315
- return a->name < b->name;
316
- }
317
- });
355
+ it++;
356
+ }
357
+
358
+ /* If we have no children and no handlers, remove us from the
359
+ * parent->children list */
360
+ if (!node->handlers.size() && !node->children.size()) {
361
+ parent->children.erase(
362
+ std::find_if(parent->children.begin(), parent->children.end(),
363
+ [node](const std::unique_ptr<Node> &a) {
364
+ return a.get() == node;
365
+ }));
366
+ /* Returning true means we removed node from parent */
367
+ return true;
368
+ }
318
369
  }
319
370
 
320
- bool cullNode(Node *parent, Node *node, uint32_t handler) {
321
- /* For all children */
322
- for (unsigned int i = 0; i < node->children.size(); ) {
323
- /* Optimization todo: only enter those with same isHighPrioirty */
324
- /* Enter child so we get depth first */
325
- if (!cullNode(node, node->children[i].get(), handler)) {
326
- /* Only increase if this node was not removed */
327
- i++;
328
- }
329
- }
330
-
331
- /* Cull this node (but skip the root node) */
332
- if (parent /*&& parent != &root*/) {
333
- /* Scan for equal (remove), greater (lower by 1) */
334
- for (auto it = node->handlers.begin(); it != node->handlers.end(); ) {
335
- if ((*it & HANDLER_MASK) > (handler & HANDLER_MASK)) {
336
- *it = ((*it & HANDLER_MASK) - 1) | (*it & ~HANDLER_MASK);
337
- } else if (*it == handler) {
338
- it = node->handlers.erase(it);
339
- continue;
340
- }
341
- it++;
342
- }
343
-
344
- /* If we have no children and no handlers, remove us from the parent->children list */
345
- if (!node->handlers.size() && !node->children.size()) {
346
- parent->children.erase(std::find_if(parent->children.begin(), parent->children.end(), [node](const std::unique_ptr<Node> &a) {
347
- return a.get() == node;
348
- }));
349
- /* Returning true means we removed node from parent */
350
- return true;
351
- }
352
- }
353
-
354
- return false;
371
+ return false;
372
+ }
373
+
374
+ /* Removes ALL routes with the same handler as can be found with the given
375
+ * parameters. Removing a wildcard is done by removing ONE OF the methods the
376
+ * wildcard would match with. Example: If wildcard includes POST, GET, PUT,
377
+ * you can remove ALL THREE by removing GET. */
378
+ void remove(std::string method, std::string pattern, uint32_t priority) {
379
+ uint32_t handler = findHandler(method, pattern, priority);
380
+ if (handler == UINT32_MAX) {
381
+ /* Not found or already removed, do nothing */
382
+ return;
355
383
  }
356
384
 
357
- /* Removes ALL routes with the same handler as can be found with the given parameters.
358
- * Removing a wildcard is done by removing ONE OF the methods the wildcard would match with.
359
- * Example: If wildcard includes POST, GET, PUT, you can remove ALL THREE by removing GET. */
360
- void remove(std::string method, std::string pattern, uint32_t priority) {
361
- uint32_t handler = findHandler(method, pattern, priority);
362
- if (handler == UINT32_MAX) {
363
- /* Not found or already removed, do nothing */
364
- return;
365
- }
366
-
367
- /* Cull the entire tree */
368
- /* For all nodes in depth first tree traveral;
369
- * if node contains handler - remove the handler -
370
- * if node holds no handlers after removal, remove the node and return */
371
- cullNode(nullptr, &root, handler);
385
+ /* Cull the entire tree */
386
+ /* For all nodes in depth first tree traveral;
387
+ * if node contains handler - remove the handler -
388
+ * if node holds no handlers after removal, remove the node and return */
389
+ cullNode(nullptr, &root, handler);
372
390
 
373
- /* Now remove the actual handler */
374
- handlers.erase(handlers.begin() + (handler & HANDLER_MASK));
375
- }
391
+ /* Now remove the actual handler */
392
+ handlers.erase(handlers.begin() + (handler & HANDLER_MASK));
393
+ }
376
394
  };
377
395
 
378
- }
396
+ } // namespace uWS
379
397
 
380
398
  #endif // UWS_HTTPROUTER_HPP