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 28320 : crlf_rule_t::
33 : parse(
34 : char const*& it,
35 : char const* end) const noexcept ->
36 : system::result<value_type>
37 : {
38 28320 : if(it == end)
39 6145 : return grammar::error::need_more;
40 22175 : if(*it != '\r')
41 29 : return grammar::error::mismatch;
42 22146 : ++it;
43 22146 : if(it == end)
44 887 : return grammar::error::need_more;
45 21259 : if(*it != '\n')
46 51 : return grammar::error::mismatch;
47 21208 : ++it;
48 21208 : return {};
49 : }
50 :
51 : //------------------------------------------------
52 :
53 : auto
54 26900 : version_rule_t::
55 : parse(
56 : char const*& it,
57 : char const* end) const noexcept ->
58 : system::result<value_type>
59 : {
60 26900 : value_type v = 0;
61 26900 : if(it == end)
62 : {
63 : // expected "HTTP/"
64 1511 : BOOST_HTTP_RETURN_EC(
65 : grammar::error::need_more);
66 : }
67 25389 : if(end - it >= 5)
68 : {
69 21083 : if(std::memcmp(
70 : it, "HTTP/", 5) != 0)
71 : {
72 MIS 0 : BOOST_HTTP_RETURN_EC(
73 : grammar::error::mismatch);
74 : }
75 HIT 21083 : it += 5;
76 : }
77 25389 : if(it == end)
78 : {
79 : // expected DIGIT
80 991 : BOOST_HTTP_RETURN_EC(
81 : grammar::error::need_more);
82 : }
83 24398 : if(! grammar::digit_chars(*it))
84 : {
85 : // expected DIGIT
86 4306 : BOOST_HTTP_RETURN_EC(
87 : grammar::error::need_more);
88 : }
89 20092 : v = 10 * (*it++ - '0');
90 20092 : if(it == end)
91 : {
92 : // expected "."
93 1119 : BOOST_HTTP_RETURN_EC(
94 : grammar::error::need_more);
95 : }
96 18973 : if(*it != '.')
97 : {
98 : // expected "."
99 MIS 0 : BOOST_HTTP_RETURN_EC(
100 : grammar::error::need_more);
101 : }
102 HIT 18973 : ++it;
103 18973 : if(it == end)
104 : {
105 : // expected DIGIT
106 959 : BOOST_HTTP_RETURN_EC(
107 : grammar::error::need_more);
108 : }
109 18014 : if(! grammar::digit_chars(*it))
110 : {
111 : // expected DIGIT
112 MIS 0 : BOOST_HTTP_RETURN_EC(
113 : grammar::error::need_more);
114 : }
115 HIT 18014 : v += *it++ - '0';
116 18014 : return v;
117 : }
118 :
119 : //------------------------------------------------
120 :
121 : auto
122 7464 : 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 17380 : [](char c) -> int
130 : {
131 17380 : unsigned char uc(c - '0');
132 17380 : if(uc > 9)
133 MIS 0 : return -1;
134 HIT 17380 : return uc;
135 : };
136 :
137 7464 : if(it == end)
138 : {
139 : // end
140 846 : BOOST_HTTP_RETURN_EC(
141 : grammar::error::need_more);
142 : }
143 6618 : auto it0 = it;
144 6618 : int v = dig(*it);
145 6618 : if(v == -1)
146 : {
147 : // expected DIGIT
148 MIS 0 : BOOST_HTTP_RETURN_EC(
149 : grammar::error::mismatch);
150 : }
151 HIT 6618 : value_type t;
152 6618 : t.v = 100 * v;
153 6618 : ++it;
154 6618 : if(it == end)
155 : {
156 : // end
157 830 : BOOST_HTTP_RETURN_EC(
158 : grammar::error::need_more);
159 : }
160 5788 : v = dig(*it);
161 5788 : if(v == -1)
162 : {
163 : // expected DIGIT
164 MIS 0 : BOOST_HTTP_RETURN_EC(
165 : grammar::error::mismatch);
166 : }
167 HIT 5788 : t.v = t.v + (10 * v);
168 5788 : ++it;
169 5788 : if(it == end)
170 : {
171 : // end
172 814 : BOOST_HTTP_RETURN_EC(
173 : grammar::error::need_more);
174 : }
175 4974 : v = dig(*it);
176 4974 : if(v == -1)
177 : {
178 : // expected DIGIT
179 MIS 0 : BOOST_HTTP_RETURN_EC(
180 : grammar::error::need_more);
181 : }
182 HIT 4974 : t.v = t.v + v;
183 4974 : ++it;
184 :
185 4974 : t.s = core::string_view(it0, it - it0);
186 4974 : t.st = int_to_status(t.v);
187 4974 : return t;
188 : }
189 :
190 : //------------------------------------------------
191 :
192 : auto
193 4176 : reason_phrase_rule_t::
194 : parse(
195 : char const*& it,
196 : char const* end) const noexcept ->
197 : system::result<value_type>
198 : {
199 4176 : auto begin = it;
200 4176 : it = grammar::find_if_not(it, end, ws_vchars);
201 4176 : return core::string_view(begin, it);
202 : }
203 :
204 : //------------------------------------------------
205 :
206 : auto
207 25313 : field_name_rule_t::
208 : parse(
209 : char const*& it,
210 : char const* end) const noexcept ->
211 : system::result<value_type>
212 : {
213 25313 : if( it == end )
214 1 : BOOST_HTTP_RETURN_EC(
215 : grammar::error::need_more);
216 :
217 25312 : value_type v;
218 :
219 25312 : auto begin = it;
220 25312 : auto rv = grammar::parse(
221 : it, end, token_rule);
222 25312 : if( rv.has_error() || (it != end) )
223 : {
224 15687 : if( it != begin )
225 : {
226 15621 : v = core::string_view(begin, it - begin);
227 15621 : return v;
228 : }
229 66 : return error::bad_field_name;
230 : }
231 :
232 9625 : v = core::string_view(begin, end - begin);
233 9625 : return v;
234 : }
235 :
236 : auto
237 15890 : field_value_rule_t::
238 : parse(
239 : char const*& it,
240 : char const* end) const noexcept ->
241 : system::result<value_type>
242 : {
243 15890 : value_type v;
244 15890 : if( it == end )
245 : {
246 651 : v.value = core::string_view(it, 0);
247 651 : 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 66277 : auto is_field_vchar = [](unsigned char ch)
260 : {
261 66277 : return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
262 : };
263 :
264 15239 : char const* s0 = nullptr;
265 15239 : char const* s1 = nullptr;
266 :
267 15239 : bool has_crlf = false;
268 15239 : bool has_obs_fold = false;
269 :
270 99363 : while( it < end )
271 : {
272 95981 : auto ch = *it;
273 95981 : if( ws(ch) )
274 : {
275 17151 : ++it;
276 17151 : continue;
277 : }
278 :
279 78830 : if( ch == '\r' )
280 : {
281 : // too short to know if we have a potential obs-fold
282 : // occurrence
283 12553 : if( end - it < 2 )
284 558 : BOOST_HTTP_RETURN_EC(
285 : grammar::error::need_more);
286 :
287 11995 : if( it[1] != '\n' )
288 53 : goto done;
289 :
290 11942 : if( end - it < 3 )
291 514 : BOOST_HTTP_RETURN_EC(
292 : grammar::error::need_more);
293 :
294 11428 : if(! ws(it[2]) )
295 : {
296 10698 : has_crlf = true;
297 10698 : goto done;
298 : }
299 :
300 730 : has_obs_fold = true;
301 730 : it = it + 3;
302 730 : continue;
303 730 : }
304 :
305 66277 : if(! is_field_vchar(ch) )
306 : {
307 34 : goto done;
308 : }
309 :
310 66243 : if(! s0 )
311 14176 : s0 = it;
312 :
313 66243 : ++it;
314 66243 : s1 = it;
315 : }
316 :
317 3382 : 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 14167 : if(! s0 )
322 : {
323 899 : s0 = it;
324 899 : s1 = s0;
325 : }
326 :
327 14167 : v.value = core::string_view(s0, s1 - s0);
328 14167 : v.has_crlf = has_crlf;
329 14167 : v.has_obs_fold = has_obs_fold;
330 14167 : return v;
331 : }
332 :
333 : auto
334 36560 : field_rule_t::
335 : parse(
336 : char const*& it,
337 : char const* end) const noexcept ->
338 : system::result<value_type>
339 : {
340 36560 : if(it == end)
341 : {
342 907 : BOOST_HTTP_RETURN_EC(
343 : grammar::error::need_more);
344 : }
345 : // check for leading CRLF
346 35653 : if(it[0] == '\r')
347 : {
348 10581 : ++it;
349 10581 : if(it == end)
350 : {
351 459 : BOOST_HTTP_RETURN_EC(
352 : grammar::error::need_more);
353 : }
354 10122 : if(*it != '\n')
355 : {
356 21 : BOOST_HTTP_RETURN_EC(
357 : grammar::error::mismatch);
358 : }
359 : // end of fields
360 10101 : ++it;
361 10101 : BOOST_HTTP_RETURN_EC(
362 : grammar::error::end_of_range);
363 : }
364 :
365 25072 : value_type v;
366 : auto rv = grammar::parse(
367 25072 : it, end, grammar::tuple_rule(
368 : field_name_rule,
369 25072 : grammar::delim_rule(':'),
370 : field_value_rule,
371 25072 : crlf_rule));
372 :
373 25072 : if( rv.has_error() )
374 14390 : return rv.error();
375 :
376 10682 : auto val = rv.value();
377 10682 : v.name = std::get<0>(val);
378 10682 : v.value = std::get<2>(val).value;
379 10682 : v.has_obs_fold = std::get<2>(val).has_obs_fold;
380 :
381 10682 : 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
|