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