Skip to content

Commit 77ffd98

Browse files
SiarheiFedartsoumattwigway
authored andcommitted
Use Boost.Beast to parse HTTP request (Project-OSRM#6294)
1 parent 7738161 commit 77ffd98

File tree

7 files changed

+74
-441
lines changed

7 files changed

+74
-441
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22
- Changes from 5.26.0
33
- API:
4+
- FIXED: Use Boost.Beast to parse HTTP request. [#6294](https://github.com/Project-OSRM/osrm-backend/pull/6294)
45
- FIXED: Fix inefficient osrm-routed connection handling [#6113](https://github.com/Project-OSRM/osrm-backend/pull/6113)
56
- Misc:
67
- FIXED: Fix bug with reading Set values from Lua scripts. [#6285](https://github.com/Project-OSRM/osrm-backend/pull/6285)

fuzz/CMakeLists.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ if (ENABLE_FUZZING)
3838
"table_parameters"
3939
"tile_parameters"
4040
"trip_parameters"
41-
"url_parser"
42-
"request_parser")
41+
"url_parser")
4342

4443
foreach (target ${ServerTargets})
4544
add_fuzz_target(${target})

fuzz/request_parser.cc

Lines changed: 0 additions & 28 deletions
This file was deleted.

include/server/connection.hpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@
44
#include "server/http/compression_type.hpp"
55
#include "server/http/reply.hpp"
66
#include "server/http/request.hpp"
7-
#include "server/request_parser.hpp"
8-
97
#include <boost/array.hpp>
108
#include <boost/asio.hpp>
9+
#include <boost/beast/core.hpp>
10+
#include <boost/beast/http.hpp>
1111
#include <boost/config.hpp>
1212
#include <boost/version.hpp>
1313

1414
#include <memory>
15+
#include <optional>
1516
#include <vector>
1617

1718
// workaround for incomplete std::shared_ptr compatibility in old boost versions
@@ -47,6 +48,7 @@ class Connection : public std::enable_shared_from_this<Connection>
4748
void start();
4849

4950
private:
51+
using RequestParser = boost::beast::http::request_parser<boost::beast::http::string_body>;
5052
void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
5153

5254
/// Handle completion of a write operation.
@@ -60,11 +62,13 @@ class Connection : public std::enable_shared_from_this<Connection>
6062
std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
6163
const http::compression_type compression_type);
6264

65+
void fill_request(const RequestParser::value_type &httpMessage, http::request &request);
66+
6367
boost::asio::strand<boost::asio::io_context::executor_type> strand;
6468
boost::asio::ip::tcp::socket TCP_socket;
6569
boost::asio::deadline_timer timer;
6670
RequestHandler &request_handler;
67-
RequestParser request_parser;
71+
std::optional<RequestParser> http_request_parser;
6872
boost::array<char, 8192> incoming_data_buffer;
6973
http::request current_request;
7074
http::reply current_reply;

include/server/request_parser.hpp

Lines changed: 0 additions & 75 deletions
This file was deleted.

src/server/connection.cpp

Lines changed: 65 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
#include "server/connection.hpp"
22
#include "server/request_handler.hpp"
3-
#include "server/request_parser.hpp"
43

54
#include <boost/algorithm/string/predicate.hpp>
65
#include <boost/bind.hpp>
76
#include <boost/iostreams/filter/gzip.hpp>
87
#include <boost/iostreams/filtering_stream.hpp>
9-
108
#include <vector>
119

1210
namespace osrm
@@ -16,12 +14,32 @@ namespace server
1614

1715
Connection::Connection(boost::asio::io_context &io_context, RequestHandler &handler)
1816
: strand(boost::asio::make_strand(io_context)), TCP_socket(strand), timer(strand),
19-
request_handler(handler)
17+
request_handler(handler), http_request_parser(std::make_optional<RequestParser>())
2018
{
2119
}
2220

2321
boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
2422

23+
namespace
24+
{
25+
26+
http::compression_type select_compression(const boost::beast::http::fields &fields)
27+
{
28+
const auto header_value = fields[boost::beast::http::field::accept_encoding];
29+
/* giving gzip precedence over deflate */
30+
if (boost::icontains(header_value, "deflate"))
31+
{
32+
return http::deflate_rfc1951;
33+
}
34+
if (boost::icontains(header_value, "gzip"))
35+
{
36+
return http::gzip_rfc1952;
37+
}
38+
return http::no_compression;
39+
}
40+
41+
} // namespace
42+
2543
/// Start the first asynchronous operation for the connection.
2644
void Connection::start()
2745
{
@@ -60,20 +78,45 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
6078
timer.expires_from_now(boost::posix_time::seconds(0));
6179
}
6280

81+
boost::beast::error_code ec;
82+
http_request_parser->put(boost::asio::buffer(incoming_data_buffer, bytes_transferred), ec);
6383
// no error detected, let's parse the request
6484
http::compression_type compression_type(http::no_compression);
65-
RequestParser::RequestStatus result;
66-
std::tie(result, compression_type) =
67-
request_parser.parse(current_request,
68-
incoming_data_buffer.data(),
69-
incoming_data_buffer.data() + bytes_transferred);
70-
71-
// the request has been parsed
72-
if (result == RequestParser::RequestStatus::valid)
85+
86+
if (ec)
87+
{
88+
if (ec == boost::beast::http::error::need_more)
89+
{
90+
// we don't have a result yet, so continue reading
91+
TCP_socket.async_read_some(boost::asio::buffer(incoming_data_buffer),
92+
boost::bind(&Connection::handle_read,
93+
this->shared_from_this(),
94+
boost::asio::placeholders::error,
95+
boost::asio::placeholders::bytes_transferred));
96+
}
97+
else
98+
{
99+
// request is not parseable
100+
current_reply = http::reply::stock_reply(http::reply::bad_request);
101+
102+
boost::asio::async_write(TCP_socket,
103+
current_reply.to_buffers(),
104+
boost::bind(&Connection::handle_write,
105+
this->shared_from_this(),
106+
boost::asio::placeholders::error));
107+
}
108+
}
109+
else
73110
{
111+
// the request has been parsed
112+
const auto &message = http_request_parser->get();
113+
compression_type = select_compression(message);
114+
115+
fill_request(message, current_request);
74116

75117
boost::system::error_code ec;
76118
current_request.endpoint = TCP_socket.remote_endpoint(ec).address();
119+
77120
if (ec)
78121
{
79122
util::Log(logDEBUG) << "Socket remote endpoint error: " << ec.message();
@@ -127,25 +170,6 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
127170
this->shared_from_this(),
128171
boost::asio::placeholders::error));
129172
}
130-
else if (result == RequestParser::RequestStatus::invalid)
131-
{ // request is not parseable
132-
current_reply = http::reply::stock_reply(http::reply::bad_request);
133-
134-
boost::asio::async_write(TCP_socket,
135-
current_reply.to_buffers(),
136-
boost::bind(&Connection::handle_write,
137-
this->shared_from_this(),
138-
boost::asio::placeholders::error));
139-
}
140-
else
141-
{
142-
// we don't have a result yet, so continue reading
143-
TCP_socket.async_read_some(boost::asio::buffer(incoming_data_buffer),
144-
boost::bind(&Connection::handle_read,
145-
this->shared_from_this(),
146-
boost::asio::placeholders::error,
147-
boost::asio::placeholders::bytes_transferred));
148-
}
149173
}
150174

151175
/// Handle completion of a write operation.
@@ -158,7 +182,7 @@ void Connection::handle_write(const boost::system::error_code &error)
158182
--processed_requests;
159183
current_request = http::request();
160184
current_reply = http::reply();
161-
request_parser = RequestParser();
185+
http_request_parser.emplace();
162186
incoming_data_buffer = boost::array<char, 8192>();
163187
output_buffer.clear();
164188
this->start();
@@ -220,5 +244,15 @@ std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompre
220244

221245
return compressed_data;
222246
}
247+
248+
void Connection::fill_request(const RequestParser::value_type &http_message,
249+
http::request &current_request)
250+
{
251+
current_request.uri = http_message.target().to_string();
252+
current_request.agent = http_message[boost::beast::http::field::user_agent].to_string();
253+
current_request.referrer = http_message[boost::beast::http::field::referer].to_string();
254+
current_request.connection = http_message[boost::beast::http::field::connection].to_string();
255+
}
256+
223257
} // namespace server
224258
} // namespace osrm

0 commit comments

Comments
 (0)