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 23763 : crlf_rule_t::
33 : parse(
34 : char const*& it,
35 : char const* end) const noexcept ->
36 : system::result<value_type>
37 : {
38 23763 : if(it == end)
39 1269 : return grammar::error::need_more;
40 22494 : if(*it != '\r')
41 29 : return grammar::error::mismatch;
42 22465 : ++it;
43 22465 : if(it == end)
44 193 : return grammar::error::need_more;
45 22272 : if(*it != '\n')
46 51 : return grammar::error::mismatch;
47 22221 : ++it;
48 22221 : return {};
49 : }
50 :
51 : //------------------------------------------------
52 :
53 : auto
54 13224 : version_rule_t::
55 : parse(
56 : char const*& it,
57 : char const* end) const noexcept ->
58 : system::result<value_type>
59 : {
60 13224 : value_type v = 0;
61 13224 : if(it == end)
62 : {
63 : // expected "HTTP/"
64 887 : BOOST_HTTP_PROTO_RETURN_EC(
65 : grammar::error::need_more);
66 : }
67 12337 : if(end - it >= 5)
68 : {
69 11665 : if(std::memcmp(
70 : it, "HTTP/", 5) != 0)
71 : {
72 0 : BOOST_HTTP_PROTO_RETURN_EC(
73 : grammar::error::mismatch);
74 : }
75 11665 : it += 5;
76 : }
77 12337 : if(it == end)
78 : {
79 : // expected DIGIT
80 123 : BOOST_HTTP_PROTO_RETURN_EC(
81 : grammar::error::need_more);
82 : }
83 12214 : if(! grammar::digit_chars(*it))
84 : {
85 : // expected DIGIT
86 672 : BOOST_HTTP_PROTO_RETURN_EC(
87 : grammar::error::need_more);
88 : }
89 11542 : v = 10 * (*it++ - '0');
90 11542 : if(it == end)
91 : {
92 : // expected "."
93 267 : BOOST_HTTP_PROTO_RETURN_EC(
94 : grammar::error::need_more);
95 : }
96 11275 : if(*it != '.')
97 : {
98 : // expected "."
99 0 : BOOST_HTTP_PROTO_RETURN_EC(
100 : grammar::error::need_more);
101 : }
102 11275 : ++it;
103 11275 : if(it == end)
104 : {
105 : // expected DIGIT
106 121 : BOOST_HTTP_PROTO_RETURN_EC(
107 : grammar::error::need_more);
108 : }
109 11154 : if(! grammar::digit_chars(*it))
110 : {
111 : // expected DIGIT
112 0 : BOOST_HTTP_PROTO_RETURN_EC(
113 : grammar::error::need_more);
114 : }
115 11154 : v += *it++ - '0';
116 11154 : return v;
117 : }
118 :
119 : //------------------------------------------------
120 :
121 : auto
122 1036 : 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 2958 : [](char c) -> int
130 : {
131 2958 : unsigned char uc(c - '0');
132 2958 : if(uc > 9)
133 0 : return -1;
134 2958 : return uc;
135 : };
136 :
137 1036 : if(it == end)
138 : {
139 : // end
140 26 : BOOST_HTTP_PROTO_RETURN_EC(
141 : grammar::error::need_more);
142 : }
143 1010 : auto it0 = it;
144 1010 : int v = dig(*it);
145 1010 : if(v == -1)
146 : {
147 : // expected DIGIT
148 0 : BOOST_HTTP_PROTO_RETURN_EC(
149 : grammar::error::mismatch);
150 : }
151 1010 : value_type t;
152 1010 : t.v = 100 * v;
153 1010 : ++it;
154 1010 : if(it == end)
155 : {
156 : // end
157 24 : BOOST_HTTP_PROTO_RETURN_EC(
158 : grammar::error::need_more);
159 : }
160 986 : v = dig(*it);
161 986 : if(v == -1)
162 : {
163 : // expected DIGIT
164 0 : BOOST_HTTP_PROTO_RETURN_EC(
165 : grammar::error::mismatch);
166 : }
167 986 : t.v = t.v + (10 * v);
168 986 : ++it;
169 986 : if(it == end)
170 : {
171 : // end
172 24 : BOOST_HTTP_PROTO_RETURN_EC(
173 : grammar::error::need_more);
174 : }
175 962 : v = dig(*it);
176 962 : if(v == -1)
177 : {
178 : // expected DIGIT
179 0 : BOOST_HTTP_PROTO_RETURN_EC(
180 : grammar::error::need_more);
181 : }
182 962 : t.v = t.v + v;
183 962 : ++it;
184 :
185 962 : t.s = core::string_view(it0, it - it0);
186 962 : t.st = int_to_status(t.v);
187 962 : return t;
188 : }
189 :
190 : //------------------------------------------------
191 :
192 : auto
193 936 : reason_phrase_rule_t::
194 : parse(
195 : char const*& it,
196 : char const* end) const noexcept ->
197 : system::result<value_type>
198 : {
199 936 : auto begin = it;
200 936 : it = grammar::find_if_not(it, end, ws_vchars);
201 936 : return core::string_view(begin, it);
202 : }
203 :
204 : //------------------------------------------------
205 :
206 : auto
207 14301 : field_name_rule_t::
208 : parse(
209 : char const*& it,
210 : char const* end) const noexcept ->
211 : system::result<value_type>
212 : {
213 14301 : if( it == end )
214 1 : BOOST_HTTP_PROTO_RETURN_EC(
215 : grammar::error::need_more);
216 :
217 14300 : value_type v;
218 :
219 14300 : auto begin = it;
220 14300 : auto rv = grammar::parse(
221 : it, end, token_rule);
222 14300 : if( rv.has_error() || (it != end) )
223 : {
224 13346 : if( it != begin )
225 : {
226 13280 : v = core::string_view(begin, it - begin);
227 13280 : return v;
228 : }
229 66 : return error::bad_field_name;
230 : }
231 :
232 954 : v = core::string_view(begin, end - begin);
233 954 : return v;
234 : }
235 :
236 : auto
237 13562 : field_value_rule_t::
238 : parse(
239 : char const*& it,
240 : char const* end) const noexcept ->
241 : system::result<value_type>
242 : {
243 13562 : value_type v;
244 13562 : 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 58260 : auto is_field_vchar = [](unsigned char ch)
260 : {
261 58260 : return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
262 : };
263 :
264 13323 : char const* s0 = nullptr;
265 13323 : char const* s1 = nullptr;
266 :
267 13323 : bool has_crlf = false;
268 13323 : bool has_obs_fold = false;
269 :
270 87482 : while( it < end )
271 : {
272 86345 : auto ch = *it;
273 86345 : if( ws(ch) )
274 : {
275 15203 : ++it;
276 15203 : continue;
277 : }
278 :
279 71142 : if( ch == '\r' )
280 : {
281 : // too short to know if we have a potential obs-fold
282 : // occurrence
283 12882 : if( end - it < 2 )
284 240 : BOOST_HTTP_PROTO_RETURN_EC(
285 : grammar::error::need_more);
286 :
287 12642 : if( it[1] != '\n' )
288 53 : goto done;
289 :
290 12589 : if( end - it < 3 )
291 214 : BOOST_HTTP_PROTO_RETURN_EC(
292 : grammar::error::need_more);
293 :
294 12375 : if(! ws(it[2]) )
295 : {
296 11645 : has_crlf = true;
297 11645 : goto done;
298 : }
299 :
300 730 : has_obs_fold = true;
301 730 : it = it + 3;
302 730 : continue;
303 730 : }
304 :
305 58260 : if(! is_field_vchar(ch) )
306 : {
307 34 : goto done;
308 : }
309 :
310 58226 : if(! s0 )
311 12654 : s0 = it;
312 :
313 58226 : ++it;
314 58226 : s1 = it;
315 : }
316 :
317 1137 : 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 12869 : if(! s0 )
322 : {
323 505 : s0 = it;
324 505 : s1 = s0;
325 : }
326 :
327 12869 : v.value = core::string_view(s0, s1 - s0);
328 12869 : v.has_crlf = has_crlf;
329 12869 : v.has_obs_fold = has_obs_fold;
330 12869 : return v;
331 : }
332 :
333 : auto
334 25077 : field_rule_t::
335 : parse(
336 : char const*& it,
337 : char const* end) const noexcept ->
338 : system::result<value_type>
339 : {
340 25077 : if(it == end)
341 : {
342 229 : BOOST_HTTP_PROTO_RETURN_EC(
343 : grammar::error::need_more);
344 : }
345 : // check for leading CRLF
346 24848 : if(it[0] == '\r')
347 : {
348 10797 : ++it;
349 10797 : if(it == end)
350 : {
351 167 : BOOST_HTTP_PROTO_RETURN_EC(
352 : grammar::error::need_more);
353 : }
354 10630 : if(*it != '\n')
355 : {
356 21 : BOOST_HTTP_PROTO_RETURN_EC(
357 : grammar::error::mismatch);
358 : }
359 : // end of fields
360 10609 : ++it;
361 10609 : BOOST_HTTP_PROTO_RETURN_EC(
362 : grammar::error::end_of_range);
363 : }
364 :
365 14051 : value_type v;
366 : auto rv = grammar::parse(
367 14051 : it, end, grammar::tuple_rule(
368 : field_name_rule,
369 14051 : grammar::delim_rule(':'),
370 : field_value_rule,
371 14051 : crlf_rule));
372 :
373 14051 : if( rv.has_error() )
374 2422 : return rv.error();
375 :
376 11629 : auto val = rv.value();
377 11629 : v.name = std::get<0>(val);
378 11629 : v.value = std::get<2>(val).value;
379 11629 : v.has_obs_fold = std::get<2>(val).has_obs_fold;
380 :
381 11629 : 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
|