391 lines
14 KiB
C++
391 lines
14 KiB
C++
//
|
|
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
// Official repository: https://github.com/boostorg/beast
|
|
//
|
|
|
|
#ifndef BOOST_BEAST_HTTP_DETAIL_RFC7230_IPP
|
|
#define BOOST_BEAST_HTTP_DETAIL_RFC7230_IPP
|
|
|
|
#include <boost/beast/core/string.hpp>
|
|
#include <iterator>
|
|
#include <utility>
|
|
|
|
namespace boost {
|
|
namespace beast {
|
|
namespace http {
|
|
namespace detail {
|
|
|
|
bool
|
|
is_digit(char c)
|
|
{
|
|
return c >= '0' && c <= '9';
|
|
}
|
|
|
|
char
|
|
is_alpha(char c)
|
|
{
|
|
static char constexpr tab[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 48
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 80
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 112
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240
|
|
};
|
|
BOOST_STATIC_ASSERT(sizeof(tab) == 256);
|
|
return tab[static_cast<unsigned char>(c)];
|
|
}
|
|
|
|
char
|
|
is_text(char c)
|
|
{
|
|
// TEXT = <any OCTET except CTLs, but including LWS>
|
|
static char constexpr tab[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
|
};
|
|
BOOST_STATIC_ASSERT(sizeof(tab) == 256);
|
|
return tab[static_cast<unsigned char>(c)];
|
|
}
|
|
|
|
char
|
|
is_token_char(char c)
|
|
{
|
|
/*
|
|
tchar = "!" | "#" | "$" | "%" | "&" |
|
|
"'" | "*" | "+" | "-" | "." |
|
|
"^" | "_" | "`" | "|" | "~" |
|
|
DIGIT | ALPHA
|
|
*/
|
|
static char constexpr tab[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
|
0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48
|
|
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, // 112
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 128
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 144
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 176
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 192
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 208
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 224
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // 240
|
|
};
|
|
BOOST_STATIC_ASSERT(sizeof(tab) == 256);
|
|
return tab[static_cast<unsigned char>(c)];
|
|
}
|
|
|
|
char
|
|
is_qdchar(char c)
|
|
{
|
|
/*
|
|
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
|
*/
|
|
static char constexpr tab[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
|
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, // 80
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
|
};
|
|
BOOST_STATIC_ASSERT(sizeof(tab) == 256);
|
|
return tab[static_cast<unsigned char>(c)];
|
|
}
|
|
|
|
char
|
|
is_qpchar(char c)
|
|
{
|
|
/*
|
|
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
|
obs-text = %x80-FF
|
|
*/
|
|
static char constexpr tab[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, // 0
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 32
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 48
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 80
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, // 112
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 128
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 144
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 160
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 176
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 192
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 208
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 224
|
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 240
|
|
};
|
|
BOOST_STATIC_ASSERT(sizeof(tab) == 256);
|
|
return tab[static_cast<unsigned char>(c)];
|
|
}
|
|
|
|
// converts to lower case,
|
|
// returns 0 if not a valid text char
|
|
//
|
|
char
|
|
to_value_char(char c)
|
|
{
|
|
// TEXT = <any OCTET except CTLs, but including LWS>
|
|
static unsigned char constexpr tab[] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, // 0
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16
|
|
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, // 32
|
|
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, // 48
|
|
64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 64
|
|
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 91, 92, 93, 94, 95, // 80
|
|
96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 96
|
|
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 0, // 112
|
|
128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, // 128
|
|
144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, // 144
|
|
160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, // 160
|
|
176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, // 176
|
|
192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, // 192
|
|
208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, // 208
|
|
224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, // 224
|
|
240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255 // 240
|
|
};
|
|
BOOST_STATIC_ASSERT(sizeof(tab) == 256);
|
|
return static_cast<char>(tab[static_cast<unsigned char>(c)]);
|
|
}
|
|
|
|
// VFALCO TODO Make this return unsigned?
|
|
std::int8_t
|
|
unhex(char c)
|
|
{
|
|
static signed char constexpr tab[] = {
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 16
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 32
|
|
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, // 48
|
|
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 64
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 80
|
|
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 96
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 112
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 128
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 144
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 160
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 176
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 192
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 208
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 224
|
|
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 // 240
|
|
};
|
|
BOOST_STATIC_ASSERT(sizeof(tab) == 256);
|
|
return tab[static_cast<unsigned char>(c)];
|
|
}
|
|
|
|
template <class ForwardIt>
|
|
void
|
|
skip_ows(ForwardIt& it, ForwardIt end)
|
|
{
|
|
while(it != end)
|
|
{
|
|
if(*it != ' ' && *it != '\t')
|
|
break;
|
|
++it;
|
|
}
|
|
}
|
|
|
|
template <class ForwardIt>
|
|
void
|
|
skip_token(ForwardIt& it, ForwardIt last)
|
|
{
|
|
while(it != last && is_token_char(*it))
|
|
++it;
|
|
}
|
|
|
|
string_view
|
|
trim(string_view s)
|
|
{
|
|
auto first = s.begin();
|
|
auto last = s.end();
|
|
skip_ows(first, last);
|
|
while(first != last)
|
|
{
|
|
auto const c = *std::prev(last);
|
|
if(c != ' ' && c != '\t')
|
|
break;
|
|
--last;
|
|
}
|
|
if(first == last)
|
|
return {};
|
|
return {&*first,
|
|
static_cast<std::size_t>(last - first)};
|
|
}
|
|
|
|
|
|
BOOST_BEAST_DECL
|
|
void
|
|
param_iter::
|
|
increment()
|
|
{
|
|
/*
|
|
param-list = *( OWS ";" OWS param )
|
|
param = token OWS [ "=" OWS ( token / quoted-string ) ]
|
|
quoted-string = DQUOTE *( qdtext / quoted-pair ) DQUOTE
|
|
qdtext = HTAB / SP / "!" / %x23-5B ; '#'-'[' / %x5D-7E ; ']'-'~' / obs-text
|
|
quoted-pair = "\" ( HTAB / SP / VCHAR / obs-text )
|
|
obs-text = %x80-FF
|
|
*/
|
|
auto const err =
|
|
[&]
|
|
{
|
|
it = first;
|
|
};
|
|
v.first = {};
|
|
v.second = {};
|
|
detail::skip_ows(it, last);
|
|
first = it;
|
|
if(it == last)
|
|
return err();
|
|
if(*it != ';')
|
|
return err();
|
|
++it;
|
|
detail::skip_ows(it, last);
|
|
if(it == last)
|
|
return err();
|
|
// param
|
|
if(! detail::is_token_char(*it))
|
|
return err();
|
|
auto const p0 = it;
|
|
skip_token(++it, last);
|
|
auto const p1 = it;
|
|
v.first = { &*p0, static_cast<std::size_t>(p1 - p0) };
|
|
detail::skip_ows(it, last);
|
|
if(it == last)
|
|
return;
|
|
if(*it == ';')
|
|
return;
|
|
if(*it != '=')
|
|
return err();
|
|
++it;
|
|
detail::skip_ows(it, last);
|
|
if(it == last)
|
|
return;
|
|
if(*it == '"')
|
|
{
|
|
// quoted-string
|
|
auto const p2 = it;
|
|
++it;
|
|
for(;;)
|
|
{
|
|
if(it == last)
|
|
return err();
|
|
auto c = *it++;
|
|
if(c == '"')
|
|
break;
|
|
if(detail::is_qdchar(c))
|
|
continue;
|
|
if(c != '\\')
|
|
return err();
|
|
if(it == last)
|
|
return err();
|
|
c = *it++;
|
|
if(! detail::is_qpchar(c))
|
|
return err();
|
|
}
|
|
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
|
}
|
|
else
|
|
{
|
|
// token
|
|
if(! detail::is_token_char(*it))
|
|
return err();
|
|
auto const p2 = it;
|
|
skip_token(++it, last);
|
|
v.second = { &*p2, static_cast<std::size_t>(it - p2) };
|
|
}
|
|
}
|
|
|
|
bool
|
|
opt_token_list_policy::operator()(value_type& v,
|
|
char const*& it, string_view s) const
|
|
{
|
|
v = {};
|
|
auto need_comma = it != s.data();
|
|
for(;;)
|
|
{
|
|
detail::skip_ows(it, (s.data() + s.size()));
|
|
if(it == (s.data() + s.size()))
|
|
{
|
|
it = nullptr;
|
|
return true;
|
|
}
|
|
auto const c = *it;
|
|
if(detail::is_token_char(c))
|
|
{
|
|
if(need_comma)
|
|
return false;
|
|
auto const p0 = it;
|
|
for(;;)
|
|
{
|
|
++it;
|
|
if(it == (s.data() + s.size()))
|
|
break;
|
|
if(! detail::is_token_char(*it))
|
|
break;
|
|
}
|
|
v = string_view{p0,
|
|
static_cast<std::size_t>(it - p0)};
|
|
return true;
|
|
}
|
|
if(c != ',')
|
|
return false;
|
|
need_comma = false;
|
|
++it;
|
|
}
|
|
}
|
|
|
|
} // detail
|
|
} // http
|
|
} // beast
|
|
} // boost
|
|
|
|
#endif // BOOST_BEAST_HTTP_DETAIL_RFC7230_IPP
|
|
|