GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/rfc/detail/rules.cpp
Date: 2024-03-22 16:56:24
Exec Total Coverage
Lines: 154 161 95.7%
Functions: 9 9 100.0%
Branches: 93 102 91.2%

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