GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/rfc/detail/rules.cpp
Date: 2024-02-09 15:32:02
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 5910 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 4908 times.
5910 if(it == end)
38 1002 return grammar::error::need_more;
39
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4879 times.
4908 if(*it != '\r')
40 29 return grammar::error::mismatch;
41 4879 ++it;
42
2/2
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 4718 times.
4879 if(it == end)
43 161 return grammar::error::need_more;
44
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 4667 times.
4718 if(*it != '\n')
45 51 return grammar::error::mismatch;
46 4667 ++it;
47 4667 return {};
48 }
49
50 //------------------------------------------------
51
52 auto
53 3488 version_rule_t::
54 parse(
55 char const*& it,
56 char const* end) const noexcept ->
57 system::result<value_type>
58 {
59 3488 value_type v = 0;
60
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3317 times.
3488 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 2777 times.
✓ Branch 1 taken 540 times.
3317 if(end - it >= 5)
67 {
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2777 times.
2777 if(std::memcmp(
69 it, "HTTP/", 5) != 0)
70 {
71 BOOST_HTTP_PROTO_RETURN_EC(
72 grammar::error::mismatch);
73 }
74 2777 it += 5;
75 }
76
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 3227 times.
3317 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 2687 times.
3227 if(! grammar::digit_chars(*it))
83 {
84 // expected DIGIT
85 540 BOOST_HTTP_PROTO_RETURN_EC(
86 grammar::error::need_more);
87 }
88 2687 v = 10 * (*it++ - '0');
89
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2453 times.
2687 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 2453 times.
2453 if(*it != '.')
96 {
97 // expected "."
98 BOOST_HTTP_PROTO_RETURN_EC(
99 grammar::error::need_more);
100 }
101 2453 ++it;
102
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 2364 times.
2453 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 2364 times.
2364 if(! grammar::digit_chars(*it))
109 {
110 // expected DIGIT
111 BOOST_HTTP_PROTO_RETURN_EC(
112 grammar::error::need_more);
113 }
114 2364 v += *it++ - '0';
115 2364 return v;
116 }
117
118 //------------------------------------------------
119
120 auto
121 508 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 1473 [](char c) -> int
129 {
130 1473 unsigned char uc(c - '0');
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1473 times.
1473 if(uc > 9)
132 return -1;
133 1473 return uc;
134 };
135
136
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 499 times.
508 if(it == end)
137 {
138 // end
139 9 BOOST_HTTP_PROTO_RETURN_EC(
140 grammar::error::need_more);
141 }
142 499 auto it0 = it;
143 499 int v = dig(*it);
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 499 times.
499 if(v == -1)
145 {
146 // expected DIGIT
147 BOOST_HTTP_PROTO_RETURN_EC(
148 grammar::error::mismatch);
149 }
150 499 value_type t;
151 499 t.v = 100 * v;
152 499 ++it;
153
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 491 times.
499 if(it == end)
154 {
155 // end
156 8 BOOST_HTTP_PROTO_RETURN_EC(
157 grammar::error::need_more);
158 }
159 491 v = dig(*it);
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 491 times.
491 if(v == -1)
161 {
162 // expected DIGIT
163 BOOST_HTTP_PROTO_RETURN_EC(
164 grammar::error::mismatch);
165 }
166 491 t.v = t.v + (10 * v);
167 491 ++it;
168
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 483 times.
491 if(it == end)
169 {
170 // end
171 8 BOOST_HTTP_PROTO_RETURN_EC(
172 grammar::error::need_more);
173 }
174 483 v = dig(*it);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 483 times.
483 if(v == -1)
176 {
177 // expected DIGIT
178 BOOST_HTTP_PROTO_RETURN_EC(
179 grammar::error::need_more);
180 }
181 483 t.v = t.v + v;
182 483 ++it;
183
184 483 t.s = core::string_view(it0, it - it0);
185 483 t.st = int_to_status(t.v);
186 483 return t;
187 }
188
189 //------------------------------------------------
190
191 auto
192 4533 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 4532 times.
4533 if( it == end )
199 1 BOOST_HTTP_PROTO_RETURN_EC(
200 grammar::error::need_more);
201
202 4532 value_type v;
203
204 4532 auto begin = it;
205 auto rv = grammar::parse(
206 4532 it, end, token_rule);
207
6/6
✓ Branch 1 taken 4467 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 4060 times.
✓ Branch 4 taken 407 times.
✓ Branch 5 taken 4125 times.
✓ Branch 6 taken 407 times.
4532 if( rv.has_error() || (it != end) )
208 {
209
2/2
✓ Branch 0 taken 4060 times.
✓ Branch 1 taken 65 times.
4125 if( it != begin )
210 {
211 4060 v = core::string_view(begin, it - begin);
212 4060 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 4107 field_value_rule_t::
223 parse(
224 char const*& it,
225 char const* end) const noexcept ->
226 system::result<value_type>
227 {
228 4107 value_type v;
229
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 3908 times.
4107 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 13657 auto is_field_vchar = [](unsigned char ch)
245 {
246
6/6
✓ Branch 0 taken 13623 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 13611 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 34 times.
13657 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
247 };
248
249 3908 char const* s0 = nullptr;
250 3908 char const* s1 = nullptr;
251
252 3908 bool has_crlf = false;
253 3908 bool has_obs_fold = false;
254
255
2/2
✓ Branch 0 taken 23508 times.
✓ Branch 1 taken 758 times.
24266 while( it < end )
256 {
257 23508 auto ch = *it;
258
2/2
✓ Branch 1 taken 6019 times.
✓ Branch 2 taken 17489 times.
23508 if( ws(ch) )
259 {
260 6019 ++it;
261 6019 continue;
262 }
263
264
2/2
✓ Branch 0 taken 3832 times.
✓ Branch 1 taken 13657 times.
17489 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 3632 times.
3832 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 3579 times.
3632 if( it[1] != '\n' )
273 53 goto done;
274
275
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3408 times.
3579 if( end - it < 3 )
276 171 BOOST_HTTP_PROTO_RETURN_EC(
277 grammar::error::need_more);
278
279
2/2
✓ Branch 1 taken 2692 times.
✓ Branch 2 taken 716 times.
3408 if(! ws(it[2]) )
280 {
281 2692 has_crlf = true;
282 2692 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 13623 times.
13657 if(! is_field_vchar(ch) )
291 {
292 34 goto done;
293 }
294
295
2/2
✓ Branch 0 taken 3283 times.
✓ Branch 1 taken 10340 times.
13623 if(! s0 )
296 3283 s0 = it;
297
298 13623 ++it;
299 13623 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 3075 times.
3537 if(! s0 )
307 {
308 462 s0 = it;
309 462 s1 = s0;
310 }
311
312 3537 v.value = core::string_view(s0, s1 - s0);
313 3537 v.has_crlf = has_crlf;
314 3537 v.has_obs_fold = has_obs_fold;
315 3537 return v;
316 }
317
318 auto
319 6738 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 6541 times.
6738 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 2117 times.
✓ Branch 1 taken 4424 times.
6541 if(it[0] == '\r')
332 {
333 2117 ++it;
334
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 1983 times.
2117 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 1962 times.
1983 if(*it != '\n')
340 {
341 21 BOOST_HTTP_PROTO_RETURN_EC(
342 grammar::error::mismatch);
343 }
344 // end of fields
345 1962 ++it;
346 1962 BOOST_HTTP_PROTO_RETURN_EC(
347 grammar::error::end_of_range);
348 }
349
350 4424 value_type v;
351 auto rv = grammar::parse(
352 4424 it, end, grammar::tuple_rule(
353 field_name_rule,
354 4424 grammar::delim_rule(':'),
355 field_value_rule,
356 4424 crlf_rule));
357
358
2/2
✓ Branch 1 taken 1739 times.
✓ Branch 2 taken 2685 times.
4424 if( rv.has_error() )
359 1739 return rv.error();
360
361 2685 auto val = rv.value();
362 2685 v.name = std::get<0>(val);
363 2685 v.value = std::get<2>(val).value;
364 2685 v.has_obs_fold = std::get<2>(val).has_obs_fold;
365
366 2685 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