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/lut_chars.hpp>
21 : #include <boost/url/grammar/parse.hpp>
22 : #include <boost/url/grammar/tuple_rule.hpp>
23 :
24 : #include "rules.hpp"
25 :
26 : namespace boost {
27 : namespace http_proto {
28 : namespace detail {
29 :
30 : auto
31 5950 : crlf_rule_t::
32 : parse(
33 : char const*& it,
34 : char const* end) const noexcept ->
35 : system::result<value_type>
36 : {
37 5950 : if(it == end)
38 1002 : return grammar::error::need_more;
39 4948 : if(*it != '\r')
40 29 : return grammar::error::mismatch;
41 4919 : ++it;
42 4919 : if(it == end)
43 161 : return grammar::error::need_more;
44 4758 : if(*it != '\n')
45 51 : return grammar::error::mismatch;
46 4707 : ++it;
47 4707 : return {};
48 : }
49 :
50 : //------------------------------------------------
51 :
52 : auto
53 3505 : version_rule_t::
54 : parse(
55 : char const*& it,
56 : char const* end) const noexcept ->
57 : system::result<value_type>
58 : {
59 3505 : value_type v = 0;
60 3505 : if(it == end)
61 : {
62 : // expected "HTTP/"
63 171 : BOOST_HTTP_PROTO_RETURN_EC(
64 : grammar::error::need_more);
65 : }
66 3334 : if(end - it >= 5)
67 : {
68 2794 : if(std::memcmp(
69 : it, "HTTP/", 5) != 0)
70 : {
71 0 : BOOST_HTTP_PROTO_RETURN_EC(
72 : grammar::error::mismatch);
73 : }
74 2794 : it += 5;
75 : }
76 3334 : if(it == end)
77 : {
78 : // expected DIGIT
79 90 : BOOST_HTTP_PROTO_RETURN_EC(
80 : grammar::error::need_more);
81 : }
82 3244 : if(! grammar::digit_chars(*it))
83 : {
84 : // expected DIGIT
85 540 : BOOST_HTTP_PROTO_RETURN_EC(
86 : grammar::error::need_more);
87 : }
88 2704 : v = 10 * (*it++ - '0');
89 2704 : if(it == end)
90 : {
91 : // expected "."
92 234 : BOOST_HTTP_PROTO_RETURN_EC(
93 : grammar::error::need_more);
94 : }
95 2470 : if(*it != '.')
96 : {
97 : // expected "."
98 0 : BOOST_HTTP_PROTO_RETURN_EC(
99 : grammar::error::need_more);
100 : }
101 2470 : ++it;
102 2470 : if(it == end)
103 : {
104 : // expected DIGIT
105 89 : BOOST_HTTP_PROTO_RETURN_EC(
106 : grammar::error::need_more);
107 : }
108 2381 : if(! grammar::digit_chars(*it))
109 : {
110 : // expected DIGIT
111 0 : BOOST_HTTP_PROTO_RETURN_EC(
112 : grammar::error::need_more);
113 : }
114 2381 : v += *it++ - '0';
115 2381 : return v;
116 : }
117 :
118 : //------------------------------------------------
119 :
120 : auto
121 519 : status_code_rule_t::
122 : parse(
123 : char const*& it,
124 : char const* end) const noexcept ->
125 : system::result<value_type>
126 : {
127 : auto const dig =
128 1506 : [](char c) -> int
129 : {
130 1506 : unsigned char uc(c - '0');
131 1506 : if(uc > 9)
132 0 : return -1;
133 1506 : return uc;
134 : };
135 :
136 519 : if(it == end)
137 : {
138 : // end
139 9 : BOOST_HTTP_PROTO_RETURN_EC(
140 : grammar::error::need_more);
141 : }
142 510 : auto it0 = it;
143 510 : int v = dig(*it);
144 510 : if(v == -1)
145 : {
146 : // expected DIGIT
147 0 : BOOST_HTTP_PROTO_RETURN_EC(
148 : grammar::error::mismatch);
149 : }
150 510 : value_type t;
151 510 : t.v = 100 * v;
152 510 : ++it;
153 510 : if(it == end)
154 : {
155 : // end
156 8 : BOOST_HTTP_PROTO_RETURN_EC(
157 : grammar::error::need_more);
158 : }
159 502 : v = dig(*it);
160 502 : if(v == -1)
161 : {
162 : // expected DIGIT
163 0 : BOOST_HTTP_PROTO_RETURN_EC(
164 : grammar::error::mismatch);
165 : }
166 502 : t.v = t.v + (10 * v);
167 502 : ++it;
168 502 : if(it == end)
169 : {
170 : // end
171 8 : BOOST_HTTP_PROTO_RETURN_EC(
172 : grammar::error::need_more);
173 : }
174 494 : v = dig(*it);
175 494 : if(v == -1)
176 : {
177 : // expected DIGIT
178 0 : BOOST_HTTP_PROTO_RETURN_EC(
179 : grammar::error::need_more);
180 : }
181 494 : t.v = t.v + v;
182 494 : ++it;
183 :
184 494 : t.s = core::string_view(it0, it - it0);
185 494 : t.st = int_to_status(t.v);
186 494 : return t;
187 : }
188 :
189 : //------------------------------------------------
190 :
191 : auto
192 4752 : field_name_rule_t::
193 : parse(
194 : char const*& it,
195 : char const* end) const noexcept ->
196 : system::result<value_type>
197 : {
198 4752 : if( it == end )
199 1 : BOOST_HTTP_PROTO_RETURN_EC(
200 : grammar::error::need_more);
201 :
202 4751 : value_type v;
203 :
204 4751 : auto begin = it;
205 4751 : auto rv = grammar::parse(
206 : it, end, token_rule);
207 4751 : if( rv.has_error() || (it != end) )
208 : {
209 4148 : if( it != begin )
210 : {
211 4083 : v = core::string_view(begin, it - begin);
212 4083 : return v;
213 : }
214 65 : return error::bad_field_name;
215 : }
216 :
217 603 : v = core::string_view(begin, end - begin);
218 603 : return v;
219 : }
220 :
221 : auto
222 4330 : field_value_rule_t::
223 : parse(
224 : char const*& it,
225 : char const* end) const noexcept ->
226 : system::result<value_type>
227 : {
228 4330 : value_type v;
229 4330 : if( it == end )
230 : {
231 199 : v.value = core::string_view(it, 0);
232 199 : return v;
233 : }
234 :
235 : // field-line = field-name ":" OWS field-value OWS
236 : // field-value = *field-content
237 : // field-content = field-vchar
238 : // [ 1*( SP / HTAB / field-vchar ) field-vchar ]
239 : // field-vchar = VCHAR / obs-text
240 : // obs-text = %x80-FF
241 : // VCHAR = %x21-7E
242 : // ; visible (printing) characters
243 :
244 15254 : auto is_field_vchar = [](unsigned char ch)
245 : {
246 15254 : return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
247 : };
248 :
249 4131 : char const* s0 = nullptr;
250 4131 : char const* s1 = nullptr;
251 :
252 4131 : bool has_crlf = false;
253 4131 : bool has_obs_fold = false;
254 :
255 26109 : while( it < end )
256 : {
257 25151 : auto ch = *it;
258 25151 : if( ws(ch) )
259 : {
260 6042 : ++it;
261 6042 : continue;
262 : }
263 :
264 19109 : if( ch == '\r' )
265 : {
266 : // too short to know if we have a potential obs-fold
267 : // occurrence
268 3855 : if( end - it < 2 )
269 200 : BOOST_HTTP_PROTO_RETURN_EC(
270 : grammar::error::need_more);
271 :
272 3655 : if( it[1] != '\n' )
273 53 : goto done;
274 :
275 3602 : if( end - it < 3 )
276 171 : BOOST_HTTP_PROTO_RETURN_EC(
277 : grammar::error::need_more);
278 :
279 3431 : if(! ws(it[2]) )
280 : {
281 2715 : has_crlf = true;
282 2715 : goto done;
283 : }
284 :
285 716 : has_obs_fold = true;
286 716 : it = it + 3;
287 716 : continue;
288 716 : }
289 :
290 15254 : if(! is_field_vchar(ch) )
291 : {
292 34 : goto done;
293 : }
294 :
295 15220 : if(! s0 )
296 3506 : s0 = it;
297 :
298 15220 : ++it;
299 15220 : s1 = it;
300 : }
301 :
302 958 : done:
303 : // later routines wind up doing pointer
304 : // subtraction using the .data() member
305 : // of the value so we need a valid 0-len range
306 3760 : if(! s0 )
307 : {
308 462 : s0 = it;
309 462 : s1 = s0;
310 : }
311 :
312 3760 : v.value = core::string_view(s0, s1 - s0);
313 3760 : v.has_crlf = has_crlf;
314 3760 : v.has_obs_fold = has_obs_fold;
315 3760 : return v;
316 : }
317 :
318 : auto
319 6779 : field_rule_t::
320 : parse(
321 : char const*& it,
322 : char const* end) const noexcept ->
323 : system::result<value_type>
324 : {
325 6779 : if(it == end)
326 : {
327 197 : BOOST_HTTP_PROTO_RETURN_EC(
328 : grammar::error::need_more);
329 : }
330 : // check for leading CRLF
331 6582 : if(it[0] == '\r')
332 : {
333 2135 : ++it;
334 2135 : if(it == end)
335 : {
336 134 : BOOST_HTTP_PROTO_RETURN_EC(
337 : grammar::error::need_more);
338 : }
339 2001 : if(*it != '\n')
340 : {
341 21 : BOOST_HTTP_PROTO_RETURN_EC(
342 : grammar::error::mismatch);
343 : }
344 : // end of fields
345 1980 : ++it;
346 1980 : BOOST_HTTP_PROTO_RETURN_EC(
347 : grammar::error::end_of_range);
348 : }
349 :
350 4447 : value_type v;
351 : auto rv = grammar::parse(
352 4447 : it, end, grammar::tuple_rule(
353 : field_name_rule,
354 4447 : grammar::delim_rule(':'),
355 : field_value_rule,
356 4447 : crlf_rule));
357 :
358 4447 : if( rv.has_error() )
359 1739 : return rv.error();
360 :
361 2708 : auto val = rv.value();
362 2708 : v.name = std::get<0>(val);
363 2708 : v.value = std::get<2>(val).value;
364 2708 : v.has_obs_fold = std::get<2>(val).has_obs_fold;
365 :
366 2708 : return v;
367 : }
368 :
369 : //------------------------------------------------
370 :
371 : void
372 241 : remove_obs_fold(
373 : char* it,
374 : char const* const end) noexcept
375 : {
376 2247 : while(it != end)
377 : {
378 2224 : if(*it != '\r')
379 : {
380 1628 : ++it;
381 1628 : continue;
382 : }
383 596 : if(end - it < 3)
384 218 : break;
385 378 : BOOST_ASSERT(it[1] == '\n');
386 756 : if( it[1] == '\n' &&
387 378 : ws(it[2]))
388 : {
389 375 : it[0] = ' ';
390 375 : it[1] = ' ';
391 375 : it += 3;
392 : }
393 : else
394 : {
395 3 : ++it;
396 : }
397 : }
398 241 : }
399 :
400 : } // detail
401 : } // http_proto
402 : } // boost
|