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_proto
8 : //
9 :
10 : #include "src/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/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_proto {
29 : namespace detail {
30 :
31 : auto
32 23584 : crlf_rule_t::
33 : parse(
34 : char const*& it,
35 : char const* end) const noexcept ->
36 : system::result<value_type>
37 : {
38 23584 : if(it == end)
39 1269 : return grammar::error::need_more;
40 22315 : if(*it != '\r')
41 29 : return grammar::error::mismatch;
42 22286 : ++it;
43 22286 : if(it == end)
44 193 : return grammar::error::need_more;
45 22093 : if(*it != '\n')
46 51 : return grammar::error::mismatch;
47 22042 : ++it;
48 22042 : return {};
49 : }
50 :
51 : //------------------------------------------------
52 :
53 : auto
54 13206 : version_rule_t::
55 : parse(
56 : char const*& it,
57 : char const* end) const noexcept ->
58 : system::result<value_type>
59 : {
60 13206 : value_type v = 0;
61 13206 : if(it == end)
62 : {
63 : // expected "HTTP/"
64 887 : BOOST_HTTP_PROTO_RETURN_EC(
65 : grammar::error::need_more);
66 : }
67 12319 : if(end - it >= 5)
68 : {
69 11647 : if(std::memcmp(
70 : it, "HTTP/", 5) != 0)
71 : {
72 0 : BOOST_HTTP_PROTO_RETURN_EC(
73 : grammar::error::mismatch);
74 : }
75 11647 : it += 5;
76 : }
77 12319 : if(it == end)
78 : {
79 : // expected DIGIT
80 123 : BOOST_HTTP_PROTO_RETURN_EC(
81 : grammar::error::need_more);
82 : }
83 12196 : if(! grammar::digit_chars(*it))
84 : {
85 : // expected DIGIT
86 672 : BOOST_HTTP_PROTO_RETURN_EC(
87 : grammar::error::need_more);
88 : }
89 11524 : v = 10 * (*it++ - '0');
90 11524 : if(it == end)
91 : {
92 : // expected "."
93 267 : BOOST_HTTP_PROTO_RETURN_EC(
94 : grammar::error::need_more);
95 : }
96 11257 : if(*it != '.')
97 : {
98 : // expected "."
99 0 : BOOST_HTTP_PROTO_RETURN_EC(
100 : grammar::error::need_more);
101 : }
102 11257 : ++it;
103 11257 : if(it == end)
104 : {
105 : // expected DIGIT
106 121 : BOOST_HTTP_PROTO_RETURN_EC(
107 : grammar::error::need_more);
108 : }
109 11136 : if(! grammar::digit_chars(*it))
110 : {
111 : // expected DIGIT
112 0 : BOOST_HTTP_PROTO_RETURN_EC(
113 : grammar::error::need_more);
114 : }
115 11136 : v += *it++ - '0';
116 11136 : return v;
117 : }
118 :
119 : //------------------------------------------------
120 :
121 : auto
122 1033 : 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 2949 : [](char c) -> int
130 : {
131 2949 : unsigned char uc(c - '0');
132 2949 : if(uc > 9)
133 0 : return -1;
134 2949 : return uc;
135 : };
136 :
137 1033 : if(it == end)
138 : {
139 : // end
140 26 : BOOST_HTTP_PROTO_RETURN_EC(
141 : grammar::error::need_more);
142 : }
143 1007 : auto it0 = it;
144 1007 : int v = dig(*it);
145 1007 : if(v == -1)
146 : {
147 : // expected DIGIT
148 0 : BOOST_HTTP_PROTO_RETURN_EC(
149 : grammar::error::mismatch);
150 : }
151 1007 : value_type t;
152 1007 : t.v = 100 * v;
153 1007 : ++it;
154 1007 : if(it == end)
155 : {
156 : // end
157 24 : BOOST_HTTP_PROTO_RETURN_EC(
158 : grammar::error::need_more);
159 : }
160 983 : v = dig(*it);
161 983 : if(v == -1)
162 : {
163 : // expected DIGIT
164 0 : BOOST_HTTP_PROTO_RETURN_EC(
165 : grammar::error::mismatch);
166 : }
167 983 : t.v = t.v + (10 * v);
168 983 : ++it;
169 983 : if(it == end)
170 : {
171 : // end
172 24 : BOOST_HTTP_PROTO_RETURN_EC(
173 : grammar::error::need_more);
174 : }
175 959 : v = dig(*it);
176 959 : if(v == -1)
177 : {
178 : // expected DIGIT
179 0 : BOOST_HTTP_PROTO_RETURN_EC(
180 : grammar::error::need_more);
181 : }
182 959 : t.v = t.v + v;
183 959 : ++it;
184 :
185 959 : t.s = core::string_view(it0, it - it0);
186 959 : t.st = int_to_status(t.v);
187 959 : return t;
188 : }
189 :
190 : //------------------------------------------------
191 :
192 : auto
193 933 : reason_phrase_rule_t::
194 : parse(
195 : char const*& it,
196 : char const* end) const noexcept ->
197 : system::result<value_type>
198 : {
199 933 : auto begin = it;
200 933 : it = grammar::find_if_not(it, end, ws_vchars);
201 933 : return core::string_view(begin, it);
202 : }
203 :
204 : //------------------------------------------------
205 :
206 : auto
207 14125 : field_name_rule_t::
208 : parse(
209 : char const*& it,
210 : char const* end) const noexcept ->
211 : system::result<value_type>
212 : {
213 14125 : if( it == end )
214 1 : BOOST_HTTP_PROTO_RETURN_EC(
215 : grammar::error::need_more);
216 :
217 14124 : value_type v;
218 :
219 14124 : auto begin = it;
220 14124 : auto rv = grammar::parse(
221 : it, end, token_rule);
222 14124 : if( rv.has_error() || (it != end) )
223 : {
224 13185 : if( it != begin )
225 : {
226 13119 : v = core::string_view(begin, it - begin);
227 13119 : return v;
228 : }
229 66 : return error::bad_field_name;
230 : }
231 :
232 939 : v = core::string_view(begin, end - begin);
233 939 : return v;
234 : }
235 :
236 : auto
237 13383 : field_value_rule_t::
238 : parse(
239 : char const*& it,
240 : char const* end) const noexcept ->
241 : system::result<value_type>
242 : {
243 13383 : value_type v;
244 13383 : if( it == end )
245 : {
246 239 : v.value = core::string_view(it, 0);
247 239 : 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 57557 : auto is_field_vchar = [](unsigned char ch)
260 : {
261 57557 : return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
262 : };
263 :
264 13144 : char const* s0 = nullptr;
265 13144 : char const* s1 = nullptr;
266 :
267 13144 : bool has_crlf = false;
268 13144 : bool has_obs_fold = false;
269 :
270 86439 : while( it < end )
271 : {
272 85320 : auto ch = *it;
273 85320 : if( ws(ch) )
274 : {
275 15042 : ++it;
276 15042 : continue;
277 : }
278 :
279 70278 : if( ch == '\r' )
280 : {
281 : // too short to know if we have a potential obs-fold
282 : // occurrence
283 12721 : if( end - it < 2 )
284 240 : BOOST_HTTP_PROTO_RETURN_EC(
285 : grammar::error::need_more);
286 :
287 12481 : if( it[1] != '\n' )
288 53 : goto done;
289 :
290 12428 : if( end - it < 3 )
291 214 : BOOST_HTTP_PROTO_RETURN_EC(
292 : grammar::error::need_more);
293 :
294 12214 : if(! ws(it[2]) )
295 : {
296 11484 : has_crlf = true;
297 11484 : goto done;
298 : }
299 :
300 730 : has_obs_fold = true;
301 730 : it = it + 3;
302 730 : continue;
303 730 : }
304 :
305 57557 : if(! is_field_vchar(ch) )
306 : {
307 34 : goto done;
308 : }
309 :
310 57523 : if(! s0 )
311 12475 : s0 = it;
312 :
313 57523 : ++it;
314 57523 : s1 = it;
315 : }
316 :
317 1119 : 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 12690 : if(! s0 )
322 : {
323 505 : s0 = it;
324 505 : s1 = s0;
325 : }
326 :
327 12690 : v.value = core::string_view(s0, s1 - s0);
328 12690 : v.has_crlf = has_crlf;
329 12690 : v.has_obs_fold = has_obs_fold;
330 12690 : return v;
331 : }
332 :
333 : auto
334 24856 : field_rule_t::
335 : parse(
336 : char const*& it,
337 : char const* end) const noexcept ->
338 : system::result<value_type>
339 : {
340 24856 : if(it == end)
341 : {
342 229 : BOOST_HTTP_PROTO_RETURN_EC(
343 : grammar::error::need_more);
344 : }
345 : // check for leading CRLF
346 24627 : if(it[0] == '\r')
347 : {
348 10737 : ++it;
349 10737 : if(it == end)
350 : {
351 167 : BOOST_HTTP_PROTO_RETURN_EC(
352 : grammar::error::need_more);
353 : }
354 10570 : if(*it != '\n')
355 : {
356 21 : BOOST_HTTP_PROTO_RETURN_EC(
357 : grammar::error::mismatch);
358 : }
359 : // end of fields
360 10549 : ++it;
361 10549 : BOOST_HTTP_PROTO_RETURN_EC(
362 : grammar::error::end_of_range);
363 : }
364 :
365 13890 : value_type v;
366 : auto rv = grammar::parse(
367 13890 : it, end, grammar::tuple_rule(
368 : field_name_rule,
369 13890 : grammar::delim_rule(':'),
370 : field_value_rule,
371 13890 : crlf_rule));
372 :
373 13890 : if( rv.has_error() )
374 2422 : return rv.error();
375 :
376 11468 : auto val = rv.value();
377 11468 : v.name = std::get<0>(val);
378 11468 : v.value = std::get<2>(val).value;
379 11468 : v.has_obs_fold = std::get<2>(val).has_obs_fold;
380 :
381 11468 : return v;
382 : }
383 :
384 : //------------------------------------------------
385 :
386 : void
387 231 : remove_obs_fold(
388 : char* it,
389 : char const* const end) noexcept
390 : {
391 2229 : while(it != end)
392 : {
393 2208 : if(*it != '\r')
394 : {
395 1624 : ++it;
396 1624 : continue;
397 : }
398 584 : if(end - it < 3)
399 210 : break;
400 374 : BOOST_ASSERT(it[1] == '\n');
401 748 : if( it[1] == '\n' &&
402 374 : ws(it[2]))
403 : {
404 374 : it[0] = ' ';
405 374 : it[1] = ' ';
406 374 : it += 3;
407 : }
408 : else
409 : {
410 0 : ++it;
411 : }
412 : }
413 231 : }
414 :
415 : } // detail
416 : } // http_proto
417 : } // boost
|