mirror of
https://github.com/boostorg/beast.git
synced 2025-08-02 14:24:31 +02:00
basic_parser is abstract, not CRTP (API Change):
* `basic_parser` now uses pure virtual member functions instead of the curiously recurring template pattern. Actions Required: * Change uses of the `basic_parser` type to omit the `Derived` template parameter * Classes derived from `basic_parser` no longer need to friend the base. * Virtual functions in the derived class may be marked `override`.
This commit is contained in:
@@ -4,6 +4,7 @@ Version 219:
|
|||||||
* Visual Studio 2017 minimum requirement for Windows
|
* Visual Studio 2017 minimum requirement for Windows
|
||||||
* Better treatment of SSL short reads
|
* Better treatment of SSL short reads
|
||||||
* ssl_stream is a public interface
|
* ssl_stream is a public interface
|
||||||
|
* basic_parser is abstract, not CRTP (API Change)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
34
Jamfile
34
Jamfile
@@ -51,29 +51,9 @@ variant beast_ubasan
|
|||||||
|
|
||||||
path-constant TEST_MAIN : include/boost/beast/_experimental/unit_test/main.cpp ;
|
path-constant TEST_MAIN : include/boost/beast/_experimental/unit_test/main.cpp ;
|
||||||
|
|
||||||
lib static_asio
|
|
||||||
: test/lib_asio.cpp
|
|
||||||
: requirements
|
|
||||||
[ requires
|
|
||||||
cxx11_constexpr
|
|
||||||
cxx11_decltype
|
|
||||||
cxx11_hdr_tuple
|
|
||||||
cxx11_template_aliases
|
|
||||||
cxx11_variadic_templates
|
|
||||||
]
|
|
||||||
<define>BOOST_ASIO_SEPARATE_COMPILATION
|
|
||||||
<define>BOOST_ASIO_NO_DEPRECATED=1
|
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_ARRAY=1
|
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_BIND=1
|
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
|
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_REGEX=1
|
|
||||||
<define>BOOST_COROUTINES_NO_DEPRECATION_WARNING=1
|
|
||||||
<target-os>windows:<define>_WIN32_WINNT=0x0601
|
|
||||||
<link>static
|
|
||||||
;
|
|
||||||
|
|
||||||
lib static_beast
|
lib static_beast
|
||||||
: test/lib_beast.cpp
|
: test/lib_beast.cpp
|
||||||
|
test/lib_asio.cpp
|
||||||
: requirements
|
: requirements
|
||||||
[ requires
|
[ requires
|
||||||
cxx11_constexpr
|
cxx11_constexpr
|
||||||
@@ -83,12 +63,14 @@ lib static_beast
|
|||||||
cxx11_variadic_templates
|
cxx11_variadic_templates
|
||||||
]
|
]
|
||||||
<define>BOOST_BEAST_SPLIT_COMPILATION
|
<define>BOOST_BEAST_SPLIT_COMPILATION
|
||||||
|
<define>BOOST_ASIO_SEPARATE_COMPILATION
|
||||||
<define>BOOST_ASIO_NO_DEPRECATED=1
|
<define>BOOST_ASIO_NO_DEPRECATED=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_ARRAY=1
|
<define>BOOST_ASIO_DISABLE_BOOST_ARRAY=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_BIND=1
|
<define>BOOST_ASIO_DISABLE_BOOST_BIND=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
|
<define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_REGEX=1
|
<define>BOOST_ASIO_DISABLE_BOOST_REGEX=1
|
||||||
<define>BOOST_COROUTINES_NO_DEPRECATION_WARNING=1
|
<define>BOOST_COROUTINES_NO_DEPRECATION_WARNING=1
|
||||||
|
<toolset>msvc-14.1:<cxxflags>"/permissive-"
|
||||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||||
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_CRT_SECURE_NO_WARNINGS=1
|
||||||
<toolset>msvc:<define>_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING
|
<toolset>msvc:<define>_SILENCE_CXX17_ALLOCATOR_VOID_DEPRECATION_WARNING
|
||||||
@@ -103,7 +85,7 @@ project /boost/beast
|
|||||||
<include>./test/extras/include
|
<include>./test/extras/include
|
||||||
<library>/boost/coroutine//boost_coroutine
|
<library>/boost/coroutine//boost_coroutine
|
||||||
<library>/boost/filesystem//boost_filesystem
|
<library>/boost/filesystem//boost_filesystem
|
||||||
<library>static_asio
|
#<library>static_asio
|
||||||
<library>static_beast
|
<library>static_beast
|
||||||
<implicit-dependency>/boost//headers
|
<implicit-dependency>/boost//headers
|
||||||
<threading>multi
|
<threading>multi
|
||||||
@@ -112,16 +94,16 @@ project /boost/beast
|
|||||||
[ ac.check-library /boost/beast//ssl : <library>/boost/beast//ssl : <build>no ]
|
[ ac.check-library /boost/beast//ssl : <library>/boost/beast//ssl : <build>no ]
|
||||||
<library>/boost/beast//crypto
|
<library>/boost/beast//crypto
|
||||||
<define>BOOST_ALL_NO_LIB=1
|
<define>BOOST_ALL_NO_LIB=1
|
||||||
|
<define>BOOST_BEAST_SPLIT_COMPILATION
|
||||||
|
<define>BOOST_ASIO_SEPARATE_COMPILATION
|
||||||
<define>BOOST_ASIO_NO_DEPRECATED=1
|
<define>BOOST_ASIO_NO_DEPRECATED=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_ARRAY=1
|
<define>BOOST_ASIO_DISABLE_BOOST_ARRAY=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_BIND=1
|
<define>BOOST_ASIO_DISABLE_BOOST_BIND=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
|
<define>BOOST_ASIO_DISABLE_BOOST_DATE_TIME=1
|
||||||
<define>BOOST_ASIO_DISABLE_BOOST_REGEX=1
|
<define>BOOST_ASIO_DISABLE_BOOST_REGEX=1
|
||||||
<define>BOOST_COROUTINES_NO_DEPRECATION_WARNING=1
|
<define>BOOST_COROUTINES_NO_DEPRECATION_WARNING=1
|
||||||
#<define>BOOST_ASIO_SEPARATE_COMPILATION
|
<define>BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE=1
|
||||||
<define>BOOST_ASIO_DISABLE_WINDOWS_RANDOM_ACCESS_HANDLE=1
|
<define>BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE=1
|
||||||
<define>BOOST_ASIO_DISABLE_WINDOWS_STREAM_HANDLE=1
|
|
||||||
#<define>BOOST_BEAST_SEPARATE_COMPILATION
|
|
||||||
<toolset>msvc:<cxxflags>"/bigobj"
|
<toolset>msvc:<cxxflags>"/bigobj"
|
||||||
<toolset>msvc-14.1:<cxxflags>"/permissive-"
|
<toolset>msvc-14.1:<cxxflags>"/permissive-"
|
||||||
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
<toolset>msvc:<define>_SCL_SECURE_NO_WARNINGS=1
|
||||||
|
@@ -151,11 +151,7 @@ receive_expect_100_continue(
|
|||||||
|
|
||||||
// Read the rest of the message.
|
// Read the rest of the message.
|
||||||
//
|
//
|
||||||
// We use parser.base() to return a basic_parser&, to avoid an
|
read(stream, buffer, parser, ec);
|
||||||
// ambiguous function error (from boost::asio::read). Another
|
|
||||||
// solution is to qualify the call, e.g. `beast::http::read`
|
|
||||||
//
|
|
||||||
read(stream, buffer, parser.base(), ec);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//]
|
//]
|
||||||
@@ -875,14 +871,9 @@ do_form_request(
|
|||||||
//[example_http_custom_parser
|
//[example_http_custom_parser
|
||||||
|
|
||||||
template<bool isRequest>
|
template<bool isRequest>
|
||||||
class custom_parser
|
class custom_parser : public basic_parser<isRequest>
|
||||||
: public basic_parser<isRequest, custom_parser<isRequest>>
|
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// The friend declaration is needed,
|
|
||||||
// otherwise the callbacks must be made public.
|
|
||||||
friend class basic_parser<isRequest, custom_parser>;
|
|
||||||
|
|
||||||
/// Called after receiving the request-line (isRequest == true).
|
/// Called after receiving the request-line (isRequest == true).
|
||||||
void
|
void
|
||||||
on_request_impl(
|
on_request_impl(
|
||||||
@@ -890,7 +881,7 @@ private:
|
|||||||
string_view method_str, // The method as a string
|
string_view method_str, // The method as a string
|
||||||
string_view target, // The request-target
|
string_view target, // The request-target
|
||||||
int version, // The HTTP-version
|
int version, // The HTTP-version
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called after receiving the start-line (isRequest == false).
|
/// Called after receiving the start-line (isRequest == false).
|
||||||
void
|
void
|
||||||
@@ -898,7 +889,7 @@ private:
|
|||||||
int code, // The status-code
|
int code, // The status-code
|
||||||
string_view reason, // The obsolete reason-phrase
|
string_view reason, // The obsolete reason-phrase
|
||||||
int version, // The HTTP-version
|
int version, // The HTTP-version
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called after receiving a header field.
|
/// Called after receiving a header field.
|
||||||
void
|
void
|
||||||
@@ -906,12 +897,12 @@ private:
|
|||||||
field f, // The known-field enumeration constant
|
field f, // The known-field enumeration constant
|
||||||
string_view name, // The field name string.
|
string_view name, // The field name string.
|
||||||
string_view value, // The field value
|
string_view value, // The field value
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called after the complete header is received.
|
/// Called after the complete header is received.
|
||||||
void
|
void
|
||||||
on_header_impl(
|
on_header_impl(
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called just before processing the body, if a body exists.
|
/// Called just before processing the body, if a body exists.
|
||||||
void
|
void
|
||||||
@@ -919,7 +910,7 @@ private:
|
|||||||
boost::optional<
|
boost::optional<
|
||||||
std::uint64_t> const&
|
std::uint64_t> const&
|
||||||
content_length, // Content length if known, else `boost::none`
|
content_length, // Content length if known, else `boost::none`
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called for each piece of the body, if a body exists.
|
/// Called for each piece of the body, if a body exists.
|
||||||
//!
|
//!
|
||||||
@@ -932,7 +923,7 @@ private:
|
|||||||
std::size_t
|
std::size_t
|
||||||
on_body_impl(
|
on_body_impl(
|
||||||
string_view s, // A portion of the body
|
string_view s, // A portion of the body
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called for each chunk header.
|
/// Called for each chunk header.
|
||||||
void
|
void
|
||||||
@@ -940,7 +931,7 @@ private:
|
|||||||
std::uint64_t size, // The size of the upcoming chunk,
|
std::uint64_t size, // The size of the upcoming chunk,
|
||||||
// or zero for the last chunk
|
// or zero for the last chunk
|
||||||
string_view extension, // The chunk extensions (may be empty)
|
string_view extension, // The chunk extensions (may be empty)
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called to deliver the chunk body.
|
/// Called to deliver the chunk body.
|
||||||
//!
|
//!
|
||||||
@@ -958,11 +949,12 @@ private:
|
|||||||
// including what is being passed here.
|
// including what is being passed here.
|
||||||
// or zero for the last chunk
|
// or zero for the last chunk
|
||||||
string_view body, // The next piece of the chunk body
|
string_view body, // The next piece of the chunk body
|
||||||
error_code& ec); // The error returned to the caller, if any
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
/// Called when the complete message is parsed.
|
/// Called when the complete message is parsed.
|
||||||
void
|
void
|
||||||
on_finish_impl(error_code& ec);
|
on_finish_impl(
|
||||||
|
error_code& ec) override; // The error returned to the caller, if any
|
||||||
|
|
||||||
public:
|
public:
|
||||||
custom_parser() = default;
|
custom_parser() = default;
|
||||||
|
@@ -33,5 +33,8 @@ enum class error
|
|||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/_experimental/test/impl/error.hpp>
|
#include <boost/beast/_experimental/test/impl/error.hpp>
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/_experimental/test/impl/error.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -63,6 +63,8 @@ public:
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/_experimental/test/impl/fail_count.hpp>
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/_experimental/test/impl/fail_count.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -37,8 +37,4 @@ make_error_code(error e) noexcept;
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
|
||||||
#include <boost/beast/_experimental/test/impl/error.ipp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -7,9 +7,10 @@
|
|||||||
// Official repository: https://github.com/boostorg/beast
|
// Official repository: https://github.com/boostorg/beast
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef BOOST_BEAST_TEST_IMPL_FAIL_COUNT_HPP
|
#ifndef BOOST_BEAST_TEST_IMPL_FAIL_COUNT_IPP
|
||||||
#define BOOST_BEAST_TEST_IMPL_FAIL_COUNT_HPP
|
#define BOOST_BEAST_TEST_IMPL_FAIL_COUNT_IPP
|
||||||
|
|
||||||
|
#include <boost/beast/_experimental/test/fail_count.hpp>
|
||||||
#include <boost/throw_exception.hpp>
|
#include <boost/throw_exception.hpp>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
@@ -433,8 +433,4 @@ connect(stream& to, Arg1&& arg1, ArgN&&... argn)
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
|
||||||
#include <boost/beast/_experimental/test/impl/stream.ipp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -550,5 +550,8 @@ connect(stream& to, Arg1&& arg1, ArgN&&... argn);
|
|||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/_experimental/test/impl/stream.hpp>
|
#include <boost/beast/_experimental/test/impl/stream.hpp>
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/_experimental/test/impl/stream.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -81,5 +81,8 @@ enum class condition
|
|||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/core/impl/error.hpp>
|
#include <boost/beast/core/impl/error.hpp>
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/core/impl/error.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -329,6 +329,7 @@ public:
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
|
#include <boost/beast/core/impl/flat_static_buffer.hpp>
|
||||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
#include <boost/beast/core/impl/flat_static_buffer.ipp>
|
#include <boost/beast/core/impl/flat_static_buffer.ipp>
|
||||||
#endif
|
#endif
|
||||||
|
@@ -41,8 +41,4 @@ make_error_condition(condition c);
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
|
||||||
#include <boost/beast/core/impl/error.ipp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
43
include/boost/beast/core/impl/flat_static_buffer.hpp
Normal file
43
include/boost/beast/core/impl/flat_static_buffer.hpp
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
//
|
||||||
|
// 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_IMPL_FLAT_STATIC_BUFFER_HPP
|
||||||
|
#define BOOST_BEAST_IMPL_FLAT_STATIC_BUFFER_HPP
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
|
||||||
|
template<std::size_t N>
|
||||||
|
flat_static_buffer<N>::
|
||||||
|
flat_static_buffer(
|
||||||
|
flat_static_buffer const& other)
|
||||||
|
: flat_static_buffer_base(buf_, N)
|
||||||
|
{
|
||||||
|
this->commit(net::buffer_copy(
|
||||||
|
this->prepare(other.size()), other.data()));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::size_t N>
|
||||||
|
auto
|
||||||
|
flat_static_buffer<N>::
|
||||||
|
operator=(flat_static_buffer const& other) ->
|
||||||
|
flat_static_buffer<N>&
|
||||||
|
{
|
||||||
|
if(this == &other)
|
||||||
|
return *this;
|
||||||
|
this->consume(this->size());
|
||||||
|
this->commit(net::buffer_copy(
|
||||||
|
this->prepare(other.size()), other.data()));
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif
|
@@ -83,31 +83,6 @@ reset(void* p, std::size_t n) noexcept
|
|||||||
end_ = begin_ + n;
|
end_ = begin_ + n;
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
template<std::size_t N>
|
|
||||||
flat_static_buffer<N>::
|
|
||||||
flat_static_buffer(flat_static_buffer const& other)
|
|
||||||
: flat_static_buffer_base(buf_, N)
|
|
||||||
{
|
|
||||||
this->commit(net::buffer_copy(
|
|
||||||
this->prepare(other.size()), other.data()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<std::size_t N>
|
|
||||||
auto
|
|
||||||
flat_static_buffer<N>::
|
|
||||||
operator=(flat_static_buffer const& other) ->
|
|
||||||
flat_static_buffer<N>&
|
|
||||||
{
|
|
||||||
if(this == &other)
|
|
||||||
return *this;
|
|
||||||
this->consume(this->size());
|
|
||||||
this->commit(net::buffer_copy(
|
|
||||||
this->prepare(other.size()), other.data()));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
|
@@ -47,133 +47,38 @@ namespace http {
|
|||||||
the structured portion of the HTTP message (header or chunk header)
|
the structured portion of the HTTP message (header or chunk header)
|
||||||
is contained in a linear buffer.
|
is contained in a linear buffer.
|
||||||
|
|
||||||
The interface uses CRTP (Curiously Recurring Template Pattern).
|
The interface to the parser uses virtual member functions.
|
||||||
To use this class directly, derive from @ref basic_parser. When
|
To use this class, derive your type from @ref basic_parser. When
|
||||||
bytes are presented, the implementation will make a series of zero
|
bytes are presented, the implementation will make a series of zero
|
||||||
or more calls to derived class members functions (termed "callbacks"
|
or more calls to virtual functions, which the derived class must
|
||||||
in this context) matching a specific signature.
|
implement.
|
||||||
|
|
||||||
Every callback must be provided by the derived class, or else
|
Every virtual function must be provided by the derived class,
|
||||||
a compilation error will be generated. This exemplar shows
|
or else a compilation error will be generated. The implementation
|
||||||
the signature and description of the callbacks required in
|
will make sure that `ec` is clear before each virtual function
|
||||||
the derived class.
|
is invoked. If a virtual function sets an error, it is propagated
|
||||||
For each callback, the function will ensure that `!ec` is `true`
|
out of the parser to the caller.
|
||||||
if there was no error or set to the appropriate error code if
|
|
||||||
there was one. If an error is set, the value is propagated to
|
|
||||||
the caller of the parser.
|
|
||||||
|
|
||||||
@par Derived Class Requirements
|
|
||||||
@code
|
|
||||||
template<bool isRequest>
|
|
||||||
class derived
|
|
||||||
: public basic_parser<isRequest, derived<isRequest>>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
// The friend declaration is needed,
|
|
||||||
// otherwise the callbacks must be made public.
|
|
||||||
friend class basic_parser<isRequest, derived>;
|
|
||||||
|
|
||||||
/// Called after receiving the request-line (isRequest == true).
|
|
||||||
void
|
|
||||||
on_request_impl(
|
|
||||||
verb method, // The method verb, verb::unknown if no match
|
|
||||||
string_view method_str, // The method as a string
|
|
||||||
string_view target, // The request-target
|
|
||||||
int version, // The HTTP-version
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called after receiving the start-line (isRequest == false).
|
|
||||||
void
|
|
||||||
on_response_impl(
|
|
||||||
int code, // The status-code
|
|
||||||
string_view reason, // The obsolete reason-phrase
|
|
||||||
int version, // The HTTP-version
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called after receiving a header field.
|
|
||||||
void
|
|
||||||
on_field_impl(
|
|
||||||
field f, // The known-field enumeration constant
|
|
||||||
string_view name, // The field name string.
|
|
||||||
string_view value, // The field value
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called after the complete header is received.
|
|
||||||
void
|
|
||||||
on_header_impl(
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called just before processing the body, if a body exists.
|
|
||||||
void
|
|
||||||
on_body_init_impl(
|
|
||||||
boost::optional<
|
|
||||||
std::uint64_t> const&
|
|
||||||
content_length, // Content length if known, else `boost::none`
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called for each piece of the body, if a body exists.
|
|
||||||
//!
|
|
||||||
//! This is used when there is no chunked transfer coding.
|
|
||||||
//!
|
|
||||||
//! The function returns the number of bytes consumed from the
|
|
||||||
//! input buffer. Any input octets not consumed will be will be
|
|
||||||
//! presented on subsequent calls.
|
|
||||||
//!
|
|
||||||
std::size_t
|
|
||||||
on_body_impl(
|
|
||||||
string_view s, // A portion of the body
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called for each chunk header.
|
|
||||||
void
|
|
||||||
on_chunk_header_impl(
|
|
||||||
std::uint64_t size, // The size of the upcoming chunk,
|
|
||||||
// or zero for the last chunk
|
|
||||||
string_view extension, // The chunk extensions (may be empty)
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called to deliver the chunk body.
|
|
||||||
//!
|
|
||||||
//! This is used when there is a chunked transfer coding. The
|
|
||||||
//! implementation will automatically remove the encoding before
|
|
||||||
//! calling this function.
|
|
||||||
//!
|
|
||||||
//! The function returns the number of bytes consumed from the
|
|
||||||
//! input buffer. Any input octets not consumed will be will be
|
|
||||||
//! presented on subsequent calls.
|
|
||||||
//!
|
|
||||||
std::size_t
|
|
||||||
on_chunk_body_impl(
|
|
||||||
std::uint64_t remain, // The number of bytes remaining in the chunk,
|
|
||||||
// including what is being passed here.
|
|
||||||
// or zero for the last chunk
|
|
||||||
string_view body, // The next piece of the chunk body
|
|
||||||
error_code& ec); // The error returned to the caller, if any
|
|
||||||
|
|
||||||
/// Called when the complete message is parsed.
|
|
||||||
void
|
|
||||||
on_finish_impl(error_code& ec);
|
|
||||||
|
|
||||||
public:
|
|
||||||
derived() = default;
|
|
||||||
};
|
|
||||||
@endcode
|
|
||||||
|
|
||||||
@tparam isRequest A `bool` indicating whether the parser will be
|
@tparam isRequest A `bool` indicating whether the parser will be
|
||||||
presented with request or response message.
|
presented with request or response message.
|
||||||
|
|
||||||
@tparam Derived The derived class type. This is part of the
|
|
||||||
Curiously Recurring Template Pattern interface.
|
|
||||||
|
|
||||||
@note If the parser encounters a field value with obs-fold
|
@note If the parser encounters a field value with obs-fold
|
||||||
longer than 4 kilobytes in length, an error is generated.
|
longer than 4 kilobytes in length, an error is generated.
|
||||||
*/
|
*/
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest>
|
||||||
class basic_parser
|
class basic_parser
|
||||||
: private detail::basic_parser_base
|
: private detail::basic_parser_base
|
||||||
{
|
{
|
||||||
template<bool OtherIsRequest, class OtherDerived>
|
std::uint64_t body_limit_ =
|
||||||
friend class basic_parser;
|
default_body_limit(is_request{}); // max payload body
|
||||||
|
std::uint64_t len_ = 0; // size of chunk or body
|
||||||
|
std::unique_ptr<char[]> buf_; // temp storage
|
||||||
|
std::size_t buf_len_ = 0; // size of buf_
|
||||||
|
std::size_t skip_ = 0; // resume search here
|
||||||
|
std::uint32_t header_limit_ = 8192; // max header size
|
||||||
|
unsigned short status_ = 0; // response status
|
||||||
|
state state_ = state::nothing_yet; // initial state
|
||||||
|
unsigned f_ = 0; // flags
|
||||||
|
|
||||||
// limit on the size of the stack flat buffer
|
// limit on the size of the stack flat buffer
|
||||||
static std::size_t constexpr max_stack_buffer = 8192;
|
static std::size_t constexpr max_stack_buffer = 8192;
|
||||||
@@ -219,27 +124,13 @@ class basic_parser
|
|||||||
return 8 * 1024 * 1024; // 8MB
|
return 8 * 1024 * 1024; // 8MB
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t body_limit_ =
|
template<bool OtherIsRequest>
|
||||||
default_body_limit(is_request{}); // max payload body
|
friend class basic_parser;
|
||||||
std::uint64_t len_ = 0; // size of chunk or body
|
|
||||||
std::unique_ptr<char[]> buf_; // temp storage
|
|
||||||
std::size_t buf_len_ = 0; // size of buf_
|
|
||||||
std::size_t skip_ = 0; // resume search here
|
|
||||||
std::uint32_t header_limit_ = 8192; // max header size
|
|
||||||
unsigned short status_ = 0; // response status
|
|
||||||
state state_ = state::nothing_yet; // initial state
|
|
||||||
unsigned f_ = 0; // flags
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Default constructor
|
/// Default constructor
|
||||||
basic_parser() = default;
|
basic_parser() = default;
|
||||||
|
|
||||||
/// Move constructor
|
|
||||||
basic_parser(basic_parser &&) = default;
|
|
||||||
|
|
||||||
/// Move assignment
|
|
||||||
basic_parser& operator=(basic_parser &&) = default;
|
|
||||||
|
|
||||||
/** Move constructor
|
/** Move constructor
|
||||||
|
|
||||||
@note
|
@note
|
||||||
@@ -247,8 +138,10 @@ protected:
|
|||||||
After the move, the only valid operation on the
|
After the move, the only valid operation on the
|
||||||
moved-from object is destruction.
|
moved-from object is destruction.
|
||||||
*/
|
*/
|
||||||
template<class OtherDerived>
|
basic_parser(basic_parser &&) = default;
|
||||||
basic_parser(basic_parser<isRequest, OtherDerived>&&);
|
|
||||||
|
/// Move assignment
|
||||||
|
basic_parser& operator=(basic_parser &&) = default;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// `true` if this parser parses requests, `false` for responses.
|
/// `true` if this parser parses requests, `false` for responses.
|
||||||
@@ -264,30 +157,6 @@ public:
|
|||||||
/// Copy assignment
|
/// Copy assignment
|
||||||
basic_parser& operator=(basic_parser const&) = delete;
|
basic_parser& operator=(basic_parser const&) = delete;
|
||||||
|
|
||||||
/** Returns a reference to this object as a `basic_parser`.
|
|
||||||
|
|
||||||
This is used to pass a derived class where a base class is
|
|
||||||
expected, to choose a correct function overload when the
|
|
||||||
resolution would be ambiguous.
|
|
||||||
*/
|
|
||||||
basic_parser&
|
|
||||||
base()
|
|
||||||
{
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a constant reference to this object as a `basic_parser`.
|
|
||||||
|
|
||||||
This is used to pass a derived class where a base class is
|
|
||||||
expected, to choose a correct function overload when the
|
|
||||||
resolution would be ambiguous.
|
|
||||||
*/
|
|
||||||
basic_parser const&
|
|
||||||
base() const
|
|
||||||
{
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the parser has received at least one byte of input.
|
/// Returns `true` if the parser has received at least one byte of input.
|
||||||
bool
|
bool
|
||||||
got_some() const
|
got_some() const
|
||||||
@@ -526,7 +395,7 @@ public:
|
|||||||
|
|
||||||
#if ! BOOST_BEAST_DOXYGEN
|
#if ! BOOST_BEAST_DOXYGEN
|
||||||
std::size_t
|
std::size_t
|
||||||
put(net::const_buffer const& buffer,
|
put(net::const_buffer buffer,
|
||||||
error_code& ec);
|
error_code& ec);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -549,19 +418,205 @@ public:
|
|||||||
void
|
void
|
||||||
put_eof(error_code& ec);
|
put_eof(error_code& ec);
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
inline
|
/** Called after receiving the request-line.
|
||||||
Derived&
|
|
||||||
impl()
|
This virtual function is invoked after receiving a request-line
|
||||||
|
when parsing HTTP requests.
|
||||||
|
It can only be called when `isRequest == true`.
|
||||||
|
|
||||||
|
@param method The verb enumeration. If the method string is not
|
||||||
|
one of the predefined strings, this value will be @ref verb::unknown.
|
||||||
|
|
||||||
|
@param method_str The unmodified string representing the verb.
|
||||||
|
|
||||||
|
@param target The request-target.
|
||||||
|
|
||||||
|
@param version The HTTP-version. This will be 10 for HTTP/1.0,
|
||||||
|
and 11 for HTTP/1.1.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
on_request_impl(
|
||||||
|
verb method,
|
||||||
|
string_view method_str,
|
||||||
|
string_view target,
|
||||||
|
int version,
|
||||||
|
error_code& ec) = 0;
|
||||||
|
|
||||||
|
/** Called after receiving the status-line.
|
||||||
|
|
||||||
|
This virtual function is invoked after receiving a status-line
|
||||||
|
when parsing HTTP responses.
|
||||||
|
It can only be called when `isRequest == false`.
|
||||||
|
|
||||||
|
@param code The numeric status code.
|
||||||
|
|
||||||
|
@param reason The reason-phrase. Note that this value is
|
||||||
|
now obsolete, and only provided for historical or diagnostic
|
||||||
|
purposes.
|
||||||
|
|
||||||
|
@param version The HTTP-version. This will be 10 for HTTP/1.0,
|
||||||
|
and 11 for HTTP/1.1.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
on_response_impl(
|
||||||
|
int code,
|
||||||
|
string_view reason,
|
||||||
|
int version,
|
||||||
|
error_code& ec) = 0;
|
||||||
|
|
||||||
|
/** Called once for each complete field in the HTTP header.
|
||||||
|
|
||||||
|
This virtual function is invoked for each field that is received
|
||||||
|
while parsing an HTTP message.
|
||||||
|
|
||||||
|
@param name The known field enum value. If the name of the field
|
||||||
|
is not recognized, this value will be @ref field::unknown.
|
||||||
|
|
||||||
|
@param name_string The exact name of the field as received from
|
||||||
|
the input, represented as a string.
|
||||||
|
|
||||||
|
@param value A string holding the value of the field.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
on_field_impl(
|
||||||
|
field name,
|
||||||
|
string_view name_string,
|
||||||
|
string_view value,
|
||||||
|
error_code& ec) = 0;
|
||||||
|
|
||||||
|
/** Called once after the complete HTTP header is received.
|
||||||
|
|
||||||
|
This virtual function is invoked once, after the complete HTTP
|
||||||
|
header is received while parsing a message.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
on_header_impl(error_code& ec) = 0;
|
||||||
|
|
||||||
|
/** Called once before the body is processed.
|
||||||
|
|
||||||
|
This virtual function is invoked once, before the content body is
|
||||||
|
processed (but after the complete header is received).
|
||||||
|
|
||||||
|
@param content_length A value representing the content length in
|
||||||
|
bytes if the length is known (this can include a zero length).
|
||||||
|
Otherwise, the value will be `boost::none`.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
on_body_init_impl(
|
||||||
|
boost::optional<std::uint64_t> const& content_length,
|
||||||
|
error_code& ec) = 0;
|
||||||
|
|
||||||
|
/** Called each time additional data is received representing the content body.
|
||||||
|
|
||||||
|
This virtual function is invoked for each piece of the body which is
|
||||||
|
received while parsing of a message. This function is only used when
|
||||||
|
no chunked transfer encoding is present.
|
||||||
|
|
||||||
|
@param body A string holding the additional body contents. This may
|
||||||
|
contain nulls or unprintable characters.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
|
||||||
|
@see on_chunk_body_impl
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
std::size_t
|
||||||
|
on_body_impl(
|
||||||
|
string_view body,
|
||||||
|
error_code& ec)
|
||||||
{
|
{
|
||||||
return *static_cast<Derived*>(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Called each time a new chunk header of a chunk encoded body is received.
|
||||||
|
|
||||||
|
This function is invoked each time a new chunk header is received.
|
||||||
|
The function is only used when the chunked transfer encoding is present.
|
||||||
|
|
||||||
|
@param size The size of this chunk, in bytes.
|
||||||
|
|
||||||
|
@param extensions A string containing the entire chunk extensions.
|
||||||
|
This may be empty, indicating no extensions are present.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
on_chunk_header_impl(
|
||||||
|
std::uint64_t size,
|
||||||
|
string_view extensions,
|
||||||
|
error_code& ec) = 0;
|
||||||
|
|
||||||
|
/** Called each time additional data is received representing part of a body chunk.
|
||||||
|
|
||||||
|
This virtual function is invoked for each piece of the body which is
|
||||||
|
received while parsing of a message. This function is only used when
|
||||||
|
no chunked transfer encoding is present.
|
||||||
|
|
||||||
|
@param remain The number of bytes remaining in this chunk. This includes
|
||||||
|
the contents of passed `body`. If this value is zero, then this represents
|
||||||
|
the final chunk.
|
||||||
|
|
||||||
|
@param body A string holding the additional body contents. This may
|
||||||
|
contain nulls or unprintable characters.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
|
||||||
|
@return This function should return the number of bytes actually consumed
|
||||||
|
from the `body` value. Any bytes that are not consumed on this call
|
||||||
|
will be presented in a subsequent call.
|
||||||
|
|
||||||
|
@see on_body_impl
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
std::size_t
|
||||||
|
on_chunk_body_impl(
|
||||||
|
std::uint64_t remain,
|
||||||
|
string_view body,
|
||||||
|
error_code& ec) = 0;
|
||||||
|
|
||||||
|
/** Called once when the complete message is received.
|
||||||
|
|
||||||
|
This virtual function is invoked once, after successfully parsing
|
||||||
|
a complete HTTP message.
|
||||||
|
|
||||||
|
@param ec An output parameter which the function may set to indicate
|
||||||
|
an error. The error will be clear before this function is invoked.
|
||||||
|
*/
|
||||||
|
virtual
|
||||||
|
void
|
||||||
|
on_finish_impl(error_code& ec) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
std::size_t
|
std::size_t
|
||||||
put_from_stack(std::size_t size,
|
put_from_stack(
|
||||||
|
std::size_t size,
|
||||||
ConstBufferSequence const& buffers,
|
ConstBufferSequence const& buffers,
|
||||||
error_code& ec);
|
error_code& ec);
|
||||||
|
|
||||||
void
|
void
|
||||||
maybe_need_more(
|
maybe_need_more(
|
||||||
@@ -617,5 +672,8 @@ private:
|
|||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/http/impl/basic_parser.hpp>
|
#include <boost/beast/http/impl/basic_parser.hpp>
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/http/impl/basic_parser.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -24,7 +24,7 @@ class header;
|
|||||||
template<bool, class, class>
|
template<bool, class, class>
|
||||||
class message;
|
class message;
|
||||||
|
|
||||||
template<bool isRequest,class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
class parser;
|
class parser;
|
||||||
|
|
||||||
namespace detail {
|
namespace detail {
|
||||||
|
@@ -152,5 +152,8 @@ enum class error
|
|||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/http/impl/error.hpp>
|
#include <boost/beast/http/impl/error.hpp>
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/http/impl/error.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -11,83 +11,17 @@
|
|||||||
#define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_HPP
|
#define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_HPP
|
||||||
|
|
||||||
#include <boost/beast/core/buffer_size.hpp>
|
#include <boost/beast/core/buffer_size.hpp>
|
||||||
#include <boost/beast/core/static_string.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>
|
|
||||||
#include <boost/asio/buffer.hpp>
|
#include <boost/asio/buffer.hpp>
|
||||||
#include <boost/make_unique.hpp>
|
#include <boost/make_unique.hpp>
|
||||||
#include <algorithm>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
namespace http {
|
namespace http {
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest>
|
||||||
template<class OtherDerived>
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
basic_parser(basic_parser<
|
|
||||||
isRequest, OtherDerived>&& other)
|
|
||||||
: body_limit_(other.body_limit_)
|
|
||||||
, len_(other.len_)
|
|
||||||
, buf_(std::move(other.buf_))
|
|
||||||
, buf_len_(other.buf_len_)
|
|
||||||
, skip_(other.skip_)
|
|
||||||
, header_limit_(other.header_limit_)
|
|
||||||
, status_(other.status_)
|
|
||||||
, state_(other.state_)
|
|
||||||
, f_(other.f_)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
bool
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
keep_alive() const
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(is_header_done());
|
|
||||||
if(f_ & flagHTTP11)
|
|
||||||
{
|
|
||||||
if(f_ & flagConnectionClose)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if(! (f_ & flagConnectionKeepAlive))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (f_ & flagNeedEOF) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
std::size_t
|
std::size_t
|
||||||
basic_parser<isRequest, Derived>::
|
basic_parser<isRequest>::
|
||||||
put(ConstBufferSequence const& buffers,
|
put(ConstBufferSequence const& buffers,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
@@ -122,180 +56,10 @@ put(ConstBufferSequence const& buffers,
|
|||||||
buf_.get(), buf_len_}, ec);
|
buf_.get(), buf_len_}, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest>
|
||||||
std::size_t
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
put(net::const_buffer const& buffer,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(state_ != state::complete);
|
|
||||||
auto p = static_cast<char const*>(buffer.data());
|
|
||||||
auto n = buffer.size();
|
|
||||||
auto const p0 = p;
|
|
||||||
auto const p1 = p0 + n;
|
|
||||||
ec = {};
|
|
||||||
loop:
|
|
||||||
switch(state_)
|
|
||||||
{
|
|
||||||
case state::nothing_yet:
|
|
||||||
if(n == 0)
|
|
||||||
{
|
|
||||||
ec = error::need_more;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
state_ = state::start_line;
|
|
||||||
BOOST_FALLTHROUGH;
|
|
||||||
|
|
||||||
case state::start_line:
|
|
||||||
{
|
|
||||||
maybe_need_more(p, n, ec);
|
|
||||||
if(ec)
|
|
||||||
goto done;
|
|
||||||
parse_start_line(p, p + (std::min<std::size_t>)(
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
BOOST_FALLTHROUGH;
|
|
||||||
}
|
|
||||||
|
|
||||||
case state::fields:
|
|
||||||
maybe_need_more(p, n, ec);
|
|
||||||
if(ec)
|
|
||||||
goto done;
|
|
||||||
parse_fields(p, p + (std::min<std::size_t>)(
|
|
||||||
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{});
|
|
||||||
break;
|
|
||||||
|
|
||||||
case state::body0:
|
|
||||||
BOOST_ASSERT(! skip_);
|
|
||||||
impl().on_body_init_impl(content_length(), ec);
|
|
||||||
if(ec)
|
|
||||||
goto done;
|
|
||||||
state_ = state::body;
|
|
||||||
BOOST_FALLTHROUGH;
|
|
||||||
|
|
||||||
case state::body:
|
|
||||||
BOOST_ASSERT(! skip_);
|
|
||||||
parse_body(p, n, ec);
|
|
||||||
if(ec)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case state::body_to_eof0:
|
|
||||||
BOOST_ASSERT(! skip_);
|
|
||||||
impl().on_body_init_impl(content_length(), ec);
|
|
||||||
if(ec)
|
|
||||||
goto done;
|
|
||||||
state_ = state::body_to_eof;
|
|
||||||
BOOST_FALLTHROUGH;
|
|
||||||
|
|
||||||
case state::body_to_eof:
|
|
||||||
BOOST_ASSERT(! skip_);
|
|
||||||
parse_body_to_eof(p, n, ec);
|
|
||||||
if(ec)
|
|
||||||
goto done;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case state::chunk_header0:
|
|
||||||
impl().on_body_init_impl(content_length(), ec);
|
|
||||||
if(ec)
|
|
||||||
goto done;
|
|
||||||
state_ = state::chunk_header;
|
|
||||||
BOOST_FALLTHROUGH;
|
|
||||||
|
|
||||||
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:
|
|
||||||
ec = {};
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if(p < p1 && ! is_done() && eager())
|
|
||||||
{
|
|
||||||
n = static_cast<std::size_t>(p1 - p);
|
|
||||||
goto loop;
|
|
||||||
}
|
|
||||||
done:
|
|
||||||
return static_cast<std::size_t>(p - p0);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
put_eof(error_code& ec)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(got_some());
|
|
||||||
if( state_ == state::start_line ||
|
|
||||||
state_ == state::fields)
|
|
||||||
{
|
|
||||||
ec = error::partial_message;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(f_ & (flagContentLength | flagChunked))
|
|
||||||
{
|
|
||||||
if(state_ != state::complete)
|
|
||||||
{
|
|
||||||
ec = error::partial_message;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ec = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
impl().on_finish_impl(ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
state_ = state::complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
template<class ConstBufferSequence>
|
template<class ConstBufferSequence>
|
||||||
std::size_t
|
std::size_t
|
||||||
basic_parser<isRequest, Derived>::
|
basic_parser<isRequest>::
|
||||||
put_from_stack(std::size_t size,
|
put_from_stack(std::size_t size,
|
||||||
ConstBufferSequence const& buffers,
|
ConstBufferSequence const& buffers,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
@@ -307,615 +71,6 @@ put_from_stack(std::size_t size,
|
|||||||
buf, size}, ec);
|
buf, size}, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
maybe_need_more(
|
|
||||||
char const* p, std::size_t n,
|
|
||||||
error_code& ec)
|
|
||||||
{
|
|
||||||
if(skip_ == 0)
|
|
||||||
return;
|
|
||||||
if( n > header_limit_)
|
|
||||||
n = header_limit_;
|
|
||||||
if(n < skip_ + 4)
|
|
||||||
{
|
|
||||||
ec = error::need_more;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto const term =
|
|
||||||
find_eom(p + skip_, p + n);
|
|
||||||
if(! term)
|
|
||||||
{
|
|
||||||
skip_ = n - 3;
|
|
||||||
if(skip_ + 4 > header_limit_)
|
|
||||||
{
|
|
||||||
ec = error::header_limit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ec = error::need_more;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
skip_ = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
parse_start_line(
|
|
||||||
char const*& in, char const* last,
|
|
||||||
error_code& ec, std::true_type)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
request-line = method SP request-target SP HTTP-version CRLF
|
|
||||||
method = token
|
|
||||||
*/
|
|
||||||
auto p = in;
|
|
||||||
|
|
||||||
string_view method;
|
|
||||||
parse_method(p, last, method, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
|
|
||||||
string_view target;
|
|
||||||
parse_target(p, last, target, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
|
|
||||||
int version = 0;
|
|
||||||
parse_version(p, last, version, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(version < 10 || version > 11)
|
|
||||||
{
|
|
||||||
ec = error::bad_version;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(p + 2 > last)
|
|
||||||
{
|
|
||||||
ec = error::need_more;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(p[0] != '\r' || p[1] != '\n')
|
|
||||||
{
|
|
||||||
ec = error::bad_version;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
p += 2;
|
|
||||||
|
|
||||||
if(version >= 11)
|
|
||||||
f_ |= flagHTTP11;
|
|
||||||
|
|
||||||
impl().on_request_impl(string_to_verb(method),
|
|
||||||
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;
|
|
||||||
|
|
||||||
int version = 0;
|
|
||||||
parse_version(p, last, version, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(version < 10 || version > 11)
|
|
||||||
{
|
|
||||||
ec = error::bad_version;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SP
|
|
||||||
if(p + 1 > last)
|
|
||||||
{
|
|
||||||
ec = error::need_more;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(*p++ != ' ')
|
|
||||||
{
|
|
||||||
ec = error::bad_version;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
parse_status(p, last, status_, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// parse reason CRLF
|
|
||||||
string_view reason;
|
|
||||||
parse_reason(p, last, reason, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(version >= 11)
|
|
||||||
f_ |= flagHTTP11;
|
|
||||||
|
|
||||||
impl().on_response_impl(
|
|
||||||
status_, reason, version, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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;
|
|
||||||
impl().on_field_impl(f, name, value, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
in = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
finish_header(error_code& ec, std::true_type)
|
|
||||||
{
|
|
||||||
// RFC 7230 section 3.3
|
|
||||||
// https://tools.ietf.org/html/rfc7230#section-3.3
|
|
||||||
|
|
||||||
if(f_ & flagSkipBody)
|
|
||||||
{
|
|
||||||
state_ = state::complete;
|
|
||||||
}
|
|
||||||
else if(f_ & flagContentLength)
|
|
||||||
{
|
|
||||||
if(len_ > body_limit_)
|
|
||||||
{
|
|
||||||
ec = error::body_limit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl().on_header_impl(ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(state_ == state::complete)
|
|
||||||
{
|
|
||||||
impl().on_finish_impl(ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
finish_header(error_code& ec, std::false_type)
|
|
||||||
{
|
|
||||||
// RFC 7230 section 3.3
|
|
||||||
// https://tools.ietf.org/html/rfc7230#section-3.3
|
|
||||||
|
|
||||||
if( (f_ & flagSkipBody) || // e.g. response to a HEAD request
|
|
||||||
status_ / 100 == 1 || // 1xx e.g. Continue
|
|
||||||
status_ == 204 || // No Content
|
|
||||||
status_ == 304) // Not Modified
|
|
||||||
{
|
|
||||||
// VFALCO Content-Length may be present, but we
|
|
||||||
// treat the message as not having a body.
|
|
||||||
// https://github.com/boostorg/beast/issues/692
|
|
||||||
state_ = state::complete;
|
|
||||||
}
|
|
||||||
else if(f_ & flagContentLength)
|
|
||||||
{
|
|
||||||
if(len_ > body_limit_)
|
|
||||||
{
|
|
||||||
ec = error::body_limit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl().on_header_impl(ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(state_ == state::complete)
|
|
||||||
{
|
|
||||||
impl().on_finish_impl(ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
inline
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
parse_body(char const*& p,
|
|
||||||
std::size_t n, error_code& ec)
|
|
||||||
{
|
|
||||||
n = impl().on_body_impl(string_view{p,
|
|
||||||
beast::detail::clamp(len_, n)}, ec);
|
|
||||||
p += n;
|
|
||||||
len_ -= n;
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(len_ > 0)
|
|
||||||
return;
|
|
||||||
impl().on_finish_impl(ec);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if(n > body_limit_)
|
|
||||||
{
|
|
||||||
ec = error::body_limit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
body_limit_ = body_limit_ - n;
|
|
||||||
n = impl().on_body_impl(string_view{p, n}, ec);
|
|
||||||
p += n;
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
parse_chunk_header(char const*& p0,
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
|
|
||||||
auto p = p0;
|
|
||||||
auto const pend = p + n;
|
|
||||||
char const* eol;
|
|
||||||
|
|
||||||
if(! (f_ & flagFinalChunk))
|
|
||||||
{
|
|
||||||
if(n < skip_ + 2)
|
|
||||||
{
|
|
||||||
ec = error::need_more;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(! eol)
|
|
||||||
{
|
|
||||||
ec = error::need_more;
|
|
||||||
skip_ = n - 1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
skip_ = static_cast<
|
|
||||||
std::size_t>(eol - 2 - p0);
|
|
||||||
|
|
||||||
std::uint64_t size;
|
|
||||||
if(! parse_hex(p, size))
|
|
||||||
{
|
|
||||||
ec = error::bad_chunk;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(size != 0)
|
|
||||||
{
|
|
||||||
if(size > body_limit_)
|
|
||||||
{
|
|
||||||
ec = error::body_limit;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
body_limit_ -= size;
|
|
||||||
auto const start = p;
|
|
||||||
parse_chunk_extensions(p, pend, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(p != eol -2 )
|
|
||||||
{
|
|
||||||
ec = error::bad_chunk_extension;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto const ext = make_string(start, p);
|
|
||||||
impl().on_chunk_header_impl(size, ext, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
len_ = size;
|
|
||||||
skip_ = 2;
|
|
||||||
p0 = eol;
|
|
||||||
f_ |= flagExpectCRLF;
|
|
||||||
state_ = state::chunk_body;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
f_ |= flagFinalChunk;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(n >= 5);
|
|
||||||
if(f_ & flagExpectCRLF)
|
|
||||||
BOOST_VERIFY(parse_crlf(p));
|
|
||||||
std::uint64_t size;
|
|
||||||
BOOST_VERIFY(parse_hex(p, size));
|
|
||||||
eol = find_eol(p, pend, ec);
|
|
||||||
BOOST_ASSERT(! ec);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto eom = find_eom(p0 + skip_, pend);
|
|
||||||
if(! eom)
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(n >= 3);
|
|
||||||
skip_ = n - 3;
|
|
||||||
ec = error::need_more;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto const start = p;
|
|
||||||
parse_chunk_extensions(p, pend, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
if(p != eol - 2)
|
|
||||||
{
|
|
||||||
ec = error::bad_chunk_extension;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto const ext = make_string(start, p);
|
|
||||||
impl().on_chunk_header_impl(0, ext, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
p = eol;
|
|
||||||
parse_fields(p, eom, ec);
|
|
||||||
if(ec)
|
|
||||||
return;
|
|
||||||
BOOST_ASSERT(p == eom);
|
|
||||||
p0 = eom;
|
|
||||||
|
|
||||||
impl().on_finish_impl(ec);
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
n = impl().on_chunk_body_impl(
|
|
||||||
len_, string_view{p,
|
|
||||||
beast::detail::clamp(len_, n)}, ec);
|
|
||||||
p += n;
|
|
||||||
len_ -= n;
|
|
||||||
if(len_ == 0)
|
|
||||||
state_ = state::chunk_header;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<bool isRequest, class Derived>
|
|
||||||
void
|
|
||||||
basic_parser<isRequest, Derived>::
|
|
||||||
do_field(field f,
|
|
||||||
string_view value, error_code& ec)
|
|
||||||
{
|
|
||||||
// Connection
|
|
||||||
if(f == field::connection ||
|
|
||||||
f == field::proxy_connection)
|
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
if(iequals({"close", 5}, s))
|
|
||||||
{
|
|
||||||
f_ |= flagConnectionClose;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(iequals({"keep-alive", 10}, s))
|
|
||||||
{
|
|
||||||
f_ |= flagConnectionKeepAlive;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(iequals({"upgrade", 7}, s))
|
|
||||||
{
|
|
||||||
f_ |= flagConnectionUpgrade;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ec = {};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Content-Length
|
|
||||||
if(f == field::content_length)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
ec = {};
|
|
||||||
len_ = v;
|
|
||||||
f_ |= flagContentLength;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer-Encoding
|
|
||||||
if(f == field::transfer_encoding)
|
|
||||||
{
|
|
||||||
if(f_ & flagChunked)
|
|
||||||
{
|
|
||||||
// duplicate
|
|
||||||
ec = error::bad_transfer_encoding;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(f_ & flagContentLength)
|
|
||||||
{
|
|
||||||
// conflicting field
|
|
||||||
ec = error::bad_transfer_encoding;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ec = {};
|
|
||||||
auto const v = token_list{value};
|
|
||||||
auto const p = std::find_if(v.begin(), v.end(),
|
|
||||||
[&](typename token_list::value_type const& s)
|
|
||||||
{
|
|
||||||
return iequals({"chunked", 7}, s);
|
|
||||||
});
|
|
||||||
if(p == v.end())
|
|
||||||
return;
|
|
||||||
if(std::next(p) != v.end())
|
|
||||||
return;
|
|
||||||
len_ = 0;
|
|
||||||
f_ |= flagChunked;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upgrade
|
|
||||||
if(f == field::upgrade)
|
|
||||||
{
|
|
||||||
ec = {};
|
|
||||||
f_ |= flagUpgrade;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ec = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
} // http
|
} // http
|
||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
857
include/boost/beast/http/impl/basic_parser.ipp
Normal file
857
include/boost/beast/http/impl/basic_parser.ipp
Normal file
@@ -0,0 +1,857 @@
|
|||||||
|
//
|
||||||
|
// 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_IMPL_BASIC_PARSER_IPP
|
||||||
|
#define BOOST_BEAST_HTTP_IMPL_BASIC_PARSER_IPP
|
||||||
|
|
||||||
|
#include <boost/beast/http/basic_parser.hpp>
|
||||||
|
#include <boost/beast/http/error.hpp>
|
||||||
|
#include <boost/beast/http/rfc7230.hpp>
|
||||||
|
#include <boost/beast/core/buffer_size.hpp>
|
||||||
|
#include <boost/beast/core/static_string.hpp>
|
||||||
|
#include <boost/beast/core/detail/clamp.hpp>
|
||||||
|
#include <boost/beast/core/detail/config.hpp>
|
||||||
|
#include <boost/asio/buffer.hpp>
|
||||||
|
#include <boost/make_unique.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace beast {
|
||||||
|
namespace http {
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
bool
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
keep_alive() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(is_header_done());
|
||||||
|
if(f_ & flagHTTP11)
|
||||||
|
{
|
||||||
|
if(f_ & flagConnectionClose)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(! (f_ & flagConnectionKeepAlive))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (f_ & flagNeedEOF) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
boost::optional<std::uint64_t>
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
content_length() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(is_header_done());
|
||||||
|
if(! (f_ & flagContentLength))
|
||||||
|
return boost::none;
|
||||||
|
return len_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
skip(bool v)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(! got_some());
|
||||||
|
if(v)
|
||||||
|
f_ |= flagSkipBody;
|
||||||
|
else
|
||||||
|
f_ &= ~flagSkipBody;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
std::size_t
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
put(net::const_buffer buffer,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(state_ != state::complete);
|
||||||
|
auto p = static_cast<char const*>(buffer.data());
|
||||||
|
auto n = buffer.size();
|
||||||
|
auto const p0 = p;
|
||||||
|
auto const p1 = p0 + n;
|
||||||
|
ec = {};
|
||||||
|
loop:
|
||||||
|
switch(state_)
|
||||||
|
{
|
||||||
|
case state::nothing_yet:
|
||||||
|
if(n == 0)
|
||||||
|
{
|
||||||
|
ec = error::need_more;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
state_ = state::start_line;
|
||||||
|
BOOST_FALLTHROUGH;
|
||||||
|
|
||||||
|
case state::start_line:
|
||||||
|
{
|
||||||
|
maybe_need_more(p, n, ec);
|
||||||
|
if(ec)
|
||||||
|
goto done;
|
||||||
|
parse_start_line(p, p + (std::min<std::size_t>)(
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
BOOST_FALLTHROUGH;
|
||||||
|
}
|
||||||
|
|
||||||
|
case state::fields:
|
||||||
|
maybe_need_more(p, n, ec);
|
||||||
|
if(ec)
|
||||||
|
goto done;
|
||||||
|
parse_fields(p, p + (std::min<std::size_t>)(
|
||||||
|
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{});
|
||||||
|
break;
|
||||||
|
|
||||||
|
case state::body0:
|
||||||
|
BOOST_ASSERT(! skip_);
|
||||||
|
this->on_body_init_impl(content_length(), ec);
|
||||||
|
if(ec)
|
||||||
|
goto done;
|
||||||
|
state_ = state::body;
|
||||||
|
BOOST_FALLTHROUGH;
|
||||||
|
|
||||||
|
case state::body:
|
||||||
|
BOOST_ASSERT(! skip_);
|
||||||
|
parse_body(p, n, ec);
|
||||||
|
if(ec)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case state::body_to_eof0:
|
||||||
|
BOOST_ASSERT(! skip_);
|
||||||
|
this->on_body_init_impl(content_length(), ec);
|
||||||
|
if(ec)
|
||||||
|
goto done;
|
||||||
|
state_ = state::body_to_eof;
|
||||||
|
BOOST_FALLTHROUGH;
|
||||||
|
|
||||||
|
case state::body_to_eof:
|
||||||
|
BOOST_ASSERT(! skip_);
|
||||||
|
parse_body_to_eof(p, n, ec);
|
||||||
|
if(ec)
|
||||||
|
goto done;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case state::chunk_header0:
|
||||||
|
this->on_body_init_impl(content_length(), ec);
|
||||||
|
if(ec)
|
||||||
|
goto done;
|
||||||
|
state_ = state::chunk_header;
|
||||||
|
BOOST_FALLTHROUGH;
|
||||||
|
|
||||||
|
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:
|
||||||
|
ec = {};
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if(p < p1 && ! is_done() && eager())
|
||||||
|
{
|
||||||
|
n = static_cast<std::size_t>(p1 - p);
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
return static_cast<std::size_t>(p - p0);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
put_eof(error_code& ec)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(got_some());
|
||||||
|
if( state_ == state::start_line ||
|
||||||
|
state_ == state::fields)
|
||||||
|
{
|
||||||
|
ec = error::partial_message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(f_ & (flagContentLength | flagChunked))
|
||||||
|
{
|
||||||
|
if(state_ != state::complete)
|
||||||
|
{
|
||||||
|
ec = error::partial_message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ec = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ec = {};
|
||||||
|
this->on_finish_impl(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
state_ = state::complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
maybe_need_more(
|
||||||
|
char const* p, std::size_t n,
|
||||||
|
error_code& ec)
|
||||||
|
{
|
||||||
|
if(skip_ == 0)
|
||||||
|
return;
|
||||||
|
if( n > header_limit_)
|
||||||
|
n = header_limit_;
|
||||||
|
if(n < skip_ + 4)
|
||||||
|
{
|
||||||
|
ec = error::need_more;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto const term =
|
||||||
|
find_eom(p + skip_, p + n);
|
||||||
|
if(! term)
|
||||||
|
{
|
||||||
|
skip_ = n - 3;
|
||||||
|
if(skip_ + 4 > header_limit_)
|
||||||
|
{
|
||||||
|
ec = error::header_limit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ec = error::need_more;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
skip_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
parse_start_line(
|
||||||
|
char const*& in, char const* last,
|
||||||
|
error_code& ec, std::true_type)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
request-line = method SP request-target SP HTTP-version CRLF
|
||||||
|
method = token
|
||||||
|
*/
|
||||||
|
auto p = in;
|
||||||
|
|
||||||
|
string_view method;
|
||||||
|
parse_method(p, last, method, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
string_view target;
|
||||||
|
parse_target(p, last, target, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int version = 0;
|
||||||
|
parse_version(p, last, version, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(version < 10 || version > 11)
|
||||||
|
{
|
||||||
|
ec = error::bad_version;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p + 2 > last)
|
||||||
|
{
|
||||||
|
ec = error::need_more;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(p[0] != '\r' || p[1] != '\n')
|
||||||
|
{
|
||||||
|
ec = error::bad_version;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p += 2;
|
||||||
|
|
||||||
|
if(version >= 11)
|
||||||
|
f_ |= flagHTTP11;
|
||||||
|
|
||||||
|
this->on_request_impl(string_to_verb(method),
|
||||||
|
method, target, version, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
in = p;
|
||||||
|
state_ = state::fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
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;
|
||||||
|
|
||||||
|
int version = 0;
|
||||||
|
parse_version(p, last, version, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(version < 10 || version > 11)
|
||||||
|
{
|
||||||
|
ec = error::bad_version;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SP
|
||||||
|
if(p + 1 > last)
|
||||||
|
{
|
||||||
|
ec = error::need_more;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(*p++ != ' ')
|
||||||
|
{
|
||||||
|
ec = error::bad_version;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
parse_status(p, last, status_, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// parse reason CRLF
|
||||||
|
string_view reason;
|
||||||
|
parse_reason(p, last, reason, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(version >= 11)
|
||||||
|
f_ |= flagHTTP11;
|
||||||
|
|
||||||
|
this->on_response_impl(
|
||||||
|
status_, reason, version, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
|
||||||
|
in = p;
|
||||||
|
state_ = state::fields;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
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;
|
||||||
|
this->on_field_impl(f, name, value, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
in = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
finish_header(error_code& ec, std::true_type)
|
||||||
|
{
|
||||||
|
// RFC 7230 section 3.3
|
||||||
|
// https://tools.ietf.org/html/rfc7230#section-3.3
|
||||||
|
|
||||||
|
if(f_ & flagSkipBody)
|
||||||
|
{
|
||||||
|
state_ = state::complete;
|
||||||
|
}
|
||||||
|
else if(f_ & flagContentLength)
|
||||||
|
{
|
||||||
|
if(len_ > body_limit_)
|
||||||
|
{
|
||||||
|
ec = error::body_limit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec = {};
|
||||||
|
this->on_header_impl(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(state_ == state::complete)
|
||||||
|
{
|
||||||
|
this->on_finish_impl(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
finish_header(error_code& ec, std::false_type)
|
||||||
|
{
|
||||||
|
// RFC 7230 section 3.3
|
||||||
|
// https://tools.ietf.org/html/rfc7230#section-3.3
|
||||||
|
|
||||||
|
if( (f_ & flagSkipBody) || // e.g. response to a HEAD request
|
||||||
|
status_ / 100 == 1 || // 1xx e.g. Continue
|
||||||
|
status_ == 204 || // No Content
|
||||||
|
status_ == 304) // Not Modified
|
||||||
|
{
|
||||||
|
// VFALCO Content-Length may be present, but we
|
||||||
|
// treat the message as not having a body.
|
||||||
|
// https://github.com/boostorg/beast/issues/692
|
||||||
|
state_ = state::complete;
|
||||||
|
}
|
||||||
|
else if(f_ & flagContentLength)
|
||||||
|
{
|
||||||
|
if(len_ > body_limit_)
|
||||||
|
{
|
||||||
|
ec = error::body_limit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec = {};
|
||||||
|
this->on_header_impl(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(state_ == state::complete)
|
||||||
|
{
|
||||||
|
this->on_finish_impl(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
parse_body(char const*& p,
|
||||||
|
std::size_t n, error_code& ec)
|
||||||
|
{
|
||||||
|
ec = {};
|
||||||
|
n = this->on_body_impl(string_view{p,
|
||||||
|
beast::detail::clamp(len_, n)}, ec);
|
||||||
|
p += n;
|
||||||
|
len_ -= n;
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(len_ > 0)
|
||||||
|
return;
|
||||||
|
this->on_finish_impl(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
state_ = state::complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
parse_body_to_eof(char const*& p,
|
||||||
|
std::size_t n, error_code& ec)
|
||||||
|
{
|
||||||
|
if(n > body_limit_)
|
||||||
|
{
|
||||||
|
ec = error::body_limit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
body_limit_ = body_limit_ - n;
|
||||||
|
ec = {};
|
||||||
|
n = this->on_body_impl(string_view{p, n}, ec);
|
||||||
|
p += n;
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
parse_chunk_header(char const*& p0,
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
auto p = p0;
|
||||||
|
auto const pend = p + n;
|
||||||
|
char const* eol;
|
||||||
|
|
||||||
|
if(! (f_ & flagFinalChunk))
|
||||||
|
{
|
||||||
|
if(n < skip_ + 2)
|
||||||
|
{
|
||||||
|
ec = error::need_more;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(! eol)
|
||||||
|
{
|
||||||
|
ec = error::need_more;
|
||||||
|
skip_ = n - 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
skip_ = static_cast<
|
||||||
|
std::size_t>(eol - 2 - p0);
|
||||||
|
|
||||||
|
std::uint64_t size;
|
||||||
|
if(! parse_hex(p, size))
|
||||||
|
{
|
||||||
|
ec = error::bad_chunk;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(size != 0)
|
||||||
|
{
|
||||||
|
if(size > body_limit_)
|
||||||
|
{
|
||||||
|
ec = error::body_limit;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
body_limit_ -= size;
|
||||||
|
auto const start = p;
|
||||||
|
parse_chunk_extensions(p, pend, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(p != eol -2 )
|
||||||
|
{
|
||||||
|
ec = error::bad_chunk_extension;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto const ext = make_string(start, p);
|
||||||
|
this->on_chunk_header_impl(size, ext, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
len_ = size;
|
||||||
|
skip_ = 2;
|
||||||
|
p0 = eol;
|
||||||
|
f_ |= flagExpectCRLF;
|
||||||
|
state_ = state::chunk_body;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
f_ |= flagFinalChunk;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(n >= 5);
|
||||||
|
if(f_ & flagExpectCRLF)
|
||||||
|
BOOST_VERIFY(parse_crlf(p));
|
||||||
|
std::uint64_t size;
|
||||||
|
BOOST_VERIFY(parse_hex(p, size));
|
||||||
|
eol = find_eol(p, pend, ec);
|
||||||
|
BOOST_ASSERT(! ec);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto eom = find_eom(p0 + skip_, pend);
|
||||||
|
if(! eom)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(n >= 3);
|
||||||
|
skip_ = n - 3;
|
||||||
|
ec = error::need_more;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto const start = p;
|
||||||
|
parse_chunk_extensions(p, pend, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
if(p != eol - 2)
|
||||||
|
{
|
||||||
|
ec = error::bad_chunk_extension;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto const ext = make_string(start, p);
|
||||||
|
this->on_chunk_header_impl(0, ext, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
p = eol;
|
||||||
|
parse_fields(p, eom, ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
BOOST_ASSERT(p == eom);
|
||||||
|
p0 = eom;
|
||||||
|
|
||||||
|
this->on_finish_impl(ec);
|
||||||
|
if(ec)
|
||||||
|
return;
|
||||||
|
state_ = state::complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
parse_chunk_body(char const*& p,
|
||||||
|
std::size_t n, error_code& ec)
|
||||||
|
{
|
||||||
|
ec = {};
|
||||||
|
n = this->on_chunk_body_impl(
|
||||||
|
len_, string_view{p,
|
||||||
|
beast::detail::clamp(len_, n)}, ec);
|
||||||
|
p += n;
|
||||||
|
len_ -= n;
|
||||||
|
if(len_ == 0)
|
||||||
|
state_ = state::chunk_header;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<bool isRequest>
|
||||||
|
void
|
||||||
|
basic_parser<isRequest>::
|
||||||
|
do_field(field f,
|
||||||
|
string_view value, error_code& ec)
|
||||||
|
{
|
||||||
|
// Connection
|
||||||
|
if(f == field::connection ||
|
||||||
|
f == field::proxy_connection)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if(iequals({"close", 5}, s))
|
||||||
|
{
|
||||||
|
f_ |= flagConnectionClose;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iequals({"keep-alive", 10}, s))
|
||||||
|
{
|
||||||
|
f_ |= flagConnectionKeepAlive;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(iequals({"upgrade", 7}, s))
|
||||||
|
{
|
||||||
|
f_ |= flagConnectionUpgrade;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ec = {};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content-Length
|
||||||
|
if(f == field::content_length)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec = {};
|
||||||
|
len_ = v;
|
||||||
|
f_ |= flagContentLength;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer-Encoding
|
||||||
|
if(f == field::transfer_encoding)
|
||||||
|
{
|
||||||
|
if(f_ & flagChunked)
|
||||||
|
{
|
||||||
|
// duplicate
|
||||||
|
ec = error::bad_transfer_encoding;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(f_ & flagContentLength)
|
||||||
|
{
|
||||||
|
// conflicting field
|
||||||
|
ec = error::bad_transfer_encoding;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec = {};
|
||||||
|
auto const v = token_list{value};
|
||||||
|
auto const p = std::find_if(v.begin(), v.end(),
|
||||||
|
[&](typename token_list::value_type const& s)
|
||||||
|
{
|
||||||
|
return iequals({"chunked", 7}, s);
|
||||||
|
});
|
||||||
|
if(p == v.end())
|
||||||
|
return;
|
||||||
|
if(std::next(p) != v.end())
|
||||||
|
return;
|
||||||
|
len_ = 0;
|
||||||
|
f_ |= flagChunked;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upgrade
|
||||||
|
if(f == field::upgrade)
|
||||||
|
{
|
||||||
|
ec = {};
|
||||||
|
f_ |= flagUpgrade;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ec = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef BOOST_BEAST_SOURCE
|
||||||
|
template class http::basic_parser<true>;
|
||||||
|
template class http::basic_parser<false>;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // http
|
||||||
|
} // beast
|
||||||
|
} // boost
|
||||||
|
|
||||||
|
#endif
|
@@ -34,8 +34,4 @@ make_error_code(error ev);
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
|
||||||
#include <boost/beast/http/impl/error.ipp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -42,7 +42,7 @@ parser<isRequest, Body, Allocator>::
|
|||||||
parser(
|
parser(
|
||||||
parser<isRequest, OtherBody, Allocator>&& other,
|
parser<isRequest, OtherBody, Allocator>&& other,
|
||||||
Args&&... args)
|
Args&&... args)
|
||||||
: base_type(std::move(other))
|
: basic_parser<isRequest>(std::move(other))
|
||||||
, m_(other.release(), std::forward<Args>(args)...)
|
, m_(other.release(), std::forward<Args>(args)...)
|
||||||
, rd_(m_.base(), m_.body())
|
, rd_(m_.base(), m_.body())
|
||||||
{
|
{
|
||||||
|
@@ -30,12 +30,12 @@ std::size_t constexpr default_max_transfer_size = 65536;
|
|||||||
|
|
||||||
template<
|
template<
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived,
|
bool isRequest,
|
||||||
class Condition>
|
class Condition>
|
||||||
std::size_t
|
std::size_t
|
||||||
parse_until(
|
parse_until(
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec,
|
error_code& ec,
|
||||||
Condition cond)
|
Condition cond)
|
||||||
{
|
{
|
||||||
@@ -92,10 +92,10 @@ parse_until(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// predicate is true on any forward parser progress
|
// predicate is true on any forward parser progress
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest>
|
||||||
struct read_some_condition
|
struct read_some_condition
|
||||||
{
|
{
|
||||||
basic_parser<isRequest, Derived>& parser;
|
basic_parser<isRequest>& parser;
|
||||||
|
|
||||||
template<class DynamicBuffer>
|
template<class DynamicBuffer>
|
||||||
std::size_t
|
std::size_t
|
||||||
@@ -112,10 +112,10 @@ struct read_some_condition
|
|||||||
};
|
};
|
||||||
|
|
||||||
// predicate is true when parser header is complete
|
// predicate is true when parser header is complete
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest>
|
||||||
struct read_header_condition
|
struct read_header_condition
|
||||||
{
|
{
|
||||||
basic_parser<isRequest, Derived>& parser;
|
basic_parser<isRequest>& parser;
|
||||||
|
|
||||||
template<class DynamicBuffer>
|
template<class DynamicBuffer>
|
||||||
std::size_t
|
std::size_t
|
||||||
@@ -132,10 +132,10 @@ struct read_header_condition
|
|||||||
};
|
};
|
||||||
|
|
||||||
// predicate is true when parser message is complete
|
// predicate is true when parser message is complete
|
||||||
template<bool isRequest, class Derived>
|
template<bool isRequest>
|
||||||
struct read_all_condition
|
struct read_all_condition
|
||||||
{
|
{
|
||||||
basic_parser<isRequest, Derived>& parser;
|
basic_parser<isRequest>& parser;
|
||||||
|
|
||||||
template<class DynamicBuffer>
|
template<class DynamicBuffer>
|
||||||
std::size_t
|
std::size_t
|
||||||
@@ -256,12 +256,12 @@ struct run_read_msg_op
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_some(
|
read_some(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser)
|
basic_parser<isRequest>& parser)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
is_sync_read_stream<SyncReadStream>::value,
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
@@ -271,7 +271,7 @@ read_some(
|
|||||||
"DynamicBuffer type requirements not met");
|
"DynamicBuffer type requirements not met");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
read_some(stream, buffer, parser, ec);
|
http::read_some(stream, buffer, parser, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||||
return bytes_transferred;
|
return bytes_transferred;
|
||||||
@@ -280,12 +280,12 @@ read_some(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_some(
|
read_some(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -296,27 +296,27 @@ read_some(
|
|||||||
"DynamicBuffer type requirements not met");
|
"DynamicBuffer type requirements not met");
|
||||||
return beast::detail::read(stream, buffer,
|
return beast::detail::read(stream, buffer,
|
||||||
detail::read_some_condition<
|
detail::read_some_condition<
|
||||||
isRequest, Derived>{parser}, ec);
|
isRequest>{parser}, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
class AsyncReadStream,
|
class AsyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived,
|
bool isRequest,
|
||||||
class ReadHandler>
|
class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
ReadHandler, void(error_code, std::size_t))
|
ReadHandler, void(error_code, std::size_t))
|
||||||
async_read_some(
|
async_read_some(
|
||||||
AsyncReadStream& stream,
|
AsyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
return beast::detail::async_read(
|
return beast::detail::async_read(
|
||||||
stream,
|
stream,
|
||||||
buffer,
|
buffer,
|
||||||
detail::read_some_condition<
|
detail::read_some_condition<
|
||||||
isRequest, Derived>{parser},
|
isRequest>{parser},
|
||||||
std::forward<ReadHandler>(handler));
|
std::forward<ReadHandler>(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -325,12 +325,12 @@ async_read_some(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_header(
|
read_header(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser)
|
basic_parser<isRequest>& parser)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
is_sync_read_stream<SyncReadStream>::value,
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
@@ -340,7 +340,7 @@ read_header(
|
|||||||
"DynamicBuffer type requirements not met");
|
"DynamicBuffer type requirements not met");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
read_header(stream, buffer, parser, ec);
|
http::read_header(stream, buffer, parser, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||||
return bytes_transferred;
|
return bytes_transferred;
|
||||||
@@ -349,12 +349,12 @@ read_header(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_header(
|
read_header(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -366,20 +366,20 @@ read_header(
|
|||||||
parser.eager(false);
|
parser.eager(false);
|
||||||
return beast::detail::read(stream, buffer,
|
return beast::detail::read(stream, buffer,
|
||||||
detail::read_header_condition<
|
detail::read_header_condition<
|
||||||
isRequest, Derived>{parser}, ec);
|
isRequest>{parser}, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
class AsyncReadStream,
|
class AsyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived,
|
bool isRequest,
|
||||||
class ReadHandler>
|
class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
ReadHandler, void(error_code, std::size_t))
|
ReadHandler, void(error_code, std::size_t))
|
||||||
async_read_header(
|
async_read_header(
|
||||||
AsyncReadStream& stream,
|
AsyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
parser.eager(false);
|
parser.eager(false);
|
||||||
@@ -387,7 +387,7 @@ async_read_header(
|
|||||||
stream,
|
stream,
|
||||||
buffer,
|
buffer,
|
||||||
detail::read_header_condition<
|
detail::read_header_condition<
|
||||||
isRequest, Derived>{parser},
|
isRequest>{parser},
|
||||||
std::forward<ReadHandler>(handler));
|
std::forward<ReadHandler>(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,12 +396,12 @@ async_read_header(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read(
|
read(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser)
|
basic_parser<isRequest>& parser)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
is_sync_read_stream<SyncReadStream>::value,
|
is_sync_read_stream<SyncReadStream>::value,
|
||||||
@@ -411,7 +411,7 @@ read(
|
|||||||
"DynamicBuffer type requirements not met");
|
"DynamicBuffer type requirements not met");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
read(stream, buffer, parser, ec);
|
http::read(stream, buffer, parser, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||||
return bytes_transferred;
|
return bytes_transferred;
|
||||||
@@ -420,12 +420,12 @@ read(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read(
|
read(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -437,20 +437,20 @@ read(
|
|||||||
parser.eager(true);
|
parser.eager(true);
|
||||||
return beast::detail::read(stream, buffer,
|
return beast::detail::read(stream, buffer,
|
||||||
detail::read_all_condition<
|
detail::read_all_condition<
|
||||||
isRequest, Derived>{parser}, ec);
|
isRequest>{parser}, ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<
|
template<
|
||||||
class AsyncReadStream,
|
class AsyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived,
|
bool isRequest,
|
||||||
class ReadHandler>
|
class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
ReadHandler, void(error_code, std::size_t))
|
ReadHandler, void(error_code, std::size_t))
|
||||||
async_read(
|
async_read(
|
||||||
AsyncReadStream& stream,
|
AsyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
ReadHandler&& handler)
|
ReadHandler&& handler)
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
@@ -464,7 +464,7 @@ async_read(
|
|||||||
stream,
|
stream,
|
||||||
buffer,
|
buffer,
|
||||||
detail::read_all_condition<
|
detail::read_all_condition<
|
||||||
isRequest, Derived>{parser},
|
isRequest>{parser},
|
||||||
std::forward<ReadHandler>(handler));
|
std::forward<ReadHandler>(handler));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +492,7 @@ read(
|
|||||||
"BodyReader type requirements not met");
|
"BodyReader type requirements not met");
|
||||||
error_code ec;
|
error_code ec;
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
read(stream, buffer, msg, ec);
|
http::read(stream, buffer, msg, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
BOOST_THROW_EXCEPTION(system_error{ec});
|
BOOST_THROW_EXCEPTION(system_error{ec});
|
||||||
return bytes_transferred;
|
return bytes_transferred;
|
||||||
@@ -522,7 +522,7 @@ read(
|
|||||||
parser<isRequest, Body, Allocator> p(std::move(msg));
|
parser<isRequest, Body, Allocator> p(std::move(msg));
|
||||||
p.eager(true);
|
p.eager(true);
|
||||||
auto const bytes_transferred =
|
auto const bytes_transferred =
|
||||||
read(stream, buffer, p.base(), ec);
|
http::read(stream, buffer, p, ec);
|
||||||
if(ec)
|
if(ec)
|
||||||
return bytes_transferred;
|
return bytes_transferred;
|
||||||
msg = p.release();
|
msg = p.release();
|
||||||
|
@@ -47,8 +47,7 @@ template<
|
|||||||
class Body,
|
class Body,
|
||||||
class Allocator = std::allocator<char>>
|
class Allocator = std::allocator<char>>
|
||||||
class parser
|
class parser
|
||||||
: public basic_parser<isRequest,
|
: public basic_parser<isRequest>
|
||||||
parser<isRequest, Body, Allocator>>
|
|
||||||
{
|
{
|
||||||
static_assert(is_body<Body>::value,
|
static_assert(is_body<Body>::value,
|
||||||
"Body type requirements not met");
|
"Body type requirements not met");
|
||||||
@@ -59,9 +58,6 @@ class parser
|
|||||||
template<bool, class, class>
|
template<bool, class, class>
|
||||||
friend class parser;
|
friend class parser;
|
||||||
|
|
||||||
using base_type = basic_parser<isRequest,
|
|
||||||
parser<isRequest, Body, Allocator>>;
|
|
||||||
|
|
||||||
message<isRequest, Body, basic_fields<Allocator>> m_;
|
message<isRequest, Body, basic_fields<Allocator>> m_;
|
||||||
typename Body::reader rd_;
|
typename Body::reader rd_;
|
||||||
bool rd_inited_ = false;
|
bool rd_inited_ = false;
|
||||||
@@ -297,8 +293,6 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class basic_parser<isRequest, parser>;
|
|
||||||
|
|
||||||
parser(std::true_type);
|
parser(std::true_type);
|
||||||
parser(std::false_type);
|
parser(std::false_type);
|
||||||
|
|
||||||
@@ -338,7 +332,8 @@ private:
|
|||||||
string_view method_str,
|
string_view method_str,
|
||||||
string_view target,
|
string_view target,
|
||||||
int version,
|
int version,
|
||||||
error_code& ec)
|
error_code& ec,
|
||||||
|
std::true_type)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -347,7 +342,6 @@ private:
|
|||||||
m_.method(method);
|
m_.method(method);
|
||||||
else
|
else
|
||||||
m_.method_string(method_str);
|
m_.method_string(method_str);
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
catch(std::bad_alloc const&)
|
catch(std::bad_alloc const&)
|
||||||
{
|
{
|
||||||
@@ -356,19 +350,39 @@ private:
|
|||||||
m_.version(version);
|
m_.version(version);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_request_impl(
|
||||||
|
verb, string_view, string_view,
|
||||||
|
int, error_code&, std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_request_impl(
|
||||||
|
verb method,
|
||||||
|
string_view method_str,
|
||||||
|
string_view target,
|
||||||
|
int version,
|
||||||
|
error_code& ec) override
|
||||||
|
{
|
||||||
|
this->on_request_impl(
|
||||||
|
method, method_str, target, version, ec,
|
||||||
|
std::integral_constant<bool, isRequest>{});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_response_impl(
|
on_response_impl(
|
||||||
int code,
|
int code,
|
||||||
string_view reason,
|
string_view reason,
|
||||||
int version,
|
int version,
|
||||||
error_code& ec)
|
error_code& ec,
|
||||||
|
std::true_type)
|
||||||
{
|
{
|
||||||
m_.result(code);
|
m_.result(code);
|
||||||
m_.version(version);
|
m_.version(version);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_.reason(reason);
|
m_.reason(reason);
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
catch(std::bad_alloc const&)
|
catch(std::bad_alloc const&)
|
||||||
{
|
{
|
||||||
@@ -376,17 +390,35 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_response_impl(
|
||||||
|
int, string_view, int,
|
||||||
|
error_code&, std::false_type)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_response_impl(
|
||||||
|
int code,
|
||||||
|
string_view reason,
|
||||||
|
int version,
|
||||||
|
error_code& ec) override
|
||||||
|
{
|
||||||
|
this->on_response_impl(
|
||||||
|
code, reason, version, ec,
|
||||||
|
std::integral_constant<bool, ! isRequest>{});
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_field_impl(
|
on_field_impl(
|
||||||
field name,
|
field name,
|
||||||
string_view name_string,
|
string_view name_string,
|
||||||
string_view value,
|
string_view value,
|
||||||
error_code& ec)
|
error_code& ec) override
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_.insert(name, name_string, value);
|
m_.insert(name, name_string, value);
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
catch(std::bad_alloc const&)
|
catch(std::bad_alloc const&)
|
||||||
{
|
{
|
||||||
@@ -395,7 +427,7 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_header_impl(error_code& ec)
|
on_header_impl(error_code& ec) override
|
||||||
{
|
{
|
||||||
ec = {};
|
ec = {};
|
||||||
}
|
}
|
||||||
@@ -403,7 +435,7 @@ private:
|
|||||||
void
|
void
|
||||||
on_body_init_impl(
|
on_body_init_impl(
|
||||||
boost::optional<std::uint64_t> const& content_length,
|
boost::optional<std::uint64_t> const& content_length,
|
||||||
error_code& ec)
|
error_code& ec) override
|
||||||
{
|
{
|
||||||
rd_.init(content_length, ec);
|
rd_.init(content_length, ec);
|
||||||
rd_inited_ = true;
|
rd_inited_ = true;
|
||||||
@@ -412,7 +444,7 @@ private:
|
|||||||
std::size_t
|
std::size_t
|
||||||
on_body_impl(
|
on_body_impl(
|
||||||
string_view body,
|
string_view body,
|
||||||
error_code& ec)
|
error_code& ec) override
|
||||||
{
|
{
|
||||||
return rd_.put(net::buffer(
|
return rd_.put(net::buffer(
|
||||||
body.data(), body.size()), ec);
|
body.data(), body.size()), ec);
|
||||||
@@ -422,18 +454,17 @@ private:
|
|||||||
on_chunk_header_impl(
|
on_chunk_header_impl(
|
||||||
std::uint64_t size,
|
std::uint64_t size,
|
||||||
string_view extensions,
|
string_view extensions,
|
||||||
error_code& ec)
|
error_code& ec) override
|
||||||
{
|
{
|
||||||
if(cb_h_)
|
if(cb_h_)
|
||||||
return cb_h_(size, extensions, ec);
|
return cb_h_(size, extensions, ec);
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
on_chunk_body_impl(
|
on_chunk_body_impl(
|
||||||
std::uint64_t remain,
|
std::uint64_t remain,
|
||||||
string_view body,
|
string_view body,
|
||||||
error_code& ec)
|
error_code& ec) override
|
||||||
{
|
{
|
||||||
if(cb_b_)
|
if(cb_b_)
|
||||||
return cb_b_(remain, body, ec);
|
return cb_b_(remain, body, ec);
|
||||||
@@ -442,7 +473,8 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_finish_impl(error_code& ec)
|
on_finish_impl(
|
||||||
|
error_code& ec) override
|
||||||
{
|
{
|
||||||
rd_.finish(ec);
|
rd_.finish(ec);
|
||||||
}
|
}
|
||||||
|
@@ -72,12 +72,12 @@ namespace http {
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_some(
|
read_some(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser);
|
basic_parser<isRequest>& parser);
|
||||||
|
|
||||||
/** Read part of a message from a stream using a parser.
|
/** Read part of a message from a stream using a parser.
|
||||||
|
|
||||||
@@ -129,12 +129,12 @@ read_some(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_some(
|
read_some(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec);
|
error_code& ec);
|
||||||
|
|
||||||
/** Read part of a message asynchronously from a stream using a parser.
|
/** Read part of a message asynchronously from a stream using a parser.
|
||||||
@@ -205,14 +205,14 @@ read_some(
|
|||||||
template<
|
template<
|
||||||
class AsyncReadStream,
|
class AsyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived,
|
bool isRequest,
|
||||||
class ReadHandler>
|
class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
ReadHandler, void(error_code, std::size_t))
|
ReadHandler, void(error_code, std::size_t))
|
||||||
async_read_some(
|
async_read_some(
|
||||||
AsyncReadStream& stream,
|
AsyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
ReadHandler&& handler);
|
ReadHandler&& handler);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -267,12 +267,12 @@ async_read_some(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_header(
|
read_header(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser);
|
basic_parser<isRequest>& parser);
|
||||||
|
|
||||||
/** Read a complete message header from a stream using a parser.
|
/** Read a complete message header from a stream using a parser.
|
||||||
|
|
||||||
@@ -324,12 +324,12 @@ read_header(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read_header(
|
read_header(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec);
|
error_code& ec);
|
||||||
|
|
||||||
/** Read a complete message header asynchronously from a stream using a parser.
|
/** Read a complete message header asynchronously from a stream using a parser.
|
||||||
@@ -401,14 +401,14 @@ read_header(
|
|||||||
template<
|
template<
|
||||||
class AsyncReadStream,
|
class AsyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived,
|
bool isRequest,
|
||||||
class ReadHandler>
|
class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
ReadHandler, void(error_code, std::size_t))
|
ReadHandler, void(error_code, std::size_t))
|
||||||
async_read_header(
|
async_read_header(
|
||||||
AsyncReadStream& stream,
|
AsyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
ReadHandler&& handler);
|
ReadHandler&& handler);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
@@ -463,12 +463,12 @@ async_read_header(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read(
|
read(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser);
|
basic_parser<isRequest>& parser);
|
||||||
|
|
||||||
/** Read a complete message from a stream using a parser.
|
/** Read a complete message from a stream using a parser.
|
||||||
|
|
||||||
@@ -520,12 +520,12 @@ read(
|
|||||||
template<
|
template<
|
||||||
class SyncReadStream,
|
class SyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
read(
|
read(
|
||||||
SyncReadStream& stream,
|
SyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec);
|
error_code& ec);
|
||||||
|
|
||||||
/** Read a complete message asynchronously from a stream using a parser.
|
/** Read a complete message asynchronously from a stream using a parser.
|
||||||
@@ -597,14 +597,14 @@ read(
|
|||||||
template<
|
template<
|
||||||
class AsyncReadStream,
|
class AsyncReadStream,
|
||||||
class DynamicBuffer,
|
class DynamicBuffer,
|
||||||
bool isRequest, class Derived,
|
bool isRequest,
|
||||||
class ReadHandler>
|
class ReadHandler>
|
||||||
BOOST_ASIO_INITFN_RESULT_TYPE(
|
BOOST_ASIO_INITFN_RESULT_TYPE(
|
||||||
ReadHandler, void(error_code, std::size_t))
|
ReadHandler, void(error_code, std::size_t))
|
||||||
async_read(
|
async_read(
|
||||||
AsyncReadStream& stream,
|
AsyncReadStream& stream,
|
||||||
DynamicBuffer& buffer,
|
DynamicBuffer& buffer,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
ReadHandler&& handler);
|
ReadHandler&& handler);
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@@ -26,6 +26,7 @@ the program, with the macro BOOST_BEAST_SPLIT_COMPILATION defined.
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/beast/_experimental/test/impl/error.ipp>
|
#include <boost/beast/_experimental/test/impl/error.ipp>
|
||||||
|
#include <boost/beast/_experimental/test/impl/fail_count.ipp>
|
||||||
#include <boost/beast/_experimental/test/impl/stream.ipp>
|
#include <boost/beast/_experimental/test/impl/stream.ipp>
|
||||||
|
|
||||||
#include <boost/beast/core/detail/base64.ipp>
|
#include <boost/beast/core/detail/base64.ipp>
|
||||||
@@ -38,6 +39,7 @@ the program, with the macro BOOST_BEAST_SPLIT_COMPILATION defined.
|
|||||||
#include <boost/beast/core/impl/saved_handler.ipp>
|
#include <boost/beast/core/impl/saved_handler.ipp>
|
||||||
#include <boost/beast/core/impl/static_buffer.ipp>
|
#include <boost/beast/core/impl/static_buffer.ipp>
|
||||||
|
|
||||||
|
#include <boost/beast/http/impl/basic_parser.ipp>
|
||||||
#include <boost/beast/http/impl/error.ipp>
|
#include <boost/beast/http/impl/error.ipp>
|
||||||
#include <boost/beast/http/impl/field.ipp>
|
#include <boost/beast/http/impl/field.ipp>
|
||||||
#include <boost/beast/http/impl/status.ipp>
|
#include <boost/beast/http/impl/status.ipp>
|
||||||
|
@@ -249,5 +249,8 @@ enum class condition
|
|||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/websocket/impl/error.hpp>
|
#include <boost/beast/websocket/impl/error.hpp>
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/websocket/impl/error.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -41,8 +41,4 @@ make_error_condition(condition c);
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
|
||||||
#include <boost/beast/websocket/impl/error.ipp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -133,6 +133,9 @@ enum class error
|
|||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#include <boost/beast/zlib/impl/error.hpp>
|
#include <boost/beast/zlib/impl/error.hpp>
|
||||||
|
#ifdef BOOST_BEAST_HEADER_ONLY
|
||||||
|
#include <boost/beast/zlib/impl/error.ipp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@@ -60,8 +60,4 @@ make_error_code(error ev);
|
|||||||
} // beast
|
} // beast
|
||||||
} // boost
|
} // boost
|
||||||
|
|
||||||
#ifdef BOOST_BEAST_HEADER_ONLY
|
|
||||||
#include <boost/beast/zlib/impl/error.ipp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@@ -894,10 +894,10 @@ public:
|
|||||||
return {s.data(), s.size()};
|
return {s.data(), s.size()};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ConstBufferSequence, bool isRequest, class Derived>
|
template<class ConstBufferSequence, bool isRequest>
|
||||||
std::size_t
|
std::size_t
|
||||||
feed(ConstBufferSequence const& buffers,
|
feed(ConstBufferSequence const& buffers,
|
||||||
basic_parser<isRequest, Derived>& p, error_code& ec)
|
basic_parser<isRequest>& p, error_code& ec)
|
||||||
{
|
{
|
||||||
p.eager(true);
|
p.eager(true);
|
||||||
return p.put(buffers, ec);
|
return p.put(buffers, ec);
|
||||||
|
@@ -45,11 +45,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class ConstBufferSequence,
|
template<class ConstBufferSequence,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
put(ConstBufferSequence const& buffers,
|
put(ConstBufferSequence const& buffers,
|
||||||
basic_parser<isRequest, Derived>& p,
|
basic_parser<isRequest>& p,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
buffers_suffix<ConstBufferSequence> cb{buffers};
|
buffers_suffix<ConstBufferSequence> cb{buffers};
|
||||||
|
@@ -21,7 +21,7 @@ namespace http {
|
|||||||
|
|
||||||
template<bool isRequest>
|
template<bool isRequest>
|
||||||
class test_parser
|
class test_parser
|
||||||
: public basic_parser<isRequest, test_parser<isRequest>>
|
: public basic_parser<isRequest>
|
||||||
{
|
{
|
||||||
test::fail_count* fc_ = nullptr;
|
test::fail_count* fc_ = nullptr;
|
||||||
|
|
||||||
@@ -65,8 +65,6 @@ public:
|
|||||||
++got_on_begin;
|
++got_on_begin;
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -81,8 +79,6 @@ public:
|
|||||||
++got_on_begin;
|
++got_on_begin;
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -92,8 +88,6 @@ public:
|
|||||||
++got_on_field;
|
++got_on_field;
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
fields[std::string(name)] = std::string(value);
|
fields[std::string(name)] = std::string(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,8 +97,6 @@ public:
|
|||||||
++got_on_header;
|
++got_on_header;
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -117,8 +109,6 @@ public:
|
|||||||
static_cast<bool>(content_length_);
|
static_cast<bool>(content_length_);
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
@@ -128,8 +118,6 @@ public:
|
|||||||
body.append(s.data(), s.size());
|
body.append(s.data(), s.size());
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
return s.size();
|
return s.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,8 +130,6 @@ public:
|
|||||||
++got_on_chunk;
|
++got_on_chunk;
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
@@ -155,8 +141,6 @@ public:
|
|||||||
body.append(s.data(), s.size());
|
body.append(s.data(), s.size());
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
return s.size();
|
return s.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,8 +151,6 @@ public:
|
|||||||
++got_on_complete;
|
++got_on_complete;
|
||||||
if(fc_)
|
if(fc_)
|
||||||
fc_->fail(ec);
|
fc_->fail(ec);
|
||||||
else
|
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -70,11 +70,11 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class ConstBufferSequence,
|
template<class ConstBufferSequence,
|
||||||
bool isRequest, class Derived>
|
bool isRequest>
|
||||||
static
|
static
|
||||||
std::size_t
|
std::size_t
|
||||||
feed(ConstBufferSequence const& buffers,
|
feed(ConstBufferSequence const& buffers,
|
||||||
basic_parser<isRequest, Derived>& parser,
|
basic_parser<isRequest>& parser,
|
||||||
error_code& ec)
|
error_code& ec)
|
||||||
{
|
{
|
||||||
beast::buffers_suffix<
|
beast::buffers_suffix<
|
||||||
@@ -149,79 +149,131 @@ public:
|
|||||||
|
|
||||||
template<bool isRequest>
|
template<bool isRequest>
|
||||||
struct null_parser :
|
struct null_parser :
|
||||||
basic_parser<isRequest, null_parser<isRequest>>
|
basic_parser<isRequest>
|
||||||
{
|
{
|
||||||
|
void
|
||||||
|
on_request_impl(
|
||||||
|
verb, string_view, string_view,
|
||||||
|
int, error_code&) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_response_impl(
|
||||||
|
int, string_view, int,
|
||||||
|
error_code&) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_field_impl(
|
||||||
|
field, string_view, string_view,
|
||||||
|
error_code&) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_header_impl(error_code&) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_body_init_impl(
|
||||||
|
boost::optional<std::uint64_t> const&,
|
||||||
|
error_code&) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
on_body_impl(
|
||||||
|
string_view,
|
||||||
|
error_code&) override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_chunk_header_impl(
|
||||||
|
std::uint64_t,
|
||||||
|
string_view,
|
||||||
|
error_code&) override
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t
|
||||||
|
on_chunk_body_impl(
|
||||||
|
std::uint64_t,
|
||||||
|
string_view,
|
||||||
|
error_code&) override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
on_finish_impl(error_code& ec) override
|
||||||
|
{
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<bool isRequest, class Body, class Fields>
|
template<bool isRequest, class Body, class Fields>
|
||||||
struct bench_parser : basic_parser<
|
struct bench_parser : basic_parser<isRequest>
|
||||||
isRequest, bench_parser<isRequest, Body, Fields>>
|
|
||||||
{
|
{
|
||||||
using mutable_buffers_type =
|
using mutable_buffers_type =
|
||||||
net::mutable_buffer;
|
net::mutable_buffer;
|
||||||
|
|
||||||
void
|
void
|
||||||
on_request_impl(verb, string_view,
|
on_request_impl(verb, string_view,
|
||||||
string_view, int, error_code& ec)
|
string_view, int, error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_response_impl(int,
|
on_response_impl(int,
|
||||||
string_view,
|
string_view, int, error_code&) override
|
||||||
int, error_code& ec)
|
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_field_impl(field,
|
on_field_impl(field,
|
||||||
string_view, string_view, error_code& ec)
|
string_view, string_view, error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_header_impl(error_code& ec)
|
on_header_impl(error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_body_init_impl(
|
on_body_init_impl(
|
||||||
boost::optional<std::uint64_t> const&,
|
boost::optional<std::uint64_t> const&,
|
||||||
error_code& ec)
|
error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
on_body_impl(string_view s, error_code& ec)
|
on_body_impl(
|
||||||
|
string_view s, error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
return s.size();
|
return s.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_chunk_header_impl(std::uint64_t,
|
on_chunk_header_impl(std::uint64_t,
|
||||||
string_view, error_code& ec)
|
string_view, error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t
|
std::size_t
|
||||||
on_chunk_body_impl(std::uint64_t,
|
on_chunk_body_impl(std::uint64_t,
|
||||||
string_view s, error_code& ec)
|
string_view s, error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
return s.size();
|
return s.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
on_finish_impl(error_code& ec)
|
on_finish_impl(error_code&) override
|
||||||
{
|
{
|
||||||
ec = {};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user