From 1754d5427dcb2ce9ae6cc4cb24c1dce502066a79 Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Wed, 25 Oct 2017 18:41:04 -0700 Subject: [PATCH] Add message::need_eof --- CHANGELOG.md | 4 + include/boost/beast/http/impl/message.ipp | 16 ++++ include/boost/beast/http/message.hpp | 37 ++++++++ test/beast/http/message.cpp | 106 ++++++++++++++++++++++ 4 files changed, 163 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index afe1ae69..f044b7fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ Version 128: * Update doc links +HTTP: + +* Add message::need_eof + API Changes: * Remove serializer::keep_alive diff --git a/include/boost/beast/http/impl/message.ipp b/include/boost/beast/http/impl/message.ipp index a984bf73..e3972fee 100644 --- a/include/boost/beast/http/impl/message.ipp +++ b/include/boost/beast/http/impl/message.ipp @@ -343,6 +343,22 @@ payload_size() const return payload_size(detail::is_body_sized{}); } +template +bool +message:: +need_eof(std::false_type) const +{ + // VFALCO Do we need a way to let the caller say "the body is intentionally skipped"? + if( this->result() == status::no_content || + this->result() == status::not_modified || + to_status_class(this->result()) == + status_class::informational || + has_content_length() || + chunked()) + return ! keep_alive(); + return true; +} + template void message:: diff --git a/include/boost/beast/http/message.hpp b/include/boost/beast/http/message.hpp index 94d389d9..51020956 100644 --- a/include/boost/beast/http/message.hpp +++ b/include/boost/beast/http/message.hpp @@ -780,6 +780,34 @@ struct message this->set_keep_alive_impl(this->version(), value); } + /** Returns `true` if the message semantics require an end of file. + + For HTTP requests, this function returns the logical + NOT of a call to @ref keep_alive. + + For HTTP responses, this function returns the logical NOT + of a call to @ref keep_alive if any of the following are true: + + @li @ref has_content_length would return `true` + + @li @ref chunked would return `true` + + @li @ref result returns @ref status::no_content + + @li @ref result returns @ref status::not_modified + + @li @ref result returns any informational status class (100 to 199) + + Otherwise, the function returns `true`. + + @see https://tools.ietf.org/html/rfc7230#section-3.3 + */ + bool + need_eof() const + { + return need_eof(typename header_type::is_request{}); + } + /** Returns the payload size of the body in octets if possible. This function invokes the @b Body algorithm to measure @@ -878,6 +906,15 @@ private: boost::ignore_unused(fields_args); } + bool + need_eof(std::true_type) const + { + return ! keep_alive(); + } + + bool + need_eof(std::false_type) const; + boost::optional payload_size(std::true_type) const { diff --git a/test/beast/http/message.cpp b/test/beast/http/message.cpp index 7f32bacc..2094829e 100644 --- a/test/beast/http/message.cpp +++ b/test/beast/http/message.cpp @@ -367,6 +367,111 @@ public: BEAST_EXPECT(h.reason() == "Not Found"); } + void + testNeedEof() + { + { + request m; + + m.version(10); + m.keep_alive(false); + BEAST_EXPECT(m.need_eof()); + m.keep_alive(true); + BEAST_EXPECT(! m.need_eof()); + + m.version(11); + m.keep_alive(false); + BEAST_EXPECT(m.need_eof()); + m.keep_alive(true); + BEAST_EXPECT(! m.need_eof()); + } + + { + response m; + m.result(status::ok); + + m.version(10); + m.keep_alive(false); + BEAST_EXPECT(! m.has_content_length()); + BEAST_EXPECT(! m.chunked()); + m.result(status::no_content); + BEAST_EXPECT(m.need_eof()); + m.result(status::not_modified); + BEAST_EXPECT(m.need_eof()); + m.result(status::continue_); + BEAST_EXPECT(m.need_eof()); + m.result(status::switching_protocols); + BEAST_EXPECT(m.need_eof()); + m.result(status::ok); + BEAST_EXPECT(m.need_eof()); + + m.version(10); + m.keep_alive(true); + BEAST_EXPECT(! m.has_content_length()); + BEAST_EXPECT(! m.chunked()); + m.result(status::no_content); + BEAST_EXPECT(! m.need_eof()); + m.result(status::not_modified); + BEAST_EXPECT(! m.need_eof()); + m.result(status::continue_); + BEAST_EXPECT(! m.need_eof()); + m.result(status::switching_protocols); + BEAST_EXPECT(! m.need_eof()); + m.result(status::ok); + BEAST_EXPECT(m.need_eof()); + m.set(field::content_length, "1"); + BEAST_EXPECT(! m.need_eof()); + } + + { + response m; + m.result(status::ok); + + m.version(11); + m.keep_alive(false); + BEAST_EXPECT(! m.has_content_length()); + BEAST_EXPECT(! m.chunked()); + m.result(status::no_content); + BEAST_EXPECT(m.need_eof()); + m.result(status::not_modified); + BEAST_EXPECT(m.need_eof()); + m.result(status::continue_); + BEAST_EXPECT(m.need_eof()); + m.result(status::switching_protocols); + BEAST_EXPECT(m.need_eof()); + m.result(status::ok); + BEAST_EXPECT(m.need_eof()); + m.chunked(true); + BEAST_EXPECT(m.need_eof()); + m.content_length(1); + BEAST_EXPECT(m.need_eof()); + } + + { + response m; + m.result(status::ok); + + m.version(11); + m.keep_alive(true); + BEAST_EXPECT(! m.has_content_length()); + BEAST_EXPECT(! m.chunked()); + m.result(status::no_content); + BEAST_EXPECT(! m.need_eof()); + m.result(status::not_modified); + BEAST_EXPECT(! m.need_eof()); + m.result(status::continue_); + BEAST_EXPECT(! m.need_eof()); + m.result(status::switching_protocols); + BEAST_EXPECT(! m.need_eof()); + m.result(status::ok); + BEAST_EXPECT(m.need_eof()); + m.chunked(true); + BEAST_EXPECT(! m.need_eof()); + m.content_length(1); + BEAST_EXPECT(! m.need_eof()); + } + } + void run() override { @@ -377,6 +482,7 @@ public: testMethod(); testStatus(); testReason(); + testNeedEof(); } };