mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Beast.HTTP:
New classes are introduced to represent HTTP messages and their associated bodies. The parser interface is reworked to use CRTP, error codes, and trait checks. New classes: * basic_headers Models field/value pairs in a HTTP message. * message Models a HTTP message, body behavior defined by template argument. Parsed message carries metadata generated during parsing. * parser Produces parsed messages. * empty_body, string_body, basic_streambuf_body Classes used to represent content bodies in various ways. New functions: * read, async_read, write, async_write Read and write HTTP messages on a socket. New concepts: * Body: Represents the HTTP Content-Body. * Field: A HTTP header field. * FieldSequence: A forward sequence of fields. * Reader: Parses a Body from a stream of bytes. * Writer: Serializes a Body to buffers. basic_parser changes: * add write methods which throw exceptions instead * error_code passed via parameter instead of return value * fold private member calls into existing callbacks * basic_parser uses CRTP instead of virtual members * add documentation on Derived requirements for CRTP impl/http-parser changes: * joyent renamed to nodejs to reflect upstream changes
This commit is contained in:
@@ -28,8 +28,10 @@
|
||||
#include <ripple/beast/net/IPAddressConversion.h>
|
||||
#include <beast/asio/placeholders.h>
|
||||
#include <beast/asio/ssl_error.h> // for is_short_read?
|
||||
#include <beast/http/read.h>
|
||||
#include <beast/http/message.h>
|
||||
#include <beast/http/parser.h>
|
||||
#include <beast/http/streambuf_body.h>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ssl/stream.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
@@ -95,8 +97,7 @@ protected:
|
||||
std::size_t nid_;
|
||||
|
||||
boost::asio::streambuf read_buf_;
|
||||
beast::http::message message_;
|
||||
beast::http::body body_;
|
||||
http_request_type message_;
|
||||
std::vector<buffer> wq_;
|
||||
std::vector<buffer> wq2_;
|
||||
std::mutex mutex_;
|
||||
@@ -186,18 +187,12 @@ protected:
|
||||
return beast::IPAddressConversion::from_asio(remote_address_);
|
||||
}
|
||||
|
||||
beast::http::message&
|
||||
http_request_type&
|
||||
request() override
|
||||
{
|
||||
return message_;
|
||||
}
|
||||
|
||||
beast::http::body const&
|
||||
body() override
|
||||
{
|
||||
return body_;
|
||||
}
|
||||
|
||||
void
|
||||
write (void const* buffer, std::size_t bytes) override;
|
||||
|
||||
@@ -319,64 +314,12 @@ void
|
||||
BaseHTTPPeer<Impl>::do_read (yield_context yield)
|
||||
{
|
||||
complete_ = false;
|
||||
|
||||
error_code ec;
|
||||
bool eof = false;
|
||||
body_.clear();
|
||||
beast::http::parser parser (message_, body_, true);
|
||||
for(;;)
|
||||
{
|
||||
if (read_buf_.size() == 0)
|
||||
{
|
||||
start_timer();
|
||||
auto const bytes_transferred = boost::asio::async_read (
|
||||
impl().stream_, read_buf_.prepare (bufferSize),
|
||||
boost::asio::transfer_at_least(1), yield[ec]);
|
||||
cancel_timer();
|
||||
|
||||
eof = ec == boost::asio::error::eof;
|
||||
if (eof)
|
||||
{
|
||||
ec = error_code{};
|
||||
}
|
||||
else if (! ec)
|
||||
{
|
||||
bytes_in_ += bytes_transferred;
|
||||
read_buf_.commit (bytes_transferred);
|
||||
}
|
||||
}
|
||||
|
||||
if (! ec)
|
||||
{
|
||||
if (! eof)
|
||||
{
|
||||
// VFALCO TODO Currently parsing errors are treated the
|
||||
// same as the connection dropping. Instead, we
|
||||
// should request that the handler compose a proper HTTP error
|
||||
// response. This requires refactoring HTTPReply() into
|
||||
// something sensible.
|
||||
std::size_t used;
|
||||
std::tie (ec, used) = parser.write (read_buf_.data());
|
||||
if (! ec)
|
||||
read_buf_.consume (used);
|
||||
}
|
||||
else
|
||||
{
|
||||
ec = parser.write_eof();
|
||||
}
|
||||
}
|
||||
|
||||
if (! ec)
|
||||
{
|
||||
if (parser.complete())
|
||||
return do_request();
|
||||
if (eof)
|
||||
ec = boost::asio::error::eof; // incomplete request
|
||||
}
|
||||
|
||||
if (ec)
|
||||
return fail (ec, "read");
|
||||
}
|
||||
beast::http::async_read(impl().stream_,
|
||||
read_buf_, message_, yield[ec]);
|
||||
// VFALCO What if the connection was closed?
|
||||
cancel_timer();
|
||||
do_request();
|
||||
}
|
||||
|
||||
// Send everything in the write queue.
|
||||
@@ -513,7 +456,7 @@ BaseHTTPPeer<Impl>::complete()
|
||||
return strand_.post(std::bind (&BaseHTTPPeer<Impl>::complete,
|
||||
impl().shared_from_this()));
|
||||
|
||||
message_ = beast::http::message{};
|
||||
message_ = {};
|
||||
complete_ = true;
|
||||
|
||||
{
|
||||
|
||||
@@ -108,7 +108,7 @@ PlainHTTPPeer::do_request()
|
||||
}
|
||||
|
||||
// Perform half-close when Connection: close and not SSL
|
||||
if (! message_.keep_alive())
|
||||
if (! is_keep_alive(message_))
|
||||
stream_.shutdown (socket_type::shutdown_receive, ec);
|
||||
if (ec)
|
||||
return fail (ec, "request");
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
#include <ripple/server/Port.h>
|
||||
#include <beast/http/rfc2616.h>
|
||||
#include <beast/module/core/text/LexicalCast.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
@@ -169,7 +169,7 @@ parse_Port (ParsedPort& port, Section const& section, std::ostream& log)
|
||||
if (*port.port == 0)
|
||||
Throw<std::exception> ();
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log <<
|
||||
"Invalid value '" << result.first << "' for key " <<
|
||||
@@ -199,7 +199,7 @@ parse_Port (ParsedPort& port, Section const& section, std::ostream& log)
|
||||
port.limit = static_cast<int> (
|
||||
beast::lexicalCastThrow<std::uint16_t>(lim));
|
||||
}
|
||||
catch (std::exception const& ex)
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log <<
|
||||
"Invalid value '" << lim << "' for key " <<
|
||||
|
||||
@@ -116,7 +116,7 @@ ServerHandlerImp::onAccept (Session& session,
|
||||
auto
|
||||
ServerHandlerImp::onHandoff (Session& session,
|
||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) ->
|
||||
Handoff
|
||||
{
|
||||
@@ -138,7 +138,7 @@ ServerHandlerImp::onHandoff (Session& session,
|
||||
auto
|
||||
ServerHandlerImp::onHandoff (Session& session,
|
||||
boost::asio::ip::tcp::socket&& socket,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) ->
|
||||
Handoff
|
||||
{
|
||||
@@ -163,6 +163,23 @@ Json::Output makeOutput (Session& session)
|
||||
};
|
||||
}
|
||||
|
||||
// HACK!
|
||||
template<class Allocator>
|
||||
static
|
||||
std::map<std::string, std::string>
|
||||
build_map(beast::http::headers<Allocator> const& h)
|
||||
{
|
||||
std::map <std::string, std::string> c;
|
||||
for (auto const& e : h)
|
||||
{
|
||||
auto key (e.first);
|
||||
// TODO Replace with safe C++14 version
|
||||
std::transform (key.begin(), key.end(), key.begin(), ::tolower);
|
||||
c [key] = e.second;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
ServerHandlerImp::onRequest (Session& session)
|
||||
{
|
||||
@@ -207,12 +224,32 @@ ServerHandlerImp::onStopped (Server&)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<class ConstBufferSequence>
|
||||
static
|
||||
std::string
|
||||
buffers_to_string(ConstBufferSequence const& bs)
|
||||
{
|
||||
using boost::asio::buffer_cast;
|
||||
using boost::asio::buffer_size;
|
||||
std::string s;
|
||||
s.reserve(buffer_size(bs));
|
||||
for(auto const& b : bs)
|
||||
s.append(buffer_cast<char const*>(b),
|
||||
buffer_size(b));
|
||||
for(auto i = s.size(); i-- > 0;)
|
||||
if(s[i] == '\r')
|
||||
s.replace(i, 1, "\\r");
|
||||
else if(s[i] == '\n')
|
||||
s.replace(i, 1, "\\n\n");
|
||||
return s;
|
||||
}
|
||||
|
||||
// Run as a couroutine.
|
||||
void
|
||||
ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
||||
std::shared_ptr<JobCoro> jobCoro)
|
||||
{
|
||||
processRequest (session->port(), to_string (session->body()),
|
||||
processRequest (session->port(), buffers_to_string(session->request().body.data()),
|
||||
session->remoteAddress().at_port (0), makeOutput (*session), jobCoro,
|
||||
[&]
|
||||
{
|
||||
@@ -233,7 +270,7 @@ ServerHandlerImp::processSession (std::shared_ptr<Session> const& session,
|
||||
return std::string{};
|
||||
}());
|
||||
|
||||
if (session->request().keep_alive())
|
||||
if(is_keep_alive(session->request()))
|
||||
session->complete();
|
||||
else
|
||||
session->close (true);
|
||||
@@ -425,9 +462,9 @@ ServerHandlerImp::processRequest (Port const& port,
|
||||
// Returns `true` if the HTTP request is a Websockets Upgrade
|
||||
// http://en.wikipedia.org/wiki/HTTP/1.1_Upgrade_header#Use_with_WebSockets
|
||||
bool
|
||||
ServerHandlerImp::isWebsocketUpgrade (beast::http::message const& request)
|
||||
ServerHandlerImp::isWebsocketUpgrade (http_request_type const& request)
|
||||
{
|
||||
if (request.upgrade())
|
||||
if (is_upgrade(request))
|
||||
return request.headers["Upgrade"] == "websocket";
|
||||
return false;
|
||||
}
|
||||
@@ -457,7 +494,7 @@ ServerHandlerImp::authorized (Port const& port,
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
ServerHandler::appendStandardFields (beast::http::message& message)
|
||||
ServerHandler::appendStandardFields (beast::deprecated_http::message& message)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -95,12 +95,12 @@ private:
|
||||
Handoff
|
||||
onHandoff (Session& session,
|
||||
std::unique_ptr <beast::asio::ssl_bundle>&& bundle,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) override;
|
||||
|
||||
Handoff
|
||||
onHandoff (Session& session, boost::asio::ip::tcp::socket&& socket,
|
||||
beast::http::message&& request,
|
||||
http_request_type&& request,
|
||||
boost::asio::ip::tcp::endpoint remote_address) override;
|
||||
void
|
||||
onRequest (Session& session) override;
|
||||
@@ -126,7 +126,7 @@ private:
|
||||
|
||||
private:
|
||||
bool
|
||||
isWebsocketUpgrade (beast::http::message const& request);
|
||||
isWebsocketUpgrade (http_request_type const& request);
|
||||
|
||||
bool
|
||||
authorized (Port const& port,
|
||||
|
||||
Reference in New Issue
Block a user