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