GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/rfc/detail/rules.cpp
Date: 2024-03-04 19:17:06
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 5916 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 4914 times.
5916 if(it == end)
38 1002 return grammar::error::need_more;
39
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4885 times.
4914 if(*it != '\r')
40 29 return grammar::error::mismatch;
41 4885 ++it;
42
2/2
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 4724 times.
4885 if(it == end)
43 161 return grammar::error::need_more;
44
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 4673 times.
4724 if(*it != '\n')
45 51 return grammar::error::mismatch;
46 4673 ++it;
47 4673 return {};
48 }
49
50 //------------------------------------------------
51
52 auto
53 3490 version_rule_t::
54 parse(
55 char const*& it,
56 char const* end) const noexcept ->
57 system::result<value_type>
58 {
59 3490 value_type v = 0;
60
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3319 times.
3490 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 2779 times.
✓ Branch 1 taken 540 times.
3319 if(end - it >= 5)
67 {
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2779 times.
2779 if(std::memcmp(
69 it, "HTTP/", 5) != 0)
70 {
71 BOOST_HTTP_PROTO_RETURN_EC(
72 grammar::error::mismatch);
73 }
74 2779 it += 5;
75 }
76
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 3229 times.
3319 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 2689 times.
3229 if(! grammar::digit_chars(*it))
83 {
84 // expected DIGIT
85 540 BOOST_HTTP_PROTO_RETURN_EC(
86 grammar::error::need_more);
87 }
88 2689 v = 10 * (*it++ - '0');
89
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2455 times.
2689 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 2455 times.
2455 if(*it != '.')
96 {
97 // expected "."
98 BOOST_HTTP_PROTO_RETURN_EC(
99 grammar::error::need_more);
100 }
101 2455 ++it;
102
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 2366 times.
2455 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 2366 times.
2366 if(! grammar::digit_chars(*it))
109 {
110 // expected DIGIT
111 BOOST_HTTP_PROTO_RETURN_EC(
112 grammar::error::need_more);
113 }
114 2366 v += *it++ - '0';
115 2366 return v;
116 }
117
118 //------------------------------------------------
119
120 auto
121 510 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 1479 [](char c) -> int
129 {
130 1479 unsigned char uc(c - '0');
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1479 times.
1479 if(uc > 9)
132 return -1;
133 1479 return uc;
134 };
135
136
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 501 times.
510 if(it == end)
137 {
138 // end
139 9 BOOST_HTTP_PROTO_RETURN_EC(
140 grammar::error::need_more);
141 }
142 501 auto it0 = it;
143 501 int v = dig(*it);
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 501 times.
501 if(v == -1)
145 {
146 // expected DIGIT
147 BOOST_HTTP_PROTO_RETURN_EC(
148 grammar::error::mismatch);
149 }
150 501 value_type t;
151 501 t.v = 100 * v;
152 501 ++it;
153
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 493 times.
501 if(it == end)
154 {
155 // end
156 8 BOOST_HTTP_PROTO_RETURN_EC(
157 grammar::error::need_more);
158 }
159 493 v = dig(*it);
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 493 times.
493 if(v == -1)
161 {
162 // expected DIGIT
163 BOOST_HTTP_PROTO_RETURN_EC(
164 grammar::error::mismatch);
165 }
166 493 t.v = t.v + (10 * v);
167 493 ++it;
168
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 485 times.
493 if(it == end)
169 {
170 // end
171 8 BOOST_HTTP_PROTO_RETURN_EC(
172 grammar::error::need_more);
173 }
174 485 v = dig(*it);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 485 times.
485 if(v == -1)
176 {
177 // expected DIGIT
178 BOOST_HTTP_PROTO_RETURN_EC(
179 grammar::error::need_more);
180 }
181 485 t.v = t.v + v;
182 485 ++it;
183
184 485 t.s = core::string_view(it0, it - it0);
185 485 t.st = int_to_status(t.v);
186 485 return t;
187 }
188
189 //------------------------------------------------
190
191 auto
192 4537 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 4536 times.
4537 if( it == end )
199 1 BOOST_HTTP_PROTO_RETURN_EC(
200 grammar::error::need_more);
201
202 4536 value_type v;
203
204 4536 auto begin = it;
205 auto rv = grammar::parse(
206 4536 it, end, token_rule);
207
6/6
✓ Branch 1 taken 4471 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 4064 times.
✓ Branch 4 taken 407 times.
✓ Branch 5 taken 4129 times.
✓ Branch 6 taken 407 times.
4536 if( rv.has_error() || (it != end) )
208 {
209
2/2
✓ Branch 0 taken 4064 times.
✓ Branch 1 taken 65 times.
4129 if( it != begin )
210 {
211 4064 v = core::string_view(begin, it - begin);
212 4064 return v;
213 }
214 65 return error::bad_field_name;
215 }
216
217 407 v = core::string_view(begin, end - begin);
218 407 return v;
219 }
220
221 auto
222 4111 field_value_rule_t::
223 parse(
224 char const*& it,
225 char const* end) const noexcept ->
226 system::result<value_type>
227 {
228 4111 value_type v;
229
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 3912 times.
4111 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 13676 auto is_field_vchar = [](unsigned char ch)
245 {
246
6/6
✓ Branch 0 taken 13642 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 13630 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 34 times.
13676 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
247 };
248
249 3912 char const* s0 = nullptr;
250 3912 char const* s1 = nullptr;
251
252 3912 bool has_crlf = false;
253 3912 bool has_obs_fold = false;
254
255
2/2
✓ Branch 0 taken 23535 times.
✓ Branch 1 taken 758 times.
24293 while( it < end )
256 {
257 23535 auto ch = *it;
258
2/2
✓ Branch 1 taken 6023 times.
✓ Branch 2 taken 17512 times.
23535 if( ws(ch) )
259 {
260 6023 ++it;
261 6023 continue;
262 }
263
264
2/2
✓ Branch 0 taken 3836 times.
✓ Branch 1 taken 13676 times.
17512 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 3636 times.
3836 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 3583 times.
3636 if( it[1] != '\n' )
273 53 goto done;
274
275
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3412 times.
3583 if( end - it < 3 )
276 171 BOOST_HTTP_PROTO_RETURN_EC(
277 grammar::error::need_more);
278
279
2/2
✓ Branch 1 taken 2696 times.
✓ Branch 2 taken 716 times.
3412 if(! ws(it[2]) )
280 {
281 2696 has_crlf = true;
282 2696 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 13642 times.
13676 if(! is_field_vchar(ch) )
291 {
292 34 goto done;
293 }
294
295
2/2
✓ Branch 0 taken 3287 times.
✓ Branch 1 taken 10355 times.
13642 if(! s0 )
296 3287 s0 = it;
297
298 13642 ++it;
299 13642 s1 = it;
300 }
301
302 758 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 3079 times.
3541 if(! s0 )
307 {
308 462 s0 = it;
309 462 s1 = s0;
310 }
311
312 3541 v.value = core::string_view(s0, s1 - s0);
313 3541 v.has_crlf = has_crlf;
314 3541 v.has_obs_fold = has_obs_fold;
315 3541 return v;
316 }
317
318 auto
319 6744 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 6547 times.
6744 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 2119 times.
✓ Branch 1 taken 4428 times.
6547 if(it[0] == '\r')
332 {
333 2119 ++it;
334
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 1985 times.
2119 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 1964 times.
1985 if(*it != '\n')
340 {
341 21 BOOST_HTTP_PROTO_RETURN_EC(
342 grammar::error::mismatch);
343 }
344 // end of fields
345 1964 ++it;
346 1964 BOOST_HTTP_PROTO_RETURN_EC(
347 grammar::error::end_of_range);
348 }
349
350 4428 value_type v;
351 auto rv = grammar::parse(
352 4428 it, end, grammar::tuple_rule(
353 field_name_rule,
354 4428 grammar::delim_rule(':'),
355 field_value_rule,
356 4428 crlf_rule));
357
358
2/2
✓ Branch 1 taken 1739 times.
✓ Branch 2 taken 2689 times.
4428 if( rv.has_error() )
359 1739 return rv.error();
360
361 2689 auto val = rv.value();
362 2689 v.name = std::get<0>(val);
363 2689 v.value = std::get<2>(val).value;
364 2689 v.has_obs_fold = std::get<2>(val).has_obs_fold;
365
366 2689 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