Coverage Report

Created: 2025-06-13 06:09

/src/uWebSockets/src/QueryParser.h
Line
Count
Source (jump to first uncovered line)
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
/* This module implements URI query parsing and retrieval of value given key */
19
20
#ifndef UWS_QUERYPARSER_H
21
#define UWS_QUERYPARSER_H
22
23
#include <string_view>
24
25
namespace uWS {
26
27
    /* Takes raw query including initial '?' sign. Will inplace decode, so input will mutate */
28
2.31k
    static inline std::string_view getDecodedQueryValue(std::string_view key, std::string_view rawQuery) {
29
30
        /* Can't have a value without a key */
31
2.31k
        if (!key.length()) {
32
0
            return {};
33
0
        }
34
35
        /* Start with the whole querystring including initial '?' */
36
2.31k
        std::string_view queryString = rawQuery;
37
38
        /* List of key, value could be cached for repeated fetches similar to how headers are, todo! */
39
3.81k
        while (queryString.length()) {
40
            /* Find boundaries of this statement */
41
2.84k
            std::string_view statement = queryString.substr(1, queryString.find('&', 1) - 1);
42
43
            /* Only bother if first char of key match (early exit) */
44
2.84k
            if (statement.length() && statement[0] == key[0]) {
45
                /* Equal sign must be present and not in the end of statement */
46
1.79k
                auto equality = statement.find('=');
47
1.79k
                if (equality != std::string_view::npos) {
48
49
1.42k
                    std::string_view statementKey = statement.substr(0, equality);
50
1.42k
                    std::string_view statementValue = statement.substr(equality + 1);
51
52
                    /* String comparison */
53
1.42k
                    if (key == statementKey) {
54
55
                        /* Decode value inplace, put null at end if before length of original */
56
982
                        char *in = (char *) statementValue.data();
57
58
                        /* Write offset */
59
982
                        unsigned int out = 0;
60
61
                        /* Walk over all chars until end or null char, decoding in place */
62
30.1k
                        for (unsigned int i = 0; i < statementValue.length() && in[i]; i++) {
63
                                /* Only bother with '%' */
64
29.4k
                                if (in[i] == '%') {
65
                                    /* Do we have enough data for two bytes hex? */
66
3.50k
                                    if (i + 2 >= statementValue.length()) {
67
232
                                        return {};
68
232
                                    }
69
70
                                    /* Two bytes hex */
71
3.27k
                                    int hex1 = in[i + 1] - '0';
72
3.27k
                                    if (hex1 > 9) {
73
865
                                        hex1 &= 223;
74
865
                                        hex1 -= 7;
75
865
                                    }
76
77
3.27k
                                    int hex2 = in[i + 2] - '0';
78
3.27k
                                    if (hex2 > 9) {
79
852
                                        hex2 &= 223;
80
852
                                        hex2 -= 7;
81
852
                                    }
82
83
3.27k
                                    *((unsigned char *) &in[out]) = (unsigned char) (hex1 * 16 + hex2);
84
3.27k
                                    i += 2;
85
25.9k
                                } else {
86
                                    /* Is this even a rule? */
87
25.9k
                                    if (in[i] == '+') {
88
427
                                        in[out] = ' ';
89
25.5k
                                    } else {
90
25.5k
                                        in[out] = in[i];
91
25.5k
                                    }
92
25.9k
                                }
93
94
                                /* We always only write one char */
95
29.2k
                                out++;
96
29.2k
                        }
97
98
                        /* If decoded string is shorter than original, put null char to stop next read */
99
750
                        if (out < statementValue.length()) {
100
316
                            in[out] = 0;
101
316
                        }
102
103
750
                        return statementValue.substr(0, out);
104
982
                    }
105
1.42k
                } else {
106
                    /* This querystring is invalid, cannot parse it */
107
366
                    return {nullptr, 0};
108
366
                }
109
1.79k
            }
110
111
1.50k
            queryString.remove_prefix(statement.length() + 1);
112
1.50k
        }
113
114
        /* Nothing found is given as nullptr, while empty string is given as some pointer to the given buffer */
115
967
        return {nullptr, 0};
116
2.31k
    }
117
118
}
119
120
#endif