Distinguish HTTP/1 messages from general HTTP messages:

The version field is moved into message_v1, all public interfaces
are reworked to identify HTTP/1 wire format operations (suffix "_v1")
versus general HTTP.
This commit is contained in:
Vinnie Falco
2016-05-01 11:14:10 -04:00
parent cdde9b5ef1
commit c309f53ed2
42 changed files with 724 additions and 697 deletions

View File

@ -122,12 +122,14 @@ INPUT = \
../include/beast/write_streambuf.hpp \
../include/beast/http/basic_headers.hpp \
../include/beast/http/basic_parser.hpp \
../include/beast/http/body_writer.hpp \
../include/beast/http/chunk_encode.hpp \
../include/beast/http/empty_body.hpp \
../include/beast/http/error.hpp \
../include/beast/http/fields.hpp \
../include/beast/http/headers.hpp \
../include/beast/http/message.hpp \
../include/beast/http/message_v1.hpp \
../include/beast/http/method.hpp \
../include/beast/http/parse_error.hpp \
../include/beast/http/parser.hpp \

View File

@ -20,8 +20,7 @@
#ifndef BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
#define BEAST_EXAMPLE_FILE_BODY_H_INCLUDED
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/http/body_writer.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/filesystem.hpp>
#include <cstdio>
@ -44,7 +43,8 @@ struct file_body
std::size_t buf_len_;
public:
static bool constexpr is_single_pass = false;
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
writer(message<isRequest, file_body, Headers> const& m) noexcept

View File

@ -41,8 +41,8 @@ class http_async_server
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using req_type = request<string_body>;
using resp_type = response<file_body>;
using req_type = request_v1<string_body>;
using resp_type = response_v1<file_body>;
boost::asio::io_service ios_;
socket_type sock_;
@ -127,7 +127,7 @@ private:
path = root_ + path;
if(! boost::filesystem::exists(path))
{
response<string_body> resp(
response_v1<string_body> resp(
{404, "Not Found", req_.version});
resp.headers.replace("Server", "http_async_server");
resp.body = "The file '" + path + "' was not found";
@ -137,7 +137,7 @@ private:
asio::placeholders::error));
return;
}
response<file_body> resp(
resp_type resp(
{200, "OK", req_.version});
resp.headers.replace("Server", "http_async_server");
resp.headers.replace("Content-Type", "text/html");

View File

@ -46,13 +46,13 @@ int main(int, char const*[])
stream<ip::tcp::socket> hs(ios);
connect(hs.lowest_layer(), it);
auto ep = hs.lowest_layer().remote_endpoint();
request<empty_body> req({"GET", "/", 11});
request_v1<empty_body> req({"GET", "/", 11});
req.headers.insert("Host", host +
std::string(":") + std::to_string(ep.port()));
req.headers.insert("User-Agent", "beast/http");
prepare(req);
hs.write(req);
response<string_body> resp;
response_v1<string_body> resp;
hs.read(resp);
std::cout << resp;
}

View File

@ -23,7 +23,7 @@ int main()
using namespace beast::http;
// Send HTTP request using beast
request<empty_body> req({"GET", "/", 11});
request_v1<empty_body> req({"GET", "/", 11});
req.headers.replace("Host", host + ":" + std::to_string(sock.remote_endpoint().port()));
req.headers.replace("User-Agent", "Beast");
prepare(req);
@ -31,7 +31,7 @@ int main()
// Receive and print HTTP response using beast
beast::streambuf sb;
response<streambuf_body> resp;
response_v1<streambuf_body> resp;
read(sock, sb, resp);
std::cout << resp;
}

View File

@ -268,7 +268,7 @@ public:
*/
template<bool isRequest, class Body, class Headers>
void
read(message<isRequest, Body, Headers>& msg)
read(message_v1<isRequest, Body, Headers>& msg)
{
error_code ec;
read(msg, ec);
@ -295,7 +295,7 @@ public:
*/
template<bool isRequest, class Body, class Headers>
void
read(message<isRequest, Body, Headers>& msg,
read(message_v1<isRequest, Body, Headers>& msg,
error_code& ec);
/** Start reading a HTTP message from the stream asynchronously.
@ -339,7 +339,7 @@ public:
typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(message<isRequest, Body, Headers>& msg,
async_read(message_v1<isRequest, Body, Headers>& msg,
ReadHandler&& handler);
/** Write a HTTP message to the stream.
@ -365,7 +365,7 @@ public:
*/
template<bool isRequest, class Body, class Headers>
void
write(message<isRequest, Body, Headers> const& msg)
write(message_v1<isRequest, Body, Headers> const& msg)
{
error_code ec;
write(msg, ec);
@ -396,7 +396,7 @@ public:
*/
template<bool isRequest, class Body, class Headers>
void
write(message<isRequest, Body, Headers> const& msg,
write(message_v1<isRequest, Body, Headers> const& msg,
error_code& ec);
/** Start pipelining a HTTP message to the stream asynchronously.
@ -434,7 +434,7 @@ public:
typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
async_write(message<isRequest, Body, Headers> const& msg,
async_write(message_v1<isRequest, Body, Headers> const& msg,
WriteHandler&& handler);
/** Start pipelining a HTTP message to the stream asynchronously.
@ -473,7 +473,7 @@ public:
typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
async_write(message<isRequest, Body, Headers>&& msg,
async_write(message_v1<isRequest, Body, Headers>&& msg,
WriteHandler&& handler);
private:

View File

@ -20,10 +20,11 @@
#ifndef BEAST_HTTP_STREAM_IPP_INCLUDED
#define BEAST_HTTP_STREAM_IPP_INCLUDED
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/http/write.hpp>
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <cassert>
namespace beast {
@ -40,14 +41,14 @@ class stream<NextLayer, Allocator>::read_op
struct data
{
stream<NextLayer>& s;
message<isRequest, Body, Headers>& m;
message_v1<isRequest, Body, Headers>& m;
Handler h;
bool cont;
int state = 0;
template<class DeducedHandler>
data(DeducedHandler&& h_, stream<NextLayer>& s_,
message<isRequest, Body, Headers>& m_)
message_v1<isRequest, Body, Headers>& m_)
: s(s_)
, m(m_)
, h(std::forward<DeducedHandler>(h_))
@ -142,14 +143,14 @@ class stream<NextLayer, Allocator>::write_op : public op
struct data
{
stream<NextLayer>& s;
message<isRequest, Body, Headers> m;
message_v1<isRequest, Body, Headers> m;
Handler h;
bool cont;
int state = 0;
template<class DeducedHandler>
data(DeducedHandler&& h_, stream<NextLayer>& s_,
message<isRequest, Body, Headers> const& m_,
message_v1<isRequest, Body, Headers> const& m_,
bool cont_)
: s(s_)
, m(m_)
@ -160,7 +161,7 @@ class stream<NextLayer, Allocator>::write_op : public op
template<class DeducedHandler>
data(DeducedHandler&& h_, stream<NextLayer>& s_,
message<isRequest, Body, Headers>&& m_,
message_v1<isRequest, Body, Headers>&& m_,
bool cont_)
: s(s_)
, m(std::move(m_))
@ -305,7 +306,7 @@ template<class NextLayer, class Allocator>
template<bool isRequest, class Body, class Headers>
void
stream<NextLayer, Allocator>::
read(message<isRequest, Body, Headers>& msg,
read(message_v1<isRequest, Body, Headers>& msg,
error_code& ec)
{
beast::http::read(next_layer_, rd_buf_, msg, ec);
@ -316,7 +317,7 @@ template<bool isRequest, class Body, class Headers,
class ReadHandler>
auto
stream<NextLayer, Allocator>::
async_read(message<isRequest, Body, Headers>& msg,
async_read(message_v1<isRequest, Body, Headers>& msg,
ReadHandler&& handler) ->
typename async_completion<
ReadHandler, void(error_code)>::result_type
@ -334,7 +335,7 @@ template<class NextLayer, class Allocator>
template<bool isRequest, class Body, class Headers>
void
stream<NextLayer, Allocator>::
write(message<isRequest, Body, Headers> const& msg,
write(message_v1<isRequest, Body, Headers> const& msg,
error_code& ec)
{
beast::http::write(next_layer_, msg, ec);
@ -345,7 +346,7 @@ template<bool isRequest, class Body, class Headers,
class WriteHandler>
auto
stream<NextLayer, Allocator>::
async_write(message<isRequest, Body, Headers> const& msg,
async_write(message_v1<isRequest, Body, Headers> const& msg,
WriteHandler&& handler) ->
typename async_completion<
WriteHandler, void(error_code)>::result_type
@ -376,7 +377,7 @@ template<bool isRequest, class Body, class Headers,
class WriteHandler>
auto
stream<NextLayer, Allocator>::
async_write(message<isRequest, Body, Headers>&& msg,
async_write(message_v1<isRequest, Body, Headers>&& msg,
WriteHandler&& handler) ->
typename async_completion<
WriteHandler, void(error_code)>::result_type

View File

@ -43,8 +43,8 @@ class http_sync_server
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
using req_type = request<string_body>;
using resp_type = response<file_body>;
using req_type = request_v1<string_body>;
using resp_type = response_v1<file_body>;
boost::asio::io_service ios_;
socket_type sock_;
@ -155,7 +155,7 @@ public:
path = root_ + path;
if(! boost::filesystem::exists(path))
{
response<string_body> resp(
response_v1<string_body> resp(
{404, "Not Found", req.version});
resp.headers.replace("Server", "http_sync_server");
resp.body = "The file '" + path + "' was not found";
@ -164,7 +164,7 @@ public:
if(ec)
break;
}
response<file_body> resp(
resp_type resp(
{200, "OK", req.version});
resp.headers.replace("Server", "http_sync_server");
resp.headers.replace("Content-Type", "text/html");

View File

@ -9,13 +9,15 @@
#define BEAST_HTTP_HPP_INCLUDED
#include <beast/http/basic_headers.hpp>
#include <beast/http/basic_parser.hpp>
#include <beast/http/basic_parser_v1.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/error.hpp>
#include <beast/http/headers.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/parse_error.hpp>
#include <beast/http/parser.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/http/reason.hpp>
#include <beast/http/resume_context.hpp>

View File

@ -5,13 +5,13 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_BASIC_PARSER_HPP
#define BEAST_HTTP_BASIC_PARSER_HPP
#ifndef BEAST_HTTP_BASIC_PARSER_v1_HPP
#define BEAST_HTTP_BASIC_PARSER_v1_HPP
#include <beast/http/message.hpp>
#include <beast/http/parse_error.hpp>
#include <beast/http/rfc7230.hpp>
#include <beast/http/detail/basic_parser.hpp>
#include <beast/http/detail/basic_parser_v1.hpp>
#include <beast/type_check.hpp>
#include <boost/asio/buffer.hpp>
#include <array>
@ -37,7 +37,7 @@ enum values
};
} // parse_flag
/** Parser for producing HTTP requests and responses.
/** Base class for parsing HTTP/1 requests and responses.
During parsing, callbacks will be made to the derived class
if those members are present (detected through SFINAE). The
@ -84,7 +84,7 @@ enum values
@li `void on_complete(error_code& ec)`
Called when the entire message has been parsed successfully.
At this point, basic_parser::complete() returns `true`, and
At this point, basic_parser_v1::complete() returns `true`, and
the parser is ready to parse another message if keep_alive()
would return `true`.
@ -109,10 +109,10 @@ enum values
and the error is returned to the caller.
*/
template<bool isRequest, class Derived>
class basic_parser
class basic_parser_v1
{
private:
using self = basic_parser;
using self = basic_parser_v1;
typedef void(self::*pmf_t)(error_code&, boost::string_ref const&);
static std::uint64_t constexpr no_content_length =
@ -237,13 +237,13 @@ private:
public:
/// Copy constructor.
basic_parser(basic_parser const&) = default;
basic_parser_v1(basic_parser_v1 const&) = default;
/// Copy assignment.
basic_parser& operator=(basic_parser const&) = default;
basic_parser_v1& operator=(basic_parser_v1 const&) = default;
/// Constructor
basic_parser()
basic_parser_v1()
{
init(std::integral_constant<bool, isRequest>{});
}
@ -759,6 +759,6 @@ private:
} // http
} // beast
#include <beast/http/impl/basic_parser.ipp>
#include <beast/http/impl/basic_parser_v1.ipp>
#endif

View File

@ -0,0 +1,19 @@
//
// Copyright (c) 2013-2016 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_BODY_WRITER_HPP
#define BEAST_HTTP_BODY_WRITER_HPP
// Convenience header to include everything necessary for
// declaring an object meeting the BodyWriter requirements.
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <boost/logic/tribool.hpp>
#endif

View File

@ -5,8 +5,8 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
#define BEAST_HTTP_DETAIL_BASIC_PARSER_HPP
#ifndef BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
#define BEAST_HTTP_DETAIL_BASIC_PARSER_V1_HPP
#include <boost/system/error_code.hpp>
#include <boost/utility/string_ref.hpp>

View File

@ -0,0 +1,43 @@
//
// Copyright (c) 2013-2016 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_DETAIL_HAS_CONTENT_LENGTH_HPP
#define BEAST_HTTP_DETAIL_HAS_CONTENT_LENGTH_HPP
#include <cstdint>
#include <type_traits>
namespace beast {
namespace http {
namespace detail {
template<class T>
class has_content_length_value
{
template<class U, class R = typename std::is_convertible<
decltype(std::declval<U>().content_length()),
std::uint64_t>>
static R check(int);
template <class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
// `true` if `T` meets the requirements.
static bool const value = type::value;
};
// Determines if the writer can provide the content length
template<class T>
using has_content_length =
std::integral_constant<bool,
has_content_length_value<T>::value>;
} // detail
} // http
} // beast
#endif

View File

@ -1,83 +0,0 @@
//
// Copyright (c) 2013-2016 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_DETAIL_WRITE_PREPARATION_HPP
#define BEAST_HTTP_DETAIL_WRITE_PREPARATION_HPP
#include <beast/http/error.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/streambuf.hpp>
#include <beast/write_streambuf.hpp>
namespace beast {
namespace http {
namespace detail {
template<class T>
class has_content_length_value
{
template<class U, class R = typename std::is_convertible<
decltype(std::declval<U>().content_length()),
std::size_t>>
static R check(int);
template <class>
static std::false_type check(...);
using type = decltype(check<T>(0));
public:
// `true` if `T` meets the requirements.
static bool const value = type::value;
};
// Determines if the writer can provide the content length
template<class T>
using has_content_length =
std::integral_constant<bool,
has_content_length_value<T>::value>;
template<bool isRequest, class Body, class Headers>
struct write_preparation
{
using headers_type =
basic_headers<std::allocator<char>>;
message<isRequest, Body, Headers> const& msg;
typename Body::writer w;
streambuf sb;
bool chunked;
bool close;
explicit
write_preparation(
message<isRequest, Body, Headers> const& msg_)
: msg(msg_)
, w(msg)
, chunked(rfc2616::token_in_list(
msg.headers["Transfer-Encoding"], "chunked"))
, close(rfc2616::token_in_list(
msg.headers["Connection"], "close") ||
(msg.version < 11 && ! msg.headers.exists(
"Content-Length")))
{
}
void
init(error_code& ec)
{
w.init(ec);
if(ec)
return;
msg.write_firstline(sb);
write_fields(sb, msg.headers);
beast::write(sb, "\r\n");
}
};
} // detail
} // http
} // beast
#endif

View File

@ -8,8 +8,7 @@
#ifndef BEAST_HTTP_EMPTY_BODY_HPP
#define BEAST_HTTP_EMPTY_BODY_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/streambuf.hpp>
#include <boost/asio/buffer.hpp>
#include <memory>
@ -35,9 +34,9 @@ private:
struct reader
{
template<bool isRequest, class Allocator>
template<bool isRequest, class Headers>
explicit
reader(message<isRequest, empty_body, Allocator>&)
reader(message<isRequest, empty_body, Headers>&)
{
}
@ -49,9 +48,12 @@ private:
struct writer
{
template<bool isRequest, class Allocator>
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<isRequest, empty_body, Allocator> const& m)
writer(message<isRequest, empty_body, Headers> const& m)
{
}

View File

@ -5,15 +5,15 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_IPP
#ifndef BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
#define BEAST_HTTP_IMPL_BASIC_PARSER_V1_IPP
namespace beast {
namespace http {
template<bool isRequest, class Derived>
bool
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
keep_alive() const
{
if(http_major_ > 0 && http_minor_ > 0)
@ -34,7 +34,7 @@ keep_alive() const
template<bool isRequest, class Derived>
template<class ConstBufferSequence, class>
std::size_t
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
write(ConstBufferSequence const& buffers, error_code& ec)
{
static_assert(is_ConstBufferSequence<ConstBufferSequence>::value,
@ -51,7 +51,7 @@ write(ConstBufferSequence const& buffers, error_code& ec)
template<bool isRequest, class Derived>
std::size_t
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
write(boost::asio::const_buffer const& buffer, error_code& ec)
{
using beast::http::detail::is_digit;
@ -1022,7 +1022,7 @@ write(boost::asio::const_buffer const& buffer, error_code& ec)
template<bool isRequest, class Derived>
void
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
write_eof(error_code& ec)
{
switch(s_)
@ -1042,7 +1042,7 @@ write_eof(error_code& ec)
template<bool isRequest, class Derived>
bool
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
needs_eof(std::true_type) const
{
return false;
@ -1050,7 +1050,7 @@ needs_eof(std::true_type) const
template<bool isRequest, class Derived>
bool
basic_parser<isRequest, Derived>::
basic_parser_v1<isRequest, Derived>::
needs_eof(std::false_type) const
{
// See RFC 2616 section 4.4

View File

@ -5,33 +5,21 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_IMPL_MESSAGE_IPP
#define BEAST_HTTP_IMPL_MESSAGE_IPP
#ifndef BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#define BEAST_HTTP_IMPL_MESSAGE_V1_IPP
#include <beast/http/resume_context.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/write_streambuf.hpp>
#include <beast/http/detail/has_content_length.hpp>
#include <beast/type_check.hpp>
#include <beast/http/detail/write_preparation.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/logic/tribool.hpp>
#include <boost/optional.hpp>
#include <condition_variable>
#include <mutex>
#include <stdexcept>
namespace beast {
namespace http {
template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message()
{
}
template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message(request_params params)
message_v1<isRequest, Body, Headers>::
message_v1(request_params params)
{
static_assert(isRequest, "message is not a request");
this->method = params.method;
@ -40,8 +28,8 @@ message(request_params params)
}
template<bool isRequest, class Body, class Headers>
message<isRequest, Body, Headers>::
message(response_params params)
message_v1<isRequest, Body, Headers>::
message_v1(response_params params)
{
static_assert(! isRequest, "message is not a response");
this->status = params.status;
@ -49,126 +37,11 @@ message(response_params params)
version = params.version;
}
template<bool isRequest, class Body, class Headers>
template<class Streambuf>
void
message<isRequest, Body, Headers>::
write_firstline(Streambuf& streambuf,
std::true_type) const
{
write(streambuf, this->method);
write(streambuf, " ");
write(streambuf, this->url);
switch(version)
{
case 10:
write(streambuf, " HTTP/1.0\r\n");
break;
case 11:
write(streambuf, " HTTP/1.1\r\n");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, version / 10);
write(streambuf, ".");
write(streambuf, version % 10);
write(streambuf, "\r\n");
break;
}
}
template<bool isRequest, class Body, class Headers>
template<class Streambuf>
void
message<isRequest, Body, Headers>::
write_firstline(Streambuf& streambuf,
std::false_type) const
{
switch(version)
{
case 10:
write(streambuf, "HTTP/1.0 ");
break;
case 11:
write(streambuf, "HTTP/1.1 ");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, version / 10);
write(streambuf, ".");
write(streambuf, version % 10);
write(streambuf, " ");
break;
}
write(streambuf, this->status);
write(streambuf, " ");
write(streambuf, this->reason);
write(streambuf, "\r\n");
}
//------------------------------------------------------------------------------
template<bool isRequest, class Body, class Headers>
void
set_connection(bool keep_alive,
message<isRequest, Body, Headers>& req)
{
if(req.version >= 11)
{
if(! keep_alive)
req.headers.replace("Connection", "close");
else
req.headers.erase("Connection");
}
else
{
if(keep_alive)
req.headers.replace("Connection", "keep-alive");
else
req.headers.erase("Connection");
}
}
template<class Body, class Headers,
class OtherBody, class OtherAllocator>
void
set_connection(bool keep_alive,
message<false, Body, Headers>& resp,
message<true, OtherBody, OtherAllocator> const& req)
{
if(req.version >= 11)
{
if(rfc2616::token_in_list(req["Connection"], "close"))
keep_alive = false;
}
else
{
if(! rfc2616::token_in_list(req["Connection"], "keep-alive"))
keep_alive = false;
}
set_connection(keep_alive, resp);
}
template<class Streambuf, class FieldSequence>
void
write_fields(Streambuf& streambuf, FieldSequence const& fields)
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
//static_assert(is_FieldSequence<FieldSequence>::value,
// "FieldSequence requirements not met");
for(auto const& field : fields)
{
write(streambuf, field.name());
write(streambuf, ": ");
write(streambuf, field.value());
write(streambuf, "\r\n");
}
}
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message<isRequest, Body, Headers> const& msg)
is_keep_alive(message_v1<isRequest, Body, Headers> const& msg)
{
if(msg.version >= 11)
{
@ -185,7 +58,7 @@ is_keep_alive(message<isRequest, Body, Headers> const& msg)
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message<isRequest, Body, Headers> const& msg)
is_upgrade(message_v1<isRequest, Body, Headers> const& msg)
{
if(msg.version < 11)
return false;
@ -207,14 +80,14 @@ template<bool isRequest, class Body, class Headers>
inline
void
prepare_options(prepare_info& pi,
message<isRequest, Body, Headers>& msg)
message_v1<isRequest, Body, Headers>& msg)
{
}
template<bool isRequest, class Body, class Headers>
void
prepare_option(prepare_info& pi,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
connection value)
{
pi.connection_value = value;
@ -225,7 +98,7 @@ template<
class Opt, class... Opts>
void
prepare_options(prepare_info& pi,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
Opt&& opt, Opts&&... opts)
{
prepare_option(pi, msg, opt);
@ -236,7 +109,7 @@ prepare_options(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_content_length(prepare_info& pi,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
std::true_type)
{
typename Body::writer w(msg);
@ -247,7 +120,7 @@ prepare_content_length(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_content_length(prepare_info& pi,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
std::false_type)
{
pi.content_length = boost::none;
@ -258,7 +131,7 @@ prepare_content_length(prepare_info& pi,
template<bool isRequest, class Body, class Headers>
void
prepare_connection(
message<isRequest, Body, Headers>& msg)
message_v1<isRequest, Body, Headers>& msg)
{
if(msg.version >= 11)
{
@ -286,7 +159,7 @@ template<
bool isRequest, class Body, class Headers,
class... Options>
void
prepare(message<isRequest, Body, Headers>& msg,
prepare(message_v1<isRequest, Body, Headers>& msg,
Options&&... options)
{
// VFALCO TODO

View File

@ -8,6 +8,7 @@
#ifndef BEAST_HTTP_IMPL_READ_IPP_HPP
#define BEAST_HTTP_IMPL_READ_IPP_HPP
#include <beast/http/parser_v1.hpp>
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <cassert>
@ -26,10 +27,10 @@ class read_op
handler_alloc<char, Handler>;
using parser_type =
parser<isRequest, Body, Headers>;
parser_v1<isRequest, Body, Headers>;
using message_type =
message<isRequest, Body, Headers>;
message_v1<isRequest, Body, Headers>;
struct data
{
@ -214,14 +215,14 @@ template<class SyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& m,
message_v1<isRequest, Body, Headers>& m,
error_code& ec)
{
static_assert(is_SyncReadStream<SyncReadStream>::value,
"SyncReadStream requirements not met");
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
parser<isRequest, Body, Headers> p;
parser_v1<isRequest, Body, Headers> p;
bool started = false;
for(;;)
{
@ -264,7 +265,7 @@ template<class AsyncReadStream, class Streambuf,
typename async_completion<
ReadHandler, void(error_code)>::result_type
async_read(AsyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& m,
message_v1<isRequest, Body, Headers>& m,
ReadHandler&& handler)
{
static_assert(is_AsyncReadStream<AsyncReadStream>::value,

View File

@ -10,12 +10,13 @@
#include <beast/http/resume_context.hpp>
#include <beast/http/detail/chunk_encode.hpp>
#include <beast/http/detail/write_preparation.hpp>
#include <beast/http/detail/has_content_length.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/bind_handler.hpp>
#include <beast/handler_alloc.hpp>
#include <beast/streambuf.hpp>
#include <beast/type_check.hpp>
#include <beast/write_streambuf.hpp>
#include <boost/asio/write.hpp>
#include <boost/logic/tribool.hpp>
#include <condition_variable>
@ -29,6 +30,114 @@ namespace http {
namespace detail {
template<class Streambuf, class Body, class Headers>
void
write_firstline(Streambuf& streambuf,
message_v1<true, Body, Headers> const& msg)
{
write(streambuf, msg.method);
write(streambuf, " ");
write(streambuf, msg.url);
switch(msg.version)
{
case 10:
write(streambuf, " HTTP/1.0\r\n");
break;
case 11:
write(streambuf, " HTTP/1.1\r\n");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, msg.version / 10);
write(streambuf, ".");
write(streambuf, msg.version % 10);
write(streambuf, "\r\n");
break;
}
}
template<class Streambuf, class Body, class Headers>
void
write_firstline(Streambuf& streambuf,
message_v1<false, Body, Headers> const& msg)
{
switch(msg.version)
{
case 10:
write(streambuf, "HTTP/1.0 ");
break;
case 11:
write(streambuf, "HTTP/1.1 ");
break;
default:
write(streambuf, " HTTP/");
write(streambuf, msg.version / 10);
write(streambuf, ".");
write(streambuf, msg.version % 10);
write(streambuf, " ");
break;
}
write(streambuf, msg.status);
write(streambuf, " ");
write(streambuf, msg.reason);
write(streambuf, "\r\n");
}
template<class Streambuf, class FieldSequence>
void
write_fields(Streambuf& streambuf, FieldSequence const& fields)
{
static_assert(is_Streambuf<Streambuf>::value,
"Streambuf requirements not met");
//static_assert(is_FieldSequence<FieldSequence>::value,
// "FieldSequence requirements not met");
for(auto const& field : fields)
{
write(streambuf, field.name());
write(streambuf, ": ");
write(streambuf, field.value());
write(streambuf, "\r\n");
}
}
template<bool isRequest, class Body, class Headers>
struct write_preparation
{
using headers_type =
basic_headers<std::allocator<char>>;
message_v1<isRequest, Body, Headers> const& msg;
typename Body::writer w;
streambuf sb;
bool chunked;
bool close;
explicit
write_preparation(
message_v1<isRequest, Body, Headers> const& msg_)
: msg(msg_)
, w(msg)
, chunked(rfc2616::token_in_list(
msg.headers["Transfer-Encoding"], "chunked"))
, close(rfc2616::token_in_list(
msg.headers["Connection"], "close") ||
(msg.version < 11 && ! msg.headers.exists(
"Content-Length")))
{
}
void
init(error_code& ec)
{
w.init(ec);
if(ec)
return;
write_firstline(sb, msg);
write_fields(sb, msg.headers);
beast::write(sb, "\r\n");
}
};
template<class Stream, class Handler,
bool isRequest, class Body, class Headers>
class write_op
@ -50,7 +159,7 @@ class write_op
template<class DeducedHandler>
data(DeducedHandler&& h_, Stream& s_,
message<isRequest, Body, Headers> const& m_)
message_v1<isRequest, Body, Headers> const& m_)
: s(s_)
, wp(m_)
, h(std::forward<DeducedHandler>(h_))
@ -356,7 +465,21 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
"SyncWriteStream requirements not met");
error_code ec;
write(stream, msg, ec);
if(ec)
throw boost::system::system_error{ec};
}
template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message_v1<isRequest, Body, Headers> const& msg,
boost::system::error_code& ec)
{
static_assert(is_SyncWriteStream<SyncWriteStream>::value,
@ -441,7 +564,7 @@ template<class AsyncWriteStream,
typename async_completion<
WriteHandler, void(error_code)>::result_type
async_write(AsyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
WriteHandler&& handler)
{
static_assert(
@ -506,7 +629,7 @@ public:
template<bool isRequest, class Body, class Headers>
std::ostream&
operator<<(std::ostream& os,
message<isRequest, Body, Headers> const& msg)
message_v1<isRequest, Body, Headers> const& msg)
{
detail::ostream_SyncStream oss(os);
error_code ec;

View File

@ -32,24 +32,6 @@ struct response_fields
} // detail
#if ! GENERATING_DOCS
struct request_params
{
std::string method;
std::string url;
int version;
};
struct response_params
{
int status;
std::string reason;
int version;
};
#endif
/** A HTTP message.
A message can be a request or response, depending on the `isRequest`
@ -70,62 +52,24 @@ struct message
: std::conditional<isRequest,
detail::request_fields, detail::response_fields>::type
{
/** The trait type characterizing the body.
/** The type controlling the body traits.
The body member will be of type body_type::value_type.
The body member will be of type `body_type::value_type`.
*/
using body_type = Body;
/// The type representing the headers.
using headers_type = Headers;
/// Indicates if the message is a request.
using is_request =
std::integral_constant<bool, isRequest>;
int version; // 10 or 11
/// The container holding the headers.
headers_type headers;
/// A container representing the body.
typename Body::value_type body;
message();
message(message&&) = default;
message(message const&) = default;
message& operator=(message&&) = default;
message& operator=(message const&) = default;
/** Construct a HTTP request.
*/
explicit
message(request_params params);
/** Construct a HTTP response.
*/
explicit
message(response_params params);
/// Serialize the request or response line to a Streambuf.
template<class Streambuf>
void
write_firstline(Streambuf& streambuf) const
{
write_firstline(streambuf,
std::integral_constant<bool, isRequest>{});
}
/// Diagnostics only
template<bool, class, class>
friend
std::ostream&
operator<<(std::ostream& os,
message const& m);
private:
template<class Streambuf>
void
write_firstline(Streambuf& streambuf,
std::true_type) const;
template<class Streambuf>
void
write_firstline(Streambuf& streambuf,
std::false_type) const;
};
#if ! GENERATING_DOCS
@ -142,53 +86,7 @@ using response = message<false, Body, Headers>;
#endif
/// Write a FieldSequence to a Streambuf.
template<class Streambuf, class FieldSequence>
void
write_fields(Streambuf& streambuf, FieldSequence const& fields);
/// Returns `true` if a message indicates a keep alive
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message<isRequest, Body, Headers> const& msg);
/// Returns `true` if a message indicates a HTTP Upgrade request or response
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message<isRequest, Body, Headers> const& msg);
/** Connection prepare options.
These values are used with prepare().
*/
enum class connection
{
/// Indicates the message should specify Connection: close semantics
close,
/// Indicates the message should specify Connection: keep-alive semantics if possible
keep_alive,
/// Indicates the message should specify a Connection: upgrade
upgrade
};
/** Prepare a message.
This function will adjust the Content-Length, Transfer-Encoding,
and Connection headers of the message based on the properties of
the body and the options passed in.
*/
template<
bool isRequest, class Body, class Headers,
class... Options>
void
prepare(message<isRequest, Body, Headers>& msg,
Options&&... options);
} // http
} // beast
#include <beast/http/impl/message.ipp>
#endif

View File

@ -0,0 +1,131 @@
//
// Copyright (c) 2013-2016 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_MESSAGE_V1_HPP
#define BEAST_HTTP_MESSAGE_V1_HPP
#include <beast/http/message.hpp>
#include <beast/type_check.hpp>
#include <memory>
#include <string>
namespace beast {
namespace http {
#if ! GENERATING_DOCS
struct request_params
{
std::string method;
std::string url;
int version;
};
struct response_params
{
int status;
std::string reason;
int version;
};
#endif
/** A HTTP/1 message.
A message can be a request or response, depending on the `isRequest`
template argument value. Requests and responses have different types,
so functions may be overloaded on them if desired.
The `Body` template argument type determines the model used
to read or write the content body of the message.
@tparam isRequest `true` if this is a request.
@tparam Body A type meeting the requirements of Body.
@tparam Headers A type meeting the requirements of Headers.
*/
template<bool isRequest, class Body, class Headers>
struct message_v1 : message<isRequest, Body, Headers>
{
/// HTTP/1 version (10 or 11)
int version;
message_v1() = default;
/// Construct a HTTP/1 request.
explicit
message_v1(request_params params);
/// Construct a HTTP/1 response.
explicit
message_v1(response_params params);
};
#if ! GENERATING_DOCS
/// A typical HTTP/1 request
template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using request_v1 = message_v1<true, Body, Headers>;
/// A typical HTTP/1 response
template<class Body,
class Headers = basic_headers<std::allocator<char>>>
using response_v1 = message_v1<false, Body, Headers>;
#endif
/// Returns `true` if a HTTP/1 message indicates a keep alive
template<bool isRequest, class Body, class Headers>
bool
is_keep_alive(message_v1<isRequest, Body, Headers> const& msg);
/// Returns `true` if a HTTP/1 message indicates an Upgrade request or response
template<bool isRequest, class Body, class Headers>
bool
is_upgrade(message_v1<isRequest, Body, Headers> const& msg);
/** HTTP/1 connection prepare options.
@note These values are used with `prepare`.
*/
enum class connection
{
/// Specify Connection: close.
close,
/// Specify Connection: keep-alive where possible.
keep_alive,
/// Specify Connection: upgrade.
upgrade
};
/** Prepare a HTTP/1 message.
This function will adjust the Content-Length, Transfer-Encoding,
and Connection headers of the message based on the properties of
the body and the options passed in.
@param msg The message to prepare. The headers may be modified.
@param options A list of prepare options.
*/
template<
bool isRequest, class Body, class Headers,
class... Options>
void
prepare(message_v1<isRequest, Body, Headers>& msg,
Options&&... options);
} // http
} // beast
#include <beast/http/impl/message_v1.ipp>
#endif

View File

@ -5,12 +5,12 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BEAST_HTTP_PARSER_HPP
#define BEAST_HTTP_PARSER_HPP
#ifndef BEAST_HTTP_PARSER_V1_HPP
#define BEAST_HTTP_PARSER_V1_HPP
#include <beast/http/basic_parser.hpp>
#include <beast/http/basic_parser_v1.hpp>
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <boost/optional.hpp>
#include <functional>
#include <string>
@ -35,15 +35,20 @@ struct parser_response
} // detail
/** A parser for producing HTTP/1 messages.
This class uses the basic HTTP/1 wire format parser to convert
a series of octets into a `message_v1`.
*/
template<bool isRequest, class Body, class Headers>
class parser
: public basic_parser<isRequest,
parser<isRequest, Body, Headers>>
class parser_v1
: public basic_parser_v1<isRequest,
parser_v1<isRequest, Body, Headers>>
, private std::conditional<isRequest,
detail::parser_request, detail::parser_response>::type
{
using message_type =
message<isRequest, Body, Headers>;
message_v1<isRequest, Body, Headers>;
std::string field_;
std::string value_;
@ -51,9 +56,9 @@ class parser
typename message_type::body_type::reader r_;
public:
parser(parser&&) = default;
parser_v1(parser_v1&&) = default;
parser()
parser_v1()
: r_(m_)
{
}
@ -65,7 +70,7 @@ public:
}
private:
friend class basic_parser<isRequest, parser>;
friend class basic_parser_v1<isRequest, parser_v1>;
void flush()
{

View File

@ -8,16 +8,16 @@
#ifndef BEAST_HTTP_READ_HPP
#define BEAST_HTTP_READ_HPP
#include <beast/async_completion.hpp>
#include <beast/http/error.hpp>
#include <beast/http/parser.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/async_completion.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/system/error_code.hpp>
namespace beast {
namespace http {
/** Read a HTTP message from a stream.
/** Read a HTTP/1 message from a stream.
@param stream The stream to read the message from.
@ -35,7 +35,7 @@ template<class SyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& msg)
message_v1<isRequest, Body, Headers>& msg)
{
error_code ec;
read(stream, streambuf, msg, ec);
@ -61,7 +61,7 @@ template<class SyncReadStream, class Streambuf,
bool isRequest, class Body, class Headers>
void
read(SyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
error_code& ec);
/** Start reading a HTTP message from a stream asynchronously.
@ -97,7 +97,7 @@ typename async_completion<
ReadHandler, void(error_code)>::result_type
#endif
async_read(AsyncReadStream& stream, Streambuf& streambuf,
message<isRequest, Body, Headers>& msg,
message_v1<isRequest, Body, Headers>& msg,
ReadHandler&& handler);
} // http

View File

@ -8,8 +8,7 @@
#ifndef BEAST_HTTP_STREAMBUF_BODY_HPP
#define BEAST_HTTP_STREAMBUF_BODY_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/streambuf.hpp>
#include <memory>
@ -59,10 +58,13 @@ private:
Streambuf const& body_;
public:
template<bool isRequest, class Allocator>
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<isRequest, basic_streambuf_body,
Allocator> const& m)
writer(message<
isRequest, basic_streambuf_body, Headers> const& m)
: body_(m.body)
{
}

View File

@ -8,9 +8,7 @@
#ifndef BEAST_HTTP_STRING_BODY_HPP
#define BEAST_HTTP_STRING_BODY_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/resume_context.hpp>
#include <beast/http/body_writer.hpp>
#include <beast/buffer_cat.hpp>
#include <beast/streambuf.hpp>
#include <memory>
@ -58,9 +56,13 @@ private:
value_type const& body_;
public:
template<bool isRequest, class Allocator>
writer(writer const&) = delete;
writer& operator=(writer const&) = delete;
template<bool isRequest, class Headers>
explicit
writer(message<isRequest, string_body, Allocator> const& msg)
writer(message<
isRequest, string_body, Headers> const& msg)
: body_(msg.body)
{
}

View File

@ -9,9 +9,8 @@
#define BEAST_HTTP_WRITE_HPP
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/async_completion.hpp>
#include <beast/type_check.hpp>
#include <boost/system/error_code.hpp>
#include <ostream>
#include <type_traits>
@ -19,7 +18,7 @@
namespace beast {
namespace http {
/** Write a HTTP message to a stream.
/** Write a HTTP/1 message to a stream.
@param stream The stream to send the message on.
@ -31,15 +30,9 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg)
{
error_code ec;
write(stream, msg, ec);
if(ec)
throw boost::system::system_error{ec};
}
message_v1<isRequest, Body, Headers> const& msg);
/** Write a HTTP message to a stream.
/** Write a HTTP/1 message to a stream.
@param stream The stream to send the message on.
@ -51,10 +44,10 @@ template<class SyncWriteStream,
bool isRequest, class Body, class Headers>
void
write(SyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
error_code& ec);
/** Start writing a HTTP message to a stream asynchronously.
/** Start writing a HTTP/1 message to a stream asynchronously.
@param stream The stream to send the message on.
@ -84,12 +77,12 @@ typename async_completion<
WriteHandler, void(error_code)>::result_type
#endif
async_write(AsyncWriteStream& stream,
message<isRequest, Body, Headers> const& msg,
message_v1<isRequest, Body, Headers> const& msg,
WriteHandler&& handler);
/** Serialize a message to an ostream.
/** Serialize a HTTP/1 message to an ostream.
The function converts the message to its HTTP/1.* serialized
The function converts the message to its HTTP/1 serialized
representation and stores the result in the output stream.
@param os The ostream to write to.
@ -99,7 +92,7 @@ async_write(AsyncWriteStream& stream,
template<bool isRequest, class Body, class Headers>
std::ostream&
operator<<(std::ostream& os,
message<isRequest, Body, Headers> const& msg);
message_v1<isRequest, Body, Headers> const& msg);
} // http
} // beast

View File

@ -9,10 +9,11 @@
#define BEAST_WEBSOCKET_IMPL_ACCEPT_OP_HPP
#include <beast/websocket/impl/response_op.ipp>
#include <beast/http/message_v1.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/handler_alloc.hpp>
#include <beast/prepare_buffers.hpp>
#include <beast/http/parser.hpp>
#include <beast/http/read.hpp>
#include <cassert>
#include <memory>
#include <type_traits>
@ -32,7 +33,7 @@ class stream<NextLayer>::accept_op
struct data
{
stream<NextLayer>& ws;
http::request<http::empty_body> req;
http::request_v1<http::empty_body> req;
Handler h;
bool cont;
int state = 0;

View File

@ -10,7 +10,7 @@
#include <beast/handler_alloc.hpp>
#include <beast/http/empty_body.hpp>
#include <beast/http/message.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/read.hpp>
#include <beast/http/write.hpp>
#include <cassert>
@ -33,8 +33,8 @@ class stream<NextLayer>::handshake_op
stream<NextLayer>& ws;
Handler h;
std::string key;
http::request<http::empty_body> req;
http::response<http::string_body> resp;
http::request_v1<http::empty_body> req;
http::response_v1<http::string_body> resp;
bool cont;
int state = 0;

View File

@ -9,6 +9,7 @@
#define BEAST_WEBSOCKET_IMPL_RESPONSE_OP_HPP
#include <beast/handler_alloc.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/string_body.hpp>
#include <beast/http/write.hpp>
#include <memory>
@ -27,7 +28,7 @@ class stream<NextLayer>::response_op
struct data
{
stream<NextLayer>& ws;
http::response<http::string_body> resp;
http::response_v1<http::string_body> resp;
Handler h;
error_code final_ec;
bool cont;
@ -36,7 +37,7 @@ class stream<NextLayer>::response_op
template<class DeducedHandler,
class Body, class Headers>
data(DeducedHandler&& h_, stream<NextLayer>& ws_,
http::message<true, Body, Headers> const& req,
http::request_v1<Body, Headers> const& req,
bool cont_)
: ws(ws_)
, resp(ws_.build_response(req))

View File

@ -241,7 +241,7 @@ accept(ConstBufferSequence const& buffers, error_code& ec)
stream_.buffer().commit(buffer_copy(
stream_.buffer().prepare(
buffer_size(buffers)), buffers));
http::request<http::empty_body> m;
http::request_v1<http::empty_body> m;
http::read(next_layer(), stream_.buffer(), m, ec);
if(ec)
return;
@ -272,7 +272,7 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
accept(http::message<true, Body, Headers> const& request)
accept(http::request_v1<Body, Headers> const& request)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
@ -285,12 +285,12 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
accept(http::message<true, Body, Headers> const& req,
accept(http::request_v1<Body, Headers> const& req,
error_code& ec)
{
static_assert(is_SyncStream<next_layer_type>::value,
"SyncStream requirements not met");
auto resp = build_response(req);
auto const resp = build_response(req);
http::write(stream_, resp, ec);
if(resp.status != 101)
{
@ -307,7 +307,7 @@ template<class Body, class Headers, class AcceptHandler>
typename async_completion<
AcceptHandler, void(error_code)>::result_type
stream<NextLayer>::
async_accept(http::message<true, Body, Headers> const& req,
async_accept(http::request_v1<Body, Headers> const& req,
AcceptHandler&& handler)
{
static_assert(is_AsyncStream<next_layer_type>::value,
@ -348,7 +348,7 @@ handshake(boost::string_ref const& host,
build_request(host, resource, key), ec);
if(ec)
return;
http::response<http::string_body> resp;
http::response_v1<http::string_body> resp;
http::read(next_layer(), stream_.buffer(), resp, ec);
if(ec)
return;
@ -826,12 +826,12 @@ async_write_frame(bool fin,
//------------------------------------------------------------------------------
template<class NextLayer>
http::request<http::empty_body>
http::request_v1<http::empty_body>
stream<NextLayer>::
build_request(boost::string_ref const& host,
boost::string_ref const& resource, std::string& key)
{
http::request<http::empty_body> req;
http::request_v1<http::empty_body> req;
req.url = "/";
req.version = 11;
req.method = "GET";
@ -847,14 +847,14 @@ build_request(boost::string_ref const& host,
template<class NextLayer>
template<class Body, class Headers>
http::response<http::string_body>
http::response_v1<http::string_body>
stream<NextLayer>::
build_response(http::message<true, Body, Headers> const& req)
build_response(http::request_v1<Body, Headers> const& req)
{
auto err =
[&](std::string const& text)
{
http::response<http::string_body> resp(
http::response_v1<http::string_body> resp(
{400, http::reason_string(400), req.version});
resp.body = text;
// VFALCO TODO respect keep-alive here
@ -881,7 +881,7 @@ build_response(http::message<true, Body, Headers> const& req)
if(! rfc2616::token_in_list(
req.headers["Upgrade"], "websocket"))
return err("Missing websocket Upgrade token");
http::response<http::string_body> resp(
http::response_v1<http::string_body> resp(
{101, http::reason_string(101), req.version});
resp.headers.insert("Upgrade", "websocket");
{
@ -901,7 +901,7 @@ template<class NextLayer>
template<class Body, class Headers>
void
stream<NextLayer>::
do_response(http::message<false, Body, Headers> const& resp,
do_response(http::response_v1<Body, Headers> const& resp,
boost::string_ref const& key, error_code& ec)
{
// VFALCO Review these error codes

View File

@ -10,11 +10,11 @@
#include <beast/websocket/option.hpp>
#include <beast/websocket/detail/stream_base.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/string_body.hpp>
#include <beast/streambuf_readstream.hpp>
#include <beast/async_completion.hpp>
#include <beast/detail/get_lowest_layer.hpp>
#include <beast/http/message.hpp>
#include <beast/http/string_body.hpp>
#include <boost/asio.hpp>
#include <boost/utility/string_ref.hpp>
#include <algorithm>
@ -495,8 +495,7 @@ public:
// VFALCO TODO This should also take a streambuf with any leftover bytes.
template<class Body, class Headers>
void
accept(http::message<true,
Body, Headers> const& request);
accept(http::request_v1<Body, Headers> const& request);
/** Respond to a WebSocket HTTP Upgrade request
@ -525,8 +524,8 @@ public:
*/
template<class Body, class Headers>
void
accept(http::message<true,
Body, Headers> const& request, error_code& ec);
accept(http::request_v1<Body, Headers> const& request,
error_code& ec);
/** Start reading and responding to a WebSocket HTTP Upgrade request.
@ -560,8 +559,8 @@ public:
template<class Body, class Headers, class AcceptHandler>
typename async_completion<
AcceptHandler, void(error_code)>::result_type
async_accept(http::message<true,
Body, Headers> const& request, AcceptHandler&& handler);
async_accept(http::request_v1<Body, Headers> const& request,
AcceptHandler&& handler);
/** Send a WebSocket Upgrade request.
@ -1129,18 +1128,18 @@ private:
template<class Buffers, class Handler> class write_op;
template<class Buffers, class Handler> class write_frame_op;
http::request<http::empty_body>
http::request_v1<http::empty_body>
build_request(boost::string_ref const& host,
boost::string_ref const& resource,
std::string& key);
template<class Body, class Headers>
http::response<http::string_body>
build_response(http::message<true, Body, Headers> const& req);
http::response_v1<http::string_body>
build_response(http::request_v1<Body, Headers> const& req);
template<class Body, class Headers>
void
do_response(http::message<false, Body, Headers> const& resp,
do_response(http::response_v1<Body, Headers> const& resp,
boost::string_ref const& key, error_code& ec);
void

View File

@ -33,11 +33,12 @@ add_executable (http-tests
${BEAST_INCLUDES}
main.cpp
http/basic_headers.cpp
http/basic_parser.cpp
http/basic_parser_v1.cpp
http/empty_body.cpp
http/error.cpp
http/headers.cpp
http/message.cpp
http/message_v1.cpp
http/parse_error.cpp
http/parser.cpp
http/read.cpp

View File

@ -31,11 +31,12 @@ unit-test core-tests :
unit-test http-tests :
main.cpp
http/basic_headers.cpp
http/basic_parser.cpp
http/basic_parser_v1.cpp
http/empty_body.cpp
http/error.cpp
http/headers.cpp
http/message.cpp
http/message_v1.cpp
http/parse_error.cpp
http/parser.cpp
http/read.cpp

View File

@ -6,7 +6,7 @@
//
// Test that header file is self-contained.
#include <beast/http/basic_parser.hpp>
#include <beast/http/basic_parser_v1.hpp>
#include "message_fuzz.hpp"
@ -27,7 +27,7 @@
namespace beast {
namespace http {
class basic_parser_test : public beast::detail::unit_test::suite
class basic_parser_v1_test : public beast::detail::unit_test::suite
{
std::mt19937 rng_;
@ -47,9 +47,9 @@ public:
template<bool isRequest>
struct cb_checker
: public basic_parser<isRequest, cb_checker<isRequest>>
: public basic_parser_v1<isRequest, cb_checker<isRequest>>
, std::conditional<isRequest,
cb_req_checker, cb_res_checker>::type
cb_req_checker, cb_res_checker>::type
{
bool field = false;
@ -59,7 +59,7 @@ public:
bool complete = false;
private:
friend class basic_parser<isRequest, cb_checker<isRequest>>;
friend class basic_parser_v1<isRequest, cb_checker<isRequest>>;
void on_method(boost::string_ref const&, error_code&)
{
@ -129,13 +129,13 @@ public:
}
template<bool isRequest>
struct null_parser : basic_parser<isRequest, null_parser<isRequest>>
struct null_parser : basic_parser_v1<isRequest, null_parser<isRequest>>
{
};
template<bool isRequest>
class test_parser :
public basic_parser<isRequest, test_parser<isRequest>>
public basic_parser_v1<isRequest, test_parser<isRequest>>
{
std::string field_;
std::string value_;
@ -635,7 +635,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(basic_parser,http,beast);
BEAST_DEFINE_TESTSUITE(basic_parser_v1,http,beast);
} // http
} // beast

View File

@ -19,168 +19,3 @@
// Test that header file is self-contained.
#include <beast/http/message.hpp>
#include <beast/detail/unit_test/suite.hpp>
#include <beast/detail/unit_test/thread.hpp>
#include <beast/placeholders.hpp>
#include <beast/streambuf.hpp>
#include <beast/http.hpp>
#include <boost/asio.hpp>
namespace beast {
namespace http {
namespace test {
class sync_echo_http_server
{
public:
using error_code = boost::system::error_code;
using endpoint_type = boost::asio::ip::tcp::endpoint;
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
private:
beast::detail::unit_test::suite& suite_;
boost::asio::io_service ios_;
socket_type sock_;
boost::asio::ip::tcp::acceptor acceptor_;
beast::detail::unit_test::thread thread_;
public:
sync_echo_http_server(
endpoint_type ep, beast::detail::unit_test::suite& suite)
: suite_(suite)
, sock_(ios_)
, acceptor_(ios_)
{
error_code ec;
acceptor_.open(ep.protocol(), ec);
maybe_throw(ec, "open");
acceptor_.bind(ep, ec);
maybe_throw(ec, "bind");
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
maybe_throw(ec, "listen");
acceptor_.async_accept(sock_,
std::bind(&sync_echo_http_server::on_accept, this,
beast::asio::placeholders::error));
thread_ = beast::detail::unit_test::thread(suite_,
[&]
{
ios_.run();
});
}
~sync_echo_http_server()
{
error_code ec;
ios_.dispatch(
[&]{ acceptor_.close(ec); });
thread_.join();
}
private:
void
fail(error_code ec, std::string what)
{
suite_.log <<
what << ": " << ec.message();
}
void
maybe_throw(error_code ec, std::string what)
{
if(ec &&
ec != boost::asio::error::operation_aborted)
{
fail(ec, what);
throw ec;
}
}
void
on_accept(error_code ec)
{
if(ec == boost::asio::error::operation_aborted)
return;
maybe_throw(ec, "accept");
std::thread{&sync_echo_http_server::do_client, this,
std::move(sock_), boost::asio::io_service::work{
sock_.get_io_service()}}.detach();
acceptor_.async_accept(sock_,
std::bind(&sync_echo_http_server::on_accept, this,
beast::asio::placeholders::error));
}
void
do_client(socket_type sock, boost::asio::io_service::work)
{
error_code ec;
streambuf rb;
for(;;)
{
request<string_body> req;
read(sock, rb, req, ec);
if(ec)
break;
response<string_body> resp(
{100, "OK", req.version});
resp.body = "Completed successfully.";
write(sock, resp, ec);
if(ec)
break;
}
}
};
class message_test : public beast::detail::unit_test::suite
{
public:
using error_code = boost::system::error_code;
using endpoint_type = boost::asio::ip::tcp::endpoint;
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
void
syncEcho(endpoint_type ep)
{
boost::asio::io_service ios;
socket_type sock(ios);
sock.connect(ep);
streambuf rb;
{
request<string_body> req({"GET", "/", 11});
req.body = "Beast.HTTP";
req.headers.replace("Host",
ep.address().to_string() + ":" +
std::to_string(ep.port()));
write(sock, req);
}
{
response<string_body> m;
read(sock, rb, m);
}
}
void
testAsio()
{
endpoint_type ep{
address_type::from_string("127.0.0.1"), 6000};
sync_echo_http_server s(ep, *this);
syncEcho(ep);
}
void run() override
{
testAsio();
pass();
}
};
BEAST_DEFINE_TESTSUITE(message,http,beast);
} // test
} // http
} // beast

View File

@ -8,7 +8,7 @@
#ifndef BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
#define BEAST_HTTP_TEST_MESSAGE_FUZZ_HPP
#include <beast/http/detail/basic_parser.hpp>
#include <beast/http/detail/basic_parser_v1.hpp>
#include <beast/write_streambuf.hpp>
#include <cstdint>
#include <random>

186
test/http/message_v1.cpp Normal file
View File

@ -0,0 +1,186 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
// Test that header file is self-contained.
#include <beast/http/message_v1.hpp>
#include <beast/detail/unit_test/suite.hpp>
#include <beast/detail/unit_test/thread.hpp>
#include <beast/placeholders.hpp>
#include <beast/streambuf.hpp>
#include <beast/http.hpp>
#include <boost/asio.hpp>
namespace beast {
namespace http {
namespace test {
class sync_echo_http_server
{
public:
using error_code = boost::system::error_code;
using endpoint_type = boost::asio::ip::tcp::endpoint;
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
private:
beast::detail::unit_test::suite& suite_;
boost::asio::io_service ios_;
socket_type sock_;
boost::asio::ip::tcp::acceptor acceptor_;
beast::detail::unit_test::thread thread_;
public:
sync_echo_http_server(
endpoint_type ep, beast::detail::unit_test::suite& suite)
: suite_(suite)
, sock_(ios_)
, acceptor_(ios_)
{
error_code ec;
acceptor_.open(ep.protocol(), ec);
maybe_throw(ec, "open");
acceptor_.bind(ep, ec);
maybe_throw(ec, "bind");
acceptor_.listen(
boost::asio::socket_base::max_connections, ec);
maybe_throw(ec, "listen");
acceptor_.async_accept(sock_,
std::bind(&sync_echo_http_server::on_accept, this,
beast::asio::placeholders::error));
thread_ = beast::detail::unit_test::thread(suite_,
[&]
{
ios_.run();
});
}
~sync_echo_http_server()
{
error_code ec;
ios_.dispatch(
[&]{ acceptor_.close(ec); });
thread_.join();
}
private:
void
fail(error_code ec, std::string what)
{
suite_.log <<
what << ": " << ec.message();
}
void
maybe_throw(error_code ec, std::string what)
{
if(ec &&
ec != boost::asio::error::operation_aborted)
{
fail(ec, what);
throw ec;
}
}
void
on_accept(error_code ec)
{
if(ec == boost::asio::error::operation_aborted)
return;
maybe_throw(ec, "accept");
std::thread{&sync_echo_http_server::do_client, this,
std::move(sock_), boost::asio::io_service::work{
sock_.get_io_service()}}.detach();
acceptor_.async_accept(sock_,
std::bind(&sync_echo_http_server::on_accept, this,
beast::asio::placeholders::error));
}
void
do_client(socket_type sock, boost::asio::io_service::work)
{
error_code ec;
streambuf rb;
for(;;)
{
request_v1<string_body> req;
read(sock, rb, req, ec);
if(ec)
break;
response_v1<string_body> resp(
{100, "OK", req.version});
resp.body = "Completed successfully.";
write(sock, resp, ec);
if(ec)
break;
}
}
};
class message_test : public beast::detail::unit_test::suite
{
public:
using error_code = boost::system::error_code;
using endpoint_type = boost::asio::ip::tcp::endpoint;
using address_type = boost::asio::ip::address;
using socket_type = boost::asio::ip::tcp::socket;
void
syncEcho(endpoint_type ep)
{
boost::asio::io_service ios;
socket_type sock(ios);
sock.connect(ep);
streambuf rb;
{
request_v1<string_body> req({"GET", "/", 11});
req.body = "Beast.HTTP";
req.headers.replace("Host",
ep.address().to_string() + ":" +
std::to_string(ep.port()));
write(sock, req);
}
{
response_v1<string_body> m;
read(sock, rb, m);
}
}
void
testAsio()
{
endpoint_type ep{
address_type::from_string("127.0.0.1"), 6000};
sync_echo_http_server s(ep, *this);
syncEcho(ep);
}
void run() override
{
testAsio();
pass();
}
};
BEAST_DEFINE_TESTSUITE(message,http,beast);
} // test
} // http
} // beast

View File

@ -10,7 +10,8 @@
#include "nodejs-parser/http_parser.h"
#include <beast/http/basic_parser.hpp>
#include <beast/http/error.hpp>
#include <beast/http/message_v1.hpp>
#include <beast/http/rfc2616.hpp>
#include <beast/type_check.hpp>
#include <boost/asio/buffer.hpp>
@ -18,6 +19,7 @@
#include <cstdint>
#include <string>
#include <type_traits>
#include <utility>
namespace beast {
namespace http {
@ -730,19 +732,6 @@ nodejs_basic_parser<Derived>::cb_chunk_complete(http_parser*)
return 0;
}
} // http
} // beast
#include <beast/http/error.hpp>
#include <beast/http/message.hpp>
#include <boost/optional.hpp>
#include <functional>
#include <type_traits>
#include <utility>
namespace beast {
namespace http {
/** A HTTP parser.
The parser may only be used once.
@ -752,7 +741,7 @@ class nodejs_parser
: public nodejs_basic_parser<nodejs_parser<isRequest, Body, Headers>>
{
using message_type =
message<isRequest, Body, Headers>;
message_v1<isRequest, Body, Headers>;
message_type m_;
typename message_type::body_type::reader r_;

View File

@ -6,7 +6,7 @@
//
// Test that header file is self-contained.
#include <beast/http/parser.hpp>
#include <beast/http/parser_v1.hpp>
#include <beast/http/headers.hpp>
#include <beast/http/string_body.hpp>
@ -23,7 +23,7 @@ public:
using boost::asio::buffer;
{
error_code ec;
parser<true, string_body,
parser_v1<true, string_body,
basic_headers<std::allocator<char>>> p;
std::string const s =
"GET / HTTP/1.1\r\n"
@ -43,7 +43,7 @@ public:
}
{
error_code ec;
parser<false, string_body,
parser_v1<false, string_body,
basic_headers<std::allocator<char>>> p;
std::string const s =
"HTTP/1.1 200 OK\r\n"

View File

@ -97,7 +97,7 @@ public:
}
template<bool isRequest>
struct null_parser : basic_parser<isRequest, null_parser<isRequest>>
struct null_parser : basic_parser_v1<isRequest, null_parser<isRequest>>
{
};
@ -108,10 +108,10 @@ public:
static std::size_t constexpr Repeat = 50;
log << "sizeof(request parser) == " <<
sizeof(basic_parser<true, null_parser<true>>);
sizeof(basic_parser_v1<true, null_parser<true>>);
log << "sizeof(response parser) == " <<
sizeof(basic_parser<false, null_parser<true>>);
sizeof(basic_parser_v1<false, null_parser<true>>);
testcase << "Parser speed test, " <<
((Repeat * size_ + 512) / 1024) << "KB in " <<
@ -127,13 +127,13 @@ public:
false, streambuf_body, headers>>(
Repeat, cres_);
});
timedTest(Trials, "http::basic_parser",
timedTest(Trials, "http::basic_parser_v1",
[&]
{
testParser<parser<
testParser<parser_v1<
true, streambuf_body, headers>>(
Repeat, creq_);
testParser<parser<
testParser<parser_v1<
false, streambuf_body, headers>>(
Repeat, cres_);
});

View File

@ -89,7 +89,7 @@ public:
template<bool isRequest, class Body, class Headers>
std::string
str(message<isRequest, Body, Headers> const& m)
str(message_v1<isRequest, Body, Headers> const& m)
{
string_SyncStream ss;
write(ss, m);
@ -101,7 +101,7 @@ public:
{
// auto content-length HTTP/1.0
{
message<true, string_body, headers> m{{
message_v1<true, string_body, headers> m{{
"GET", "/", 10}};
m.headers.insert("User-Agent", "test");
m.body = "*";
@ -116,7 +116,7 @@ public:
}
// keep-alive HTTP/1.0
{
message<true, string_body, headers> m{{
message_v1<true, string_body, headers> m{{
"GET", "/", 10}};
m.headers.insert("User-Agent", "test");
m.body = "*";
@ -132,7 +132,7 @@ public:
}
// upgrade HTTP/1.0
{
message<true, string_body, headers> m{{
message_v1<true, string_body, headers> m{{
"GET", "/", 10}};
m.headers.insert("User-Agent", "test");
m.body = "*";
@ -148,7 +148,7 @@ public:
}
// no content-length HTTP/1.0
{
message<true, test_Body, headers> m{{
message_v1<true, test_Body, headers> m{{
"GET", "/", 10}};
m.headers.insert("User-Agent", "test");
m.body = "*";
@ -166,7 +166,7 @@ public:
}
// auto content-length HTTP/1.1
{
message<true, string_body, headers> m{{
message_v1<true, string_body, headers> m{{
"GET", "/", 11}};
m.headers.insert("User-Agent", "test");
m.body = "*";
@ -181,7 +181,7 @@ public:
}
// close HTTP/1.1
{
message<true, string_body, headers> m{{
message_v1<true, string_body, headers> m{{
"GET", "/", 11}};
m.headers.insert("User-Agent", "test");
m.body = "*";
@ -201,7 +201,7 @@ public:
}
// upgrade HTTP/1.1
{
message<true, empty_body, headers> m{{
message_v1<true, empty_body, headers> m{{
"GET", "/", 11}};
m.headers.insert("User-Agent", "test");
prepare(m, connection::upgrade);
@ -214,7 +214,7 @@ public:
}
// no content-length HTTP/1.1
{
message<true, test_Body, headers> m{{
message_v1<true, test_Body, headers> m{{
"GET", "/", 11}};
m.headers.insert("User-Agent", "test");
m.body = "*";
@ -236,7 +236,7 @@ public:
void testConvert()
{
message<true, string_body, headers> m{{
message_v1<true, string_body, headers> m{{
"GET", "/", 11}};
m.headers.insert("User-Agent", "test");
m.body = "*";

View File

@ -22,7 +22,7 @@
#include <mutex>
#include <thread>
#include <beast/http/parser.hpp>
#include <beast/http/parser_v1.hpp>
namespace beast {
namespace websocket {