GCC Code Coverage Report


Directory: libs/http_proto/
File: libs/http_proto/src/rfc/detail/rules.cpp
Date: 2024-01-10 20:31:06
Exec Total Coverage
Lines: 138 149 92.6%
Functions: 6 6 100.0%
Branches: 74 90 82.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 #include <boost/url/grammar/digit_chars.hpp>
12
13 namespace boost {
14 namespace http_proto {
15 namespace detail {
16
17 auto
18 4912 crlf_rule_t::
19 parse(
20 char const*& it,
21 char const* end) const noexcept ->
22 system::result<value_type>
23 {
24
2/2
✓ Branch 0 taken 529 times.
✓ Branch 1 taken 4383 times.
4912 if(it == end)
25 529 return grammar::error::need_more;
26
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4383 times.
4383 if(*it != '\r')
27 return grammar::error::mismatch;
28 4383 ++it;
29
2/2
✓ Branch 0 taken 219 times.
✓ Branch 1 taken 4164 times.
4383 if(it == end)
30 219 return grammar::error::need_more;
31
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4164 times.
4164 if(*it != '\n')
32 return grammar::error::mismatch;
33 4164 ++it;
34 4164 return {};
35 }
36
37 //------------------------------------------------
38
39 auto
40 2904 version_rule_t::
41 parse(
42 char const*& it,
43 char const* end) const noexcept ->
44 system::result<value_type>
45 {
46 2904 value_type v = 0;
47
2/2
✓ Branch 0 taken 135 times.
✓ Branch 1 taken 2769 times.
2904 if(it == end)
48 {
49 // expected "HTTP/"
50 135 BOOST_HTTP_PROTO_RETURN_EC(
51 grammar::error::need_more);
52 }
53
2/2
✓ Branch 0 taken 2346 times.
✓ Branch 1 taken 423 times.
2769 if(end - it >= 5)
54 {
55
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2346 times.
2346 if(std::memcmp(
56 it, "HTTP/", 5) != 0)
57 {
58 BOOST_HTTP_PROTO_RETURN_EC(
59 grammar::error::mismatch);
60 }
61 2346 it += 5;
62 }
63
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 2697 times.
2769 if(it == end)
64 {
65 // expected DIGIT
66 72 BOOST_HTTP_PROTO_RETURN_EC(
67 grammar::error::need_more);
68 }
69
2/2
✓ Branch 1 taken 423 times.
✓ Branch 2 taken 2274 times.
2697 if(! grammar::digit_chars(*it))
70 {
71 // expected DIGIT
72 423 BOOST_HTTP_PROTO_RETURN_EC(
73 grammar::error::need_more);
74 }
75 2274 v = 10 * (*it++ - '0');
76
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 2094 times.
2274 if(it == end)
77 {
78 // expected "."
79 180 BOOST_HTTP_PROTO_RETURN_EC(
80 grammar::error::need_more);
81 }
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2094 times.
2094 if(*it != '.')
83 {
84 // expected "."
85 BOOST_HTTP_PROTO_RETURN_EC(
86 grammar::error::need_more);
87 }
88 2094 ++it;
89
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 2023 times.
2094 if(it == end)
90 {
91 // expected DIGIT
92 71 BOOST_HTTP_PROTO_RETURN_EC(
93 grammar::error::need_more);
94 }
95
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2023 times.
2023 if(! grammar::digit_chars(*it))
96 {
97 // expected DIGIT
98 BOOST_HTTP_PROTO_RETURN_EC(
99 grammar::error::need_more);
100 }
101 2023 v += *it++ - '0';
102 2023 return v;
103 }
104
105 //------------------------------------------------
106
107 auto
108 500 status_code_rule_t::
109 parse(
110 char const*& it,
111 char const* end) const noexcept ->
112 system::result<value_type>
113 {
114 auto const dig =
115 1449 [](char c) -> int
116 {
117 1449 unsigned char uc(c - '0');
118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1449 times.
1449 if(uc > 9)
119 return -1;
120 1449 return uc;
121 };
122
123
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 491 times.
500 if(it == end)
124 {
125 // end
126 9 BOOST_HTTP_PROTO_RETURN_EC(
127 grammar::error::need_more);
128 }
129 491 auto it0 = it;
130 491 int v = dig(*it);
131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 491 times.
491 if(v == -1)
132 {
133 // expected DIGIT
134 BOOST_HTTP_PROTO_RETURN_EC(
135 grammar::error::mismatch);
136 }
137 491 value_type t;
138 491 t.v = 100 * v;
139 491 ++it;
140
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 483 times.
491 if(it == end)
141 {
142 // end
143 8 BOOST_HTTP_PROTO_RETURN_EC(
144 grammar::error::need_more);
145 }
146 483 v = dig(*it);
147
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 483 times.
483 if(v == -1)
148 {
149 // expected DIGIT
150 BOOST_HTTP_PROTO_RETURN_EC(
151 grammar::error::mismatch);
152 }
153 483 t.v = t.v + (10 * v);
154 483 ++it;
155
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 475 times.
483 if(it == end)
156 {
157 // end
158 8 BOOST_HTTP_PROTO_RETURN_EC(
159 grammar::error::need_more);
160 }
161 475 v = dig(*it);
162
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 475 times.
475 if(v == -1)
163 {
164 // expected DIGIT
165 BOOST_HTTP_PROTO_RETURN_EC(
166 grammar::error::need_more);
167 }
168 475 t.v = t.v + v;
169 475 ++it;
170
171 475 t.s = core::string_view(it0, it - it0);
172 475 t.st = int_to_status(t.v);
173 475 return t;
174 }
175
176 //------------------------------------------------
177
178 auto
179 5837 field_rule_t::
180 parse(
181 char const*& it,
182 char const* end) const noexcept ->
183 system::result<value_type>
184 {
185
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 5685 times.
5837 if(it == end)
186 {
187 152 BOOST_HTTP_PROTO_RETURN_EC(
188 grammar::error::need_more);
189 }
190 // check for leading CRLF
191
2/2
✓ Branch 0 taken 1898 times.
✓ Branch 1 taken 3787 times.
5685 if(it[0] == '\r')
192 {
193 1898 ++it;
194
2/2
✓ Branch 0 taken 112 times.
✓ Branch 1 taken 1786 times.
1898 if(it == end)
195 {
196 112 BOOST_HTTP_PROTO_RETURN_EC(
197 grammar::error::need_more);
198 }
199
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1786 times.
1786 if(*it != '\n')
200 {
201 BOOST_HTTP_PROTO_RETURN_EC(
202 grammar::error::mismatch);
203 }
204 // end of fields
205 1786 ++it;
206 1786 BOOST_HTTP_PROTO_RETURN_EC(
207 grammar::error::end_of_range);
208 }
209
210 3787 value_type v;
211
212 // field name
213 {
214 auto rv = grammar::parse(
215 3787 it, end, grammar::tuple_rule(
216 token_rule,
217 3787 grammar::squelch(
218 3787 grammar::delim_rule(':'))));
219
2/2
✓ Branch 1 taken 397 times.
✓ Branch 2 taken 3390 times.
3787 if(! rv)
220 397 return rv.error();
221 3390 v.name = rv.value();
222 }
223
224 // consume all obs-fold until field char or end of field:
225 //
226 // HTTP-message = start-line *( header-field CRLF ) CRLF [ message-body ]
227 // header-field = field-name ":" OWS field-value OWS
228 // field-value = *( field-content / obs-fold )
229 // field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
230 // obs-fold = CRLF 1*( SP / HTAB )
231 //
232 for(;;)
233 {
234 3684 skip_ows(it, end);
235
2/2
✓ Branch 0 taken 227 times.
✓ Branch 1 taken 3457 times.
3684 if(it == end)
236 {
237 227 BOOST_HTTP_PROTO_RETURN_EC(
238 grammar::error::need_more);
239 }
240
2/2
✓ Branch 0 taken 2897 times.
✓ Branch 1 taken 560 times.
3457 if(*it != '\r')
241 {
242 // start of value
243 2897 break;
244 }
245 560 ++it;
246
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 500 times.
560 if(it == end)
247 {
248 60 BOOST_HTTP_PROTO_RETURN_EC(
249 grammar::error::need_more);
250 }
251
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 500 times.
500 if(*it != '\n')
252 {
253 BOOST_HTTP_PROTO_RETURN_EC(
254 grammar::error::mismatch);
255 }
256 500 ++it;
257
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 444 times.
500 if(it == end)
258 {
259 56 BOOST_HTTP_PROTO_RETURN_EC(
260 grammar::error::need_more);
261 }
262 // FIXME: this should be a loop of some kind as we've detected a valid
263 // CRLF at this stage but need to account for the ABNF specifying:
264 // obs-fold = CRLF 1*( SP / HTAB )
265
2/2
✓ Branch 0 taken 150 times.
✓ Branch 1 taken 294 times.
444 if(*it != ' ' &&
266
1/2
✓ Branch 0 taken 150 times.
✗ Branch 1 not taken.
150 *it != '\t')
267 {
268 // because we saw a CRLF and didn't see the required SP / HTAB,
269 // we know we have a zero length field value
270 150 v.value = core::string_view(it, 0);
271 150 return v;
272 }
273 // eat obs-fold
274 294 ++it;
275 294 v.has_obs_fold = true;
276 294 }
277
278 2897 char const* s0 = it; // start of value
279 for(;;)
280 {
281 auto rv = grammar::parse(
282 2939 it, end, grammar::tuple_rule(
283 2939 grammar::token_rule(
284 2939 ws_vchars),
285 2939 crlf_rule));
286
2/2
✓ Branch 1 taken 488 times.
✓ Branch 2 taken 2451 times.
2939 if(! rv)
287 488 return rv.error();
288
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 2380 times.
2451 if(it == end)
289 {
290 71 BOOST_HTTP_PROTO_RETURN_EC(
291 grammar::error::need_more);
292 }
293
2/2
✓ Branch 0 taken 2338 times.
✓ Branch 1 taken 42 times.
2380 if( *it != ' ' &&
294
1/2
✓ Branch 0 taken 2338 times.
✗ Branch 1 not taken.
2338 *it != '\t')
295 {
296 // end of field
297 2338 break;
298 }
299 // *it will match field_value_rule
300 42 v.has_obs_fold = true;
301 42 }
302
303 2338 v.value = core::string_view(s0, (it - s0) - 2);
304
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2338 times.
2338 BOOST_ASSERT(! v.value.empty());
305 //BOOST_ASSERT(! ws(t.v.value.front()));
306
307 // remove trailing SP,HTAB,CR,LF
308 2338 auto p = &v.value.back();
309 for(;;)
310 {
311
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 2338 times.
2543 switch(*p)
312 {
313 205 case ' ': case '\t':
314 case '\r': case '\n':
315 205 --p;
316 205 continue;
317 2338 default:
318 2338 ++p;
319 2338 goto done;
320 }
321 }
322 2338 done:
323 2338 v.value = core::string_view(
324 v.value.data(),
325 2338 p - v.value.data());
326 2338 return v;
327 }
328
329 //------------------------------------------------
330
331 void
332 946 remove_obs_fold(
333 char* it,
334 char const* const end) noexcept
335 {
336
2/2
✓ Branch 0 taken 941 times.
✓ Branch 1 taken 5 times.
946 while(it != end)
337 {
338
2/2
✓ Branch 0 taken 593 times.
✓ Branch 1 taken 348 times.
941 if(*it != '\r')
339 {
340 593 ++it;
341 593 continue;
342 }
343
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 203 times.
348 if(end - it < 3)
344 145 break;
345
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 BOOST_ASSERT(it[1] == '\n');
346
5/6
✓ Branch 0 taken 203 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 200 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 200 times.
✓ Branch 5 taken 3 times.
406 if( it[1] == '\n' &&
347 203 ws(it[2]))
348 {
349 200 it[0] = ' ';
350 200 it[1] = ' ';
351 200 it += 3;
352 }
353 else
354 {
355 3 ++it;
356 }
357 }
358 150 }
359
360 } // detail
361 } // http_proto
362 } // boost
363