diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0f0a06c4..75052faa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,7 @@ Version 47
API Changes:
* Refactor treatment of request-method
+* Refactor treatment of status code and obsolete reason
--------------------------------------------------------------------------------
diff --git a/doc/quickref.xml b/doc/quickref.xml
index 93f5a67e..b2a15f7f 100644
--- a/doc/quickref.xml
+++ b/doc/quickref.xml
@@ -65,11 +65,11 @@
is_keep_alive
is_upgrade
make_serializer
+ obsolete_reason
operator<<
prepare
read
read_some
- reason_string
string_to_verb
swap
to_string
@@ -88,6 +88,7 @@
connection
error
+ status
verb
Concepts
diff --git a/include/beast/http.hpp b/include/beast/http.hpp
index 398bf211..16eb2625 100644
--- a/include/beast/http.hpp
+++ b/include/beast/http.hpp
@@ -22,6 +22,7 @@
#include
#include
#include
+#include
#include
#include
#include
diff --git a/include/beast/http/impl/message.ipp b/include/beast/http/impl/message.ipp
index 1ee68257..d951f951 100644
--- a/include/beast/http/impl/message.ipp
+++ b/include/beast/http/impl/message.ipp
@@ -254,71 +254,6 @@ prepare(message& msg,
"invalid version for Connection: upgrade"});
}
-namespace detail {
-
-template
-string_view
-reason_string(int status)
-{
- switch(status)
- {
- case 100: return "Continue";
- case 101: return "Switching Protocols";
- case 200: return "OK";
- case 201: return "Created";
- case 202: return "Accepted";
- case 203: return "Non-Authoritative Information";
- case 204: return "No Content";
- case 205: return "Reset Content";
- case 206: return "Partial Content";
- case 300: return "Multiple Choices";
- case 301: return "Moved Permanently";
- case 302: return "Found";
- case 303: return "See Other";
- case 304: return "Not Modified";
- case 305: return "Use Proxy";
- case 307: return "Temporary Redirect";
- case 400: return "Bad Request";
- case 401: return "Unauthorized";
- case 402: return "Payment Required";
- case 403: return "Forbidden";
- case 404: return "Not Found";
- case 405: return "Method Not Allowed";
- case 406: return "Not Acceptable";
- case 407: return "Proxy Authentication Required";
- case 408: return "Request Timeout";
- case 409: return "Conflict";
- case 410: return "Gone";
- case 411: return "Length Required";
- case 412: return "Precondition Failed";
- case 413: return "Request Entity Too Large";
- case 414: return "Request-URI Too Long";
- case 415: return "Unsupported Media Type";
- case 416: return "Requested Range Not Satisfiable";
- case 417: return "Expectation Failed";
- case 500: return "Internal Server Error";
- case 501: return "Not Implemented";
- case 502: return "Bad Gateway";
- case 503: return "Service Unavailable";
- case 504: return "Gateway Timeout";
- case 505: return "HTTP Version Not Supported";
-
- case 306: return "";
- default:
- break;
- }
- return "";
-}
-
-} // detail
-
-inline
-string_view const
-reason_string(int status)
-{
- return detail::reason_string(status);
-}
-
} // http
} // beast
diff --git a/include/beast/http/impl/serializer.ipp b/include/beast/http/impl/serializer.ipp
index 7b3600f4..b8f9db29 100644
--- a/include/beast/http/impl/serializer.ipp
+++ b/include/beast/http/impl/serializer.ipp
@@ -9,9 +9,11 @@
#define BEAST_HTTP_IMPL_SERIALIZER_IPP
#include
+#include
#include
#include
+
namespace beast {
namespace http {
namespace detail {
@@ -41,7 +43,12 @@ write_start_line(std::ostream& os,
case 10: os << "HTTP/1.0 "; break;
case 11: os << "HTTP/1.1 "; break;
}
- os << msg.status << " " << msg.reason() << "\r\n";
+ auto const reason = msg.reason();
+ if(reason.empty())
+ os << msg.status << " " << msg.reason() << "\r\n";
+ else
+ os << msg.status << " " <<
+ obsolete_reason(static_cast(msg.status)) << "\r\n";
}
template
diff --git a/include/beast/http/impl/status.ipp b/include/beast/http/impl/status.ipp
new file mode 100644
index 00000000..93f9e104
--- /dev/null
+++ b/include/beast/http/impl/status.ipp
@@ -0,0 +1,118 @@
+//
+// Copyright (c) 2013-2017 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)
+//
+
+#ifndef BEAST_HTTP_IMPL_STATUS_IPP
+#define BEAST_HTTP_IMPL_STATUS_IPP
+
+namespace beast {
+namespace http {
+namespace detail {
+
+template
+string_view
+status_to_string(int v)
+{
+ switch(static_cast(v))
+ {
+ // 1xx
+ case status::continue_: return "Continue";
+ case status::switching_protocols: return "Switching Protocols";
+ case status::processing: return "Processing";
+
+ // 2xx
+ case status::ok: return "OK";
+ case status::created: return "Created";
+ case status::accepted: return "Accepted";
+ case status::non_authoritative_information: return "Non-Authoritative Information";
+ case status::no_content: return "No Content";
+ case status::reset_content: return "Reset Content";
+ case status::partial_content: return "Partial Content";
+ case status::multi_status: return "Multi-Status";
+ case status::already_reported: return "Already Reported";
+ case status::im_used: return "IM Used";
+
+ // 3xx
+ case status::multiple_choices: return "Multiple Choices";
+ case status::moved_permanently: return "Moved Permanently";
+ case status::found: return "Found";
+ case status::see_other: return "See Other";
+ case status::not_modified: return "Not Modified";
+ case status::use_proxy: return "Use Proxy";
+ case status::temporary_redirect: return "Temporary Redirect";
+ case status::permanent_redirect: return "Permanent Redirect";
+
+ // 4xx
+ case status::bad_request: return "Bad Request";
+ case status::unauthorized: return "Unauthorized";
+ case status::payment_required: return "Payment Required";
+ case status::forbidden: return "Forbidden";
+ case status::not_found: return "Not Found";
+ case status::method_not_allowed: return "Method Not Allowed";
+ case status::not_acceptable: return "Not Acceptable";
+ case status::proxy_authentication_required: return "Proxy Authentication Required";
+ case status::request_timeout: return "Request Timeout";
+ case status::conflict: return "Conflict";
+ case status::gone: return "Gone";
+ case status::length_required: return "Length Required";
+ case status::precondition_failed: return "Precondition Failed";
+ case status::payload_too_large: return "Payload Too Large";
+ case status::uri_too_long: return "URI Too Long";
+ case status::unsupported_media_type: return "Unsupported Media Type";
+ case status::range_not_satisfiable: return "Range Not Satisfiable";
+ case status::expectation_failed: return "Expectation Failed";
+ case status::misdirected_request: return "Misdirected Request";
+ case status::unprocessable_entity: return "Unprocessable Entity";
+ case status::locked: return "Locked";
+ case status::failed_dependency: return "Failed Dependency";
+ case status::upgrade_required: return "Upgrade Required";
+ case status::precondition_required: return "Precondition Required";
+ case status::too_many_requests: return "Too Many Requests";
+ case status::request_header_fields_too_large: return "Request Header Fields Too Large";
+ case status::connection_closed_without_response: return "Connection Closed Without Response";
+ case status::unavailable_for_legal_reasons: return "Unavailable For Legal Reasons";
+ case status::client_closed_request: return "Client Closed Request";
+ // 5xx
+ case status::internal_server_error: return "Internal Server Error";
+ case status::not_implemented: return "Not Implemented";
+ case status::bad_gateway: return "Bad Gateway";
+ case status::service_unavailable: return "Service Unavailable";
+ case status::gateway_timeout: return "Gateway Timeout";
+ case status::http_version_not_supported: return "HTTP Version Not Supported";
+ case status::variant_also_negotiates: return "Variant Also Negotiates";
+ case status::insufficient_storage: return "Insufficient Storage";
+ case status::loop_detected: return "Loop Detected";
+ case status::not_extended: return "Not Extended";
+ case status::network_authentication_required: return "Network Authentication Required";
+ case status::network_connect_timeout_error: return "Network Connect Timeout Error";
+
+ default:
+ break;
+ }
+ return "Unknown Status";
+}
+
+} // detail
+
+inline
+string_view
+obsolete_reason(status v)
+{
+ return detail::status_to_string(
+ static_cast(v));
+}
+
+inline
+std::ostream&
+operator<<(std::ostream& os, status v)
+{
+ return os << obsolete_reason(v);
+}
+
+} // http
+} // beast
+
+#endif
diff --git a/include/beast/http/message.hpp b/include/beast/http/message.hpp
index 5ee7589c..629fe72e 100644
--- a/include/beast/http/message.hpp
+++ b/include/beast/http/message.hpp
@@ -527,10 +527,6 @@ void
prepare(message& msg,
Options&&... options);
-/** Returns the text for a known HTTP status code. */
-string_view const
-reason_string(int status);
-
} // http
} // beast
diff --git a/include/beast/http/reason.hpp b/include/beast/http/reason.hpp
deleted file mode 100644
index fb8d3a15..00000000
--- a/include/beast/http/reason.hpp
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// Copyright (c) 2013-2017 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)
-//
-
-#ifndef BEAST_HTTP_REASON_HPP
-#define BEAST_HTTP_REASON_HPP
-
-#include
-#include
-
-namespace beast {
-namespace http {
-
-namespace detail {
-
-
-} // detail
-
-
-} // http
-} // beast
-
-#endif
diff --git a/include/beast/http/status.hpp b/include/beast/http/status.hpp
new file mode 100644
index 00000000..3fcfd7ce
--- /dev/null
+++ b/include/beast/http/status.hpp
@@ -0,0 +1,101 @@
+//
+// Copyright (c) 2013-2017 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)
+//
+
+#ifndef BEAST_HTTP_STATUS_HPP
+#define BEAST_HTTP_STATUS_HPP
+
+#include
+#include
+#include
+
+namespace beast {
+namespace http {
+
+enum class status : int
+{
+ continue_ = 100,
+ switching_protocols = 101,
+ processing = 102,
+
+ ok = 200,
+ created = 201,
+ accepted = 202,
+ non_authoritative_information = 203,
+ no_content = 204,
+ reset_content = 205,
+ partial_content = 206,
+ multi_status = 207,
+ already_reported = 208,
+ im_used = 226,
+
+ multiple_choices = 300,
+ moved_permanently = 301,
+ found = 302,
+ see_other = 303,
+ not_modified = 304,
+ use_proxy = 305,
+ temporary_redirect = 307,
+ permanent_redirect = 308,
+
+ bad_request = 400,
+ unauthorized = 401,
+ payment_required = 402,
+ forbidden = 403,
+ not_found = 404,
+ method_not_allowed = 405,
+ not_acceptable = 406,
+ proxy_authentication_required = 407,
+ request_timeout = 408,
+ conflict = 409,
+ gone = 410,
+ length_required = 411,
+ precondition_failed = 412,
+ payload_too_large = 413,
+ uri_too_long = 414,
+ unsupported_media_type = 415,
+ range_not_satisfiable = 416,
+ expectation_failed = 417,
+ misdirected_request = 421,
+ unprocessable_entity = 422,
+ locked = 423,
+ failed_dependency = 424,
+ upgrade_required = 426,
+ precondition_required = 428,
+ too_many_requests = 429,
+ request_header_fields_too_large = 431,
+ connection_closed_without_response = 444,
+ unavailable_for_legal_reasons = 451,
+ client_closed_request = 499,
+
+ internal_server_error = 500,
+ not_implemented = 501,
+ bad_gateway = 502,
+ service_unavailable = 503,
+ gateway_timeout = 504,
+ http_version_not_supported = 505,
+ variant_also_negotiates = 506,
+ insufficient_storage = 507,
+ loop_detected = 508,
+ not_extended = 510,
+ network_authentication_required = 511,
+ network_connect_timeout_error = 599
+};
+
+/// Returns the obsolete reason-phrase text for a status code.
+string_view
+obsolete_reason(status v);
+
+/// Outputs the reason phrase of a status code to a stream.
+std::ostream&
+operator<<(std::ostream& os, status v);
+
+} // http
+} // beast
+
+#include
+
+#endif
diff --git a/include/beast/websocket/impl/stream.ipp b/include/beast/websocket/impl/stream.ipp
index 7083ef0a..dcdde93c 100644
--- a/include/beast/websocket/impl/stream.ipp
+++ b/include/beast/websocket/impl/stream.ipp
@@ -217,7 +217,6 @@ build_response(http::header const& req,
{
response_type res;
res.status = 400;
- res.reason(http::reason_string(res.status));
res.version = req.version;
res.body = text;
prepare(res);
@@ -248,7 +247,6 @@ build_response(http::header const& req,
{
response_type res;
res.status = 426;
- res.reason(http::reason_string(res.status));
res.version = req.version;
res.fields.insert("Sec-WebSocket-Version", "13");
prepare(res);
@@ -266,7 +264,6 @@ build_response(http::header const& req,
res.fields, unused, offer, pmd_opts_);
}
res.status = 101;
- res.reason(http::reason_string(res.status));
res.version = req.version;
res.fields.insert("Upgrade", "websocket");
res.fields.insert("Connection", "upgrade");
diff --git a/test/Jamfile b/test/Jamfile
index 2254674e..902fd5dc 100644
--- a/test/Jamfile
+++ b/test/Jamfile
@@ -53,6 +53,7 @@ unit-test http-tests :
http/read.cpp
http/rfc7230.cpp
http/serializer.cpp
+ http/status.cpp
http/string_body.cpp
http/type_traits.cpp
http/verb.cpp
diff --git a/test/http/CMakeLists.txt b/test/http/CMakeLists.txt
index fb87e7ea..8e54e9fa 100644
--- a/test/http/CMakeLists.txt
+++ b/test/http/CMakeLists.txt
@@ -23,6 +23,7 @@ add_executable (http-tests
read.cpp
rfc7230.cpp
serializer.cpp
+ status.cpp
string_body.cpp
type_traits.cpp
verb.cpp
diff --git a/test/http/message.cpp b/test/http/message.cpp
index 8e9f2695..14b817b6 100644
--- a/test/http/message.cpp
+++ b/test/http/message.cpp
@@ -296,13 +296,6 @@ public:
}();
}
- void
- testReasonString()
- {
- for(int i = 1; i <= 999; ++i)
- BEAST_EXPECT(! reason_string(i).empty());
- }
-
void
run() override
{
@@ -312,7 +305,6 @@ public:
testPrepare();
testSwap();
testSpecialMembers();
- testReasonString();
}
};
diff --git a/test/http/status.cpp b/test/http/status.cpp
new file mode 100644
index 00000000..e7389d5a
--- /dev/null
+++ b/test/http/status.cpp
@@ -0,0 +1,100 @@
+//
+// Copyright (c) 2013-2017 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)
+//
+
+// Test that header file is self-contained.
+#include
+
+#include
+
+namespace beast {
+namespace http {
+
+class status_test
+ : public beast::unit_test::suite
+{
+public:
+ void
+ testStatus()
+ {
+ auto const good =
+ [&](status v)
+ {
+ BEAST_EXPECT(obsolete_reason(v) != "Unknown Status");
+ };
+ good(status::continue_);
+ good(status::switching_protocols);
+ good(status::processing);
+ good(status::ok);
+ good(status::created);
+ good(status::accepted);
+ good(status::non_authoritative_information);
+ good(status::no_content);
+ good(status::reset_content);
+ good(status::partial_content);
+ good(status::multi_status);
+ good(status::already_reported);
+ good(status::im_used);
+ good(status::multiple_choices);
+ good(status::moved_permanently);
+ good(status::found);
+ good(status::see_other);
+ good(status::not_modified);
+ good(status::use_proxy);
+ good(status::temporary_redirect);
+ good(status::permanent_redirect);
+ good(status::bad_request);
+ good(status::unauthorized);
+ good(status::payment_required);
+ good(status::forbidden);
+ good(status::not_found);
+ good(status::method_not_allowed);
+ good(status::not_acceptable);
+ good(status::proxy_authentication_required);
+ good(status::request_timeout);
+ good(status::conflict);
+ good(status::gone);
+ good(status::length_required);
+ good(status::precondition_failed);
+ good(status::payload_too_large);
+ good(status::uri_too_long);
+ good(status::unsupported_media_type);
+ good(status::range_not_satisfiable);
+ good(status::expectation_failed);
+ good(status::misdirected_request);
+ good(status::unprocessable_entity);
+ good(status::locked);
+ good(status::failed_dependency);
+ good(status::upgrade_required);
+ good(status::precondition_required);
+ good(status::too_many_requests);
+ good(status::request_header_fields_too_large);
+ good(status::unavailable_for_legal_reasons);
+ good(status::internal_server_error);
+ good(status::not_implemented);
+ good(status::bad_gateway);
+ good(status::service_unavailable);
+ good(status::gateway_timeout);
+ good(status::http_version_not_supported);
+ good(status::variant_also_negotiates);
+ good(status::insufficient_storage);
+ good(status::loop_detected);
+ good(status::not_extended);
+ good(status::network_authentication_required);
+ }
+
+ void
+ run()
+ {
+ testStatus();
+ }
+};
+
+BEAST_DEFINE_TESTSUITE(status,http,beast);
+
+} // http
+} // beast
+