Use field in basic_fields and call sites

This commit is contained in:
Vinnie Falco
2017-06-06 12:49:03 -07:00
parent d5f22adeca
commit ca25eee0dd
18 changed files with 220 additions and 69 deletions

View File

@@ -4,6 +4,7 @@ Version 50
* Add field enumeration
* Use allocator more in basic_fields
* Fix basic_fields allocator awareness
* Use field in basic_fields and call sites
API Changes:

View File

@@ -59,3 +59,44 @@ In this table:
]
[endsect]
[/
[section:Fields Fields]
A type meeting the requirements of [*Fields] represents a container
used to store HTTP header fields.
In this table:
* `X` denotes a type that meets the requirements of [*Fields].
* `c` is a value of type `X const`.
[table FieldSequence requirements
[[expression][type][semantics, pre/post-conditions]]
[
[]
[]
[
]
]
]
[endsect]
Operations we'd like to perform
Determine if a field exists
bool exists(field f) const;
bool exists(string_view s) const;
iterator find(field f) const;
iterator find(string_view s);
]

View File

@@ -136,7 +136,7 @@ receive_expect_100_continue(
response<empty_body> res;
res.version = 11;
res.result(status::continue_);
res.insert("Server", "test");
res.insert(field::server, "test");
write(stream, res, ec);
if(ec)
return;
@@ -198,8 +198,8 @@ send_cgi_response(
res.result(status::ok);
res.version = 11;
res.insert("Server", "Beast");
res.insert("Transfer-Encoding", "chunked");
res.insert(field::server, "Beast");
res.insert(field::transfer_encoding, "chunked");
// No data yet, but we set more = true to indicate
// that it might be coming later. Otherwise the
@@ -307,7 +307,7 @@ void do_server_head(
// Set up the response, starting with the common fields
response<string_body> res;
res.version = 11;
res.insert("Server", "test");
res.insert(field::server, "test");
// Now handle request-specific fields
switch(req.method())
@@ -319,7 +319,7 @@ void do_server_head(
// set of headers that would be sent for a GET request,
// including the Content-Length, except for the body.
res.result(status::ok);
res.insert("Content-Length", payload.size());
res.content_length(payload.size());
// For GET requests, we include the body
if(req.method() == verb::get)
@@ -337,7 +337,7 @@ void do_server_head(
// We return responses indicating an error if
// we do not recognize the request method.
res.result(status::bad_request);
res.insert("Content-Type", "text/plain");
res.insert(field::content_type, "text/plain");
res.body = "Invalid request-method '" + req.method_string().to_string() + "'";
break;
}
@@ -397,11 +397,11 @@ do_head_request(
req.version = 11;
req.method(verb::head);
req.target(target);
req.insert("User-Agent", "test");
req.insert(field::user_agent, "test");
// A client MUST send a Host header field in all HTTP/1.1 request messages.
// https://tools.ietf.org/html/rfc7230#section-5.4
req.insert("Host", "localhost");
req.insert(field::host, "localhost");
// Now send it
write(stream, req, ec);

View File

@@ -236,8 +236,8 @@ private:
response<string_body> res;
res.result(status::not_found);
res.version = req_.version;
res.insert("Server", "http_async_server");
res.insert("Content-Type", "text/html");
res.insert(field::server, "http_async_server");
res.insert(field::content_type, "text/html");
res.body = "The file '" + path + "' was not found";
res.prepare();
async_write(sock_, std::move(res),
@@ -250,8 +250,8 @@ private:
resp_type res;
res.result(status::ok);
res.version = req_.version;
res.insert("Server", "http_async_server");
res.insert("Content-Type", mime_type(path));
res.insert(field::server, "http_async_server");
res.insert(field::content_type, mime_type(path));
res.body = path;
res.prepare();
async_write(sock_, std::move(res),
@@ -263,8 +263,8 @@ private:
response<string_body> res;
res.result(status::internal_server_error);
res.version = req_.version;
res.insert("Server", "http_async_server");
res.insert("Content-Type", "text/html");
res.insert(field::server, "http_async_server");
res.insert(field::content_type, "text/html");
res.body =
std::string{"An internal error occurred"} + e.what();
res.prepare();

View File

@@ -40,9 +40,9 @@ int main(int, char const*[])
req.method(verb::get);
req.version = 11;
req.target("/");
req.insert("Host", host + std::string(":") +
req.insert(field::host, host + std::string(":") +
boost::lexical_cast<std::string>(ep.port()));
req.insert("User-Agent", "beast/http");
req.insert(field::user_agent, "beast/http");
req.prepare();
write(sock, req);
response<string_body> res;

View File

@@ -166,8 +166,8 @@ private:
response<string_body> res;
res.result(status::not_found);
res.version = req.version;
res.insert("Server", "http_sync_server");
res.insert("Content-Type", "text/html");
res.insert(field::server, "http_sync_server");
res.insert(field::content_type, "text/html");
res.body = "The file '" + path + "' was not found";
res.prepare();
write(sock, res, ec);
@@ -181,8 +181,8 @@ private:
res.result(status::ok);
res.reason("OK");
res.version = req.version;
res.insert("Server", "http_sync_server");
res.insert("Content-Type", mime_type(path));
res.insert(field::server, "http_sync_server");
res.insert(field::content_type, mime_type(path));
res.body = path;
res.prepare();
write(sock, res, ec);
@@ -195,8 +195,8 @@ private:
res.result(status::internal_server_error);
res.reason("Internal Error");
res.version = req.version;
res.insert("Server", "http_sync_server");
res.insert("Content-Type", "text/html");
res.insert(field::server, "http_sync_server");
res.insert(field::content_type, "text/html");
res.body =
std::string{"An internal error occurred: "} + e.what();
res.prepare();

View File

@@ -38,9 +38,9 @@ int main()
req.method(beast::http::verb::get);
req.target("/");
req.version = 11;
req.insert("Host", host + ":" +
req.insert(beast::http::field::host, host + ":" +
boost::lexical_cast<std::string>(sock.remote_endpoint().port()));
req.insert("User-Agent", "Beast");
req.insert(beast::http::field::user_agent, "Beast");
req.prepare();
beast::http::write(stream, req);

View File

@@ -59,7 +59,7 @@ connection_impl<_>::upgrade;
req.version = 11;
req.method(verb::upgrade);
req.target("/");
req.insert("User-Agent", "Beast");
req.insert(field::user_agent, "Beast");
req.prepare(connection::close, connection::upgrade);
@endcode

View File

@@ -12,6 +12,7 @@
#include <beast/core/string_view.hpp>
#include <beast/core/detail/ci_char_traits.hpp>
#include <beast/http/connection.hpp>
#include <beast/http/field.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/intrusive/set.hpp>
@@ -226,7 +227,19 @@ public:
void
clear() noexcept;
/** Remove a field.
/** Remove zero or more known fields.
If more than one field with the specified name exists, all
matching fields will be removed.
@param f The known field constant.
@return The number of fields removed.
*/
std::size_t
erase(field f);
/** Remove zero or more fields by name.
If more than one field with the specified name exists, all
matching fields will be removed.
@@ -238,7 +251,22 @@ public:
std::size_t
erase(string_view name);
/** Insert a field value.
/** Insert a value for a known field.
If a field with the same name already exists, the
existing field is untouched and a new field value pair
is inserted into the container.
@param f The known field constant.
@param name The name of the field.
@param value A string holding the value of the field.
*/
void
insert(field f, string_view value);
/** Insert a value for a field by name.
If a field with the same name already exists, the
existing field is untouched and a new field value pair
@@ -314,16 +342,70 @@ protected:
// for `header
//
/** Returns the stored request-method string.
@note This is called by the @ref header implementation.
*/
string_view method_impl() const;
/** Returns the stored request-target string.
@note This is called by the @ref header implementation.
*/
string_view target_impl() const;
/** Returns the stored obsolete reason-phrase string.
@note This is called by the @ref header implementation.
*/
string_view reason_impl() const;
/** Set or clear the stored request-method string.
@note This is called by the @ref header implementation.
*/
void method_impl(string_view s);
/** Set or clear the stored request-target string.
@note This is called by the @ref header implementation.
*/
void target_impl(string_view s);
/** Set or clear the stored obsolete reason-phrase string.
@note This is called by the @ref header implementation.
*/
void reason_impl(string_view s);
/** Set the Content-Length field to the specified value.
@note This is called by the @ref header implementation.
*/
void content_length_impl(std::uint64_t n);
/** Add close to the Connection field.
@note This is called by the @ref header implementation.
*/
void connection_impl(close_t);
/** Add keep-alive to the Connection field.
@note This is called by the @ref header implementation.
*/
void connection_impl(keep_alive_t);
/** Add upgrade to the Connection field.
@note This is called by the @ref header implementation.
*/
void connection_impl(upgrade_t);
/** Add chunked to the Transfer-Encoding field.
@note This is called by the @ref header implementation.
*/
void chunked_impl();
private:

View File

@@ -300,6 +300,14 @@ clear() noexcept
list_.clear();
}
template<class Allocator>
std::size_t
basic_fields<Allocator>::
erase(field f)
{
return erase(to_string(f));
}
template<class Allocator>
std::size_t
basic_fields<Allocator>::
@@ -323,6 +331,14 @@ erase(string_view name)
return n;
}
template<class Allocator>
void
basic_fields<Allocator>::
insert(field f, string_view value)
{
insert(to_string(f), value);
}
template<class Allocator>
void
basic_fields<Allocator>::

View File

@@ -103,6 +103,14 @@ size() const
Body, decltype(*this)>{});
}
template<bool isRequest, class Body, class Fields>
void
message<isRequest, Body, Fields>::
content_length(std::uint64_t n)
{
this->content_length_impl(n);
}
template<bool isRequest, class Body, class Fields>
template<class... Args>
void

View File

@@ -559,6 +559,8 @@ struct message : header<isRequest, Fields>
The value of the Content-Length field will be unconditionally
set to the specified number of octets.
@para n The number of octets to set for the Content-Length field.
*/
void
content_length(std::uint64_t n);
@@ -575,7 +577,7 @@ struct message : header<isRequest, Fields>
req.version = 11;
req.method(verb::upgrade);
req.target("/");
req.insert("User-Agent", "Beast");
req.insert(field::user_agent, "Beast");
req.prepare(connection::close, connection::upgrade);
@endcode

View File

@@ -163,12 +163,12 @@ build_request(detail::sec_ws_key_type& key,
req.target(target);
req.version = 11;
req.method(http::verb::get);
req.insert("Host", host);
req.insert("Upgrade", "websocket");
req.insert("Connection", "upgrade");
req.insert(http::field::host, host);
req.insert(http::field::upgrade, "websocket");
req.insert(http::field::connection, "upgrade");
detail::make_sec_ws_key(key, maskgen_);
req.insert("Sec-WebSocket-Key", key);
req.insert("Sec-WebSocket-Version", "13");
req.insert(http::field::sec_websocket_key, key);
req.insert(http::field::sec_websocket_version, "13");
if(pmd_opts_.client_enable)
{
detail::pmd_offer config;
@@ -187,7 +187,7 @@ build_request(detail::sec_ws_key_type& key,
if(! req.exists("User-Agent"))
{
static_string<20> s(BEAST_VERSION_STRING);
req.insert("User-Agent", s);
req.insert(http::field::user_agent, s);
}
return req;
}
@@ -205,8 +205,9 @@ build_response(http::header<true, Fields> const& req,
decorator(res);
if(! res.exists("Server"))
{
BOOST_STATIC_ASSERT(sizeof(BEAST_VERSION_STRING) < 20);
static_string<20> s(BEAST_VERSION_STRING);
res.insert("Server", s);
res.insert(http::field::server, s);
}
};
auto err =
@@ -245,7 +246,7 @@ build_response(http::header<true, Fields> const& req,
response_type res;
res.result(http::status::upgrade_required);
res.version = req.version;
res.insert("Sec-WebSocket-Version", "13");
res.insert(http::field::sec_websocket_version, "13");
res.prepare();
decorate(res);
return res;
@@ -261,12 +262,12 @@ build_response(http::header<true, Fields> const& req,
}
res.result(http::status::switching_protocols);
res.version = req.version;
res.insert("Upgrade", "websocket");
res.insert("Connection", "upgrade");
res.insert(http::field::upgrade, "websocket");
res.insert(http::field::connection, "upgrade");
{
detail::sec_ws_accept_type accept;
detail::make_sec_ws_accept(accept, key);
res.insert("Sec-WebSocket-Accept", accept);
res.insert(http::field::sec_websocket_accept, accept);
}
decorate(res);
return res;

View File

@@ -1563,7 +1563,7 @@ public:
ws.handshake("localhost", "/",
[](request_type& req)
{
req.insert("User-Agent", "Beast");
req.insert(field::user_agent, "Beast");
});
}
catch(...)
@@ -1625,7 +1625,7 @@ public:
ws.handshake(res, "localhost", "/",
[](request_type& req)
{
req.insert("User-Agent", "Beast");
req.insert(field::user_agent, "Beast");
});
}
catch(...)
@@ -1771,7 +1771,7 @@ public:
ws.handshake("localhost", "/",
[](request_type& req)
{
req.insert("User-Agent", "Beast");
req.insert(field::user_agent, "Beast");
},
ec);
if(ec)
@@ -1833,7 +1833,7 @@ public:
ws.handshake(res, "localhost", "/",
[](request_type& req)
{
req.insert("User-Agent", "Beast");
req.insert(field::user_agent, "Beast");
},
ec);
if(ec)

View File

@@ -70,7 +70,7 @@ public:
req.version = 11;
req.method("POST");
req.target("/");
req.insert("User-Agent", "test");
req.insert(field::user_agent, "test");
req.body = "Hello, world!";
req.prepare();
@@ -103,7 +103,7 @@ public:
req.version = 11;
req.method("POST");
req.target("/");
req.insert("User-Agent", "test");
req.insert(field::user_agent, "test");
req.body = "Hello, world!";
req.prepare();
@@ -155,7 +155,7 @@ public:
req.version = 11;
req.method(verb::get);
req.target("/");
req.insert("User-Agent", "test");
req.insert(field::user_agent, "test");
error_code ec;
write_ostream(os, req, ec);
BEAST_EXPECTS(! ec, ec.message());

View File

@@ -36,8 +36,8 @@ void fxx() {
req.version = 11; // HTTP/1.1
req.method(verb::get);
req.target("/index.htm");
req.insert("Accept", "text/html");
req.insert("User-Agent", "Beast");
req.insert(field::accept, "text/html");
req.insert(field::user_agent, "Beast");
req.prepare(connection::close);
//]
@@ -49,7 +49,7 @@ void fxx() {
response<string_body> res;
res.version = 11; // HTTP/1.1
res.result(status::ok);
res.insert("Server", "Beast");
res.insert(field::server, "Beast");
res.body = "Hello, world!";
res.prepare();
@@ -101,7 +101,7 @@ void fxx() {
response<string_body> res;
res.version = 11;
res.result(status::ok);
res.insert("Server", "Beast");
res.insert(field::server, "Beast");
res.body = "Hello, world!";
write(sock, res, ec);

View File

@@ -115,14 +115,14 @@ public:
{
header<true, fields> h;
h.insert("User-Agent", "test");
h.insert(field::user_agent, "test");
message<true, one_arg_body, fields> m{Arg1{}, h};
BEAST_EXPECT(h["User-Agent"] == "test");
BEAST_EXPECT(m["User-Agent"] == "test");
}
{
header<true, fields> h;
h.insert("User-Agent", "test");
h.insert(field::user_agent, "test");
message<true, one_arg_body, fields> m{Arg1{}, std::move(h)};
BEAST_EXPECT(! h.exists("User-Agent"));
BEAST_EXPECT(m["User-Agent"] == "test");

View File

@@ -293,7 +293,7 @@ public:
m.version = 10;
m.result(status::ok);
m.reason("OK");
m.insert("Server", "test");
m.insert(field::server, "test");
m.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
@@ -312,7 +312,7 @@ public:
m.version = 11;
m.result(status::ok);
m.reason("OK");
m.insert("Server", "test");
m.insert(field::server, "test");
m.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
@@ -345,7 +345,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.insert("Content-Length", "5");
m.body = "*****";
try
@@ -376,7 +376,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
@@ -409,7 +409,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.insert("Transfer-Encoding", "chunked");
m.body = "*****";
error_code ec;
@@ -442,7 +442,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
@@ -470,7 +470,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.insert("Content-Length", "5");
m.body = "*****";
error_code ec;
@@ -499,7 +499,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
m.prepare();
BEAST_EXPECT(str(m) ==
@@ -516,7 +516,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
m.prepare(connection::keep_alive);
BEAST_EXPECT(str(m) ==
@@ -534,7 +534,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
try
{
@@ -552,7 +552,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 10;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
m.prepare();
test::string_ostream ss(ios_);
@@ -572,7 +572,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 11;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
m.prepare();
BEAST_EXPECT(str(m) ==
@@ -589,7 +589,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 11;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
m.prepare(connection::close);
test::string_ostream ss(ios_);
@@ -611,7 +611,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 11;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.prepare(connection::upgrade);
BEAST_EXPECT(str(m) ==
"GET / HTTP/1.1\r\n"
@@ -626,7 +626,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 11;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
m.prepare();
test::string_ostream ss(ios_);
@@ -651,7 +651,7 @@ public:
m.method(verb::get);
m.target("/");
m.version = 11;
m.insert("User-Agent", "test");
m.insert(field::user_agent, "test");
m.body = "*";
BEAST_EXPECT(boost::lexical_cast<std::string>(m) ==
"GET / HTTP/1.1\r\nUser-Agent: test\r\n\r\n*");
@@ -785,7 +785,7 @@ public:
m0.version = 11;
m0.result(status::ok);
m0.reason("OK");
m0.insert("Server", "test");
m0.insert(field::server, "test");
m0.body.s = "Hello, world!\n";
{