mirror of
https://github.com/boostorg/beast.git
synced 2025-07-31 05:17:26 +02:00
Refactor header status, reason, and target (API Change):
* header::result is a family of functions to replace header::status * header interface now uses status enum and also ints * reason-phrase is no longer stored unless the user explicitly requests it. * When serializing, the standard reason is used for the corresponding status code unless the user has changed it.
This commit is contained in:
@ -4,6 +4,8 @@ API Changes:
|
||||
|
||||
* Refactor method and verb
|
||||
* Canonicalize string_view parameter types
|
||||
* Tidy up empty_body writer error
|
||||
* Refactor header status, reason, and target
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
|
@ -147,8 +147,7 @@ objects:
|
||||
```
|
||||
response<string_body> res;
|
||||
res.version = 11; // HTTP/1.1
|
||||
res.status = 200;
|
||||
res.reason("OK");
|
||||
res.result(status::ok);
|
||||
res.body = "Hello, world!";
|
||||
res.fields.insert("Server", "Beast");
|
||||
res.fields.insert("Content-Length", res.body.size());
|
||||
|
@ -128,8 +128,7 @@ the number of octets received prior to the server closing the connection:
|
||||
{
|
||||
response<string_body> res;
|
||||
res.version = 11;
|
||||
res.status = 200;
|
||||
res.reason("OK");
|
||||
res.result(status::ok);
|
||||
res.fields.insert("Server", "Beast");
|
||||
res.body = "Hello, world!";
|
||||
|
||||
|
@ -164,7 +164,7 @@ send_expect_100_continue(
|
||||
{
|
||||
response<string_body> res;
|
||||
read(stream, buffer, res);
|
||||
if(res.status != 100)
|
||||
if(res.result() != status::continue_)
|
||||
{
|
||||
// The server indicated that it will not
|
||||
// accept the request, so skip sending the body.
|
||||
@ -229,7 +229,7 @@ send_cgi_response(
|
||||
// allowing serialization to use manually provided buffers.
|
||||
message<false, buffer_body, fields> res;
|
||||
|
||||
res.status = 200;
|
||||
res.result(status::ok);
|
||||
res.version = 11;
|
||||
res.fields.insert("Server", "Beast");
|
||||
res.fields.insert("Transfer-Encoding", "chunked");
|
||||
|
@ -197,8 +197,7 @@ receive_expect_100_continue(
|
||||
// send 100 response
|
||||
response<empty_body> res;
|
||||
res.version = 11;
|
||||
res.status = 100;
|
||||
res.reason("Continue");
|
||||
res.result(status::continue_);
|
||||
res.fields.insert("Server", "test");
|
||||
write(stream, res, ec);
|
||||
if(ec)
|
||||
|
@ -56,7 +56,7 @@ class custom_parser
|
||||
/// Called after receiving the start-line (isRequest == false).
|
||||
void
|
||||
on_response(
|
||||
int status, // The status-code
|
||||
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
|
||||
|
@ -256,13 +256,13 @@ struct header<false, Fields>
|
||||
string_view
|
||||
reason() const
|
||||
{
|
||||
return fields.reason();
|
||||
return fields.reason_impl();
|
||||
}
|
||||
|
||||
void
|
||||
reason(string_view s)
|
||||
{
|
||||
fields.reason(s);
|
||||
fields.reason_impl(s);
|
||||
}
|
||||
|
||||
Fields fields;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 37 KiB |
@ -88,6 +88,7 @@
|
||||
<member><link linkend="beast.ref.http__connection">connection</link></member>
|
||||
<member><link linkend="beast.ref.http__error">error</link></member>
|
||||
<member><link linkend="beast.ref.http__status">status</link></member>
|
||||
<member><link linkend="beast.ref.http__status_class">status_class</link></member>
|
||||
<member><link linkend="beast.ref.http__verb">verb</link></member>
|
||||
</simplelist>
|
||||
<bridgehead renderas="sect3">Type Traits</bridgehead>
|
||||
|
@ -234,8 +234,7 @@ private:
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response<string_body> res;
|
||||
res.status = 404;
|
||||
res.reason("Not Found");
|
||||
res.result(status::not_found);
|
||||
res.version = req_.version;
|
||||
res.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
@ -249,8 +248,7 @@ private:
|
||||
try
|
||||
{
|
||||
resp_type res;
|
||||
res.status = 200;
|
||||
res.reason("OK");
|
||||
res.result(status::ok);
|
||||
res.version = req_.version;
|
||||
res.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", mime_type(path));
|
||||
@ -263,8 +261,7 @@ private:
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
response<string_body> res;
|
||||
res.status = 500;
|
||||
res.reason("Internal Error");
|
||||
res.result(status::internal_server_error);
|
||||
res.version = req_.version;
|
||||
res.fields.insert("Server", "http_async_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
|
@ -164,8 +164,7 @@ private:
|
||||
if(! boost::filesystem::exists(path))
|
||||
{
|
||||
response<string_body> res;
|
||||
res.status = 404;
|
||||
res.reason("Not Found");
|
||||
res.result(status::not_found);
|
||||
res.version = req.version;
|
||||
res.fields.insert("Server", "http_sync_server");
|
||||
res.fields.insert("Content-Type", "text/html");
|
||||
@ -179,7 +178,7 @@ private:
|
||||
try
|
||||
{
|
||||
resp_type res;
|
||||
res.status = 200;
|
||||
res.result(status::ok);
|
||||
res.reason("OK");
|
||||
res.version = req.version;
|
||||
res.fields.insert("Server", "http_sync_server");
|
||||
@ -193,7 +192,7 @@ private:
|
||||
catch(std::exception const& e)
|
||||
{
|
||||
response<string_body> res;
|
||||
res.status = 500;
|
||||
res.result(status::internal_server_error);
|
||||
res.reason("Internal Error");
|
||||
res.version = req.version;
|
||||
res.fields.insert("Server", "http_sync_server");
|
||||
|
@ -286,33 +286,48 @@ private:
|
||||
#endif
|
||||
|
||||
string_view
|
||||
method_string() const;
|
||||
method_impl() const
|
||||
{
|
||||
return (*this)[":method"];
|
||||
}
|
||||
|
||||
void
|
||||
method_string(string_view s);
|
||||
method_impl(string_view s)
|
||||
{
|
||||
if(s.empty())
|
||||
this->erase(":method");
|
||||
else
|
||||
this->replace(":method", s);
|
||||
}
|
||||
|
||||
string_view
|
||||
target() const
|
||||
target_impl() const
|
||||
{
|
||||
return (*this)[":target"];
|
||||
}
|
||||
|
||||
void
|
||||
target(string_view s)
|
||||
target_impl(string_view s)
|
||||
{
|
||||
return this->replace(":target", s);
|
||||
if(s.empty())
|
||||
this->erase(":target");
|
||||
else
|
||||
return this->replace(":target", s);
|
||||
}
|
||||
|
||||
string_view
|
||||
reason() const
|
||||
reason_impl() const
|
||||
{
|
||||
return (*this)[":reason"];
|
||||
}
|
||||
|
||||
void
|
||||
reason(string_view s)
|
||||
reason_impl(string_view s)
|
||||
{
|
||||
return this->replace(":reason", s);
|
||||
if(s.empty())
|
||||
this->erase(":reason");
|
||||
else
|
||||
this->replace(":reason", s);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -42,6 +42,8 @@ public:
|
||||
case error::end_of_stream: return "end of stream";
|
||||
case error::partial_message: return "partial message";
|
||||
case error::need_more: return "need more";
|
||||
case error::unexpected_body: return "unexpected body";
|
||||
case error::need_buffer: return "need buffer";
|
||||
case error::buffer_overflow: return "buffer overflow";
|
||||
case error::bad_line_ending: return "bad line ending";
|
||||
case error::bad_method: return "bad method";
|
||||
|
@ -230,8 +230,7 @@ erase(string_view name)
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
insert(string_view name,
|
||||
string_view value)
|
||||
insert(string_view name, string_view value)
|
||||
{
|
||||
value = detail::trim(value);
|
||||
auto const p = alloc_traits::allocate(this->member(), 1);
|
||||
@ -243,33 +242,13 @@ insert(string_view name,
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
replace(string_view name,
|
||||
string_view value)
|
||||
replace(string_view name, string_view value)
|
||||
{
|
||||
value = detail::trim(value);
|
||||
erase(name);
|
||||
insert(name, value);
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
string_view
|
||||
basic_fields<Allocator>::
|
||||
method_string() const
|
||||
{
|
||||
return (*this)[":method"];
|
||||
}
|
||||
|
||||
template<class Allocator>
|
||||
void
|
||||
basic_fields<Allocator>::
|
||||
method_string(string_view s)
|
||||
{
|
||||
if(s.empty())
|
||||
this->erase(":method");
|
||||
else
|
||||
this->replace(":method", s);
|
||||
}
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
||||
|
@ -30,7 +30,7 @@ get_method_string() const
|
||||
{
|
||||
if(method_ != verb::unknown)
|
||||
return to_string(method_);
|
||||
return fields.method_string();
|
||||
return fields.method_impl();
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
@ -43,7 +43,7 @@ set_method(verb v)
|
||||
BOOST_THROW_EXCEPTION(
|
||||
std::invalid_argument{"unknown verb"});
|
||||
method_ = v;
|
||||
fields.method_string({});
|
||||
fields.method_impl({});
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
@ -54,9 +54,21 @@ set_method(string_view s)
|
||||
{
|
||||
method_ = string_to_verb(s);
|
||||
if(method_ != verb::unknown)
|
||||
fields.method_string({});
|
||||
fields.method_impl({});
|
||||
else
|
||||
fields.method_string(s);
|
||||
fields.method_impl(s);
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
template<class>
|
||||
string_view
|
||||
header<false, Fields>::
|
||||
get_reason() const
|
||||
{
|
||||
auto const s = fields.reason_impl();
|
||||
if(! s.empty())
|
||||
return s;
|
||||
return obsolete_reason(result_);
|
||||
}
|
||||
|
||||
template<class Fields>
|
||||
@ -79,8 +91,8 @@ swap(
|
||||
{
|
||||
using std::swap;
|
||||
swap(a.version, b.version);
|
||||
swap(a.status, b.status);
|
||||
swap(a.fields, b.fields);
|
||||
swap(a.result_, b.result_);
|
||||
}
|
||||
|
||||
template<bool isRequest, class Body, class Fields>
|
||||
@ -242,9 +254,9 @@ prepare(message<isRequest, Body, Fields>& msg,
|
||||
operator()(message<false, Body, Fields>& msg,
|
||||
detail::prepare_info const& pi) const
|
||||
{
|
||||
if((msg.status / 100 ) != 1 &&
|
||||
msg.status != 204 &&
|
||||
msg.status != 304)
|
||||
if(to_status_class(msg.result()) != status_class::informational &&
|
||||
msg.result() != status::no_content &&
|
||||
msg.result() != status::not_modified)
|
||||
{
|
||||
msg.fields.insert(
|
||||
"Content-Length", *pi.content_length);
|
||||
|
@ -23,6 +23,7 @@ void
|
||||
write_start_line(std::ostream& os,
|
||||
header<true, Fields> const& msg)
|
||||
{
|
||||
// VFALCO This should all be done without dynamic allocation
|
||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||
os << msg.method() << " " << msg.target();
|
||||
switch(msg.version)
|
||||
@ -37,18 +38,14 @@ void
|
||||
write_start_line(std::ostream& os,
|
||||
header<false, Fields> const& msg)
|
||||
{
|
||||
// VFALCO This should all be done without dynamic allocation
|
||||
BOOST_ASSERT(msg.version == 10 || msg.version == 11);
|
||||
switch(msg.version)
|
||||
{
|
||||
case 10: os << "HTTP/1.0 "; break;
|
||||
case 11: os << "HTTP/1.1 "; break;
|
||||
}
|
||||
auto const reason = msg.reason();
|
||||
if(reason.empty())
|
||||
os << msg.status << " " << msg.reason() << "\r\n";
|
||||
else
|
||||
os << msg.status << " " <<
|
||||
obsolete_reason(static_cast<status>(msg.status)) << "\r\n";
|
||||
os << msg.result_int() << " " << msg.reason() << "\r\n";
|
||||
}
|
||||
|
||||
template<class FieldSequence>
|
||||
|
@ -8,10 +8,101 @@
|
||||
#ifndef BEAST_HTTP_IMPL_STATUS_IPP
|
||||
#define BEAST_HTTP_IMPL_STATUS_IPP
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
namespace beast {
|
||||
namespace http {
|
||||
namespace detail {
|
||||
|
||||
template<class = void>
|
||||
status
|
||||
int_to_status(int v)
|
||||
{
|
||||
switch(static_cast<status>(v))
|
||||
{
|
||||
// 1xx
|
||||
case status::continue_:
|
||||
case status::switching_protocols:
|
||||
case status::processing:
|
||||
// [[fallthrough]]
|
||||
|
||||
// 2xx
|
||||
case status::ok:
|
||||
case status::created:
|
||||
case status::accepted:
|
||||
case status::non_authoritative_information:
|
||||
case status::no_content:
|
||||
case status::reset_content:
|
||||
case status::partial_content:
|
||||
case status::multi_status:
|
||||
case status::already_reported:
|
||||
case status::im_used:
|
||||
// [[fallthrough]]
|
||||
|
||||
// 3xx
|
||||
case status::multiple_choices:
|
||||
case status::moved_permanently:
|
||||
case status::found:
|
||||
case status::see_other:
|
||||
case status::not_modified:
|
||||
case status::use_proxy:
|
||||
case status::temporary_redirect:
|
||||
case status::permanent_redirect:
|
||||
// [[fallthrough]]
|
||||
|
||||
// 4xx
|
||||
case status::bad_request:
|
||||
case status::unauthorized:
|
||||
case status::payment_required:
|
||||
case status::forbidden:
|
||||
case status::not_found:
|
||||
case status::method_not_allowed:
|
||||
case status::not_acceptable:
|
||||
case status::proxy_authentication_required:
|
||||
case status::request_timeout:
|
||||
case status::conflict:
|
||||
case status::gone:
|
||||
case status::length_required:
|
||||
case status::precondition_failed:
|
||||
case status::payload_too_large:
|
||||
case status::uri_too_long:
|
||||
case status::unsupported_media_type:
|
||||
case status::range_not_satisfiable:
|
||||
case status::expectation_failed:
|
||||
case status::misdirected_request:
|
||||
case status::unprocessable_entity:
|
||||
case status::locked:
|
||||
case status::failed_dependency:
|
||||
case status::upgrade_required:
|
||||
case status::precondition_required:
|
||||
case status::too_many_requests:
|
||||
case status::request_header_fields_too_large:
|
||||
case status::connection_closed_without_response:
|
||||
case status::unavailable_for_legal_reasons:
|
||||
case status::client_closed_request:
|
||||
// [[fallthrough]]
|
||||
|
||||
// 5xx
|
||||
case status::internal_server_error:
|
||||
case status::not_implemented:
|
||||
case status::bad_gateway:
|
||||
case status::service_unavailable:
|
||||
case status::gateway_timeout:
|
||||
case status::http_version_not_supported:
|
||||
case status::variant_also_negotiates:
|
||||
case status::insufficient_storage:
|
||||
case status::loop_detected:
|
||||
case status::not_extended:
|
||||
case status::network_authentication_required:
|
||||
case status::network_connect_timeout_error:
|
||||
return static_cast<status>(v);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return status::unknown;
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
string_view
|
||||
status_to_string(int v)
|
||||
@ -92,11 +183,49 @@ status_to_string(int v)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return "Unknown Status";
|
||||
return "<unknown-status>";
|
||||
}
|
||||
|
||||
template<class = void>
|
||||
status_class
|
||||
to_status_class(int v)
|
||||
{
|
||||
switch(v / 100)
|
||||
{
|
||||
case 1: return status_class::informational;
|
||||
case 2: return status_class::successful;
|
||||
case 3: return status_class::redirection;
|
||||
case 4: return status_class::client_error;
|
||||
case 5: return status_class::server_error;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return status_class::unknown;
|
||||
}
|
||||
|
||||
} // detail
|
||||
|
||||
inline
|
||||
status
|
||||
int_to_status(int v)
|
||||
{
|
||||
return detail::int_to_status(v);
|
||||
}
|
||||
|
||||
inline
|
||||
status_class
|
||||
to_status_class(int v)
|
||||
{
|
||||
return detail::to_status_class(v);
|
||||
}
|
||||
|
||||
inline
|
||||
status_class
|
||||
to_status_class(status v)
|
||||
{
|
||||
return to_status_class(static_cast<int>(v));
|
||||
}
|
||||
|
||||
inline
|
||||
string_view
|
||||
obsolete_reason(status v)
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <beast/config.hpp>
|
||||
#include <beast/http/fields.hpp>
|
||||
#include <beast/http/verb.hpp>
|
||||
#include <beast/http/status.hpp>
|
||||
#include <beast/core/string_view.hpp>
|
||||
#include <beast/core/detail/integer_sequence.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
@ -58,104 +59,6 @@ struct header<true, Fields>
|
||||
/// The type representing the fields.
|
||||
using fields_type = Fields;
|
||||
|
||||
/** The HTTP version.
|
||||
|
||||
This holds both the major and minor version numbers,
|
||||
using these formulas:
|
||||
@code
|
||||
major = version / 10;
|
||||
minor = version % 10;
|
||||
@endcode
|
||||
*/
|
||||
int version;
|
||||
|
||||
/** Return the request-method verb.
|
||||
|
||||
If the request-method is not one of the recognized verbs,
|
||||
@ref verb::unknown is returned. Callers may use @ref method_string
|
||||
to retrieve the exact text.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
|
||||
@see @ref method_string
|
||||
*/
|
||||
verb
|
||||
method() const
|
||||
{
|
||||
return method_;
|
||||
}
|
||||
|
||||
/** Set the request-method verb.
|
||||
|
||||
This function will set the method for requests to one
|
||||
of the known verbs.
|
||||
|
||||
@param v The request method verb to set.
|
||||
This may not be @ref verb::unknown.
|
||||
|
||||
@throw std::invalid_argument when `v == verb::unknown`.
|
||||
*/
|
||||
void
|
||||
method(verb v)
|
||||
{
|
||||
set_method(v);
|
||||
}
|
||||
|
||||
/** Return the request-method as a string.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
|
||||
@see @ref method
|
||||
*/
|
||||
string_view
|
||||
method_string() const
|
||||
{
|
||||
return get_method_string();
|
||||
}
|
||||
|
||||
/** Set the request-method using a string.
|
||||
|
||||
This function will set the method for requests to a verb
|
||||
if the string matches a known verb, otherwise it will
|
||||
store a copy of the passed string as the method.
|
||||
|
||||
@param s A string representing the request method.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
*/
|
||||
void
|
||||
method(string_view s)
|
||||
{
|
||||
set_method(s);
|
||||
}
|
||||
|
||||
/** Return the Request Target
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
*/
|
||||
auto
|
||||
target() const ->
|
||||
decltype(std::declval<Fields>().target()) const
|
||||
{
|
||||
return fields.target();
|
||||
}
|
||||
|
||||
/** Set the Request Target
|
||||
|
||||
@param value A value that represents the request method.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
*/
|
||||
template<class Value>
|
||||
void
|
||||
target(Value&& value)
|
||||
{
|
||||
fields.target(std::forward<Value>(value));
|
||||
}
|
||||
|
||||
/// The HTTP field values.
|
||||
fields_type fields;
|
||||
|
||||
/// Default constructor
|
||||
header() = default;
|
||||
|
||||
@ -198,13 +101,106 @@ struct header<true, Fields>
|
||||
{
|
||||
}
|
||||
|
||||
/** The HTTP-version.
|
||||
|
||||
This holds both the major and minor version numbers,
|
||||
using these formulas:
|
||||
@code
|
||||
int major = version / 10;
|
||||
int minor = version % 10;
|
||||
@endcode
|
||||
*/
|
||||
int version;
|
||||
|
||||
/// The HTTP field values.
|
||||
fields_type fields;
|
||||
|
||||
/** Return the request-method verb.
|
||||
|
||||
If the request-method is not one of the recognized verbs,
|
||||
@ref verb::unknown is returned. Callers may use @ref method_string
|
||||
to retrieve the exact text.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
|
||||
@see @ref method_string
|
||||
*/
|
||||
verb
|
||||
method() const
|
||||
{
|
||||
return method_;
|
||||
}
|
||||
|
||||
/** Set the request-method verb.
|
||||
|
||||
This function will set the method for requests to a known verb.
|
||||
|
||||
@param v The request method verb to set.
|
||||
This may not be @ref verb::unknown.
|
||||
|
||||
@throw std::invalid_argument when `v == verb::unknown`.
|
||||
*/
|
||||
void
|
||||
method(verb v)
|
||||
{
|
||||
set_method(v);
|
||||
}
|
||||
|
||||
/** Return the request-method string.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
|
||||
@see @ref method
|
||||
*/
|
||||
string_view
|
||||
method_string() const
|
||||
{
|
||||
return get_method_string();
|
||||
}
|
||||
|
||||
/** Set the request-method string.
|
||||
|
||||
This function will set the method for requests to a verb
|
||||
if the string matches a known verb, otherwise it will
|
||||
store a copy of the passed string as the method.
|
||||
|
||||
@param s A string representing the request-method.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
*/
|
||||
void
|
||||
method(string_view s)
|
||||
{
|
||||
set_method(s);
|
||||
}
|
||||
|
||||
/** Returns the request-target string.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
*/
|
||||
string_view
|
||||
target() const
|
||||
{
|
||||
return fields.target_impl();
|
||||
}
|
||||
|
||||
/** Set the request-target string.
|
||||
|
||||
@param s A string representing the request-target.
|
||||
|
||||
@note This function is only available if `isRequest == true`.
|
||||
*/
|
||||
void
|
||||
target(string_view s)
|
||||
{
|
||||
fields.target_impl(s);
|
||||
}
|
||||
|
||||
private:
|
||||
template<class Fields>
|
||||
template<class T>
|
||||
friend
|
||||
void
|
||||
swap(
|
||||
header<true, Fields>& m1,
|
||||
header<true, Fields>& m2);
|
||||
swap(header<true, T>& m1, header<true, T>& m2);
|
||||
|
||||
template<class = void>
|
||||
string_view
|
||||
@ -256,7 +252,7 @@ struct header<false, Fields>
|
||||
/// The HTTP field values.
|
||||
fields_type fields;
|
||||
|
||||
/// Default constructor
|
||||
/// Default constructor.
|
||||
header() = default;
|
||||
|
||||
/// Move constructor
|
||||
@ -293,11 +289,62 @@ struct header<false, Fields>
|
||||
}
|
||||
#endif
|
||||
|
||||
/** The Response Status-Code.
|
||||
/** The response status-code result.
|
||||
|
||||
If the actual status code is not a known code, this
|
||||
function returns @ref status::unknown. Use @ref result_int
|
||||
to return the raw status code as a number.
|
||||
|
||||
@note This member is only available if `isRequest == false`.
|
||||
*/
|
||||
int status;
|
||||
status
|
||||
result() const
|
||||
{
|
||||
return int_to_status(
|
||||
static_cast<int>(result_));
|
||||
}
|
||||
|
||||
/** Set the response status-code result.
|
||||
|
||||
@param v The code to set.
|
||||
|
||||
@note This member is only available if `isRequest == false`.
|
||||
*/
|
||||
void
|
||||
result(status v)
|
||||
{
|
||||
result_ = v;
|
||||
}
|
||||
|
||||
/** Set the raw status-code result as an integer.
|
||||
|
||||
This sets the status code to the exact number passed in.
|
||||
If the number does not correspond to one of the known
|
||||
status codes, the function @ref result will return
|
||||
@ref status::unknown. Use @ref result_int to obtain the
|
||||
original raw status-code.
|
||||
|
||||
@param v The status-code integer to set.
|
||||
*/
|
||||
void
|
||||
result(int v)
|
||||
{
|
||||
result_ = static_cast<status>(v);
|
||||
}
|
||||
|
||||
/** The response status-code result expressed as an integer.
|
||||
|
||||
This returns the raw status code as an integer, even
|
||||
when that code is not in the list of known status codes.
|
||||
|
||||
@note This member is only available if `isRequest == false`.
|
||||
*/
|
||||
int
|
||||
result_int() const
|
||||
{
|
||||
return static_cast<int>(result_);
|
||||
}
|
||||
|
||||
|
||||
/** Return the Reason-Phrase.
|
||||
|
||||
@ -305,26 +352,47 @@ struct header<false, Fields>
|
||||
|
||||
@note This function is only available if `isRequest == false`.
|
||||
*/
|
||||
auto
|
||||
reason() const ->
|
||||
decltype(std::declval<Fields>().reason()) const
|
||||
string_view
|
||||
reason() const
|
||||
{
|
||||
return fields.reason();
|
||||
return get_reason();
|
||||
}
|
||||
|
||||
/** Set the Reason-Phrase
|
||||
|
||||
This function sets a custom reason-phrase to a copy of
|
||||
the string passed in. Normally it is not necessary to set
|
||||
the reason phrase on an outgoing response object; the
|
||||
implementation will automatically use the standard reason
|
||||
text for the corresponding status code.
|
||||
|
||||
To clear a previously set custom phrase, pass an empty
|
||||
string. This will restore the default standard reason text
|
||||
based on the status code used when serializing.
|
||||
|
||||
The Reason-Phrase is obsolete as of rfc7230.
|
||||
|
||||
@param value A value that represents the reason phrase.
|
||||
|
||||
@note This function is only available if `isRequest == false`.
|
||||
*/
|
||||
template<class Value>
|
||||
void
|
||||
reason(Value&& value)
|
||||
reason(string_view s)
|
||||
{
|
||||
fields.reason(std::forward<Value>(value));
|
||||
fields.reason_impl(s);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
template<class T>
|
||||
friend
|
||||
void
|
||||
swap(header<false, T>& m1, header<false, T>& m2);
|
||||
|
||||
template<class = void>
|
||||
string_view
|
||||
get_reason() const;
|
||||
|
||||
status result_;
|
||||
};
|
||||
|
||||
/** A container for a complete HTTP message.
|
||||
|
@ -153,10 +153,10 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
on_response(int status, string_view reason,
|
||||
on_response(int code, string_view reason,
|
||||
int version, error_code&)
|
||||
{
|
||||
h_.status = status;
|
||||
h_.result(code);
|
||||
h_.version = version;
|
||||
h_.reason(reason);
|
||||
}
|
||||
@ -341,11 +341,11 @@ private:
|
||||
}
|
||||
|
||||
void
|
||||
on_response(int status,
|
||||
on_response(int code,
|
||||
string_view reason,
|
||||
int version, error_code&)
|
||||
{
|
||||
m_.status = status;
|
||||
m_.result(code);
|
||||
m_.version = version;
|
||||
m_.reason(reason);
|
||||
}
|
||||
|
@ -15,8 +15,17 @@
|
||||
namespace beast {
|
||||
namespace http {
|
||||
|
||||
enum class status : int
|
||||
enum class status : unsigned short
|
||||
{
|
||||
/** An unknown status-code.
|
||||
|
||||
This value indicates that the value for the status code
|
||||
is not in the list of commonly recognized status codes.
|
||||
Callers interested in the exactly value should use the
|
||||
interface which provides the raw integer.
|
||||
*/
|
||||
unknown = 0,
|
||||
|
||||
continue_ = 100,
|
||||
switching_protocols = 101,
|
||||
processing = 102,
|
||||
@ -85,13 +94,66 @@ enum class status : int
|
||||
network_connect_timeout_error = 599
|
||||
};
|
||||
|
||||
/// Returns the obsolete reason-phrase text for a status code.
|
||||
/** Represents the class of a status-code.
|
||||
*/
|
||||
enum class status_class : int
|
||||
{
|
||||
/// Unknown status-class
|
||||
unknown = 0,
|
||||
|
||||
/// The request was received, continuing processing.
|
||||
informational = 1,
|
||||
|
||||
/// The request was successfully received, understood, and accepted.
|
||||
successful = 2,
|
||||
|
||||
/// Further action needs to be taken in order to complete the request.
|
||||
redirection = 3,
|
||||
|
||||
/// The request contains bad syntax or cannot be fulfilled.
|
||||
client_error = 4,
|
||||
|
||||
/// The server failed to fulfill an apparently valid request.
|
||||
server_error = 5,
|
||||
};
|
||||
|
||||
/** Converts the integer to a known status-code.
|
||||
|
||||
If the integer does not match a known status code,
|
||||
@ref status::unknown is returned.
|
||||
*/
|
||||
status
|
||||
int_to_status(int v);
|
||||
|
||||
/** Convert an integer to a status_class.
|
||||
|
||||
@param v The integer representing a status code.
|
||||
|
||||
@return The status class. If the integer does not match
|
||||
a known status class, @ref status_class::unknown is returned.
|
||||
*/
|
||||
status_class
|
||||
to_status_class(int v);
|
||||
|
||||
/** Convert a status_code to a status_class.
|
||||
|
||||
@param v The status code to convert.
|
||||
|
||||
@return The status class.
|
||||
*/
|
||||
status_class
|
||||
to_status_class(status v);
|
||||
|
||||
/** Returns the obsolete reason-phrase text for a status code.
|
||||
|
||||
@param v The status code to use.
|
||||
*/
|
||||
string_view
|
||||
obsolete_reason(status v);
|
||||
|
||||
/// Outputs the reason phrase of a status code to a stream.
|
||||
/// Outputs the standard reason phrase of a status code to a stream.
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, status v);
|
||||
operator<<(std::ostream&, status);
|
||||
|
||||
} // http
|
||||
} // beast
|
||||
|
@ -128,7 +128,7 @@ enum class verb
|
||||
/** Converts a string to the request method verb.
|
||||
|
||||
If the string does not match a known request method,
|
||||
`boost::none` is returned.
|
||||
@ref verb::unknown is returned.
|
||||
*/
|
||||
verb
|
||||
string_to_verb(string_view s);
|
||||
|
@ -148,7 +148,8 @@ operator()(error_code ec, bool again)
|
||||
// sent response
|
||||
case 1:
|
||||
d.state = 99;
|
||||
if(d.res.status != 101)
|
||||
if(d.res.result() !=
|
||||
http::status::switching_protocols)
|
||||
ec = error::handshake_failed;
|
||||
if(! ec)
|
||||
{
|
||||
|
@ -112,7 +112,7 @@ do_accept(http::header<true, Fields> const& req,
|
||||
http::write(stream_, res, ec);
|
||||
if(ec)
|
||||
return;
|
||||
if(res.status != 101)
|
||||
if(res.result() != http::status::switching_protocols)
|
||||
{
|
||||
ec = error::handshake_failed;
|
||||
// VFALCO TODO Respect keep alive setting, perform
|
||||
@ -216,7 +216,7 @@ build_response(http::header<true, Fields> const& req,
|
||||
[&](std::string const& text)
|
||||
{
|
||||
response_type res;
|
||||
res.status = 400;
|
||||
res.result(http::status::bad_request);
|
||||
res.version = req.version;
|
||||
res.body = text;
|
||||
prepare(res);
|
||||
@ -246,7 +246,7 @@ build_response(http::header<true, Fields> const& req,
|
||||
if(version != "13")
|
||||
{
|
||||
response_type res;
|
||||
res.status = 426;
|
||||
res.result(http::status::upgrade_required);
|
||||
res.version = req.version;
|
||||
res.fields.insert("Sec-WebSocket-Version", "13");
|
||||
prepare(res);
|
||||
@ -263,7 +263,7 @@ build_response(http::header<true, Fields> const& req,
|
||||
pmd_negotiate(
|
||||
res.fields, unused, offer, pmd_opts_);
|
||||
}
|
||||
res.status = 101;
|
||||
res.result(http::status::switching_protocols);
|
||||
res.version = req.version;
|
||||
res.fields.insert("Upgrade", "websocket");
|
||||
res.fields.insert("Connection", "upgrade");
|
||||
@ -286,7 +286,7 @@ do_response(http::header<false> const& res,
|
||||
{
|
||||
if(res.version < 11)
|
||||
return false;
|
||||
if(res.status != 101)
|
||||
if(res.result() != http::status::switching_protocols)
|
||||
return false;
|
||||
if(! is_upgrade(res))
|
||||
return false;
|
||||
|
@ -46,7 +46,7 @@ class custom_parser
|
||||
/// Called after receiving the start-line (isRequest == false).
|
||||
void
|
||||
on_response(
|
||||
int status, // The status-code
|
||||
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
|
||||
@ -238,7 +238,7 @@ public:
|
||||
read(stream, buffer, res, ec);
|
||||
if(ec)
|
||||
return;
|
||||
if(res.status != 100)
|
||||
if(res.result() != status::continue_)
|
||||
{
|
||||
// The server indicated that it will not
|
||||
// accept the request, so skip sending the body.
|
||||
@ -291,8 +291,7 @@ public:
|
||||
// send 100 response
|
||||
response<empty_body> res;
|
||||
res.version = 11;
|
||||
res.status = 100;
|
||||
res.reason("Continue");
|
||||
res.result(status::continue_);
|
||||
res.fields.insert("Server", "test");
|
||||
write(stream, res, ec);
|
||||
if(ec)
|
||||
@ -383,7 +382,7 @@ public:
|
||||
// allowing serialization to use manually provided buffers.
|
||||
message<false, buffer_body, fields> res;
|
||||
|
||||
res.status = 200;
|
||||
res.result(status::ok);
|
||||
res.version = 11;
|
||||
res.fields.insert("Server", "Beast");
|
||||
res.fields.insert("Transfer-Encoding", "chunked");
|
||||
|
@ -103,12 +103,12 @@ public:
|
||||
testMethodString()
|
||||
{
|
||||
f_t f;
|
||||
f.method_string("CRY");
|
||||
BEAST_EXPECTS(f.method_string() == "CRY", f.method_string());
|
||||
f.method_string("PUT");
|
||||
BEAST_EXPECTS(f.method_string() == "PUT", f.method_string());
|
||||
f.method_string({});
|
||||
BEAST_EXPECTS(f.method_string().empty(), f.method_string());
|
||||
f.method_impl("CRY");
|
||||
BEAST_EXPECTS(f.method_impl() == "CRY", f.method_impl());
|
||||
f.method_impl("PUT");
|
||||
BEAST_EXPECTS(f.method_impl() == "PUT", f.method_impl());
|
||||
f.method_impl({});
|
||||
BEAST_EXPECTS(f.method_impl().empty(), f.method_impl());
|
||||
}
|
||||
|
||||
void run() override
|
||||
|
@ -262,19 +262,20 @@ public:
|
||||
{
|
||||
message<false, string_body, fields> m1;
|
||||
message<false, string_body, fields> m2;
|
||||
m1.status = 200;
|
||||
m1.result(status::ok);
|
||||
m1.version = 10;
|
||||
m1.body = "1";
|
||||
m1.fields.insert("h", "v");
|
||||
m2.status = 404;
|
||||
m2.reason("OK");
|
||||
m2.result(status::not_found);
|
||||
m2.body = "2";
|
||||
m2.version = 11;
|
||||
swap(m1, m2);
|
||||
BEAST_EXPECT(m1.status == 404);
|
||||
BEAST_EXPECT(m2.status == 200);
|
||||
BEAST_EXPECT(m1.reason() == "OK");
|
||||
BEAST_EXPECT(m2.reason().empty());
|
||||
BEAST_EXPECT(m1.result() == status::not_found);
|
||||
BEAST_EXPECT(m1.result_int() == 404);
|
||||
BEAST_EXPECT(m2.result() == status::ok);
|
||||
BEAST_EXPECT(m2.result_int() == 200);
|
||||
BEAST_EXPECT(m1.reason() == "Not Found");
|
||||
BEAST_EXPECT(m2.reason() == "OK");
|
||||
BEAST_EXPECT(m1.version == 11);
|
||||
BEAST_EXPECT(m2.version == 10);
|
||||
BEAST_EXPECT(m1.body == "2");
|
||||
@ -321,6 +322,35 @@ public:
|
||||
scheck("XYZ");
|
||||
}
|
||||
|
||||
void
|
||||
testStatus()
|
||||
{
|
||||
header<false> h;
|
||||
h.result(200);
|
||||
BEAST_EXPECT(h.result_int() == 200);
|
||||
BEAST_EXPECT(h.result() == status::ok);
|
||||
h.result(status::switching_protocols);
|
||||
BEAST_EXPECT(h.result_int() == 101);
|
||||
BEAST_EXPECT(h.result() == status::switching_protocols);
|
||||
h.result(1);
|
||||
BEAST_EXPECT(h.result_int() == 1);
|
||||
BEAST_EXPECT(h.result() == status::unknown);
|
||||
}
|
||||
|
||||
void
|
||||
testReason()
|
||||
{
|
||||
header<false> h;
|
||||
h.result(status::ok);
|
||||
BEAST_EXPECT(h.reason() == "OK");
|
||||
h.reason("Pepe");
|
||||
BEAST_EXPECT(h.reason() == "Pepe");
|
||||
h.result(status::not_found);
|
||||
BEAST_EXPECT(h.reason() == "Pepe");
|
||||
h.reason({});
|
||||
BEAST_EXPECT(h.reason() == "Not Found");
|
||||
}
|
||||
|
||||
void
|
||||
run() override
|
||||
{
|
||||
@ -331,6 +361,8 @@ public:
|
||||
testSwap();
|
||||
testSpecialMembers();
|
||||
testMethod();
|
||||
testStatus();
|
||||
testReason();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -182,7 +182,7 @@ public:
|
||||
BEAST_EXPECT(p.need_eof());
|
||||
BEAST_EXPECT(p.content_length() == boost::none);
|
||||
BEAST_EXPECT(m.version == 10);
|
||||
BEAST_EXPECT(m.status == 200);
|
||||
BEAST_EXPECT(m.result() == status::ok);
|
||||
BEAST_EXPECT(m.reason() == "OK");
|
||||
BEAST_EXPECT(m.fields["Server"] == "test");
|
||||
BEAST_EXPECT(m.body == "Hello, world!");
|
||||
@ -209,7 +209,7 @@ public:
|
||||
BEAST_EXPECT(p.is_chunked());
|
||||
BEAST_EXPECT(p.content_length() == boost::none);
|
||||
BEAST_EXPECT(m.version == 11);
|
||||
BEAST_EXPECT(m.status == 200);
|
||||
BEAST_EXPECT(m.result() == status::ok);
|
||||
BEAST_EXPECT(m.reason() == "OK");
|
||||
BEAST_EXPECT(m.fields["Server"] == "test");
|
||||
BEAST_EXPECT(m.fields["Transfer-Encoding"] == "chunked");
|
||||
|
@ -20,6 +20,82 @@ public:
|
||||
void
|
||||
testStatus()
|
||||
{
|
||||
auto const check = [&](status s, int i, status_class sc)
|
||||
{
|
||||
BEAST_EXPECT(int_to_status(i) == s);
|
||||
BEAST_EXPECT(to_status_class(i) == sc);
|
||||
BEAST_EXPECT(to_status_class(int_to_status(i)) == sc);
|
||||
};
|
||||
check(status::continue_ ,100, status_class::informational);
|
||||
check(status::switching_protocols ,101, status_class::informational);
|
||||
check(status::processing ,102, status_class::informational);
|
||||
|
||||
check(status::ok ,200, status_class::successful);
|
||||
check(status::created ,201, status_class::successful);
|
||||
check(status::accepted ,202, status_class::successful);
|
||||
check(status::non_authoritative_information ,203, status_class::successful);
|
||||
check(status::no_content ,204, status_class::successful);
|
||||
check(status::reset_content ,205, status_class::successful);
|
||||
check(status::partial_content ,206, status_class::successful);
|
||||
check(status::multi_status ,207, status_class::successful);
|
||||
check(status::already_reported ,208, status_class::successful);
|
||||
check(status::im_used ,226, status_class::successful);
|
||||
|
||||
check(status::multiple_choices ,300, status_class::redirection);
|
||||
check(status::moved_permanently ,301, status_class::redirection);
|
||||
check(status::found ,302, status_class::redirection);
|
||||
check(status::see_other ,303, status_class::redirection);
|
||||
check(status::not_modified ,304, status_class::redirection);
|
||||
check(status::use_proxy ,305, status_class::redirection);
|
||||
check(status::temporary_redirect ,307, status_class::redirection);
|
||||
check(status::permanent_redirect ,308, status_class::redirection);
|
||||
|
||||
check(status::bad_request ,400, status_class::client_error);
|
||||
check(status::unauthorized ,401, status_class::client_error);
|
||||
check(status::payment_required ,402, status_class::client_error);
|
||||
check(status::forbidden ,403, status_class::client_error);
|
||||
check(status::not_found ,404, status_class::client_error);
|
||||
check(status::method_not_allowed ,405, status_class::client_error);
|
||||
check(status::not_acceptable ,406, status_class::client_error);
|
||||
check(status::proxy_authentication_required ,407, status_class::client_error);
|
||||
check(status::request_timeout ,408, status_class::client_error);
|
||||
check(status::conflict ,409, status_class::client_error);
|
||||
check(status::gone ,410, status_class::client_error);
|
||||
check(status::length_required ,411, status_class::client_error);
|
||||
check(status::precondition_failed ,412, status_class::client_error);
|
||||
check(status::payload_too_large ,413, status_class::client_error);
|
||||
check(status::uri_too_long ,414, status_class::client_error);
|
||||
check(status::unsupported_media_type ,415, status_class::client_error);
|
||||
check(status::range_not_satisfiable ,416, status_class::client_error);
|
||||
check(status::expectation_failed ,417, status_class::client_error);
|
||||
check(status::misdirected_request ,421, status_class::client_error);
|
||||
check(status::unprocessable_entity ,422, status_class::client_error);
|
||||
check(status::locked ,423, status_class::client_error);
|
||||
check(status::failed_dependency ,424, status_class::client_error);
|
||||
check(status::upgrade_required ,426, status_class::client_error);
|
||||
check(status::precondition_required ,428, status_class::client_error);
|
||||
check(status::too_many_requests ,429, status_class::client_error);
|
||||
check(status::request_header_fields_too_large ,431, status_class::client_error);
|
||||
check(status::connection_closed_without_response ,444, status_class::client_error);
|
||||
check(status::unavailable_for_legal_reasons ,451, status_class::client_error);
|
||||
check(status::client_closed_request ,499, status_class::client_error);
|
||||
|
||||
check(status::internal_server_error ,500, status_class::server_error);
|
||||
check(status::not_implemented ,501, status_class::server_error);
|
||||
check(status::bad_gateway ,502, status_class::server_error);
|
||||
check(status::service_unavailable ,503, status_class::server_error);
|
||||
check(status::gateway_timeout ,504, status_class::server_error);
|
||||
check(status::http_version_not_supported ,505, status_class::server_error);
|
||||
check(status::variant_also_negotiates ,506, status_class::server_error);
|
||||
check(status::insufficient_storage ,507, status_class::server_error);
|
||||
check(status::loop_detected ,508, status_class::server_error);
|
||||
check(status::not_extended ,510, status_class::server_error);
|
||||
check(status::network_authentication_required ,511, status_class::server_error);
|
||||
check(status::network_connect_timeout_error ,599, status_class::server_error);
|
||||
|
||||
BEAST_EXPECT(to_status_class(1) == status_class::unknown);
|
||||
BEAST_EXPECT(to_status_class(status::unknown) == status_class::unknown);
|
||||
|
||||
auto const good =
|
||||
[&](status v)
|
||||
{
|
||||
|
@ -62,11 +62,11 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
on_response(int status_,
|
||||
on_response(int code,
|
||||
string_view reason_,
|
||||
int version_, error_code& ec)
|
||||
{
|
||||
status = status_;
|
||||
status = code;
|
||||
reason = std::string(
|
||||
reason_.data(), reason_.size());
|
||||
version = version_;
|
||||
|
@ -292,7 +292,7 @@ public:
|
||||
{
|
||||
message<false, string_body, fields> m;
|
||||
m.version = 10;
|
||||
m.status = 200;
|
||||
m.result(status::ok);
|
||||
m.reason("OK");
|
||||
m.fields.insert("Server", "test");
|
||||
m.fields.insert("Content-Length", "5");
|
||||
@ -311,7 +311,7 @@ public:
|
||||
{
|
||||
message<false, string_body, fields> m;
|
||||
m.version = 11;
|
||||
m.status = 200;
|
||||
m.result(status::ok);
|
||||
m.reason("OK");
|
||||
m.fields.insert("Server", "test");
|
||||
m.fields.insert("Transfer-Encoding", "chunked");
|
||||
@ -786,7 +786,7 @@ public:
|
||||
|
||||
message<false, Body, fields> m0;
|
||||
m0.version = 11;
|
||||
m0.status = 200;
|
||||
m0.result(status::ok);
|
||||
m0.reason("OK");
|
||||
m0.fields.insert("Server", "test");
|
||||
m0.body.s = "Hello, world!\n";
|
||||
|
Reference in New Issue
Block a user