Line | Branch | Exec | Source |
---|---|---|---|
1 | // | ||
2 | // Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.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_proto | ||
8 | // | ||
9 | |||
10 | #include <boost/http_proto/rfc/detail/rules.hpp> | ||
11 | |||
12 | #include <boost/http_proto/error.hpp> | ||
13 | #include <boost/http_proto/detail/config.hpp> | ||
14 | #include <boost/http_proto/rfc/token_rule.hpp> | ||
15 | |||
16 | #include <boost/core/detail/string_view.hpp> | ||
17 | #include <boost/url/grammar/delim_rule.hpp> | ||
18 | #include <boost/url/grammar/digit_chars.hpp> | ||
19 | #include <boost/url/grammar/error.hpp> | ||
20 | #include <boost/url/grammar/lut_chars.hpp> | ||
21 | #include <boost/url/grammar/parse.hpp> | ||
22 | #include <boost/url/grammar/tuple_rule.hpp> | ||
23 | |||
24 | #include "rules.hpp" | ||
25 | |||
26 | namespace boost { | ||
27 | namespace http_proto { | ||
28 | namespace detail { | ||
29 | |||
30 | auto | ||
31 | 5935 | crlf_rule_t:: | |
32 | parse( | ||
33 | char const*& it, | ||
34 | char const* end) const noexcept -> | ||
35 | system::result<value_type> | ||
36 | { | ||
37 |
2/2✓ Branch 0 taken 1002 times.
✓ Branch 1 taken 4933 times.
|
5935 | if(it == end) |
38 | 1002 | return grammar::error::need_more; | |
39 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4904 times.
|
4933 | if(*it != '\r') |
40 | 29 | return grammar::error::mismatch; | |
41 | 4904 | ++it; | |
42 |
2/2✓ Branch 0 taken 161 times.
✓ Branch 1 taken 4743 times.
|
4904 | if(it == end) |
43 | 161 | return grammar::error::need_more; | |
44 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 4692 times.
|
4743 | if(*it != '\n') |
45 | 51 | return grammar::error::mismatch; | |
46 | 4692 | ++it; | |
47 | 4692 | return {}; | |
48 | } | ||
49 | |||
50 | //------------------------------------------------ | ||
51 | |||
52 | auto | ||
53 | 3498 | version_rule_t:: | |
54 | parse( | ||
55 | char const*& it, | ||
56 | char const* end) const noexcept -> | ||
57 | system::result<value_type> | ||
58 | { | ||
59 | 3498 | value_type v = 0; | |
60 |
2/2✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3327 times.
|
3498 | if(it == end) |
61 | { | ||
62 | // expected "HTTP/" | ||
63 | 171 | BOOST_HTTP_PROTO_RETURN_EC( | |
64 | grammar::error::need_more); | ||
65 | } | ||
66 |
2/2✓ Branch 0 taken 2787 times.
✓ Branch 1 taken 540 times.
|
3327 | if(end - it >= 5) |
67 | { | ||
68 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2787 times.
|
2787 | if(std::memcmp( |
69 | it, "HTTP/", 5) != 0) | ||
70 | { | ||
71 | ✗ | BOOST_HTTP_PROTO_RETURN_EC( | |
72 | grammar::error::mismatch); | ||
73 | } | ||
74 | 2787 | it += 5; | |
75 | } | ||
76 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 3237 times.
|
3327 | if(it == end) |
77 | { | ||
78 | // expected DIGIT | ||
79 | 90 | BOOST_HTTP_PROTO_RETURN_EC( | |
80 | grammar::error::need_more); | ||
81 | } | ||
82 |
2/2✓ Branch 1 taken 540 times.
✓ Branch 2 taken 2697 times.
|
3237 | if(! grammar::digit_chars(*it)) |
83 | { | ||
84 | // expected DIGIT | ||
85 | 540 | BOOST_HTTP_PROTO_RETURN_EC( | |
86 | grammar::error::need_more); | ||
87 | } | ||
88 | 2697 | v = 10 * (*it++ - '0'); | |
89 |
2/2✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2463 times.
|
2697 | if(it == end) |
90 | { | ||
91 | // expected "." | ||
92 | 234 | BOOST_HTTP_PROTO_RETURN_EC( | |
93 | grammar::error::need_more); | ||
94 | } | ||
95 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2463 times.
|
2463 | if(*it != '.') |
96 | { | ||
97 | // expected "." | ||
98 | ✗ | BOOST_HTTP_PROTO_RETURN_EC( | |
99 | grammar::error::need_more); | ||
100 | } | ||
101 | 2463 | ++it; | |
102 |
2/2✓ Branch 0 taken 89 times.
✓ Branch 1 taken 2374 times.
|
2463 | if(it == end) |
103 | { | ||
104 | // expected DIGIT | ||
105 | 89 | BOOST_HTTP_PROTO_RETURN_EC( | |
106 | grammar::error::need_more); | ||
107 | } | ||
108 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2374 times.
|
2374 | if(! grammar::digit_chars(*it)) |
109 | { | ||
110 | // expected DIGIT | ||
111 | ✗ | BOOST_HTTP_PROTO_RETURN_EC( | |
112 | grammar::error::need_more); | ||
113 | } | ||
114 | 2374 | v += *it++ - '0'; | |
115 | 2374 | return v; | |
116 | } | ||
117 | |||
118 | //------------------------------------------------ | ||
119 | |||
120 | auto | ||
121 | 513 | status_code_rule_t:: | |
122 | parse( | ||
123 | char const*& it, | ||
124 | char const* end) const noexcept -> | ||
125 | system::result<value_type> | ||
126 | { | ||
127 | auto const dig = | ||
128 | 1488 | [](char c) -> int | |
129 | { | ||
130 | 1488 | unsigned char uc(c - '0'); | |
131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1488 times.
|
1488 | if(uc > 9) |
132 | ✗ | return -1; | |
133 | 1488 | return uc; | |
134 | }; | ||
135 | |||
136 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 504 times.
|
513 | if(it == end) |
137 | { | ||
138 | // end | ||
139 | 9 | BOOST_HTTP_PROTO_RETURN_EC( | |
140 | grammar::error::need_more); | ||
141 | } | ||
142 | 504 | auto it0 = it; | |
143 | 504 | int v = dig(*it); | |
144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 504 times.
|
504 | if(v == -1) |
145 | { | ||
146 | // expected DIGIT | ||
147 | ✗ | BOOST_HTTP_PROTO_RETURN_EC( | |
148 | grammar::error::mismatch); | ||
149 | } | ||
150 | 504 | value_type t; | |
151 | 504 | t.v = 100 * v; | |
152 | 504 | ++it; | |
153 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 496 times.
|
504 | if(it == end) |
154 | { | ||
155 | // end | ||
156 | 8 | BOOST_HTTP_PROTO_RETURN_EC( | |
157 | grammar::error::need_more); | ||
158 | } | ||
159 | 496 | v = dig(*it); | |
160 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 496 times.
|
496 | if(v == -1) |
161 | { | ||
162 | // expected DIGIT | ||
163 | ✗ | BOOST_HTTP_PROTO_RETURN_EC( | |
164 | grammar::error::mismatch); | ||
165 | } | ||
166 | 496 | t.v = t.v + (10 * v); | |
167 | 496 | ++it; | |
168 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 488 times.
|
496 | if(it == end) |
169 | { | ||
170 | // end | ||
171 | 8 | BOOST_HTTP_PROTO_RETURN_EC( | |
172 | grammar::error::need_more); | ||
173 | } | ||
174 | 488 | v = dig(*it); | |
175 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 488 times.
|
488 | if(v == -1) |
176 | { | ||
177 | // expected DIGIT | ||
178 | ✗ | BOOST_HTTP_PROTO_RETURN_EC( | |
179 | grammar::error::need_more); | ||
180 | } | ||
181 | 488 | t.v = t.v + v; | |
182 | 488 | ++it; | |
183 | |||
184 | 488 | t.s = core::string_view(it0, it - it0); | |
185 | 488 | t.st = int_to_status(t.v); | |
186 | 488 | return t; | |
187 | } | ||
188 | |||
189 | //------------------------------------------------ | ||
190 | |||
191 | auto | ||
192 | 4561 | field_name_rule_t:: | |
193 | parse( | ||
194 | char const*& it, | ||
195 | char const* end) const noexcept -> | ||
196 | system::result<value_type> | ||
197 | { | ||
198 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4560 times.
|
4561 | if( it == end ) |
199 | 1 | BOOST_HTTP_PROTO_RETURN_EC( | |
200 | grammar::error::need_more); | ||
201 | |||
202 | 4560 | value_type v; | |
203 | |||
204 | 4560 | auto begin = it; | |
205 | auto rv = grammar::parse( | ||
206 | 4560 | it, end, token_rule); | |
207 |
6/6✓ Branch 1 taken 4495 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 4075 times.
✓ Branch 4 taken 420 times.
✓ Branch 5 taken 4140 times.
✓ Branch 6 taken 420 times.
|
4560 | if( rv.has_error() || (it != end) ) |
208 | { | ||
209 |
2/2✓ Branch 0 taken 4075 times.
✓ Branch 1 taken 65 times.
|
4140 | if( it != begin ) |
210 | { | ||
211 | 4075 | v = core::string_view(begin, it - begin); | |
212 | 4075 | return v; | |
213 | } | ||
214 | 65 | return error::bad_field_name; | |
215 | } | ||
216 | |||
217 | 420 | v = core::string_view(begin, end - begin); | |
218 | 420 | return v; | |
219 | } | ||
220 | |||
221 | auto | ||
222 | 4139 | field_value_rule_t:: | |
223 | parse( | ||
224 | char const*& it, | ||
225 | char const* end) const noexcept -> | ||
226 | system::result<value_type> | ||
227 | { | ||
228 | 4139 | value_type v; | |
229 |
2/2✓ Branch 0 taken 199 times.
✓ Branch 1 taken 3940 times.
|
4139 | if( it == end ) |
230 | { | ||
231 | 199 | v.value = core::string_view(it, 0); | |
232 | 199 | return v; | |
233 | } | ||
234 | |||
235 | // field-line = field-name ":" OWS field-value OWS | ||
236 | // field-value = *field-content | ||
237 | // field-content = field-vchar | ||
238 | // [ 1*( SP / HTAB / field-vchar ) field-vchar ] | ||
239 | // field-vchar = VCHAR / obs-text | ||
240 | // obs-text = %x80-FF | ||
241 | // VCHAR = %x21-7E | ||
242 | // ; visible (printing) characters | ||
243 | |||
244 | 13910 | auto is_field_vchar = [](unsigned char ch) | |
245 | { | ||
246 |
6/6✓ Branch 0 taken 13876 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 13864 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 34 times.
|
13910 | return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80; |
247 | }; | ||
248 | |||
249 | 3940 | char const* s0 = nullptr; | |
250 | 3940 | char const* s1 = nullptr; | |
251 | |||
252 | 3940 | bool has_crlf = false; | |
253 | 3940 | bool has_obs_fold = false; | |
254 | |||
255 |
2/2✓ Branch 0 taken 23791 times.
✓ Branch 1 taken 775 times.
|
24566 | while( it < end ) |
256 | { | ||
257 | 23791 | auto ch = *it; | |
258 |
2/2✓ Branch 1 taken 6034 times.
✓ Branch 2 taken 17757 times.
|
23791 | if( ws(ch) ) |
259 | { | ||
260 | 6034 | ++it; | |
261 | 6034 | continue; | |
262 | } | ||
263 | |||
264 |
2/2✓ Branch 0 taken 3847 times.
✓ Branch 1 taken 13910 times.
|
17757 | if( ch == '\r' ) |
265 | { | ||
266 | // too short to know if we have a potential obs-fold | ||
267 | // occurrence | ||
268 |
2/2✓ Branch 0 taken 200 times.
✓ Branch 1 taken 3647 times.
|
3847 | if( end - it < 2 ) |
269 | 200 | BOOST_HTTP_PROTO_RETURN_EC( | |
270 | grammar::error::need_more); | ||
271 | |||
272 |
2/2✓ Branch 0 taken 53 times.
✓ Branch 1 taken 3594 times.
|
3647 | if( it[1] != '\n' ) |
273 | 53 | goto done; | |
274 | |||
275 |
2/2✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3423 times.
|
3594 | if( end - it < 3 ) |
276 | 171 | BOOST_HTTP_PROTO_RETURN_EC( | |
277 | grammar::error::need_more); | ||
278 | |||
279 |
2/2✓ Branch 1 taken 2707 times.
✓ Branch 2 taken 716 times.
|
3423 | if(! ws(it[2]) ) |
280 | { | ||
281 | 2707 | has_crlf = true; | |
282 | 2707 | goto done; | |
283 | } | ||
284 | |||
285 | 716 | has_obs_fold = true; | |
286 | 716 | it = it + 3; | |
287 | 716 | continue; | |
288 | } | ||
289 | |||
290 |
2/2✓ Branch 1 taken 34 times.
✓ Branch 2 taken 13876 times.
|
13910 | if(! is_field_vchar(ch) ) |
291 | { | ||
292 | 34 | goto done; | |
293 | } | ||
294 | |||
295 |
2/2✓ Branch 0 taken 3315 times.
✓ Branch 1 taken 10561 times.
|
13876 | if(! s0 ) |
296 | 3315 | s0 = it; | |
297 | |||
298 | 13876 | ++it; | |
299 | 13876 | s1 = it; | |
300 | } | ||
301 | |||
302 | 775 | done: | |
303 | // later routines wind up doing pointer | ||
304 | // subtraction using the .data() member | ||
305 | // of the value so we need a valid 0-len range | ||
306 |
2/2✓ Branch 0 taken 462 times.
✓ Branch 1 taken 3107 times.
|
3569 | if(! s0 ) |
307 | { | ||
308 | 462 | s0 = it; | |
309 | 462 | s1 = s0; | |
310 | } | ||
311 | |||
312 | 3569 | v.value = core::string_view(s0, s1 - s0); | |
313 | 3569 | v.has_crlf = has_crlf; | |
314 | 3569 | v.has_obs_fold = has_obs_fold; | |
315 | 3569 | return v; | |
316 | } | ||
317 | |||
318 | auto | ||
319 | 6763 | field_rule_t:: | |
320 | parse( | ||
321 | char const*& it, | ||
322 | char const* end) const noexcept -> | ||
323 | system::result<value_type> | ||
324 | { | ||
325 |
2/2✓ Branch 0 taken 197 times.
✓ Branch 1 taken 6566 times.
|
6763 | if(it == end) |
326 | { | ||
327 | 197 | BOOST_HTTP_PROTO_RETURN_EC( | |
328 | grammar::error::need_more); | ||
329 | } | ||
330 | // check for leading CRLF | ||
331 |
2/2✓ Branch 0 taken 2127 times.
✓ Branch 1 taken 4439 times.
|
6566 | if(it[0] == '\r') |
332 | { | ||
333 | 2127 | ++it; | |
334 |
2/2✓ Branch 0 taken 134 times.
✓ Branch 1 taken 1993 times.
|
2127 | if(it == end) |
335 | { | ||
336 | 134 | BOOST_HTTP_PROTO_RETURN_EC( | |
337 | grammar::error::need_more); | ||
338 | } | ||
339 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 1972 times.
|
1993 | if(*it != '\n') |
340 | { | ||
341 | 21 | BOOST_HTTP_PROTO_RETURN_EC( | |
342 | grammar::error::mismatch); | ||
343 | } | ||
344 | // end of fields | ||
345 | 1972 | ++it; | |
346 | 1972 | BOOST_HTTP_PROTO_RETURN_EC( | |
347 | grammar::error::end_of_range); | ||
348 | } | ||
349 | |||
350 | 4439 | value_type v; | |
351 | auto rv = grammar::parse( | ||
352 | 4439 | it, end, grammar::tuple_rule( | |
353 | field_name_rule, | ||
354 | 4439 | grammar::delim_rule(':'), | |
355 | field_value_rule, | ||
356 | 4439 | crlf_rule)); | |
357 | |||
358 |
2/2✓ Branch 1 taken 1739 times.
✓ Branch 2 taken 2700 times.
|
4439 | if( rv.has_error() ) |
359 | 1739 | return rv.error(); | |
360 | |||
361 | 2700 | auto val = rv.value(); | |
362 | 2700 | v.name = std::get<0>(val); | |
363 | 2700 | v.value = std::get<2>(val).value; | |
364 | 2700 | v.has_obs_fold = std::get<2>(val).has_obs_fold; | |
365 | |||
366 | 2700 | return v; | |
367 | } | ||
368 | |||
369 | //------------------------------------------------ | ||
370 | |||
371 | void | ||
372 | 2247 | remove_obs_fold( | |
373 | char* it, | ||
374 | char const* const end) noexcept | ||
375 | { | ||
376 |
2/2✓ Branch 0 taken 2224 times.
✓ Branch 1 taken 23 times.
|
2247 | while(it != end) |
377 | { | ||
378 |
2/2✓ Branch 0 taken 1628 times.
✓ Branch 1 taken 596 times.
|
2224 | if(*it != '\r') |
379 | { | ||
380 | 1628 | ++it; | |
381 | 1628 | continue; | |
382 | } | ||
383 |
2/2✓ Branch 0 taken 218 times.
✓ Branch 1 taken 378 times.
|
596 | if(end - it < 3) |
384 | 218 | break; | |
385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 378 times.
|
378 | BOOST_ASSERT(it[1] == '\n'); |
386 |
5/6✓ Branch 0 taken 378 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 375 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 375 times.
✓ Branch 5 taken 3 times.
|
756 | if( it[1] == '\n' && |
387 | 378 | ws(it[2])) | |
388 | { | ||
389 | 375 | it[0] = ' '; | |
390 | 375 | it[1] = ' '; | |
391 | 375 | it += 3; | |
392 | } | ||
393 | else | ||
394 | { | ||
395 | 3 | ++it; | |
396 | } | ||
397 | } | ||
398 | 241 | } | |
399 | |||
400 | } // detail | ||
401 | } // http_proto | ||
402 | } // boost | ||
403 |