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();
}
};