2016-11-20 07:32:41 -05:00
|
|
|
//
|
2017-07-24 09:42:36 -07:00
|
|
|
// Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
|
2016-11-20 07:32:41 -05:00
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
//
|
2017-07-20 13:40:34 -07:00
|
|
|
// Official repository: https://github.com/boostorg/beast
|
|
|
|
//
|
2016-11-20 07:32:41 -05:00
|
|
|
|
2017-07-20 13:40:34 -07:00
|
|
|
#ifndef BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP
|
|
|
|
#define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP
|
2016-11-20 07:32:41 -05:00
|
|
|
|
2017-07-20 13:40:34 -07:00
|
|
|
#include <boost/beast/core/static_string.hpp>
|
|
|
|
#include <boost/beast/core/type_traits.hpp>
|
|
|
|
#include <boost/beast/core/detail/clamp.hpp>
|
|
|
|
#include <boost/beast/core/detail/config.hpp>
|
|
|
|
#include <boost/beast/http/error.hpp>
|
|
|
|
#include <boost/beast/http/rfc7230.hpp>
|
2016-11-20 07:32:41 -05:00
|
|
|
#include <boost/asio/buffer.hpp>
|
2017-07-08 20:45:35 -07:00
|
|
|
#include <boost/make_unique.hpp>
|
2016-11-20 07:32:41 -05:00
|
|
|
#include <algorithm>
|
|
|
|
#include <utility>
|
|
|
|
|
2017-07-20 13:40:34 -07:00
|
|
|
namespace boost {
|
2016-11-20 07:32:41 -05:00
|
|
|
namespace beast {
|
|
|
|
namespace http {
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
template<class OtherDerived>
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
basic_parser(basic_parser<
|
|
|
|
isRequest, OtherDerived>&& other)
|
2017-06-27 21:00:53 -07:00
|
|
|
: body_limit_(other.body_limit_)
|
|
|
|
, len_(other.len_)
|
2016-11-20 07:32:41 -05:00
|
|
|
, buf_(std::move(other.buf_))
|
|
|
|
, buf_len_(other.buf_len_)
|
|
|
|
, skip_(other.skip_)
|
2017-11-07 18:59:28 +01:00
|
|
|
, header_limit_(other.header_limit_)
|
|
|
|
, status_(other.status_)
|
2016-11-20 07:32:41 -05:00
|
|
|
, state_(other.state_)
|
2017-05-31 08:01:55 -07:00
|
|
|
, f_(other.f_)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2016-11-20 07:32:41 -05:00
|
|
|
bool
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
2017-10-25 18:04:54 -07:00
|
|
|
keep_alive() const
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
BOOST_ASSERT(is_header_done());
|
2016-11-20 07:32:41 -05:00
|
|
|
if(f_ & flagHTTP11)
|
|
|
|
{
|
|
|
|
if(f_ & flagConnectionClose)
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if(! (f_ & flagConnectionKeepAlive))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return (f_ & flagNeedEOF) == 0;
|
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
boost::optional<std::uint64_t>
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
content_length() const
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(is_header_done());
|
|
|
|
if(! (f_ & flagContentLength))
|
|
|
|
return boost::none;
|
|
|
|
return len_;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
skip(bool v)
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(! got_some());
|
|
|
|
if(v)
|
|
|
|
f_ |= flagSkipBody;
|
|
|
|
else
|
|
|
|
f_ &= ~flagSkipBody;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
2016-11-20 07:32:41 -05:00
|
|
|
template<class ConstBufferSequence>
|
|
|
|
std::size_t
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
put(ConstBufferSequence const& buffers,
|
2016-11-20 07:32:41 -05:00
|
|
|
error_code& ec)
|
|
|
|
{
|
2017-09-07 07:39:52 -07:00
|
|
|
static_assert(boost::asio::is_const_buffer_sequence<
|
2016-11-20 07:32:41 -05:00
|
|
|
ConstBufferSequence>::value,
|
|
|
|
"ConstBufferSequence requirements not met");
|
2017-06-11 17:55:05 -07:00
|
|
|
using boost::asio::buffer_copy;
|
|
|
|
using boost::asio::buffer_size;
|
2017-09-07 07:39:52 -07:00
|
|
|
auto const p = boost::asio::buffer_sequence_begin(buffers);
|
|
|
|
auto const last = boost::asio::buffer_sequence_end(buffers);
|
2017-06-11 17:55:05 -07:00
|
|
|
if(p == last)
|
2017-06-13 07:08:52 -07:00
|
|
|
{
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-06-11 17:55:05 -07:00
|
|
|
return 0;
|
2017-06-13 07:08:52 -07:00
|
|
|
}
|
2017-06-11 17:55:05 -07:00
|
|
|
if(std::next(p) == last)
|
|
|
|
{
|
|
|
|
// single buffer
|
2017-09-07 07:39:52 -07:00
|
|
|
return put(boost::asio::const_buffer(*p), ec);
|
2017-06-11 17:55:05 -07:00
|
|
|
}
|
|
|
|
auto const size = buffer_size(buffers);
|
|
|
|
if(size <= max_stack_buffer)
|
|
|
|
return put_from_stack(size, buffers, ec);
|
|
|
|
if(size > buf_len_)
|
|
|
|
{
|
|
|
|
// reallocate
|
2017-07-08 20:45:35 -07:00
|
|
|
buf_ = boost::make_unique_noinit<char[]>(size);
|
2017-06-11 17:55:05 -07:00
|
|
|
buf_len_ = size;
|
|
|
|
}
|
|
|
|
// flatten
|
|
|
|
buffer_copy(boost::asio::buffer(
|
|
|
|
buf_.get(), buf_len_), buffers);
|
2017-09-07 07:39:52 -07:00
|
|
|
return put(boost::asio::const_buffer{
|
2017-06-11 17:55:05 -07:00
|
|
|
buf_.get(), buf_len_}, ec);
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2016-11-20 07:32:41 -05:00
|
|
|
std::size_t
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
2017-09-07 07:39:52 -07:00
|
|
|
put(boost::asio::const_buffer const& buffer,
|
2016-11-20 07:32:41 -05:00
|
|
|
error_code& ec)
|
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
BOOST_ASSERT(state_ != state::complete);
|
|
|
|
using boost::asio::buffer_size;
|
2017-09-07 07:39:52 -07:00
|
|
|
auto p = reinterpret_cast<
|
|
|
|
char const*>(buffer.data());
|
|
|
|
auto n = buffer.size();
|
2017-05-31 08:01:55 -07:00
|
|
|
auto const p0 = p;
|
|
|
|
auto const p1 = p0 + n;
|
2017-06-30 08:46:22 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-05-31 08:01:55 -07:00
|
|
|
loop:
|
|
|
|
switch(state_)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
case state::nothing_yet:
|
|
|
|
if(n == 0)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
ec = error::need_more;
|
|
|
|
return 0;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
2017-06-30 08:46:22 -07:00
|
|
|
state_ = state::start_line;
|
2018-01-05 17:46:34 -08:00
|
|
|
BOOST_FALLTHROUGH;
|
2016-11-20 07:32:41 -05:00
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
case state::start_line:
|
|
|
|
{
|
|
|
|
maybe_need_more(p, n, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
goto done;
|
2017-11-06 03:20:46 +07:00
|
|
|
parse_start_line(p, p + (std::min<std::size_t>)(
|
2017-06-30 08:46:22 -07:00
|
|
|
header_limit_, n), ec, is_request{});
|
|
|
|
if(ec)
|
|
|
|
{
|
|
|
|
if(ec == error::need_more)
|
|
|
|
{
|
|
|
|
if(n >= header_limit_)
|
|
|
|
{
|
|
|
|
ec = error::header_limit;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if(p + 3 <= p1)
|
|
|
|
skip_ = static_cast<
|
|
|
|
std::size_t>(p1 - p - 3);
|
|
|
|
}
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
BOOST_ASSERT(! is_done());
|
|
|
|
n = static_cast<std::size_t>(p1 - p);
|
|
|
|
if(p >= p1)
|
|
|
|
{
|
|
|
|
ec = error::need_more;
|
|
|
|
goto done;
|
|
|
|
}
|
2018-01-05 17:46:34 -08:00
|
|
|
BOOST_FALLTHROUGH;
|
2017-06-30 08:46:22 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
case state::fields:
|
|
|
|
maybe_need_more(p, n, ec);
|
|
|
|
if(ec)
|
|
|
|
goto done;
|
2017-11-06 03:20:46 +07:00
|
|
|
parse_fields(p, p + (std::min<std::size_t>)(
|
2017-06-30 08:46:22 -07:00
|
|
|
header_limit_, n), ec);
|
|
|
|
if(ec)
|
|
|
|
{
|
|
|
|
if(ec == error::need_more)
|
|
|
|
{
|
|
|
|
if(n >= header_limit_)
|
|
|
|
{
|
|
|
|
ec = error::header_limit;
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
if(p + 3 <= p1)
|
|
|
|
skip_ = static_cast<
|
|
|
|
std::size_t>(p1 - p - 3);
|
|
|
|
}
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
finish_header(ec, is_request{});
|
2017-05-31 08:01:55 -07:00
|
|
|
break;
|
2016-11-20 07:32:41 -05:00
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
case state::body0:
|
2017-06-30 08:46:22 -07:00
|
|
|
BOOST_ASSERT(! skip_);
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_body_init_impl(content_length(), ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
goto done;
|
|
|
|
state_ = state::body;
|
2018-01-05 17:46:34 -08:00
|
|
|
BOOST_FALLTHROUGH;
|
2016-11-20 07:32:41 -05:00
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
case state::body:
|
2017-06-30 08:46:22 -07:00
|
|
|
BOOST_ASSERT(! skip_);
|
2017-05-31 08:01:55 -07:00
|
|
|
parse_body(p, n, ec);
|
|
|
|
if(ec)
|
|
|
|
goto done;
|
|
|
|
break;
|
2016-11-20 07:32:41 -05:00
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
case state::body_to_eof0:
|
2017-06-30 08:46:22 -07:00
|
|
|
BOOST_ASSERT(! skip_);
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_body_init_impl(content_length(), ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
goto done;
|
|
|
|
state_ = state::body_to_eof;
|
2018-01-05 17:46:34 -08:00
|
|
|
BOOST_FALLTHROUGH;
|
2017-05-31 08:01:55 -07:00
|
|
|
|
|
|
|
case state::body_to_eof:
|
2017-06-30 08:46:22 -07:00
|
|
|
BOOST_ASSERT(! skip_);
|
2017-05-31 08:01:55 -07:00
|
|
|
parse_body_to_eof(p, n, ec);
|
|
|
|
if(ec)
|
|
|
|
goto done;
|
2016-11-20 07:32:41 -05:00
|
|
|
break;
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
case state::chunk_header0:
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_body_init_impl(content_length(), ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
2017-06-07 10:48:35 -07:00
|
|
|
goto done;
|
2017-05-31 08:01:55 -07:00
|
|
|
state_ = state::chunk_header;
|
2018-01-05 17:46:34 -08:00
|
|
|
BOOST_FALLTHROUGH;
|
2017-05-31 08:01:55 -07:00
|
|
|
|
|
|
|
case state::chunk_header:
|
|
|
|
parse_chunk_header(p, n, ec);
|
|
|
|
if(ec)
|
|
|
|
goto done;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case state::chunk_body:
|
|
|
|
parse_chunk_body(p, n, ec);
|
|
|
|
if(ec)
|
|
|
|
goto done;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case state::complete:
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-06-13 07:08:52 -07:00
|
|
|
goto done;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
2017-06-09 13:27:38 -07:00
|
|
|
if(p < p1 && ! is_done() && eager())
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
|
|
|
n = static_cast<std::size_t>(p1 - p);
|
|
|
|
goto loop;
|
|
|
|
}
|
|
|
|
done:
|
|
|
|
return static_cast<std::size_t>(p - p0);
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2016-11-20 07:32:41 -05:00
|
|
|
void
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
put_eof(error_code& ec)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
BOOST_ASSERT(got_some());
|
2017-06-30 08:46:22 -07:00
|
|
|
if( state_ == state::start_line ||
|
|
|
|
state_ == state::fields)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
ec = error::partial_message;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(f_ & (flagContentLength | flagChunked))
|
|
|
|
{
|
|
|
|
if(state_ != state::complete)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
ec = error::partial_message;
|
|
|
|
return;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-05-31 08:01:55 -07:00
|
|
|
return;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_finish_impl(ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
state_ = state::complete;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2016-11-20 07:32:41 -05:00
|
|
|
template<class ConstBufferSequence>
|
2017-06-11 17:55:05 -07:00
|
|
|
std::size_t
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
2017-06-11 17:55:05 -07:00
|
|
|
put_from_stack(std::size_t size,
|
|
|
|
ConstBufferSequence const& buffers,
|
|
|
|
error_code& ec)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-06-11 17:55:05 -07:00
|
|
|
char buf[max_stack_buffer];
|
|
|
|
using boost::asio::buffer;
|
2016-11-20 07:32:41 -05:00
|
|
|
using boost::asio::buffer_copy;
|
2017-06-11 17:55:05 -07:00
|
|
|
buffer_copy(buffer(buf, sizeof(buf)), buffers);
|
2017-09-07 07:39:52 -07:00
|
|
|
return put(boost::asio::const_buffer{
|
2017-06-11 17:55:05 -07:00
|
|
|
buf, size}, ec);
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2016-11-20 07:32:41 -05:00
|
|
|
inline
|
2017-05-31 08:01:55 -07:00
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
2017-06-30 08:46:22 -07:00
|
|
|
maybe_need_more(
|
|
|
|
char const* p, std::size_t n,
|
|
|
|
error_code& ec)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-06-30 08:46:22 -07:00
|
|
|
if(skip_ == 0)
|
|
|
|
return;
|
2017-06-27 21:00:53 -07:00
|
|
|
if( n > header_limit_)
|
|
|
|
n = header_limit_;
|
2017-05-31 08:01:55 -07:00
|
|
|
if(n < skip_ + 4)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-06-27 21:00:53 -07:00
|
|
|
ec = error::need_more;
|
2017-05-31 08:01:55 -07:00
|
|
|
return;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
2017-06-26 15:32:35 -07:00
|
|
|
auto const term =
|
|
|
|
find_eom(p + skip_, p + n);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(! term)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
skip_ = n - 3;
|
2017-06-27 21:00:53 -07:00
|
|
|
if(skip_ + 4 > header_limit_)
|
|
|
|
{
|
|
|
|
ec = error::header_limit;
|
|
|
|
return;
|
|
|
|
}
|
2017-06-30 08:46:22 -07:00
|
|
|
ec = error::need_more;
|
2017-05-31 08:01:55 -07:00
|
|
|
return;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
2017-05-31 08:01:55 -07:00
|
|
|
skip_ = 0;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2017-06-30 08:46:22 -07:00
|
|
|
inline
|
2016-11-20 07:32:41 -05:00
|
|
|
void
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
2017-06-30 08:46:22 -07:00
|
|
|
parse_start_line(
|
|
|
|
char const*& in, char const* last,
|
2017-05-31 08:01:55 -07:00
|
|
|
error_code& ec, std::true_type)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
request-line = method SP request-target SP HTTP-version CRLF
|
|
|
|
method = token
|
|
|
|
*/
|
2017-06-30 08:46:22 -07:00
|
|
|
auto p = in;
|
|
|
|
|
|
|
|
string_view method;
|
|
|
|
parse_method(p, last, method, ec);
|
|
|
|
if(ec)
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
2017-06-30 08:46:22 -07:00
|
|
|
|
|
|
|
string_view target;
|
|
|
|
parse_target(p, last, target, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
|
2017-07-05 10:12:42 -07:00
|
|
|
int version = 0;
|
2017-06-30 08:46:22 -07:00
|
|
|
parse_version(p, last, version, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
if(version < 10 || version > 11)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-06-30 08:46:22 -07:00
|
|
|
ec = error::bad_version;
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
if(p + 2 > last)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-06-30 08:46:22 -07:00
|
|
|
ec = error::need_more;
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2017-06-30 08:46:22 -07:00
|
|
|
if(p[0] != '\r' || p[1] != '\n')
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-06-30 08:46:22 -07:00
|
|
|
ec = error::bad_version;
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2017-06-30 08:46:22 -07:00
|
|
|
p += 2;
|
2016-11-20 07:32:41 -05:00
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
if(version >= 11)
|
|
|
|
f_ |= flagHTTP11;
|
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_request_impl(string_to_verb(method),
|
2017-06-30 08:46:22 -07:00
|
|
|
method, target, version, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
|
|
|
|
in = p;
|
|
|
|
state_ = state::fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
inline
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
parse_start_line(
|
|
|
|
char const*& in, char const* last,
|
|
|
|
error_code& ec, std::false_type)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
status-line = HTTP-version SP status-code SP reason-phrase CRLF
|
|
|
|
status-code = 3*DIGIT
|
|
|
|
reason-phrase = *( HTAB / SP / VCHAR / obs-text )
|
|
|
|
*/
|
|
|
|
auto p = in;
|
|
|
|
|
2017-07-05 10:12:42 -07:00
|
|
|
int version = 0;
|
2017-06-30 08:46:22 -07:00
|
|
|
parse_version(p, last, version, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
if(version < 10 || version > 11)
|
2017-06-26 15:32:35 -07:00
|
|
|
{
|
|
|
|
ec = error::bad_version;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
// SP
|
|
|
|
if(p + 1 > last)
|
|
|
|
{
|
|
|
|
ec = error::need_more;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(*p++ != ' ')
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
ec = error::bad_version;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
parse_status(p, last, status_, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
2017-05-31 08:01:55 -07:00
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
// parse reason CRLF
|
|
|
|
string_view reason;
|
|
|
|
parse_reason(p, last, reason, ec);
|
2016-11-20 07:32:41 -05:00
|
|
|
if(ec)
|
|
|
|
return;
|
2017-05-31 08:01:55 -07:00
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
if(version >= 11)
|
|
|
|
f_ |= flagHTTP11;
|
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_response_impl(
|
2017-06-30 08:46:22 -07:00
|
|
|
status_, reason, version, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
in = p;
|
|
|
|
state_ = state::fields;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
parse_fields(char const*& in,
|
|
|
|
char const* last, error_code& ec)
|
|
|
|
{
|
|
|
|
string_view name;
|
|
|
|
string_view value;
|
|
|
|
// https://stackoverflow.com/questions/686217/maximum-on-http-header-values
|
|
|
|
static_string<max_obs_fold> buf;
|
|
|
|
auto p = in;
|
|
|
|
for(;;)
|
|
|
|
{
|
|
|
|
if(p + 2 > last)
|
|
|
|
{
|
|
|
|
ec = error::need_more;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(p[0] == '\r')
|
|
|
|
{
|
|
|
|
if(p[1] != '\n')
|
|
|
|
ec = error::bad_line_ending;
|
|
|
|
in = p + 2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
parse_field(p, last, name, value, buf, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
auto const f = string_to_field(name);
|
|
|
|
do_field(f, value, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_field_impl(f, name, value, ec);
|
2017-06-30 08:46:22 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
in = p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
inline
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
finish_header(error_code& ec, std::true_type)
|
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
// RFC 7230 section 3.3
|
|
|
|
// https://tools.ietf.org/html/rfc7230#section-3.3
|
|
|
|
|
|
|
|
if(f_ & flagSkipBody)
|
|
|
|
{
|
|
|
|
state_ = state::complete;
|
|
|
|
}
|
|
|
|
else if(f_ & flagContentLength)
|
|
|
|
{
|
2017-07-29 05:24:44 -07:00
|
|
|
if(len_ > body_limit_)
|
|
|
|
{
|
|
|
|
ec = error::body_limit;
|
|
|
|
return;
|
|
|
|
}
|
2017-05-31 08:01:55 -07:00
|
|
|
if(len_ > 0)
|
|
|
|
{
|
|
|
|
f_ |= flagHasBody;
|
|
|
|
state_ = state::body0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
state_ = state::complete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(f_ & flagChunked)
|
|
|
|
{
|
|
|
|
f_ |= flagHasBody;
|
|
|
|
state_ = state::chunk_header0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len_ = 0;
|
|
|
|
state_ = state::complete;
|
|
|
|
}
|
2017-06-30 08:46:22 -07:00
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_header_impl(ec);
|
2017-06-30 08:46:22 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
if(state_ == state::complete)
|
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_finish_impl(ec);
|
2017-06-30 08:46:22 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
}
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2017-06-30 08:46:22 -07:00
|
|
|
inline
|
2016-11-20 07:32:41 -05:00
|
|
|
void
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
2017-06-30 08:46:22 -07:00
|
|
|
finish_header(error_code& ec, std::false_type)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-05-31 08:01:55 -07:00
|
|
|
// RFC 7230 section 3.3
|
|
|
|
// https://tools.ietf.org/html/rfc7230#section-3.3
|
|
|
|
|
|
|
|
if( (f_ & flagSkipBody) || // e.g. response to a HEAD request
|
2017-06-30 08:46:22 -07:00
|
|
|
status_ / 100 == 1 || // 1xx e.g. Continue
|
|
|
|
status_ == 204 || // No Content
|
|
|
|
status_ == 304) // Not Modified
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
2017-07-29 05:24:44 -07:00
|
|
|
// VFALCO Content-Length may be present, but we
|
|
|
|
// treat the message as not having a body.
|
|
|
|
// https://github.com/boostorg/beast/issues/692
|
2017-05-31 08:01:55 -07:00
|
|
|
state_ = state::complete;
|
|
|
|
}
|
2017-08-15 06:58:33 -07:00
|
|
|
else if(f_ & flagContentLength)
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
2017-07-29 05:24:44 -07:00
|
|
|
if(len_ > body_limit_)
|
|
|
|
{
|
|
|
|
ec = error::body_limit;
|
|
|
|
return;
|
|
|
|
}
|
2017-05-31 08:01:55 -07:00
|
|
|
if(len_ > 0)
|
|
|
|
{
|
|
|
|
f_ |= flagHasBody;
|
|
|
|
state_ = state::body0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
state_ = state::complete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(f_ & flagChunked)
|
|
|
|
{
|
|
|
|
f_ |= flagHasBody;
|
|
|
|
state_ = state::chunk_header0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
f_ |= flagHasBody;
|
|
|
|
f_ |= flagNeedEOF;
|
|
|
|
state_ = state::body_to_eof0;
|
|
|
|
}
|
2017-06-30 08:46:22 -07:00
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_header_impl(ec);
|
2017-06-30 08:46:22 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
if(state_ == state::complete)
|
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_finish_impl(ec);
|
2017-06-30 08:46:22 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
}
|
2017-05-31 08:01:55 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
inline
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
parse_body(char const*& p,
|
|
|
|
std::size_t n, error_code& ec)
|
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
n = impl().on_body_impl(string_view{p,
|
2017-07-02 06:32:19 -07:00
|
|
|
beast::detail::clamp(len_, n)}, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
p += n;
|
|
|
|
len_ -= n;
|
2017-07-02 06:32:19 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
2017-05-31 08:01:55 -07:00
|
|
|
if(len_ > 0)
|
|
|
|
return;
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_finish_impl(ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
state_ = state::complete;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
inline
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
parse_body_to_eof(char const*& p,
|
|
|
|
std::size_t n, error_code& ec)
|
|
|
|
{
|
2017-06-27 21:00:53 -07:00
|
|
|
if(n > body_limit_)
|
|
|
|
{
|
|
|
|
ec = error::body_limit;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
body_limit_ = body_limit_ - n;
|
2017-07-12 18:06:36 -07:00
|
|
|
n = impl().on_body_impl(string_view{p, n}, ec);
|
2017-07-02 06:32:19 -07:00
|
|
|
p += n;
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
2017-06-07 10:48:35 -07:00
|
|
|
parse_chunk_header(char const*& p0,
|
2017-05-31 08:01:55 -07:00
|
|
|
std::size_t n, error_code& ec)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
chunked-body = *chunk last-chunk trailer-part CRLF
|
|
|
|
|
|
|
|
chunk = chunk-size [ chunk-ext ] CRLF chunk-data CRLF
|
|
|
|
last-chunk = 1*("0") [ chunk-ext ] CRLF
|
|
|
|
trailer-part = *( header-field CRLF )
|
|
|
|
|
|
|
|
chunk-size = 1*HEXDIG
|
|
|
|
chunk-data = 1*OCTET ; a sequence of chunk-size octets
|
|
|
|
chunk-ext = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
|
|
|
|
chunk-ext-name = token
|
|
|
|
chunk-ext-val = token / quoted-string
|
|
|
|
*/
|
|
|
|
|
2017-06-07 10:48:35 -07:00
|
|
|
auto p = p0;
|
2017-05-31 08:01:55 -07:00
|
|
|
auto const pend = p + n;
|
2017-06-07 10:48:35 -07:00
|
|
|
char const* eol;
|
2017-05-31 08:01:55 -07:00
|
|
|
|
|
|
|
if(! (f_ & flagFinalChunk))
|
|
|
|
{
|
|
|
|
if(n < skip_ + 2)
|
|
|
|
{
|
|
|
|
ec = error::need_more;
|
|
|
|
return;
|
|
|
|
}
|
2017-06-07 10:48:35 -07:00
|
|
|
if(f_ & flagExpectCRLF)
|
|
|
|
{
|
|
|
|
// Treat the last CRLF in a chunk as
|
|
|
|
// part of the next chunk, so p can
|
|
|
|
// be parsed in one call instead of two.
|
|
|
|
if(! parse_crlf(p))
|
|
|
|
{
|
|
|
|
ec = error::bad_chunk;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
eol = find_eol(p0 + skip_, pend, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
2017-06-07 10:48:35 -07:00
|
|
|
if(! eol)
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
|
|
|
ec = error::need_more;
|
|
|
|
skip_ = n - 1;
|
|
|
|
return;
|
|
|
|
}
|
2017-06-07 10:48:35 -07:00
|
|
|
skip_ = static_cast<
|
|
|
|
std::size_t>(eol - 2 - p0);
|
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
std::uint64_t size;
|
|
|
|
if(! parse_hex(p, size))
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
|
|
|
ec = error::bad_chunk;
|
|
|
|
return;
|
|
|
|
}
|
2017-07-12 18:06:36 -07:00
|
|
|
if(size != 0)
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
if(size > body_limit_)
|
2017-06-27 21:00:53 -07:00
|
|
|
{
|
|
|
|
ec = error::body_limit;
|
|
|
|
return;
|
|
|
|
}
|
2017-07-12 18:06:36 -07:00
|
|
|
body_limit_ -= size;
|
|
|
|
auto const start = p;
|
|
|
|
parse_chunk_extensions(p, pend, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
if(p != eol -2 )
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
ec = error::bad_chunk_extension;
|
2017-05-31 08:01:55 -07:00
|
|
|
return;
|
|
|
|
}
|
2017-07-12 18:06:36 -07:00
|
|
|
auto const ext = make_string(start, p);
|
|
|
|
impl().on_chunk_header_impl(size, ext, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
len_ = size;
|
2017-06-07 10:48:35 -07:00
|
|
|
skip_ = 2;
|
|
|
|
p0 = eol;
|
2017-05-31 08:01:55 -07:00
|
|
|
f_ |= flagExpectCRLF;
|
|
|
|
state_ = state::chunk_body;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
f_ |= flagFinalChunk;
|
|
|
|
}
|
2017-06-07 10:48:35 -07:00
|
|
|
else
|
|
|
|
{
|
|
|
|
BOOST_ASSERT(n >= 5);
|
|
|
|
if(f_ & flagExpectCRLF)
|
|
|
|
BOOST_VERIFY(parse_crlf(p));
|
2017-07-12 18:06:36 -07:00
|
|
|
std::uint64_t size;
|
|
|
|
BOOST_VERIFY(parse_hex(p, size));
|
2017-06-07 10:48:35 -07:00
|
|
|
eol = find_eol(p, pend, ec);
|
|
|
|
BOOST_ASSERT(! ec);
|
|
|
|
}
|
2017-05-31 08:01:55 -07:00
|
|
|
|
2017-06-26 15:32:35 -07:00
|
|
|
auto eom = find_eom(p0 + skip_, pend);
|
2017-06-07 10:48:35 -07:00
|
|
|
if(! eom)
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
2017-06-07 10:48:35 -07:00
|
|
|
BOOST_ASSERT(n >= 3);
|
|
|
|
skip_ = n - 3;
|
2017-05-31 08:01:55 -07:00
|
|
|
ec = error::need_more;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
auto const start = p;
|
|
|
|
parse_chunk_extensions(p, pend, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
if(p != eol - 2)
|
2017-05-31 08:01:55 -07:00
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
ec = error::bad_chunk_extension;
|
|
|
|
return;
|
2017-05-31 08:01:55 -07:00
|
|
|
}
|
2017-07-12 18:06:36 -07:00
|
|
|
auto const ext = make_string(start, p);
|
|
|
|
impl().on_chunk_header_impl(0, ext, ec);
|
|
|
|
if(ec)
|
|
|
|
return;
|
2017-06-07 10:48:35 -07:00
|
|
|
p = eol;
|
|
|
|
parse_fields(p, eom, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
2017-06-07 10:48:35 -07:00
|
|
|
BOOST_ASSERT(p == eom);
|
|
|
|
p0 = eom;
|
2017-05-31 08:01:55 -07:00
|
|
|
|
2017-07-12 18:06:36 -07:00
|
|
|
impl().on_finish_impl(ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
if(ec)
|
|
|
|
return;
|
|
|
|
state_ = state::complete;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<bool isRequest, class Derived>
|
|
|
|
inline
|
|
|
|
void
|
|
|
|
basic_parser<isRequest, Derived>::
|
|
|
|
parse_chunk_body(char const*& p,
|
|
|
|
std::size_t n, error_code& ec)
|
|
|
|
{
|
2017-07-12 18:06:36 -07:00
|
|
|
n = impl().on_chunk_body_impl(
|
|
|
|
len_, string_view{p,
|
|
|
|
beast::detail::clamp(len_, n)}, ec);
|
2017-05-31 08:01:55 -07:00
|
|
|
p += n;
|
|
|
|
len_ -= n;
|
2017-07-12 18:06:36 -07:00
|
|
|
if(len_ == 0)
|
|
|
|
state_ = state::chunk_header;
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
2017-05-31 08:01:55 -07:00
|
|
|
template<bool isRequest, class Derived>
|
2016-11-20 07:32:41 -05:00
|
|
|
void
|
2017-05-31 08:01:55 -07:00
|
|
|
basic_parser<isRequest, Derived>::
|
2017-06-06 14:04:17 -07:00
|
|
|
do_field(field f,
|
|
|
|
string_view value, error_code& ec)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
// Connection
|
2017-06-06 14:04:17 -07:00
|
|
|
if(f == field::connection ||
|
|
|
|
f == field::proxy_connection)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
auto const list = opt_token_list{value};
|
|
|
|
if(! validate_list(list))
|
|
|
|
{
|
|
|
|
// VFALCO Should this be a field specific error?
|
|
|
|
ec = error::bad_value;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
for(auto const& s : list)
|
|
|
|
{
|
2017-06-30 08:46:22 -07:00
|
|
|
if(iequals({"close", 5}, s))
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
f_ |= flagConnectionClose;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
if(iequals({"keep-alive", 10}, s))
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
f_ |= flagConnectionKeepAlive;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-06-30 08:46:22 -07:00
|
|
|
if(iequals({"upgrade", 7}, s))
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
f_ |= flagConnectionUpgrade;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Content-Length
|
2017-06-06 14:04:17 -07:00
|
|
|
if(f == field::content_length)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
if(f_ & flagContentLength)
|
|
|
|
{
|
|
|
|
// duplicate
|
|
|
|
ec = error::bad_content_length;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(f_ & flagChunked)
|
|
|
|
{
|
|
|
|
// conflicting field
|
|
|
|
ec = error::bad_content_length;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::uint64_t v;
|
|
|
|
if(! parse_dec(
|
|
|
|
value.begin(), value.end(), v))
|
|
|
|
{
|
|
|
|
ec = error::bad_content_length;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2016-11-20 07:32:41 -05:00
|
|
|
len_ = v;
|
|
|
|
f_ |= flagContentLength;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transfer-Encoding
|
2017-06-06 14:04:17 -07:00
|
|
|
if(f == field::transfer_encoding)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
|
|
|
if(f_ & flagChunked)
|
|
|
|
{
|
|
|
|
// duplicate
|
|
|
|
ec = error::bad_transfer_encoding;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(f_ & flagContentLength)
|
|
|
|
{
|
|
|
|
// conflicting field
|
|
|
|
ec = error::bad_transfer_encoding;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2016-11-20 07:32:41 -05:00
|
|
|
auto const v = token_list{value};
|
2017-05-31 08:01:55 -07:00
|
|
|
auto const p = std::find_if(v.begin(), v.end(),
|
2016-11-20 07:32:41 -05:00
|
|
|
[&](typename token_list::value_type const& s)
|
|
|
|
{
|
2017-06-30 08:46:22 -07:00
|
|
|
return iequals({"chunked", 7}, s);
|
2016-11-20 07:32:41 -05:00
|
|
|
});
|
2017-05-31 08:01:55 -07:00
|
|
|
if(p == v.end())
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
2017-05-31 08:01:55 -07:00
|
|
|
if(std::next(p) != v.end())
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
|
|
|
len_ = 0;
|
|
|
|
f_ |= flagChunked;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Upgrade
|
2017-06-06 14:04:17 -07:00
|
|
|
if(f == field::upgrade)
|
2016-11-20 07:32:41 -05:00
|
|
|
{
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2017-06-13 07:08:52 -07:00
|
|
|
f_ |= flagUpgrade;
|
2016-11-20 07:32:41 -05:00
|
|
|
return;
|
|
|
|
}
|
2017-06-13 07:08:52 -07:00
|
|
|
|
2017-06-19 16:57:12 -07:00
|
|
|
ec.assign(0, ec.category());
|
2016-11-20 07:32:41 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
} // http
|
|
|
|
} // beast
|
2017-07-20 13:40:34 -07:00
|
|
|
} // boost
|
2016-11-20 07:32:41 -05:00
|
|
|
|
|
|
|
#endif
|