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 3af4cf0a28
commit 9e5e16c18d
42 changed files with 724 additions and 697 deletions

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;