GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/rfc/detail/rules.cpp
Date: 2024-05-23 18:56:45
Exec Total Coverage
Lines: 155 162 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 5952 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 4950 times.
5952 if(it == end)
38 1002 return grammar::error::need_more;
39
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 4921 times.
4950 if(*it != '\r')
40 29 return grammar::error::mismatch;
41 4921 ++it;
42
2/2
✓ Branch 0 taken 161 times.
✓ Branch 1 taken 4760 times.
4921 if(it == end)
43 161 return grammar::error::need_more;
44
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 4709 times.
4760 if(*it != '\n')
45 51 return grammar::error::mismatch;
46 4709 ++it;
47 4709 return {};
48 }
49
50 //------------------------------------------------
51
52 auto
53 3506 version_rule_t::
54 parse(
55 char const*& it,
56 char const* end) const noexcept ->
57 system::result<value_type>
58 {
59 3506 value_type v = 0;
60
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3335 times.
3506 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 2795 times.
✓ Branch 1 taken 540 times.
3335 if(end - it >= 5)
67 {
68
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2795 times.
2795 if(std::memcmp(
69 it, "HTTP/", 5) != 0)
70 {
71 BOOST_HTTP_PROTO_RETURN_EC(
72 grammar::error::mismatch);
73 }
74 2795 it += 5;
75 }
76
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 3245 times.
3335 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 2705 times.
3245 if(! grammar::digit_chars(*it))
83 {
84 // expected DIGIT
85 540 BOOST_HTTP_PROTO_RETURN_EC(
86 grammar::error::need_more);
87 }
88 2705 v = 10 * (*it++ - '0');
89
2/2
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2471 times.
2705 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 2471 times.
2471 if(*it != '.')
96 {
97 // expected "."
98 BOOST_HTTP_PROTO_RETURN_EC(
99 grammar::error::need_more);
100 }
101 2471 ++it;
102
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 2382 times.
2471 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 2382 times.
2382 if(! grammar::digit_chars(*it))
109 {
110 // expected DIGIT
111 BOOST_HTTP_PROTO_RETURN_EC(
112 grammar::error::need_more);
113 }
114 2382 v += *it++ - '0';
115 2382 return v;
116 }
117
118 //------------------------------------------------
119
120 auto
121 520 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 1509 [](char c) -> int
129 {
130 1509 unsigned char uc(c - '0');
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1509 times.
1509 if(uc > 9)
132 return -1;
133 1509 return uc;
134 };
135
136
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 511 times.
520 if(it == end)
137 {
138 // end
139 9 BOOST_HTTP_PROTO_RETURN_EC(
140 grammar::error::need_more);
141 }
142 511 auto it0 = it;
143 511 int v = dig(*it);
144
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 511 times.
511 if(v == -1)
145 {
146 // expected DIGIT
147 BOOST_HTTP_PROTO_RETURN_EC(
148 grammar::error::mismatch);
149 }
150 511 value_type t;
151 511 t.v = 100 * v;
152 511 ++it;
153
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 503 times.
511 if(it == end)
154 {
155 // end
156 8 BOOST_HTTP_PROTO_RETURN_EC(
157 grammar::error::need_more);
158 }
159 503 v = dig(*it);
160
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 503 times.
503 if(v == -1)
161 {
162 // expected DIGIT
163 BOOST_HTTP_PROTO_RETURN_EC(
164 grammar::error::mismatch);
165 }
166 503 t.v = t.v + (10 * v);
167 503 ++it;
168
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 495 times.
503 if(it == end)
169 {
170 // end
171 8 BOOST_HTTP_PROTO_RETURN_EC(
172 grammar::error::need_more);
173 }
174 495 v = dig(*it);
175
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 495 times.
495 if(v == -1)
176 {
177 // expected DIGIT
178 BOOST_HTTP_PROTO_RETURN_EC(
179 grammar::error::need_more);
180 }
181 495 t.v = t.v + v;
182 495 ++it;
183
184 495 t.s = core::string_view(it0, it - it0);
185 495 t.st = int_to_status(t.v);
186 495 return t;
187 }
188
189 //------------------------------------------------
190
191 auto
192 4681 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 4680 times.
4681 if( it == end )
199 1 BOOST_HTTP_PROTO_RETURN_EC(
200 grammar::error::need_more);
201
202 4680 value_type v;
203
204 4680 auto begin = it;
205 4680 auto rv = grammar::parse(
206 it, end, token_rule);
207
6/6
✓ Branch 1 taken 4615 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 4084 times.
✓ Branch 4 taken 531 times.
✓ Branch 5 taken 4149 times.
✓ Branch 6 taken 531 times.
4680 if( rv.has_error() || (it != end) )
208 {
209
2/2
✓ Branch 0 taken 4084 times.
✓ Branch 1 taken 65 times.
4149 if( it != begin )
210 {
211 4084 v = core::string_view(begin, it - begin);
212 4084 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 4259 field_value_rule_t::
223 parse(
224 char const*& it,
225 char const* end) const noexcept ->
226 system::result<value_type>
227 {
228 4259 value_type v;
229
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 4060 times.
4259 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 14829 auto is_field_vchar = [](unsigned char ch)
245 {
246
6/6
✓ Branch 0 taken 14795 times.
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 14783 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 34 times.
14829 return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
247 };
248
249 4060 char const* s0 = nullptr;
250 4060 char const* s1 = nullptr;
251
252 4060 bool has_crlf = false;
253 4060 bool has_obs_fold = false;
254
255
2/2
✓ Branch 0 taken 24728 times.
✓ Branch 1 taken 886 times.
25614 while( it < end )
256 {
257 24728 auto ch = *it;
258
2/2
✓ Branch 1 taken 6043 times.
✓ Branch 2 taken 18685 times.
24728 if( ws(ch) )
259 {
260 6043 ++it;
261 6043 continue;
262 }
263
264
2/2
✓ Branch 0 taken 3856 times.
✓ Branch 1 taken 14829 times.
18685 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 3656 times.
3856 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 3603 times.
3656 if( it[1] != '\n' )
273 53 goto done;
274
275
2/2
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 3432 times.
3603 if( end - it < 3 )
276 171 BOOST_HTTP_PROTO_RETURN_EC(
277 grammar::error::need_more);
278
279
2/2
✓ Branch 1 taken 2716 times.
✓ Branch 2 taken 716 times.
3432 if(! ws(it[2]) )
280 {
281 2716 has_crlf = true;
282 2716 goto done;
283 }
284
285 716 has_obs_fold = true;
286 716 it = it + 3;
287 716 continue;
288 716 }
289
290
2/2
✓ Branch 1 taken 34 times.
✓ Branch 2 taken 14795 times.
14829 if(! is_field_vchar(ch) )
291 {
292 34 goto done;
293 }
294
295
2/2
✓ Branch 0 taken 3435 times.
✓ Branch 1 taken 11360 times.
14795 if(! s0 )
296 3435 s0 = it;
297
298 14795 ++it;
299 14795 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 3227 times.
3689 if(! s0 )
307 {
308 462 s0 = it;
309 462 s1 = s0;
310 }
311
312 3689 v.value = core::string_view(s0, s1 - s0);
313 3689 v.has_crlf = has_crlf;
314 3689 v.has_obs_fold = has_obs_fold;
315 3689 return v;
316 }
317
318 auto
319 6781 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 6584 times.
6781 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 2136 times.
✓ Branch 1 taken 4448 times.
6584 if(it[0] == '\r')
332 {
333 2136 ++it;
334
2/2
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 2002 times.
2136 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 1981 times.
2002 if(*it != '\n')
340 {
341 21 BOOST_HTTP_PROTO_RETURN_EC(
342 grammar::error::mismatch);
343 }
344 // end of fields
345 1981 ++it;
346 1981 BOOST_HTTP_PROTO_RETURN_EC(
347 grammar::error::end_of_range);
348 }
349
350 4448 value_type v;
351 auto rv = grammar::parse(
352 4448 it, end, grammar::tuple_rule(
353 field_name_rule,
354 4448 grammar::delim_rule(':'),
355 field_value_rule,
356 4448 crlf_rule));
357
358
2/2
✓ Branch 1 taken 1739 times.
✓ Branch 2 taken 2709 times.
4448 if( rv.has_error() )
359 1739 return rv.error();
360
361 2709 auto val = rv.value();
362 2709 v.name = std::get<0>(val);
363 2709 v.value = std::get<2>(val).value;
364 2709 v.has_obs_fold = std::get<2>(val).has_obs_fold;
365
366 2709 return v;
367 }
368
369 //------------------------------------------------
370
371 void
372 241 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