TLA Line data Source code
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
8 : //
9 :
10 : #include "src/rfc/detail/rules.hpp"
11 :
12 : #include <boost/http/error.hpp>
13 : #include <boost/http/detail/config.hpp>
14 : #include <boost/http/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/hexdig_chars.hpp>
21 : #include <boost/url/grammar/lut_chars.hpp>
22 : #include <boost/url/grammar/parse.hpp>
23 : #include <boost/url/grammar/tuple_rule.hpp>
24 :
25 : #include "src/rfc/detail/rules.hpp"
26 :
27 : namespace boost {
28 : namespace http {
29 : namespace detail {
30 :
31 : auto
32 HIT 28890 : crlf_rule_t::
33 : parse(
34 : char const*& it,
35 : char const* end) const noexcept ->
36 : system::result<value_type>
37 : {
38 28890 : if(it == end)
39 6535 : return grammar::error::need_more;
40 22355 : if(*it != '\r')
41 29 : return grammar::error::mismatch;
42 22326 : ++it;
43 22326 : if(it == end)
44 961 : return grammar::error::need_more;
45 21365 : if(*it != '\n')
46 51 : return grammar::error::mismatch;
47 21314 : ++it;
48 21314 : return {};
49 : }
50 :
51 : //------------------------------------------------
52 :
53 : auto
54 28506 : version_rule_t::
55 : parse(
56 : char const*& it,
57 : char const* end) const noexcept ->
58 : system::result<value_type>
59 : {
60 28506 : value_type v = 0;
61 28506 : if(it == end)
62 : {
63 : // expected "HTTP/"
64 1619 : BOOST_HTTP_RETURN_EC(
65 : grammar::error::need_more);
66 : }
67 26887 : if(end - it >= 5)
68 : {
69 22177 : if(std::memcmp(
70 : it, "HTTP/", 5) != 0)
71 : {
72 MIS 0 : BOOST_HTTP_RETURN_EC(
73 : grammar::error::mismatch);
74 : }
75 HIT 22177 : it += 5;
76 : }
77 26887 : if(it == end)
78 : {
79 : // expected DIGIT
80 1087 : BOOST_HTTP_RETURN_EC(
81 : grammar::error::need_more);
82 : }
83 25800 : if(! grammar::digit_chars(*it))
84 : {
85 : // expected DIGIT
86 4710 : BOOST_HTTP_RETURN_EC(
87 : grammar::error::need_more);
88 : }
89 21090 : v = 10 * (*it++ - '0');
90 21090 : if(it == end)
91 : {
92 : // expected "."
93 1213 : BOOST_HTTP_RETURN_EC(
94 : grammar::error::need_more);
95 : }
96 19877 : if(*it != '.')
97 : {
98 : // expected "."
99 MIS 0 : BOOST_HTTP_RETURN_EC(
100 : grammar::error::need_more);
101 : }
102 HIT 19877 : ++it;
103 19877 : if(it == end)
104 : {
105 : // expected DIGIT
106 1051 : BOOST_HTTP_RETURN_EC(
107 : grammar::error::need_more);
108 : }
109 18826 : if(! grammar::digit_chars(*it))
110 : {
111 : // expected DIGIT
112 MIS 0 : BOOST_HTTP_RETURN_EC(
113 : grammar::error::need_more);
114 : }
115 HIT 18826 : v += *it++ - '0';
116 18826 : return v;
117 : }
118 :
119 : //------------------------------------------------
120 :
121 : auto
122 8184 : status_code_rule_t::
123 : parse(
124 : char const*& it,
125 : char const* end) const noexcept ->
126 : system::result<value_type>
127 : {
128 : auto const dig =
129 19020 : [](char c) -> int
130 : {
131 19020 : unsigned char uc(c - '0');
132 19020 : if(uc > 9)
133 MIS 0 : return -1;
134 HIT 19020 : return uc;
135 : };
136 :
137 8184 : if(it == end)
138 : {
139 : // end
140 934 : BOOST_HTTP_RETURN_EC(
141 : grammar::error::need_more);
142 : }
143 7250 : auto it0 = it;
144 7250 : int v = dig(*it);
145 7250 : if(v == -1)
146 : {
147 : // expected DIGIT
148 MIS 0 : BOOST_HTTP_RETURN_EC(
149 : grammar::error::mismatch);
150 : }
151 HIT 7250 : value_type t;
152 7250 : t.v = 100 * v;
153 7250 : ++it;
154 7250 : if(it == end)
155 : {
156 : // end
157 916 : BOOST_HTTP_RETURN_EC(
158 : grammar::error::need_more);
159 : }
160 6334 : v = dig(*it);
161 6334 : if(v == -1)
162 : {
163 : // expected DIGIT
164 MIS 0 : BOOST_HTTP_RETURN_EC(
165 : grammar::error::mismatch);
166 : }
167 HIT 6334 : t.v = t.v + (10 * v);
168 6334 : ++it;
169 6334 : if(it == end)
170 : {
171 : // end
172 898 : BOOST_HTTP_RETURN_EC(
173 : grammar::error::need_more);
174 : }
175 5436 : v = dig(*it);
176 5436 : if(v == -1)
177 : {
178 : // expected DIGIT
179 MIS 0 : BOOST_HTTP_RETURN_EC(
180 : grammar::error::need_more);
181 : }
182 HIT 5436 : t.v = t.v + v;
183 5436 : ++it;
184 :
185 5436 : t.s = core::string_view(it0, it - it0);
186 5436 : t.st = int_to_status(t.v);
187 5436 : return t;
188 : }
189 :
190 : //------------------------------------------------
191 :
192 : auto
193 4556 : reason_phrase_rule_t::
194 : parse(
195 : char const*& it,
196 : char const* end) const noexcept ->
197 : system::result<value_type>
198 : {
199 4556 : auto begin = it;
200 4556 : it = grammar::find_if_not(it, end, ws_vchars);
201 4556 : return core::string_view(begin, it);
202 : }
203 :
204 : //------------------------------------------------
205 :
206 : auto
207 26365 : field_name_rule_t::
208 : parse(
209 : char const*& it,
210 : char const* end) const noexcept ->
211 : system::result<value_type>
212 : {
213 26365 : if( it == end )
214 1 : BOOST_HTTP_RETURN_EC(
215 : grammar::error::need_more);
216 :
217 26364 : value_type v;
218 :
219 26364 : auto begin = it;
220 26364 : auto rv = grammar::parse(
221 : it, end, token_rule);
222 26364 : if( rv.has_error() || (it != end) )
223 : {
224 15941 : if( it != begin )
225 : {
226 15875 : v = core::string_view(begin, it - begin);
227 15875 : return v;
228 : }
229 66 : return error::bad_field_name;
230 : }
231 :
232 10423 : v = core::string_view(begin, end - begin);
233 10423 : return v;
234 : }
235 :
236 : auto
237 16144 : field_value_rule_t::
238 : parse(
239 : char const*& it,
240 : char const* end) const noexcept ->
241 : system::result<value_type>
242 : {
243 16144 : value_type v;
244 16144 : if( it == end )
245 : {
246 693 : v.value = core::string_view(it, 0);
247 693 : return v;
248 : }
249 :
250 : // field-line = field-name ":" OWS field-value OWS
251 : // field-value = *field-content
252 : // field-content = field-vchar
253 : // [ 1*( SP / HTAB / field-vchar ) field-vchar ]
254 : // field-vchar = VCHAR / obs-text
255 : // obs-text = %x80-FF
256 : // VCHAR = %x21-7E
257 : // ; visible (printing) characters
258 :
259 66585 : auto is_field_vchar = [](unsigned char ch)
260 : {
261 66585 : return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
262 : };
263 :
264 15451 : char const* s0 = nullptr;
265 15451 : char const* s1 = nullptr;
266 :
267 15451 : bool has_crlf = false;
268 15451 : bool has_obs_fold = false;
269 :
270 100095 : while( it < end )
271 : {
272 96599 : auto ch = *it;
273 96599 : if( ws(ch) )
274 : {
275 17363 : ++it;
276 17363 : continue;
277 : }
278 :
279 79236 : if( ch == '\r' )
280 : {
281 : // too short to know if we have a potential obs-fold
282 : // occurrence
283 12651 : if( end - it < 2 )
284 592 : BOOST_HTTP_RETURN_EC(
285 : grammar::error::need_more);
286 :
287 12059 : if( it[1] != '\n' )
288 53 : goto done;
289 :
290 12006 : if( end - it < 3 )
291 546 : BOOST_HTTP_RETURN_EC(
292 : grammar::error::need_more);
293 :
294 11460 : if(! ws(it[2]) )
295 : {
296 10730 : has_crlf = true;
297 10730 : goto done;
298 : }
299 :
300 730 : has_obs_fold = true;
301 730 : it = it + 3;
302 730 : continue;
303 730 : }
304 :
305 66585 : if(! is_field_vchar(ch) )
306 : {
307 34 : goto done;
308 : }
309 :
310 66551 : if(! s0 )
311 14348 : s0 = it;
312 :
313 66551 : ++it;
314 66551 : s1 = it;
315 : }
316 :
317 3496 : done:
318 : // later routines wind up doing pointer
319 : // subtraction using the .data() member
320 : // of the value so we need a valid 0-len range
321 14313 : if(! s0 )
322 : {
323 939 : s0 = it;
324 939 : s1 = s0;
325 : }
326 :
327 14313 : v.value = core::string_view(s0, s1 - s0);
328 14313 : v.has_crlf = has_crlf;
329 14313 : v.has_obs_fold = has_obs_fold;
330 14313 : return v;
331 : }
332 :
333 : auto
334 37744 : field_rule_t::
335 : parse(
336 : char const*& it,
337 : char const* end) const noexcept ->
338 : system::result<value_type>
339 : {
340 37744 : if(it == end)
341 : {
342 979 : BOOST_HTTP_RETURN_EC(
343 : grammar::error::need_more);
344 : }
345 : // check for leading CRLF
346 36765 : if(it[0] == '\r')
347 : {
348 10641 : ++it;
349 10641 : if(it == end)
350 : {
351 489 : BOOST_HTTP_RETURN_EC(
352 : grammar::error::need_more);
353 : }
354 10152 : if(*it != '\n')
355 : {
356 21 : BOOST_HTTP_RETURN_EC(
357 : grammar::error::mismatch);
358 : }
359 : // end of fields
360 10131 : ++it;
361 10131 : BOOST_HTTP_RETURN_EC(
362 : grammar::error::end_of_range);
363 : }
364 :
365 26124 : value_type v;
366 : auto rv = grammar::parse(
367 26124 : it, end, grammar::tuple_rule(
368 : field_name_rule,
369 26124 : grammar::delim_rule(':'),
370 : field_value_rule,
371 26124 : crlf_rule));
372 :
373 26124 : if( rv.has_error() )
374 15410 : return rv.error();
375 :
376 10714 : auto val = rv.value();
377 10714 : v.name = std::get<0>(val);
378 10714 : v.value = std::get<2>(val).value;
379 10714 : v.has_obs_fold = std::get<2>(val).has_obs_fold;
380 :
381 10714 : return v;
382 : }
383 :
384 : //------------------------------------------------
385 :
386 : void
387 244 : remove_obs_fold(
388 : char* it,
389 : char const* const end) noexcept
390 : {
391 2262 : while(it != end)
392 : {
393 2236 : if(*it != '\r')
394 : {
395 1637 : ++it;
396 1637 : continue;
397 : }
398 599 : if(end - it < 3)
399 218 : break;
400 381 : BOOST_ASSERT(it[1] == '\n');
401 762 : if( it[1] == '\n' &&
402 381 : ws(it[2]))
403 : {
404 378 : it[0] = ' ';
405 378 : it[1] = ' ';
406 378 : it += 3;
407 : }
408 : else
409 : {
410 3 : ++it;
411 : }
412 : }
413 244 : }
414 :
415 : } // detail
416 : } // http
417 : } // boost
|