src/rfc/detail/rules.cpp

95.8% Lines (159/0/166) 100.0% List of functions (10/0/10)
rules.cpp
f(x) Functions (10)
Line TLA Hits 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
8 //
9
10 #include "src/rfc/detail/rules.hpp"
11
12 #include <boost/http/error.hpp>
13 #include <boost/http/detail/config.hpp>
14 #include <boost/http/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 {
29 namespace detail {
30
31 auto
32 28890x crlf_rule_t::
33 parse(
34 char const*& it,
35 char const* end) const noexcept ->
36 system::result<value_type>
37 {
38 28890x if(it == end)
39 6535x return grammar::error::need_more;
40 22355x if(*it != '\r')
41 29x return grammar::error::mismatch;
42 22326x ++it;
43 22326x if(it == end)
44 961x return grammar::error::need_more;
45 21365x if(*it != '\n')
46 51x return grammar::error::mismatch;
47 21314x ++it;
48 21314x return {};
49 }
50
51 //------------------------------------------------
52
53 auto
54 28506x version_rule_t::
55 parse(
56 char const*& it,
57 char const* end) const noexcept ->
58 system::result<value_type>
59 {
60 28506x value_type v = 0;
61 28506x if(it == end)
62 {
63 // expected "HTTP/"
64 1619x return grammar::error::need_more;
65 }
66 26887x if(end - it >= 5)
67 {
68 22177x if(std::memcmp(
69 it, "HTTP/", 5) != 0)
70 {
71 return grammar::error::mismatch;
72 }
73 22177x it += 5;
74 }
75 26887x if(it == end)
76 {
77 // expected DIGIT
78 1087x return grammar::error::need_more;
79 }
80 25800x if(! grammar::digit_chars(*it))
81 {
82 // expected DIGIT
83 4710x return grammar::error::need_more;
84 }
85 21090x v = 10 * (*it++ - '0');
86 21090x if(it == end)
87 {
88 // expected "."
89 1213x return grammar::error::need_more;
90 }
91 19877x if(*it != '.')
92 {
93 // expected "."
94 return grammar::error::need_more;
95 }
96 19877x ++it;
97 19877x if(it == end)
98 {
99 // expected DIGIT
100 1051x return grammar::error::need_more;
101 }
102 18826x if(! grammar::digit_chars(*it))
103 {
104 // expected DIGIT
105 return grammar::error::need_more;
106 }
107 18826x v += *it++ - '0';
108 18826x return v;
109 }
110
111 //------------------------------------------------
112
113 auto
114 8184x status_code_rule_t::
115 parse(
116 char const*& it,
117 char const* end) const noexcept ->
118 system::result<value_type>
119 {
120 auto const dig =
121 19020x [](char c) -> int
122 {
123 19020x unsigned char uc(c - '0');
124 19020x if(uc > 9)
125 return -1;
126 19020x return uc;
127 };
128
129 8184x if(it == end)
130 {
131 // end
132 934x return grammar::error::need_more;
133 }
134 7250x auto it0 = it;
135 7250x int v = dig(*it);
136 7250x if(v == -1)
137 {
138 // expected DIGIT
139 return grammar::error::mismatch;
140 }
141 7250x value_type t;
142 7250x t.v = 100 * v;
143 7250x ++it;
144 7250x if(it == end)
145 {
146 // end
147 916x return grammar::error::need_more;
148 }
149 6334x v = dig(*it);
150 6334x if(v == -1)
151 {
152 // expected DIGIT
153 return grammar::error::mismatch;
154 }
155 6334x t.v = t.v + (10 * v);
156 6334x ++it;
157 6334x if(it == end)
158 {
159 // end
160 898x return grammar::error::need_more;
161 }
162 5436x v = dig(*it);
163 5436x if(v == -1)
164 {
165 // expected DIGIT
166 return grammar::error::need_more;
167 }
168 5436x t.v = t.v + v;
169 5436x ++it;
170
171 5436x t.s = core::string_view(it0, it - it0);
172 5436x t.st = int_to_status(t.v);
173 5436x return t;
174 }
175
176 //------------------------------------------------
177
178 auto
179 4556x reason_phrase_rule_t::
180 parse(
181 char const*& it,
182 char const* end) const noexcept ->
183 system::result<value_type>
184 {
185 4556x auto begin = it;
186 4556x it = grammar::find_if_not(it, end, ws_vchars);
187 4556x return core::string_view(begin, it);
188 }
189
190 //------------------------------------------------
191
192 auto
193 26365x field_name_rule_t::
194 parse(
195 char const*& it,
196 char const* end) const noexcept ->
197 system::result<value_type>
198 {
199 26365x if( it == end )
200 1x return grammar::error::need_more;
201
202 26364x value_type v;
203
204 26364x auto begin = it;
205 26364x auto rv = grammar::parse(
206 it, end, token_rule);
207 26364x if( rv.has_error() || (it != end) )
208 {
209 15941x if( it != begin )
210 {
211 15875x v = core::string_view(begin, it - begin);
212 15875x return v;
213 }
214 132x return make_error_code(
215 66x error::bad_field_name);
216 }
217
218 10423x v = core::string_view(begin, end - begin);
219 10423x return v;
220 }
221
222 auto
223 16144x field_value_rule_t::
224 parse(
225 char const*& it,
226 char const* end) const noexcept ->
227 system::result<value_type>
228 {
229 16144x value_type v;
230 16144x if( it == end )
231 {
232 693x v.value = core::string_view(it, 0);
233 693x 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 66585x auto is_field_vchar = [](unsigned char ch)
246 {
247 66585x return (ch >= 0x21 && ch <= 0x7e) || ch >= 0x80;
248 };
249
250 15451x char const* s0 = nullptr;
251 15451x char const* s1 = nullptr;
252
253 15451x bool has_crlf = false;
254 15451x bool has_obs_fold = false;
255
256 100095x while( it < end )
257 {
258 96599x auto ch = *it;
259 96599x if( ws(ch) )
260 {
261 17363x ++it;
262 17363x continue;
263 }
264
265 79236x if( ch == '\r' )
266 {
267 // too short to know if we have a potential obs-fold
268 // occurrence
269 12651x if( end - it < 2 )
270 592x return grammar::error::need_more;
271
272 12059x if( it[1] != '\n' )
273 53x goto done;
274
275 12006x if( end - it < 3 )
276 546x return grammar::error::need_more;
277
278 11460x if(! ws(it[2]) )
279 {
280 10730x has_crlf = true;
281 10730x goto done;
282 }
283
284 730x has_obs_fold = true;
285 730x it = it + 3;
286 730x continue;
287 }
288
289 66585x if(! is_field_vchar(ch) )
290 {
291 34x goto done;
292 }
293
294 66551x if(! s0 )
295 14348x s0 = it;
296
297 66551x ++it;
298 66551x s1 = it;
299 }
300
301 3496x done:
302 // later routines wind up doing pointer
303 // subtraction using the .data() member
304 // of the value so we need a valid 0-len range
305 14313x if(! s0 )
306 {
307 939x s0 = it;
308 939x s1 = s0;
309 }
310
311 14313x v.value = core::string_view(s0, s1 - s0);
312 14313x v.has_crlf = has_crlf;
313 14313x v.has_obs_fold = has_obs_fold;
314 14313x return v;
315 }
316
317 auto
318 37744x field_rule_t::
319 parse(
320 char const*& it,
321 char const* end) const noexcept ->
322 system::result<value_type>
323 {
324 37744x if(it == end)
325 {
326 979x return grammar::error::need_more;
327 }
328 // check for leading CRLF
329 36765x if(it[0] == '\r')
330 {
331 10641x ++it;
332 10641x if(it == end)
333 {
334 489x return grammar::error::need_more;
335 }
336 10152x if(*it != '\n')
337 {
338 21x return grammar::error::mismatch;
339 }
340 // end of fields
341 10131x ++it;
342 10131x return grammar::error::end_of_range;
343 }
344
345 26124x value_type v;
346 auto rv = grammar::parse(
347 26124x it, end, grammar::tuple_rule(
348 field_name_rule,
349 26124x grammar::delim_rule(':'),
350 field_value_rule,
351 26124x crlf_rule));
352
353 26124x if( rv.has_error() )
354 15410x return rv.error();
355
356 10714x auto val = rv.value();
357 10714x v.name = std::get<0>(val);
358 10714x v.value = std::get<2>(val).value;
359 10714x v.has_obs_fold = std::get<2>(val).has_obs_fold;
360
361 10714x return v;
362 }
363
364 //------------------------------------------------
365
366 void
367 244x remove_obs_fold(
368 char* it,
369 char const* const end) noexcept
370 {
371 2262x while(it != end)
372 {
373 2236x if(*it != '\r')
374 {
375 1637x ++it;
376 1637x continue;
377 }
378 599x if(end - it < 3)
379 218x break;
380 381x BOOST_ASSERT(it[1] == '\n');
381 762x if( it[1] == '\n' &&
382 381x ws(it[2]))
383 {
384 378x it[0] = ' ';
385 378x it[1] = ' ';
386 378x it += 3;
387 }
388 else
389 {
390 3x ++it;
391 }
392 }
393 244x }
394
395 } // detail
396 } // http
397 } // boost
398