diff --git a/CHANGELOG.md b/CHANGELOG.md index 99c1fa9d..cc0f1698 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Version 50 * parser is constructible from other body types +API Changes: + +* Remove header_parser + -------------------------------------------------------------------------------- Version 49 diff --git a/doc/0_main.qbk b/doc/0_main.qbk index da53d3c6..afa936fa 100644 --- a/doc/0_main.qbk +++ b/doc/0_main.qbk @@ -63,7 +63,6 @@ [def __fields__ [link beast.ref.http__fields `fields`]] [def __flat_buffer__ [link beast.ref.flat_buffer `flat_buffer`]] [def __header__ [link beast.ref.http__header `header`]] -[def __header_parser__ [link beast.ref.http__header_parser `header_parser`]] [def __message__ [link beast.ref.http__message `message`]] [def __multi_buffer__ [link beast.ref.multi_buffer `multi_buffer`]] [def __parser__ [link beast.ref.http__parser `parser`]] diff --git a/doc/4_05_parser_streams.qbk b/doc/4_05_parser_streams.qbk index ec698922..a9123535 100644 --- a/doc/4_05_parser_streams.qbk +++ b/doc/4_05_parser_streams.qbk @@ -38,18 +38,6 @@ defined types deriving from the basic parser are possible: : public basic_parser<...>; ``` ]] -[[ - __header_parser__ -][ - ``` - /// An HTTP/1 parser for producing a header. - template< - bool isRequest, // `true` to parse an HTTP request - class Fields> // The type of container representing the fields - class header_parser - : public basic_parser<...>; - ``` -]] [[ [link beast.ref.http__request_parser `request_parser`] ][ diff --git a/doc/4_07_parser_buffers.qbk b/doc/4_07_parser_buffers.qbk index 2e38f06c..3e07e02e 100644 --- a/doc/4_07_parser_buffers.qbk +++ b/doc/4_07_parser_buffers.qbk @@ -7,11 +7,11 @@ [section:parser_buffers Buffer-Oriented Parsing] -In extreme cases, users may wish to create an instance of __parser__, -__header_parser__, or a user-defined type derived from __basic_parser__ and -invoke its methods directly instead of using the provided stream algorithms. -This could be useful for implementing algorithms on streams whose interface -does not conform to any __Stream__. For example, a +In some cases, users may wish to create an instance of __parser__, or a +user-defined type derived from __basic_parser__ and invoke its methods +directly instead of using the provided stream algorithms. This could be +useful for implementing algorithms on streams whose interface does not +conform to any __Stream__. For example, a [@http://zeromq.org/ *ZeroMQ* socket]. The basic parser interface is interactive; the caller invokes the function [link beast.ref.http__basic_parser.put `basic_parser::put`] diff --git a/doc/quickref.xml b/doc/quickref.xml index b9530ef6..339413c6 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -37,7 +37,6 @@ empty_body fields header - header_parser message parser no_chunk_decorator diff --git a/include/beast/http/detail/type_traits.hpp b/include/beast/http/detail/type_traits.hpp index d27f6fbc..6c9b62cc 100644 --- a/include/beast/http/detail/type_traits.hpp +++ b/include/beast/http/detail/type_traits.hpp @@ -19,6 +19,9 @@ struct header; template struct message; +template +class parser; + namespace detail { template @@ -35,6 +38,12 @@ public: template using is_header = typename is_header_impl::type; +template +struct is_parser : std::false_type {}; + +template +struct is_parser> : std::true_type {}; + struct fields_model { string_view method() const; diff --git a/include/beast/http/impl/parser.ipp b/include/beast/http/impl/parser.ipp index 9124edd4..90f4abbc 100644 --- a/include/beast/http/impl/parser.ipp +++ b/include/beast/http/impl/parser.ipp @@ -14,15 +14,6 @@ namespace beast { namespace http { -template -template -header_parser:: -header_parser(Arg0&& arg0, ArgN&&... argn) - : h_(std::forward(arg0), - std::forward(argn)...) -{ -} - template template parser:: @@ -33,7 +24,7 @@ parser(Arg1&& arg1, ArgN&&... argn) } template -template +template parser:: parser(parser&& parser, Args&&... args) @@ -46,17 +37,6 @@ parser(parser&& parser, "moved-from parser has a body"}); } -template -template -parser:: -parser(header_parser< - isRequest, Fields>&& parser, Args&&... args) - : base_type(std::move(static_cast>&>(parser))) - , m_(parser.release(), std::forward(args)...) -{ -} - } // http } // beast diff --git a/include/beast/http/parser.hpp b/include/beast/http/parser.hpp index 3adab28f..0271eff8 100644 --- a/include/beast/http/parser.hpp +++ b/include/beast/http/parser.hpp @@ -20,199 +20,6 @@ namespace beast { namespace http { -/** An HTTP/1 parser for producing a header. - - This class uses the basic HTTP/1 wire format parser to convert - a series of octets into a @ref header. - - @note A new instance of the parser is required for each message. - - @tparam isRequest Indicates whether a request or response - will be parsed. - - @tparam Fields The type of container used to represent the fields. -*/ -template -class header_parser - : public basic_parser> -{ - header h_; - string_view body_; - -public: - /// The type of @ref header this object produces. - using value_type = header; - - /// Default constructor. - header_parser() = default; - - /// Copy constructor. - header_parser(header_parser const&) = default; - - /// Copy assignment. - header_parser& operator=(header_parser const&) = default; - - /** Move constructor. - - After the move, the only valid operation - on the moved-from object is destruction. - */ - header_parser(header_parser&&) = default; - - /** Move assignment - - After the move, the only valid operation - on the moved-from object is destruction. - */ - header_parser& operator=(header_parser&&) = default; - - /** Constructor - - @param args Optional arguments forwarded - forwarded to the @ref http::header constructor. - */ -#if BEAST_DOXYGEN - template - explicit - header_parser(Args&&... args); -#else - template::type, - header_parser>::value>> - explicit - header_parser(Arg0&& arg0, ArgN&&... argn); -#endif - - /** Returns parsed body octets. - - This function will return the most recent buffer - of octets corresponding to the parsed body. This - buffer will become invalidated on any subsequent - call to @ref put or @ref put_eof - */ - string_view - body() const - { - return body_; - } - - /** Returns the parsed header - - @note The return value is undefined unless - @ref is_header_done would return `true`. - */ - value_type const& - get() const - { - return h_; - } - - /** Returns the parsed header. - - @note The return value is undefined unless - @ref is_header_done would return `true`. - */ - value_type& - get() - { - return h_; - } - - /** Returns ownership of the parsed header. - - Ownership is transferred to the caller. - - @note The return value is undefined unless - @ref is_header_done would return `true`. - - Requires: - @ref value_type is @b MoveConstructible - */ - value_type - release() - { - static_assert( - std::is_move_constructible::value, - "MoveConstructible requirements not met"); - return std::move(h_); - } - -private: - friend class basic_parser; - - void - on_request(string_view method, - string_view path, int version, error_code&) - { - h_.target(path); - h_.method(method); - h_.version = version; - } - - void - on_response(int code, string_view reason, - int version, error_code&) - { - h_.result(code); - h_.version = version; - h_.reason(reason); - } - - void - on_field(string_view name, - string_view value, error_code&) - { - h_.fields.insert(name, value); - } - - void - on_header(error_code&) - { - } - - void - on_body(boost::optional const&, error_code&) - { - } - - void - on_data(string_view s, error_code&) - { - body_ = s; - } - - void - on_chunk(std::uint64_t, - string_view, error_code&) - { - body_ = {}; - } - - void - on_complete(error_code&) - { - body_ = {}; - } -}; - -template< - bool isRequest,class Body, class Fields = fields> -class parser; - -namespace detail { - -template -struct is_parser : std::false_type {}; - -template -struct is_parser> : std::true_type {}; - -} // detail - /** An HTTP/1 parser for producing a message. This class uses the basic HTTP/1 wire format parser to convert @@ -227,7 +34,10 @@ struct is_parser> : std::true_type {}; @note A new instance of the parser is required for each message. */ -template +template< + bool isRequest, + class Body, + class Fields = fields> class parser : public basic_parser> @@ -265,7 +75,7 @@ public: After the move, the only valid operation on the moved-from object is destruction. */ - parser(parser&& other); + parser(parser&& other) = default; /** Constructor @@ -320,22 +130,14 @@ public: #if BEAST_DOXYGEN template #else - template + template::value>::type> #endif explicit parser(parser&& parser, Args&&... args); - /** Construct a parser from a @ref header_parser. - @param parser The header parser to construct from. - @param args Optional arguments forwarded to the message - constructor. - */ - template - explicit - parser(header_parser< - isRequest, Fields>&& parser, Args&&... args); - /** Returns the parsed message. Depending on the progress of the parser, portions diff --git a/include/beast/websocket/impl/accept.ipp b/include/beast/websocket/impl/accept.ipp index 944e7725..901b16ce 100644 --- a/include/beast/websocket/impl/accept.ipp +++ b/include/beast/websocket/impl/accept.ipp @@ -173,19 +173,15 @@ class stream::accept_op { struct data { - bool cont; stream& ws; Decorator decorator; - http::header_parser p; - int state = 0; + http::request_parser p; data(Handler& handler, stream& ws_, Decorator const& decorator_) : ws(ws_) , decorator(decorator_) { - using boost::asio::asio_handler_is_continuation; - cont = asio_handler_is_continuation(std::addressof(handler)); } template @@ -195,8 +191,6 @@ class stream::accept_op : ws(ws_) , decorator(decorator_) { - using boost::asio::asio_handler_is_continuation; - cont = asio_handler_is_continuation(std::addressof(handler)); using boost::asio::buffer_copy; using boost::asio::buffer_size; // VFALCO What about catch(std::length_error const&)? @@ -218,11 +212,11 @@ public: : d_(std::forward(h), ws, std::forward(args)...) { - (*this)(error_code{}, 0, false); } - void operator()(error_code ec, - std::size_t bytes_used, bool again = true); + void operator()(); + + void operator()(error_code ec); friend void* asio_handler_allocate( @@ -245,7 +239,9 @@ public: friend bool asio_handler_is_continuation(accept_op* op) { - return op->d_->cont; + using boost::asio::asio_handler_is_continuation; + return asio_handler_is_continuation( + std::addressof(op->d_.handler())); } template @@ -262,27 +258,24 @@ template template void stream::accept_op:: -operator()(error_code ec, - std::size_t bytes_used, bool again) +operator()() { auto& d = *d_; - d.cont = d.cont || again; - if(ec) - goto upcall; - switch(d.state) - { - case 0: - // read message - d.state = 1; - http::async_read_some(d.ws.next_layer(), - d.ws.stream_.buffer(), d.p, - std::move(*this)); - return; + http::async_read_header(d.ws.next_layer(), + d.ws.stream_.buffer(), d.p, + std::move(*this)); +} - case 1: +template +template +void +stream::accept_op:: +operator()(error_code ec) +{ + auto& d = *d_; + if(! ec) { BOOST_ASSERT(d.p.is_header_done()); - d.ws.stream_.buffer().consume(bytes_used); // Arguments from our state must be // moved to the stack before releasing // the handler. @@ -302,8 +295,6 @@ operator()(error_code ec, #endif return; } - } -upcall: d_.invoke(ec); } @@ -619,7 +610,7 @@ async_accept(AcceptHandler&& handler) reset(); accept_op>{ - init.completion_handler, *this, &default_decorate_res}; + init.completion_handler, *this, &default_decorate_res}(); return init.result.get(); } @@ -641,7 +632,7 @@ async_accept_ex(ResponseDecorator const& decorator, reset(); accept_op>{ - init.completion_handler, *this, decorator}; + init.completion_handler, *this, decorator}(); return init.result.get(); } @@ -664,7 +655,8 @@ async_accept(ConstBufferSequence const& buffers, reset(); accept_op>{ - init.completion_handler, *this, buffers, &default_decorate_res}; + init.completion_handler, *this, buffers, + &default_decorate_res}(); return init.result.get(); } @@ -692,7 +684,8 @@ async_accept_ex(ConstBufferSequence const& buffers, reset(); accept_op>{ - init.completion_handler, *this, buffers, decorator}; + init.completion_handler, *this, buffers, + decorator}(); return init.result.get(); } diff --git a/include/beast/websocket/impl/stream.ipp b/include/beast/websocket/impl/stream.ipp index 865f302a..aebaef09 100644 --- a/include/beast/websocket/impl/stream.ipp +++ b/include/beast/websocket/impl/stream.ipp @@ -91,13 +91,11 @@ stream:: do_accept( Decorator const& decorator, error_code& ec) { - http::header_parser p; - auto const bytes_used = http::read_some( - next_layer(), stream_.buffer(), p, ec); + http::request_parser p; + http::read_header(next_layer(), + stream_.buffer(), p, ec); if(ec) return; - BOOST_ASSERT(p.is_header_done()); - stream_.buffer().consume(bytes_used); do_accept(p.get(), decorator, ec); } diff --git a/include/beast/websocket/stream.hpp b/include/beast/websocket/stream.hpp index bf565d8e..daf357e4 100644 --- a/include/beast/websocket/stream.hpp +++ b/include/beast/websocket/stream.hpp @@ -30,12 +30,10 @@ namespace beast { namespace websocket { /// The type of object holding HTTP Upgrade requests -using request_type = - http::message; +using request_type = http::request; /// The type of object holding HTTP Upgrade responses -using response_type = - http::message; +using response_type = http::response; /** Information about a WebSocket frame. diff --git a/test/http/doc_http_samples.cpp b/test/http/doc_http_samples.cpp index 888895ec..2280b964 100644 --- a/test/http/doc_http_samples.cpp +++ b/test/http/doc_http_samples.cpp @@ -256,134 +256,6 @@ public: } //-------------------------------------------------------------------------- -#if 0 - // VFALCO This is broken - /* - Efficiently relay a message from one stream to another - */ - template< - bool isRequest, - class SyncWriteStream, - class DynamicBuffer, - class SyncReadStream> - void - relay( - SyncWriteStream& out, - DynamicBuffer& b, - SyncReadStream& in) - { - flat_buffer buffer{4096}; // 4K limit - header_parser parser; - serializer, - fields> ws{parser.get()}; - error_code ec; - do - { - auto const state0 = parser.state(); - auto const bytes_used = - read_some(in, buffer, parser, ec); - BEAST_EXPECTS(! ec, ec.message()); - switch(state0) - { - case parse_state::header: - { - BEAST_EXPECT(parser.is_header_done()); - for(;;) - { - ws.write_some(out, ec); - if(ec == http::error::need_more) - { - ec = {}; - break; - } - if(ec) - BOOST_THROW_EXCEPTION(system_error{ec}); - } - break; - } - - case parse_state::chunk_header: - { - // inspect parser.chunk_extension() here - if(parser.is_done()) - boost::asio::write(out, - chunk_encode_final()); - break; - } - - case parse_state::body: - case parse_state::body_to_eof: - case parse_state::chunk_body: - { - if(! parser.is_done()) - { - auto const body = parser.body(); - boost::asio::write(out, chunk_encode( - false, boost::asio::buffer( - body.data(), body.size()))); - } - break; - } - - case parse_state::complete: - break; - } - buffer.consume(bytes_used); - } - while(! parser.is_done()); - } - - void - testRelay() - { - // Content-Length - { - test::string_istream is{ios_, - "GET / HTTP/1.1\r\n" - "Content-Length: 5\r\n" - "\r\n" // 37 byte header - "*****", - 3 // max_read - }; - test::string_ostream os{ios_}; - flat_buffer b{16}; - relay(os, b, is); - } - - // end of file - { - test::string_istream is{ios_, - "HTTP/1.1 200 OK\r\n" - "\r\n" // 19 byte header - "*****", - 3 // max_read - }; - test::string_ostream os{ios_}; - flat_buffer b{16}; - relay(os, b, is); - } - - // chunked - { - test::string_istream is{ios_, - "GET / HTTP/1.1\r\n" - "Transfer-Encoding: chunked\r\n" - "\r\n" - "5;x;y=1;z=\"-\"\r\n*****\r\n" - "3\r\n---\r\n" - "1\r\n+\r\n" - "0\r\n\r\n", - 2 // max_read - }; - test::string_ostream os{ios_}; - flat_buffer b{16}; - relay(os, b, is); - } - } -#endif - - //-------------------------------------------------------------------------- void run() @@ -395,7 +267,6 @@ public: doWriteStdStream(); doCustomParser(); doHEAD(); - doDeferredBody(); } }; diff --git a/test/http/parser.cpp b/test/http/parser.cpp index 1b1ce19a..32cdc076 100644 --- a/test/http/parser.cpp +++ b/test/http/parser.cpp @@ -25,57 +25,6 @@ namespace beast { namespace http { -class header_parser_test - : public beast::unit_test::suite - , public test::enable_yield_to -{ -public: - static - boost::asio::const_buffers_1 - buf(string_view s) - { - return {s.data(), s.size()}; - } - - void - testParse() - { - { - test::string_istream is{ios_, - "GET / HTTP/1.1\r\n" - "User-Agent: test\r\n" - "\r\n" - }; - flat_buffer db{1024}; - header_parser p; - read_some(is, db, p); - BEAST_EXPECT(p.is_header_done()); - } - { - test::string_istream is{ios_, - "POST / HTTP/1.1\r\n" - "User-Agent: test\r\n" - "Content-Length: 1\r\n" - "\r\n" - "*" - }; - flat_buffer db{1024}; - header_parser p; - read_some(is, db, p); - BEAST_EXPECT(p.is_header_done()); - BEAST_EXPECT(! p.is_done()); - } - } - - void - run() override - { - testParse(); - } -}; - -BEAST_DEFINE_TESTSUITE(header_parser,http,beast); - class parser_test : public beast::unit_test::suite , public beast::test::enable_yield_to @@ -335,30 +284,6 @@ public: } } - void - testExpect100Continue() - { - test::string_istream ss{ios_, - "POST / HTTP/1.1\r\n" - "Expect: 100-continue\r\n" - "Content-Length: 5\r\n" - "\r\n" - "*****"}; - multi_buffer b; - error_code ec; - header_parser p0; - auto const bytes_used = - read_some(ss, b, p0, ec); - b.consume(bytes_used); - BEAST_EXPECTS(! ec, ec.message()); - BEAST_EXPECT(p0.is_header_done()); - BEAST_EXPECT(! p0.is_done()); - request_parser p1{std::move(p0)}; - read(ss, b, p1, ec); - BEAST_EXPECTS(! ec, ec.message()); - BEAST_EXPECT(p1.get().body == "*****"); - } - //-------------------------------------------------------------------------- template