libs/http/src/server/detail/pct_decode.cpp

63.3% Lines (38/60) 66.7% Functions (2/3) 63.0% Branches (17/27)
libs/http/src/server/detail/pct_decode.cpp
Line Branch Hits Source Code
1 //
2 // Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/cppalliance/http
8 //
9
10 #include "src/server/detail/pct_decode.hpp"
11
12 namespace boost {
13 namespace http {
14 namespace detail {
15
16 bool
17 ci_is_equal(
18 core::string_view s0,
19 core::string_view s1) noexcept
20 {
21 auto n = s0.size();
22 if(s1.size() != n)
23 return false;
24 auto p1 = s0.data();
25 auto p2 = s1.data();
26 char a, b;
27 // fast loop
28 while(n--)
29 {
30 a = *p1++;
31 b = *p2++;
32 if(a != b)
33 goto slow;
34 }
35 return true;
36 do
37 {
38 a = *p1++;
39 b = *p2++;
40 slow:
41 if( grammar::to_lower(a) !=
42 grammar::to_lower(b))
43 return false;
44 }
45 while(n--);
46 return true;
47 }
48
49 std::string
50 179 pct_decode(
51 urls::pct_string_view s)
52 {
53 179 std::string result;
54 179 core::string_view sv(s);
55
1/1
✓ Branch 2 taken 179 times.
179 result.reserve(s.size());
56 179 auto it = sv.data();
57 179 auto const end = it + sv.size();
58 for(;;)
59 {
60
2/2
✓ Branch 0 taken 179 times.
✓ Branch 1 taken 864 times.
1043 if(it == end)
61 179 break;
62
2/2
✓ Branch 0 taken 863 times.
✓ Branch 1 taken 1 time.
864 if(*it != '%')
63 {
64
1/1
✓ Branch 1 taken 863 times.
863 result.push_back(*it++);
65 863 continue;
66 }
67 1 ++it;
68 #if 0
69 // pct_string_view can never have invalid pct-encodings
70 if(it == end)
71 goto invalid;
72 #endif
73 1 auto d0 = urls::grammar::hexdig_value(*it++);
74 #if 0
75 // pct_string_view can never have invalid pct-encodings
76 if( d0 < 0 ||
77 it == end)
78 goto invalid;
79 #endif
80 1 auto d1 = urls::grammar::hexdig_value(*it++);
81 #if 0
82 // pct_string_view can never have invalid pct-encodings
83 if(d1 < 0)
84 goto invalid;
85 #endif
86
1/1
✓ Branch 1 taken 1 time.
1 result.push_back(d0 * 16 + d1);
87 864 }
88 358 return result;
89 #if 0
90 invalid:
91 // can't get here, as received a pct_string_view
92 detail::throw_invalid_argument();
93 #endif
94 }
95
96 // decode all percent escapes except forward slash '/'
97 // (backslash is decoded since it's not a path separator in URLs)
98 std::string
99 107 pct_decode_path(
100 urls::pct_string_view s)
101 {
102 107 std::string result;
103 107 core::string_view sv(s);
104
1/1
✓ Branch 2 taken 107 times.
107 result.reserve(s.size());
105 107 auto it = sv.data();
106 107 auto const end = it + sv.size();
107 for(;;)
108 {
109
2/2
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 681 times.
788 if(it == end)
110 107 break;
111
2/2
✓ Branch 0 taken 675 times.
✓ Branch 1 taken 6 times.
681 if(*it != '%')
112 {
113
1/1
✓ Branch 1 taken 675 times.
675 result.push_back(*it++);
114 675 continue;
115 }
116 6 ++it;
117 #if 0
118 // pct_string_view can never have invalid pct-encodings
119 if(it == end)
120 goto invalid;
121 #endif
122 6 auto d0 = urls::grammar::hexdig_value(*it++);
123 #if 0
124 // pct_string_view can never have invalid pct-encodings
125 if( d0 < 0 ||
126 it == end)
127 goto invalid;
128 #endif
129 6 auto d1 = urls::grammar::hexdig_value(*it++);
130 #if 0
131 // pct_string_view can never have invalid pct-encodings
132 if(d1 < 0)
133 goto invalid;
134 #endif
135 6 char c = d0 * 16 + d1;
136
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
6 if(c != '/')
137 {
138
1/1
✓ Branch 1 taken 5 times.
5 result.push_back(c);
139 5 continue;
140 }
141
1/1
✓ Branch 1 taken 1 time.
1 result.append(it - 3, 3);
142 681 }
143 214 return result;
144 #if 0
145 invalid:
146 // can't get here, as received a pct_string_view
147 detail::throw_invalid_argument();
148 #endif
149 }
150
151 } // detail
152 } // http
153 } // boost
154