GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/rfc/detail/rules.cpp
Date: 2024-04-04 20:17:10
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 5949 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 4947 times.
5949 if(it == end)
38 1002 return grammar::error::need_more;
39
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4918 times.
4947 if(*it != '\r')
40 29 return grammar::error::mismatch;
41 4918 ++it;
42
2/2
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 4757 times.
4918 if(it == end)
43 161 return grammar::error::need_more;
44
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 4706 times.
4757 if(*it != '\n')
45 51 return grammar::error::mismatch;
46 4706 ++it;
47 4706 return {};
48 }
49
50 //------------------------------------------------
51
52 auto
53 3505 version_rule_t::
54 parse(
55 char const*& it,
56 char const* end) const noexcept ->
57 system::result<value_type>
58 {
59 3505 value_type v = 0;
60
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3334 times.
3505 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 2794 times.
✓ Branch 1 taken 540 times.
3334 if(end - it >= 5)
67 {
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2794 times.
2794 if(std::memcmp(
69 it, "HTTP/", 5) != 0)
70 {
71 BOOST_HTTP_PROTO_RETURN_EC(
72 grammar::error::mismatch);
73 }
74 2794 it += 5;
75 }
76
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 3244 times.
3334 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 2704 times.
3244 if(! grammar::digit_chars(*it))
83 {
84 // expected DIGIT
85 540 BOOST_HTTP_PROTO_RETURN_EC(
86 grammar::error::need_more);
87 }
88 2704 v = 10 * (*it++ - '0');
89
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2470 times.
2704 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 2470 times.
2470 if(*it != '.')
96 {
97 // expected "."
98 BOOST_HTTP_PROTO_RETURN_EC(
99 grammar::error::need_more);
100 }
101 2470 ++it;
102
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 2381 times.
2470 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 2381 times.
2381 if(! grammar::digit_chars(*it))
109 {
110 // expected DIGIT
111 BOOST_HTTP_PROTO_RETURN_EC(
112 grammar::error::need_more);
113 }
114 2381 v += *it++ - '0';
115 2381 return v;
116 }
117
118 //------------------------------------------------
119
120 auto
121 519 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 1506 [](char c) -> int
129 {
130 1506 unsigned char uc(c - '0');
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1506 times.
1506 if(uc > 9)
132 return -1;
133 1506 return uc;
134 };
135
136
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 510 times.
519 if(it == end)
137 {
138 // end
139 9 BOOST_HTTP_PROTO_RETURN_EC(
140 grammar::error::need_more);
141 }
142 510 auto it0 = it;
143 510 int v = dig(*it);
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 510 times.
510 if(v == -1)
145 {
146 // expected DIGIT
147 BOOST_HTTP_PROTO_RETURN_EC(
148 grammar::error::mismatch);
149 }
150 510 value_type t;
151 510 t.v = 100 * v;
152 510 ++it;
153
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 502 times.
510 if(it == end)
154 {
155 // end
156 8 BOOST_HTTP_PROTO_RETURN_EC(
157 grammar::error::need_more);
158 }
159 502 v = dig(*it);
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 502 times.
502 if(v == -1)
161 {
162 // expected DIGIT
163 BOOST_HTTP_PROTO_RETURN_EC(
164 grammar::error::mismatch);
165 }
166 502 t.v = t.v + (10 * v);
167 502 ++it;
168
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 494 times.
502 if(it == end)
169 {
170 // end
171 8 BOOST_HTTP_PROTO_RETURN_EC(
172 grammar::error::need_more);
173 }
174 494 v = dig(*it);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 494 times.
494 if(v == -1)
176 {
177 // expected DIGIT
178 BOOST_HTTP_PROTO_RETURN_EC(
179 grammar::error::need_more);
180 }
181 494 t.v = t.v + v;
182 494 ++it;
183
184 494 t.s = core::string_view(it0, it - it0);
185 494 t.st = int_to_status(t.v);
186 494 return t;
187 }
188
189 //------------------------------------------------
190
191 auto
192 4679 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 4678 times.
4679 if( it == end )
199 1 BOOST_HTTP_PROTO_RETURN_EC(
200 grammar::error::need_more);
201
202 4678 value_type v;
203
204 4678 auto begin = it;
205 auto rv = grammar::parse(
206 4678 it, end, token_rule);
207
6/6
✓ Branch 1 taken 4613 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 4082 times.
✓ Branch 4 taken 531 times.
✓ Branch 5 taken 4147 times.
✓ Branch 6 taken 531 times.
4678 if( rv.has_error() || (it != end) )
208 {
209
2/2
✓ Branch 0 taken 4082 times.
✓ Branch 1 taken 65 times.
4147 if( it != begin )
210 {
211 4082 v = core::string_view(begin, it - begin);
212 4082 return v;
213 }
214 65 return error::bad_field_name;
215 }
216
217 531 v = core::string_view(begin, end - begin);
218 531 return v;
219 }
220
221 auto
222 4257 field_value_rule_t::
223 parse(
224 char const*& it,
225 char const* end) const noexcept ->
226 system::result<value_type>
227 {
228 4257 value_type v;
229
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 4058 times.
4257 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 14817 auto is_field_vchar = [](unsigned char ch)
245 {
246
6/6
✓ Branch 0 taken 14783 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 14771 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 34 times.
14817 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
247 };
248
249 4058 char const* s0 = nullptr;
250 4058 char const* s1 = nullptr;
251
252 4058 bool has_crlf = false;
253 4058 bool has_obs_fold = false;
254
255
2/2
✓ Branch 0 taken 24712 times.
✓ Branch 1 taken 886 times.
25598 while( it < end )
256 {
257 24712 auto ch = *it;
258
2/2
✓ Branch 1 taken 6041 times.
✓ Branch 2 taken 18671 times.
24712 if( ws(ch) )
259 {
260 6041 ++it;
261 6041 continue;
262 }
263
264
2/2
✓ Branch 0 taken 3854 times.
✓ Branch 1 taken 14817 times.
18671 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 3654 times.
3854 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 3601 times.
3654 if( it[1] != '\n' )
273 53 goto done;
274
275
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3430 times.
3601 if( end - it < 3 )
276 171 BOOST_HTTP_PROTO_RETURN_EC(
277 grammar::error::need_more);
278
279
2/2
✓ Branch 1 taken 2714 times.
✓ Branch 2 taken 716 times.
3430 if(! ws(it[2]) )
280 {
281 2714 has_crlf = true;
282 2714 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 14783 times.
14817 if(! is_field_vchar(ch) )
291 {
292 34 goto done;
293 }
294
295
2/2
✓ Branch 0 taken 3433 times.
✓ Branch 1 taken 11350 times.
14783 if(! s0 )
296 3433 s0 = it;
297
298 14783 ++it;
299 14783 s1 = it;
300 }
301
302 886 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 3225 times.
3687 if(! s0 )
307 {
308 462 s0 = it;
309 462 s1 = s0;
310 }
311
312 3687 v.value = core::string_view(s0, s1 - s0);
313 3687 v.has_crlf = has_crlf;
314 3687 v.has_obs_fold = has_obs_fold;
315 3687 return v;
316 }
317
318 auto
319 6778 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 6581 times.
6778 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 2135 times.
✓ Branch 1 taken 4446 times.
6581 if(it[0] == '\r')
332 {
333 2135 ++it;
334
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 2001 times.
2135 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 1980 times.
2001 if(*it != '\n')
340 {
341 21 BOOST_HTTP_PROTO_RETURN_EC(
342 grammar::error::mismatch);
343 }
344 // end of fields
345 1980 ++it;
346 1980 BOOST_HTTP_PROTO_RETURN_EC(
347 grammar::error::end_of_range);
348 }
349
350 4446 value_type v;
351 auto rv = grammar::parse(
352 4446 it, end, grammar::tuple_rule(
353 field_name_rule,
354 4446 grammar::delim_rule(':'),
355 field_value_rule,
356 4446 crlf_rule));
357
358
2/2
✓ Branch 1 taken 1739 times.
✓ Branch 2 taken 2707 times.
4446 if( rv.has_error() )
359 1739 return rv.error();
360
361 2707 auto val = rv.value();
362 2707 v.name = std::get<0>(val);
363 2707 v.value = std::get<2>(val).value;
364 2707 v.has_obs_fold = std::get<2>(val).has_obs_fold;
365
366 2707 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