Compare commits
31 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e29b3d5dc1 | |||
| 0ead590a00 | |||
| 0a454ee873 | |||
| 2577c8fdb9 | |||
| 7c4b2f11e6 | |||
| b43583af70 | |||
| 9ae1abcc9d | |||
| df221479d1 | |||
| 62310c3ef8 | |||
| 97819c4622 | |||
| 5870ca658d | |||
| 9feecad226 | |||
| f36537a5b5 | |||
| 7f1016973e | |||
| 41e36a75ae | |||
| a8af28d381 | |||
| 968004ed44 | |||
| 099bfca60b | |||
| 681169cd22 | |||
| ba6979ff36 | |||
| c8c240ea07 | |||
| 3cc3729704 | |||
| 53de5f26bb | |||
| 820b60f079 | |||
| 1c9812bfec | |||
| 438227db7f | |||
| 761ce3b8bf | |||
| ae9151d092 | |||
| 533ecfbf28 | |||
| 8e27ddf6bf | |||
| 5bc283d6b2 |
+510
-459
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -1,7 +1,6 @@
|
|||||||
# 5.27.1
|
# Unreleased
|
||||||
- Changes from 5.27.0
|
- Changes from 5.27.0
|
||||||
- Misc:
|
- Misc:
|
||||||
- FIXED: Revert back to using custom HTTP parser instead of Boost.Beast. [#6407](https://github.com/Project-OSRM/osrm-backend/pull/6407)
|
|
||||||
- FIXED: Fix bug with large HTTP requests leading to Bad Request in osrm-routed. [#6403](https://github.com/Project-OSRM/osrm-backend/pull/6403)
|
- FIXED: Fix bug with large HTTP requests leading to Bad Request in osrm-routed. [#6403](https://github.com/Project-OSRM/osrm-backend/pull/6403)
|
||||||
- Routing:
|
- Routing:
|
||||||
- CHANGED: Add support for surface=metal,grass_paver,woodchips in bicyle profile. [#6395](https://github.com/Project-OSRM/osrm-backend/pull/6395)
|
- CHANGED: Add support for surface=metal,grass_paver,woodchips in bicyle profile. [#6395](https://github.com/Project-OSRM/osrm-backend/pull/6395)
|
||||||
|
|||||||
+6
-2
@@ -492,6 +492,9 @@ if(ENABLE_CONAN)
|
|||||||
set(TBB_SHARED True)
|
set(TBB_SHARED True)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(NOT CONAN_CMAKE_SYSTEM_PROCESSOR)
|
||||||
|
set(CONAN_CMAKE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR})
|
||||||
|
endif()
|
||||||
set(CONAN_ARGS
|
set(CONAN_ARGS
|
||||||
REQUIRES
|
REQUIRES
|
||||||
"boost/${CONAN_BOOST_VERSION}"
|
"boost/${CONAN_BOOST_VERSION}"
|
||||||
@@ -503,6 +506,7 @@ if(ENABLE_CONAN)
|
|||||||
GENERATORS cmake_find_package json # json generator generates a conanbuildinfo.json in the build folder so (non-CMake) projects can easily parse OSRM's dependencies
|
GENERATORS cmake_find_package json # json generator generates a conanbuildinfo.json in the build folder so (non-CMake) projects can easily parse OSRM's dependencies
|
||||||
KEEP_RPATHS
|
KEEP_RPATHS
|
||||||
NO_OUTPUT_DIRS
|
NO_OUTPUT_DIRS
|
||||||
|
ENV CONAN_CMAKE_SYSTEM_PROCESSOR=aarch64
|
||||||
OPTIONS boost:filesystem_version=3 # https://stackoverflow.com/questions/73392648/error-with-boost-filesystem-version-in-cmake
|
OPTIONS boost:filesystem_version=3 # https://stackoverflow.com/questions/73392648/error-with-boost-filesystem-version-in-cmake
|
||||||
onetbb:shared=${TBB_SHARED}
|
onetbb:shared=${TBB_SHARED}
|
||||||
boost:without_stacktrace=True # Apple Silicon cross-compilation fails without it
|
boost:without_stacktrace=True # Apple Silicon cross-compilation fails without it
|
||||||
@@ -511,8 +515,8 @@ if(ENABLE_CONAN)
|
|||||||
# explicitly say Conan to use x86 dependencies if build for x86 platforms (https://github.com/conan-io/cmake-conan/issues/141)
|
# explicitly say Conan to use x86 dependencies if build for x86 platforms (https://github.com/conan-io/cmake-conan/issues/141)
|
||||||
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
conan_cmake_run("${CONAN_ARGS};ARCH;x86")
|
conan_cmake_run("${CONAN_ARGS};ARCH;x86")
|
||||||
# cross-compilation for Apple Silicon
|
# cross-compilation for arm64 processors
|
||||||
elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
elseif((CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "x86_64")
|
||||||
conan_cmake_run("${CONAN_ARGS};ARCH;armv8")
|
conan_cmake_run("${CONAN_ARGS};ARCH;armv8")
|
||||||
else()
|
else()
|
||||||
conan_cmake_run("${CONAN_ARGS}")
|
conan_cmake_run("${CONAN_ARGS}")
|
||||||
|
|||||||
@@ -55,4 +55,4 @@ module.exports = function () {
|
|||||||
assert.equal(this.processError.process, binary);
|
assert.equal(this.processError.process, binary);
|
||||||
assert.equal(parseInt(this.processError.code), parseInt(code));
|
assert.equal(parseInt(this.processError.code), parseInt(code));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
+1
-2
@@ -38,8 +38,7 @@ if (ENABLE_FUZZING)
|
|||||||
"table_parameters"
|
"table_parameters"
|
||||||
"tile_parameters"
|
"tile_parameters"
|
||||||
"trip_parameters"
|
"trip_parameters"
|
||||||
"url_parser"
|
"url_parser")
|
||||||
"request_parser")
|
|
||||||
|
|
||||||
foreach (target ${ServerTargets})
|
foreach (target ${ServerTargets})
|
||||||
add_fuzz_target(${target})
|
add_fuzz_target(${target})
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
#include "server/request_parser.hpp"
|
|
||||||
#include "server/http/request.hpp"
|
|
||||||
|
|
||||||
#include "util.hpp"
|
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using osrm::server::RequestParser;
|
|
||||||
using osrm::server::http::request;
|
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *data, unsigned long size)
|
|
||||||
{
|
|
||||||
std::string in(reinterpret_cast<const char *>(data), size);
|
|
||||||
|
|
||||||
auto first = begin(in);
|
|
||||||
auto last = end(in);
|
|
||||||
|
|
||||||
RequestParser parser;
|
|
||||||
request req;
|
|
||||||
|
|
||||||
// &(*it) is needed to go from iterator to underlying item to pointer to underlying item
|
|
||||||
parser.parse(req, &(*first), &(*last));
|
|
||||||
|
|
||||||
escape(&req);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -4,14 +4,15 @@
|
|||||||
#include "server/http/compression_type.hpp"
|
#include "server/http/compression_type.hpp"
|
||||||
#include "server/http/reply.hpp"
|
#include "server/http/reply.hpp"
|
||||||
#include "server/http/request.hpp"
|
#include "server/http/request.hpp"
|
||||||
#include "server/request_parser.hpp"
|
|
||||||
|
|
||||||
#include <boost/array.hpp>
|
#include <boost/array.hpp>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
#include <boost/beast/core.hpp>
|
||||||
|
#include <boost/beast/http.hpp>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/version.hpp>
|
#include <boost/version.hpp>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
// workaround for incomplete std::shared_ptr compatibility in old boost versions
|
// workaround for incomplete std::shared_ptr compatibility in old boost versions
|
||||||
@@ -47,6 +48,7 @@ class Connection : public std::enable_shared_from_this<Connection>
|
|||||||
void start();
|
void start();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
using RequestParser = boost::beast::http::request_parser<boost::beast::http::string_body>;
|
||||||
void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
|
void handle_read(const boost::system::error_code &e, std::size_t bytes_transferred);
|
||||||
|
|
||||||
/// Handle completion of a write operation.
|
/// Handle completion of a write operation.
|
||||||
@@ -60,12 +62,14 @@ class Connection : public std::enable_shared_from_this<Connection>
|
|||||||
std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
|
std::vector<char> compress_buffers(const std::vector<char> &uncompressed_data,
|
||||||
const http::compression_type compression_type);
|
const http::compression_type compression_type);
|
||||||
|
|
||||||
|
void fill_request(const RequestParser::value_type &httpMessage, http::request &request);
|
||||||
|
|
||||||
boost::asio::strand<boost::asio::io_context::executor_type> strand;
|
boost::asio::strand<boost::asio::io_context::executor_type> strand;
|
||||||
boost::asio::ip::tcp::socket TCP_socket;
|
boost::asio::ip::tcp::socket TCP_socket;
|
||||||
boost::asio::deadline_timer timer;
|
boost::asio::deadline_timer timer;
|
||||||
RequestHandler &request_handler;
|
RequestHandler &request_handler;
|
||||||
RequestParser request_parser;
|
std::optional<RequestParser> http_request_parser;
|
||||||
boost::array<char, 8192> incoming_data_buffer;
|
std::vector<char> incoming_data_buffer;
|
||||||
http::request current_request;
|
http::request current_request;
|
||||||
http::reply current_reply;
|
http::reply current_reply;
|
||||||
std::vector<char> compressed_output;
|
std::vector<char> compressed_output;
|
||||||
|
|||||||
@@ -1,75 +0,0 @@
|
|||||||
#ifndef REQUEST_PARSER_HPP
|
|
||||||
#define REQUEST_PARSER_HPP
|
|
||||||
|
|
||||||
#include "server/http/compression_type.hpp"
|
|
||||||
#include "server/http/header.hpp"
|
|
||||||
|
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace server
|
|
||||||
{
|
|
||||||
|
|
||||||
namespace http
|
|
||||||
{
|
|
||||||
struct request;
|
|
||||||
}
|
|
||||||
|
|
||||||
class RequestParser
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
RequestParser();
|
|
||||||
|
|
||||||
enum class RequestStatus : char
|
|
||||||
{
|
|
||||||
valid,
|
|
||||||
invalid,
|
|
||||||
indeterminate
|
|
||||||
};
|
|
||||||
|
|
||||||
std::tuple<RequestStatus, http::compression_type>
|
|
||||||
parse(http::request ¤t_request, char *begin, char *end);
|
|
||||||
|
|
||||||
private:
|
|
||||||
RequestStatus consume(http::request ¤t_request, const char input);
|
|
||||||
|
|
||||||
bool is_char(const int character) const;
|
|
||||||
|
|
||||||
bool is_CTL(const int character) const;
|
|
||||||
|
|
||||||
bool is_special(const int character) const;
|
|
||||||
|
|
||||||
bool is_digit(const int character) const;
|
|
||||||
|
|
||||||
enum class internal_state : unsigned char
|
|
||||||
{
|
|
||||||
method_start,
|
|
||||||
method,
|
|
||||||
uri_start,
|
|
||||||
uri,
|
|
||||||
http_version_h,
|
|
||||||
http_version_t_1,
|
|
||||||
http_version_t_2,
|
|
||||||
http_version_p,
|
|
||||||
http_version_slash,
|
|
||||||
http_version_major_start,
|
|
||||||
http_version_major,
|
|
||||||
http_version_minor_start,
|
|
||||||
http_version_minor,
|
|
||||||
expecting_newline_1,
|
|
||||||
header_line_start,
|
|
||||||
header_lws,
|
|
||||||
header_name,
|
|
||||||
header_value,
|
|
||||||
expecting_newline_2,
|
|
||||||
expecting_newline_3
|
|
||||||
} state;
|
|
||||||
|
|
||||||
http::header current_header;
|
|
||||||
http::compression_type selected_compression;
|
|
||||||
};
|
|
||||||
} // namespace server
|
|
||||||
} // namespace osrm
|
|
||||||
|
|
||||||
#endif // REQUEST_PARSER_HPP
|
|
||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@project-osrm/osrm",
|
"name": "@project-osrm/osrm",
|
||||||
"version": "5.27.1",
|
"version": "5.28.0-unreleased",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
"description": "The Open Source Routing Machine is a high performance routing engine written in C++14 designed to run on OpenStreetMap data.",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
+77
-32
@@ -1,12 +1,10 @@
|
|||||||
#include "server/connection.hpp"
|
#include "server/connection.hpp"
|
||||||
#include "server/request_handler.hpp"
|
#include "server/request_handler.hpp"
|
||||||
#include "server/request_parser.hpp"
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/bind.hpp>
|
#include <boost/bind.hpp>
|
||||||
#include <boost/iostreams/filter/gzip.hpp>
|
#include <boost/iostreams/filter/gzip.hpp>
|
||||||
#include <boost/iostreams/filtering_stream.hpp>
|
#include <boost/iostreams/filtering_stream.hpp>
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace osrm
|
namespace osrm
|
||||||
@@ -14,14 +12,40 @@ namespace osrm
|
|||||||
namespace server
|
namespace server
|
||||||
{
|
{
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
const size_t CHUNK_SIZE = 8192;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
Connection::Connection(boost::asio::io_context &io_context, RequestHandler &handler)
|
Connection::Connection(boost::asio::io_context &io_context, RequestHandler &handler)
|
||||||
: strand(boost::asio::make_strand(io_context)), TCP_socket(strand), timer(strand),
|
: strand(boost::asio::make_strand(io_context)), TCP_socket(strand), timer(strand),
|
||||||
request_handler(handler)
|
request_handler(handler), http_request_parser(std::make_optional<RequestParser>())
|
||||||
{
|
{
|
||||||
|
http_request_parser->header_limit(std::numeric_limits<std::uint32_t>::max());
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
|
boost::asio::ip::tcp::socket &Connection::socket() { return TCP_socket; }
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
http::compression_type select_compression(const boost::beast::http::fields &fields)
|
||||||
|
{
|
||||||
|
const auto header_value = fields[boost::beast::http::field::accept_encoding];
|
||||||
|
/* giving gzip precedence over deflate */
|
||||||
|
if (boost::icontains(header_value, "gzip"))
|
||||||
|
{
|
||||||
|
return http::gzip_rfc1952;
|
||||||
|
}
|
||||||
|
if (boost::icontains(header_value, "deflate"))
|
||||||
|
{
|
||||||
|
return http::deflate_rfc1951;
|
||||||
|
}
|
||||||
|
return http::no_compression;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/// Start the first asynchronous operation for the connection.
|
/// Start the first asynchronous operation for the connection.
|
||||||
void Connection::start()
|
void Connection::start()
|
||||||
{
|
{
|
||||||
@@ -41,7 +65,8 @@ void Connection::start()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::handle_read(const boost::system::error_code &error, std::size_t bytes_transferred)
|
void Connection::handle_read(const boost::system::error_code &error,
|
||||||
|
std::size_t /*bytes_transferred*/)
|
||||||
{
|
{
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
@@ -60,20 +85,48 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
|
|||||||
timer.expires_from_now(boost::posix_time::seconds(0));
|
timer.expires_from_now(boost::posix_time::seconds(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::beast::error_code ec;
|
||||||
|
http_request_parser->put(boost::asio::buffer(incoming_data_buffer), ec);
|
||||||
// no error detected, let's parse the request
|
// no error detected, let's parse the request
|
||||||
http::compression_type compression_type(http::no_compression);
|
http::compression_type compression_type(http::no_compression);
|
||||||
RequestParser::RequestStatus result;
|
|
||||||
std::tie(result, compression_type) =
|
|
||||||
request_parser.parse(current_request,
|
|
||||||
incoming_data_buffer.data(),
|
|
||||||
incoming_data_buffer.data() + bytes_transferred);
|
|
||||||
|
|
||||||
// the request has been parsed
|
if (ec)
|
||||||
if (result == RequestParser::RequestStatus::valid)
|
|
||||||
{
|
{
|
||||||
|
if (ec == boost::beast::http::error::need_more)
|
||||||
|
{
|
||||||
|
const auto current_size = incoming_data_buffer.size();
|
||||||
|
incoming_data_buffer.resize(incoming_data_buffer.size() + CHUNK_SIZE, 0);
|
||||||
|
// we don't have a result yet, so continue reading
|
||||||
|
TCP_socket.async_read_some(
|
||||||
|
boost::asio::buffer(incoming_data_buffer.data() + current_size, CHUNK_SIZE),
|
||||||
|
boost::bind(&Connection::handle_read,
|
||||||
|
this->shared_from_this(),
|
||||||
|
boost::asio::placeholders::error,
|
||||||
|
boost::asio::placeholders::bytes_transferred));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// request is not parseable
|
||||||
|
current_reply = http::reply::stock_reply(http::reply::bad_request);
|
||||||
|
|
||||||
|
boost::asio::async_write(TCP_socket,
|
||||||
|
current_reply.to_buffers(),
|
||||||
|
boost::bind(&Connection::handle_write,
|
||||||
|
this->shared_from_this(),
|
||||||
|
boost::asio::placeholders::error));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// the request has been parsed
|
||||||
|
const auto &message = http_request_parser->get();
|
||||||
|
compression_type = select_compression(message);
|
||||||
|
|
||||||
|
fill_request(message, current_request);
|
||||||
|
|
||||||
boost::system::error_code ec;
|
boost::system::error_code ec;
|
||||||
current_request.endpoint = TCP_socket.remote_endpoint(ec).address();
|
current_request.endpoint = TCP_socket.remote_endpoint(ec).address();
|
||||||
|
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
util::Log(logDEBUG) << "Socket remote endpoint error: " << ec.message();
|
util::Log(logDEBUG) << "Socket remote endpoint error: " << ec.message();
|
||||||
@@ -127,25 +180,6 @@ void Connection::handle_read(const boost::system::error_code &error, std::size_t
|
|||||||
this->shared_from_this(),
|
this->shared_from_this(),
|
||||||
boost::asio::placeholders::error));
|
boost::asio::placeholders::error));
|
||||||
}
|
}
|
||||||
else if (result == RequestParser::RequestStatus::invalid)
|
|
||||||
{ // request is not parseable
|
|
||||||
current_reply = http::reply::stock_reply(http::reply::bad_request);
|
|
||||||
|
|
||||||
boost::asio::async_write(TCP_socket,
|
|
||||||
current_reply.to_buffers(),
|
|
||||||
boost::bind(&Connection::handle_write,
|
|
||||||
this->shared_from_this(),
|
|
||||||
boost::asio::placeholders::error));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// we don't have a result yet, so continue reading
|
|
||||||
TCP_socket.async_read_some(boost::asio::buffer(incoming_data_buffer),
|
|
||||||
boost::bind(&Connection::handle_read,
|
|
||||||
this->shared_from_this(),
|
|
||||||
boost::asio::placeholders::error,
|
|
||||||
boost::asio::placeholders::bytes_transferred));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handle completion of a write operation.
|
/// Handle completion of a write operation.
|
||||||
@@ -158,8 +192,9 @@ void Connection::handle_write(const boost::system::error_code &error)
|
|||||||
--processed_requests;
|
--processed_requests;
|
||||||
current_request = http::request();
|
current_request = http::request();
|
||||||
current_reply = http::reply();
|
current_reply = http::reply();
|
||||||
request_parser = RequestParser();
|
http_request_parser.emplace();
|
||||||
incoming_data_buffer = boost::array<char, 8192>();
|
http_request_parser->header_limit(std::numeric_limits<std::uint32_t>::max());
|
||||||
|
incoming_data_buffer.resize(CHUNK_SIZE, 0);
|
||||||
output_buffer.clear();
|
output_buffer.clear();
|
||||||
this->start();
|
this->start();
|
||||||
}
|
}
|
||||||
@@ -220,5 +255,15 @@ std::vector<char> Connection::compress_buffers(const std::vector<char> &uncompre
|
|||||||
|
|
||||||
return compressed_data;
|
return compressed_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Connection::fill_request(const RequestParser::value_type &http_message,
|
||||||
|
http::request ¤t_request)
|
||||||
|
{
|
||||||
|
current_request.uri = http_message.target().to_string();
|
||||||
|
current_request.agent = http_message[boost::beast::http::field::user_agent].to_string();
|
||||||
|
current_request.referrer = http_message[boost::beast::http::field::referer].to_string();
|
||||||
|
current_request.connection = http_message[boost::beast::http::field::connection].to_string();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace server
|
} // namespace server
|
||||||
} // namespace osrm
|
} // namespace osrm
|
||||||
|
|||||||
@@ -1,302 +0,0 @@
|
|||||||
#include "server/request_parser.hpp"
|
|
||||||
|
|
||||||
#include "server/http/compression_type.hpp"
|
|
||||||
#include "server/http/header.hpp"
|
|
||||||
#include "server/http/request.hpp"
|
|
||||||
|
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace osrm
|
|
||||||
{
|
|
||||||
namespace server
|
|
||||||
{
|
|
||||||
|
|
||||||
RequestParser::RequestParser()
|
|
||||||
: state(internal_state::method_start), current_header({"", ""}),
|
|
||||||
selected_compression(http::no_compression)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<RequestParser::RequestStatus, http::compression_type>
|
|
||||||
RequestParser::parse(http::request ¤t_request, char *begin, char *end)
|
|
||||||
{
|
|
||||||
while (begin != end)
|
|
||||||
{
|
|
||||||
RequestStatus result = consume(current_request, *begin++);
|
|
||||||
if (result != RequestStatus::indeterminate)
|
|
||||||
{
|
|
||||||
return std::make_tuple(result, selected_compression);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RequestStatus result = RequestStatus::indeterminate;
|
|
||||||
|
|
||||||
return std::make_tuple(result, selected_compression);
|
|
||||||
}
|
|
||||||
|
|
||||||
RequestParser::RequestStatus RequestParser::consume(http::request ¤t_request,
|
|
||||||
const char input)
|
|
||||||
{
|
|
||||||
switch (state)
|
|
||||||
{
|
|
||||||
case internal_state::method_start:
|
|
||||||
if (!is_char(input) || is_CTL(input) || is_special(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
state = internal_state::method;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::method:
|
|
||||||
if (input == ' ')
|
|
||||||
{
|
|
||||||
state = internal_state::uri;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (!is_char(input) || is_CTL(input) || is_special(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::uri_start:
|
|
||||||
if (is_CTL(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
state = internal_state::uri;
|
|
||||||
current_request.uri.push_back(input);
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::uri:
|
|
||||||
if (input == ' ')
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_h;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (is_CTL(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
current_request.uri.push_back(input);
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::http_version_h:
|
|
||||||
if (input == 'H')
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_t_1;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_t_1:
|
|
||||||
if (input == 'T')
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_t_2;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_t_2:
|
|
||||||
if (input == 'T')
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_p;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_p:
|
|
||||||
if (input == 'P')
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_slash;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_slash:
|
|
||||||
if (input == '/')
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_major_start;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_major_start:
|
|
||||||
if (is_digit(input))
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_major;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_major:
|
|
||||||
if (input == '.')
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_minor_start;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (is_digit(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_minor_start:
|
|
||||||
if (is_digit(input))
|
|
||||||
{
|
|
||||||
state = internal_state::http_version_minor;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::http_version_minor:
|
|
||||||
if (input == '\r')
|
|
||||||
{
|
|
||||||
state = internal_state::expecting_newline_1;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (is_digit(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::expecting_newline_1:
|
|
||||||
if (input == '\n')
|
|
||||||
{
|
|
||||||
state = internal_state::header_line_start;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
case internal_state::header_line_start:
|
|
||||||
if (boost::iequals(current_header.name, "Accept-Encoding"))
|
|
||||||
{
|
|
||||||
/* giving gzip precedence over deflate */
|
|
||||||
if (boost::icontains(current_header.value, "deflate"))
|
|
||||||
{
|
|
||||||
selected_compression = http::deflate_rfc1951;
|
|
||||||
}
|
|
||||||
if (boost::icontains(current_header.value, "gzip"))
|
|
||||||
{
|
|
||||||
selected_compression = http::gzip_rfc1952;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::iequals(current_header.name, "Referer"))
|
|
||||||
{
|
|
||||||
current_request.referrer = current_header.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::iequals(current_header.name, "User-Agent"))
|
|
||||||
{
|
|
||||||
current_request.agent = current_header.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (boost::iequals(current_header.name, "Connection"))
|
|
||||||
{
|
|
||||||
current_request.connection = current_header.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (input == '\r')
|
|
||||||
{
|
|
||||||
state = internal_state::expecting_newline_3;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (!is_char(input) || is_CTL(input) || is_special(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
state = internal_state::header_name;
|
|
||||||
current_header.clear();
|
|
||||||
current_header.name.push_back(input);
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::header_lws:
|
|
||||||
if (input == '\r')
|
|
||||||
{
|
|
||||||
state = internal_state::expecting_newline_2;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (input == ' ' || input == '\t')
|
|
||||||
{
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (is_CTL(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
state = internal_state::header_value;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::header_name:
|
|
||||||
if (input == ':')
|
|
||||||
{
|
|
||||||
state = internal_state::header_value;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (!is_char(input) || is_CTL(input) || is_special(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
current_header.name.push_back(input);
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::header_value:
|
|
||||||
if (input == ' ')
|
|
||||||
{
|
|
||||||
state = internal_state::header_value;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (input == '\r')
|
|
||||||
{
|
|
||||||
state = internal_state::expecting_newline_2;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
if (is_CTL(input))
|
|
||||||
{
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
current_header.value.push_back(input);
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
case internal_state::expecting_newline_2:
|
|
||||||
if (input == '\n')
|
|
||||||
{
|
|
||||||
state = internal_state::header_line_start;
|
|
||||||
return RequestStatus::indeterminate;
|
|
||||||
}
|
|
||||||
return RequestStatus::invalid;
|
|
||||||
default: // expecting_newline_3
|
|
||||||
return input == '\n' ? RequestStatus::valid : RequestStatus::invalid;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RequestParser::is_char(const int character) const
|
|
||||||
{
|
|
||||||
return character >= 0 && character <= 127;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RequestParser::is_CTL(const int character) const
|
|
||||||
{
|
|
||||||
return (character >= 0 && character <= 31) || (character == 127);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RequestParser::is_special(const int character) const
|
|
||||||
{
|
|
||||||
switch (character)
|
|
||||||
{
|
|
||||||
case '(':
|
|
||||||
case ')':
|
|
||||||
case '<':
|
|
||||||
case '>':
|
|
||||||
case '@':
|
|
||||||
case ',':
|
|
||||||
case ';':
|
|
||||||
case ':':
|
|
||||||
case '\\':
|
|
||||||
case '"':
|
|
||||||
case '/':
|
|
||||||
case '[':
|
|
||||||
case ']':
|
|
||||||
case '?':
|
|
||||||
case '=':
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case ' ':
|
|
||||||
case '\t':
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RequestParser::is_digit(const int character) const
|
|
||||||
{
|
|
||||||
return character >= '0' && character <= '9';
|
|
||||||
}
|
|
||||||
} // namespace server
|
|
||||||
} // namespace osrm
|
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
# Conan automatically generated toolchain file
|
||||||
|
# DO NOT EDIT MANUALLY, it will be overwritten
|
||||||
|
|
||||||
|
# Avoid including toolchain file several times (bad if appending to variables like
|
||||||
|
# CMAKE_CXX_FLAGS. See https://github.com/android/ndk/issues/323
|
||||||
|
include_guard()
|
||||||
|
|
||||||
|
message(STATUS "Using Conan toolchain: ${CMAKE_CURRENT_LIST_FILE}")
|
||||||
|
|
||||||
|
if(${CMAKE_VERSION} VERSION_LESS "3.15")
|
||||||
|
message(FATAL_ERROR "The 'CMakeToolchain' generator only works with CMake >= 3.15")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Extra c, cxx, linkflags and defines
|
||||||
|
|
||||||
|
|
||||||
|
if(DEFINED CONAN_CXX_FLAGS)
|
||||||
|
string(APPEND CMAKE_CXX_FLAGS_INIT " ${CONAN_CXX_FLAGS}")
|
||||||
|
endif()
|
||||||
|
if(DEFINED CONAN_C_FLAGS)
|
||||||
|
string(APPEND CMAKE_C_FLAGS_INIT " ${CONAN_C_FLAGS}")
|
||||||
|
endif()
|
||||||
|
if(DEFINED CONAN_SHARED_LINKER_FLAGS)
|
||||||
|
string(APPEND CMAKE_SHARED_LINKER_FLAGS_INIT " ${CONAN_SHARED_LINKER_FLAGS}")
|
||||||
|
endif()
|
||||||
|
if(DEFINED CONAN_EXE_LINKER_FLAGS)
|
||||||
|
string(APPEND CMAKE_EXE_LINKER_FLAGS_INIT " ${CONAN_EXE_LINKER_FLAGS}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE )
|
||||||
|
if(_CMAKE_IN_TRY_COMPILE)
|
||||||
|
message(STATUS "Running toolchain IN_TRY_COMPILE")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
|
||||||
|
|
||||||
|
# Definition of CMAKE_MODULE_PATH
|
||||||
|
# the generators folder (where conan generates files, like this toolchain)
|
||||||
|
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR})
|
||||||
|
|
||||||
|
# Definition of CMAKE_PREFIX_PATH, CMAKE_XXXXX_PATH
|
||||||
|
# The Conan local "generators" folder, where this toolchain is saved.
|
||||||
|
list(PREPEND CMAKE_PREFIX_PATH ${CMAKE_CURRENT_LIST_DIR} )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
message(STATUS "Conan toolchain: Setting BUILD_SHARED_LIBS = ON")
|
||||||
|
set(BUILD_SHARED_LIBS ON)
|
||||||
|
|
||||||
|
set(CMAKE_INSTALL_PREFIX "/home/runner/.conan/data/onetbb/2021.3.0/_/_/package/a36e366b2b0ea0e76bafba6092e0a74838fad5fd")
|
||||||
|
set(CMAKE_INSTALL_BINDIR "bin")
|
||||||
|
set(CMAKE_INSTALL_SBINDIR "bin")
|
||||||
|
set(CMAKE_INSTALL_LIBEXECDIR "bin")
|
||||||
|
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||||
|
set(CMAKE_INSTALL_INCLUDEDIR "include")
|
||||||
|
set(CMAKE_INSTALL_OLDINCLUDEDIR "include")
|
||||||
|
set(CMAKE_SYSTEM_PROCESSOR "aarch64")
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
set(TBB_TEST OFF CACHE BOOL "Variable TBB_TEST conan-toolchain defined")
|
||||||
|
set(TBB_STRICT OFF CACHE BOOL "Variable TBB_STRICT conan-toolchain defined")
|
||||||
|
# Variables per configuration
|
||||||
|
|
||||||
|
|
||||||
|
# Preprocessor definitions
|
||||||
|
# Preprocessor definitions per configuration
|
||||||
Reference in New Issue
Block a user