]> git.proxmox.com Git - ceph.git/blob - ceph/src/Beast/include/beast/http/detail/basic_parser.hpp
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / Beast / include / beast / http / detail / basic_parser.hpp
1 //
2 // Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot 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
8 #ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
9 #define BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
10
11 #include <beast/core/detail/ci_char_traits.hpp>
12 #include <beast/http/error.hpp>
13 #include <beast/http/detail/rfc7230.hpp>
14 #include <boost/utility/string_ref.hpp>
15 #include <boost/version.hpp>
16 #include <cstddef>
17 #include <utility>
18
19 /*
20 Portions of this file based on code from picophttpparser,
21 copyright notice below.
22 https://github.com/h2o/picohttpparser
23 */
24 /*
25 * Copyright (c) 2009-2014 Kazuho Oku, Tokuhiro Matsuno, Daisuke Murase,
26 * Shigeo Mitsunari
27 *
28 * The software is licensed under either the MIT License (below) or the Perl
29 * license.
30 *
31 * Permission is hereby granted, free of charge, to any person obtaining a copy
32 * of this software and associated documentation files (the "Software"), to
33 * deal in the Software without restriction, including without limitation the
34 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
35 * sell copies of the Software, and to permit persons to whom the Software is
36 * furnished to do so, subject to the following conditions:
37 *
38 * The above copyright notice and this permission notice shall be included in
39 * all copies or substantial portions of the Software.
40 *
41 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
42 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
43 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
44 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
45 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
46 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
47 * IN THE SOFTWARE.
48 */
49
50 namespace beast {
51 namespace http {
52 namespace detail {
53
54 #if __GNUC__ >= 3
55 # define BEAST_LIKELY(x) __builtin_expect(!!(x), 1)
56 # define BEAST_UNLIKELY(x) __builtin_expect(!!(x), 0)
57 #else
58 #define BEAST_LIKELY(x) (x)
59 #define BEAST_UNLIKELY(x) (x)
60 #endif
61
62 class basic_parser_base
63 {
64 protected:
65 static
66 bool
67 is_pathchar(char c)
68 {
69 // VFALCO This looks the same as the one below...
70
71 // TEXT = <any OCTET except CTLs, and excluding LWS>
72 static bool constexpr tab[256] = {
73 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
75 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
76 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
77 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
78 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
79 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
80 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
81 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
82 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
83 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
84 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
85 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
86 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
87 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
88 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
89 };
90 return tab[static_cast<unsigned char>(c)];
91 }
92
93 static
94 bool
95 is_value_char(char c)
96 {
97 // any OCTET except CTLs and LWS
98 static bool constexpr tab[256] = {
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
101 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
102 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
103 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
104 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
105 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
106 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
107 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
108 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
109 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
110 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
111 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
112 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
113 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
114 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
115 };
116 return tab[static_cast<unsigned char>(c)];
117 }
118
119 static
120 inline
121 bool
122 is_text(char c)
123 {
124 // VCHAR / SP / HT / obs-text
125 static bool constexpr tab[256] = {
126 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
128 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
129 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
130 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
131 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
132 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
133 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
134 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
135 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
136 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
137 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
138 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
139 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
140 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
141 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
142 };
143 return tab[static_cast<unsigned char>(c)];
144 }
145
146 static
147 inline
148 bool
149 unhex(unsigned char& d, char c)
150 {
151 static signed char constexpr tab[256] = {
152 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 0
153 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 16
154 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 32
155 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 48
156 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 64
157 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 80
158 -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 96
159 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 112
160
161 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 128
162 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 144
163 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 160
164 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 176
165 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 192
166 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 208
167 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 224
168 -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1 // 240
169 };
170 d = static_cast<unsigned char>(
171 tab[static_cast<unsigned char>(c)]);
172 return d != static_cast<unsigned char>(-1);
173 }
174
175 static
176 bool
177 is_digit(char c)
178 {
179 return static_cast<unsigned char>(c-'0') < 10;
180 }
181
182 static
183 bool
184 is_print(char c)
185 {
186 return static_cast<unsigned char>(c-33) < 94;
187 }
188
189 static
190 boost::string_ref
191 make_string(char const* first, char const* last)
192 {
193 return {first, static_cast<
194 std::size_t>(last - first)};
195 }
196
197 template<class = void>
198 static
199 bool
200 strieq(boost::string_ref const& s1,
201 boost::string_ref const& s2)
202 {
203 if(s1.size() != s2.size())
204 return false;
205 auto p1 = s1.data();
206 auto p2 = s2.data();
207 for(auto n = s1.size(); n--; ++p1, ++p2)
208 if(*p1 != tolower(*p2))
209 return false;
210 return true;
211 }
212
213 template<std::size_t N>
214 bool
215 strieq(const char (&s1)[N],
216 boost::string_ref const& s2)
217 {
218 return strieq({s1, N-1}, s2);
219 }
220
221 template<class Iter, class Unsigned>
222 static
223 bool
224 parse_dec(Iter it, Iter last, Unsigned& v)
225 {
226 if(! is_digit(*it))
227 return false;
228 v = *it - '0';
229 for(;;)
230 {
231 if(! is_digit(*++it))
232 break;
233 auto const d = *it - '0';
234 if(v > ((std::numeric_limits<
235 Unsigned>::max)() - 10) / 10)
236 return false;
237 v = 10 * v + d;
238 }
239 return it == last;
240 }
241
242 template<class Iter, class Unsigned>
243 bool
244 parse_hex(Iter& it, Unsigned& v)
245 {
246 unsigned char d;
247 if(! unhex(d, *it))
248 return false;
249 v = d;
250 for(;;)
251 {
252 if(! unhex(d, *++it))
253 break;
254 auto const v0 = v;
255 v = 16 * v + d;
256 if(v <= v0)
257 return false;
258 }
259 return true;
260 }
261
262 static
263 bool
264 parse_crlf(char const*& it)
265 {
266 if(*it != '\r')
267 return false;
268 if(*++it != '\n')
269 return false;
270 ++it;
271 return true;
272 }
273
274 static
275 boost::string_ref
276 parse_method(char const*& it)
277 {
278 auto const first = it;
279 while(detail::is_tchar(*it))
280 ++it;
281 return {first, static_cast<
282 boost::string_ref::size_type>(
283 it - first)};
284 }
285
286 static
287 boost::string_ref
288 parse_path(char const*& it)
289 {
290 auto const first = it;
291 while(is_pathchar(*it))
292 ++it;
293 if(*it != ' ')
294 return {};
295 return {first, static_cast<
296 boost::string_ref::size_type>(
297 it - first)};
298 }
299
300 static
301 boost::string_ref
302 parse_name(char const*& it)
303 {
304 auto const first = it;
305 while(to_field_char(*it))
306 ++it;
307 return {first, static_cast<
308 boost::string_ref::size_type>(
309 it - first)};
310 }
311
312 static
313 int
314 parse_version(char const*& it)
315 {
316 if(*it != 'H')
317 return -1;
318 if(*++it != 'T')
319 return -1;
320 if(*++it != 'T')
321 return -1;
322 if(*++it != 'P')
323 return -1;
324 if(*++it != '/')
325 return -1;
326 if(! is_digit(*++it))
327 return -1;
328 int v = 10 * (*it - '0');
329 if(*++it != '.')
330 return -1;
331 if(! is_digit(*++it))
332 return -1;
333 v += *it++ - '0';
334 return v;
335 }
336
337 static
338 int
339 parse_status(char const*& it)
340 {
341 int v;
342 if(! is_digit(*it))
343 return -1;
344 v = 100 * (*it - '0');
345 if(! is_digit(*++it))
346 return -1;
347 v += 10 * (*it - '0');
348 if(! is_digit(*++it))
349 return -1;
350 v += (*it++ - '0');
351 return v;
352 }
353
354 static
355 boost::string_ref
356 parse_reason(char const*& it)
357 {
358 auto const first = it;
359 while(*it != '\r')
360 {
361 if(! is_text(*it))
362 return {};
363 ++it;
364 }
365 return {first, static_cast<
366 std::size_t>(it - first)};
367 }
368
369 // VFALCO Can SIMD help this?
370 static
371 char const*
372 find_eol(
373 char const* first, char const* last,
374 error_code& ec)
375 {
376 auto it = first;
377 for(;;)
378 {
379 if(it == last)
380 return nullptr;
381 if(*it == '\r')
382 {
383 if(++it == last)
384 return nullptr;
385 if(*it != '\n')
386 {
387 ec = error::bad_line_ending;
388 return nullptr;
389 }
390 return ++it;
391 }
392 // VFALCO Should we handle the legacy case
393 // for lines terminated with a single '\n'?
394 ++it;
395 }
396 }
397
398 // VFALCO Can SIMD help this?
399 static
400 char const*
401 find_eom(
402 char const* first, char const* last,
403 error_code& ec)
404 {
405 auto it = first;
406 for(;;)
407 {
408 if(it == last)
409 return nullptr;
410 if(*it == '\r')
411 {
412 if(++it == last)
413 return nullptr;
414 if(*it != '\n')
415 {
416 ec = error::bad_line_ending;
417 return nullptr;
418 }
419 if(++it == last)
420 return nullptr;
421 if(*it != '\r')
422 {
423 ++it;
424 continue;
425 }
426 if(++it == last)
427 return nullptr;
428 if(*it != '\n')
429 {
430 ec = error::bad_line_ending;
431 return nullptr;
432 }
433 return ++it;
434 }
435 // VFALCO Should we handle the legacy case
436 // for lines terminated with a single '\n'?
437 ++it;
438 }
439 }
440 };
441
442 } // detail
443 } // http
444 } // beast
445
446 #endif