Coverage Report

Created: 2026-09-14 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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>&) const
Line
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>&) const
Line
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>&) const
Line
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&) const
Line
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&) const
Line
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&) const
Line
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&) const
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)::{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&) const
Unexecuted 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