Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4f3ee609ec | |||
| 9d160a9b5d | |||
| d143de597d | |||
| 4026ed54c0 | |||
| 895e4bf6d5 | |||
| cb90d587be |
@@ -29,7 +29,7 @@ jobs:
|
|||||||
ENABLE_APPLE_SILICON: "OFF"
|
ENABLE_APPLE_SILICON: "OFF"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- run: pip install conan==1.51.3
|
- run: pip install conan==1.53.0
|
||||||
- run: conan --version
|
- run: conan --version
|
||||||
- run: cmake --version
|
- run: cmake --version
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
@@ -252,7 +252,7 @@ jobs:
|
|||||||
CXXFLAGS: "-m32 -msse2 -mfpmath=sse"
|
CXXFLAGS: "-m32 -msse2 -mfpmath=sse"
|
||||||
TARGET_ARCH: i686
|
TARGET_ARCH: i686
|
||||||
ENABLE_CONAN: ON
|
ENABLE_CONAN: ON
|
||||||
|
|
||||||
- name: gcc-8-release
|
- name: gcc-8-release
|
||||||
continue-on-error: false
|
continue-on-error: false
|
||||||
node: 12
|
node: 12
|
||||||
@@ -460,7 +460,7 @@ jobs:
|
|||||||
CUCUMBER_TIMEOUT: 60000
|
CUCUMBER_TIMEOUT: 60000
|
||||||
ENABLE_ASSERTIONS: ON
|
ENABLE_ASSERTIONS: ON
|
||||||
ENABLE_CONAN: ON
|
ENABLE_CONAN: ON
|
||||||
|
|
||||||
- name: conan-macos-arm64-release-node-lts
|
- name: conan-macos-arm64-release-node-lts
|
||||||
build_node_package: true
|
build_node_package: true
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
@@ -553,7 +553,7 @@ jobs:
|
|||||||
key: v3-test-${{ matrix.name }}-${{ github.sha }}
|
key: v3-test-${{ matrix.name }}-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
v3-test-${{ matrix.name }}-
|
v3-test-${{ matrix.name }}-
|
||||||
|
|
||||||
- name: Prepare environment
|
- name: Prepare environment
|
||||||
run: |
|
run: |
|
||||||
PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
|
PACKAGE_JSON_VERSION=$(node -e "console.log(require('./package.json').version)")
|
||||||
@@ -574,7 +574,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Install dev dependencies
|
- name: Install dev dependencies
|
||||||
run: |
|
run: |
|
||||||
python3 -m pip install conan==1.51.3
|
python3 -m pip install conan==1.53.0
|
||||||
|
|
||||||
# ccache
|
# ccache
|
||||||
if [[ "${RUNNER_OS}" == "Linux" ]]; then
|
if [[ "${RUNNER_OS}" == "Linux" ]]; then
|
||||||
@@ -582,12 +582,12 @@ jobs:
|
|||||||
elif [[ "${RUNNER_OS}" == "macOS" ]]; then
|
elif [[ "${RUNNER_OS}" == "macOS" ]]; then
|
||||||
brew install ccache
|
brew install ccache
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# clang
|
# clang
|
||||||
if [[ "${CCOMPILER}" == "clang-6.0" ]]; then
|
if [[ "${CCOMPILER}" == "clang-6.0" ]]; then
|
||||||
sudo apt-get update -y && sudo apt-get install clang++-6
|
sudo apt-get update -y && sudo apt-get install clang++-6
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Linux dev packages
|
# Linux dev packages
|
||||||
if [ "${TARGET_ARCH}" != "i686" ] && [ "${ENABLE_CONAN}" != "ON" ]; then
|
if [ "${TARGET_ARCH}" != "i686" ] && [ "${ENABLE_CONAN}" != "ON" ]; then
|
||||||
sudo apt-get update -y
|
sudo apt-get update -y
|
||||||
@@ -697,7 +697,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
pushd ${OSRM_BUILD_DIR}
|
pushd ${OSRM_BUILD_DIR}
|
||||||
make --jobs=${JOBS} benchmarks
|
make --jobs=${JOBS} benchmarks
|
||||||
./src/benchmarks/alias-bench
|
./src/benchmarks/alias-bench
|
||||||
./src/benchmarks/json-render-bench ../src/benchmarks/portugal_to_korea.json
|
./src/benchmarks/json-render-bench ../src/benchmarks/portugal_to_korea.json
|
||||||
./src/benchmarks/match-bench ../test/data/ch/monaco.osrm
|
./src/benchmarks/match-bench ../test/data/ch/monaco.osrm
|
||||||
./src/benchmarks/packedvector-bench
|
./src/benchmarks/packedvector-bench
|
||||||
|
|||||||
+9
-1
@@ -1,4 +1,12 @@
|
|||||||
# Unreleased
|
# 5.27.1
|
||||||
|
- Changes from 5.27.0
|
||||||
|
- 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)
|
||||||
|
- Routing:
|
||||||
|
- CHANGED: Add support for surface=metal,grass_paver,woodchips in bicyle profile. [#6395](https://github.com/Project-OSRM/osrm-backend/pull/6395)
|
||||||
|
|
||||||
|
# 5.27.0
|
||||||
- Changes from 5.26.0
|
- Changes from 5.26.0
|
||||||
- API:
|
- API:
|
||||||
- ADDED: Add Flatbuffers support to NodeJS bindings. [#6338](https://github.com/Project-OSRM/osrm-backend/pull/6338)
|
- ADDED: Add Flatbuffers support to NodeJS bindings. [#6338](https://github.com/Project-OSRM/osrm-backend/pull/6338)
|
||||||
|
|||||||
@@ -58,16 +58,16 @@ Download OpenStreetMap extracts for example from [Geofabrik](http://download.geo
|
|||||||
|
|
||||||
Pre-process the extract with the car profile and start a routing engine HTTP server on port 5000
|
Pre-process the extract with the car profile and start a routing engine HTTP server on port 5000
|
||||||
|
|
||||||
docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf
|
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-extract -p /opt/car.lua /data/berlin-latest.osm.pbf
|
||||||
|
|
||||||
The flag `-v "${PWD}:/data"` creates the directory `/data` inside the docker container and makes the current working directory `"${PWD}"` available there. The file `/data/berlin-latest.osm.pbf` inside the container is referring to `"${PWD}/berlin-latest.osm.pbf"` on the host.
|
The flag `-v "${PWD}:/data"` creates the directory `/data` inside the docker container and makes the current working directory `"${PWD}"` available there. The file `/data/berlin-latest.osm.pbf` inside the container is referring to `"${PWD}/berlin-latest.osm.pbf"` on the host.
|
||||||
|
|
||||||
docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-partition /data/berlin-latest.osrm
|
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-partition /data/berlin-latest.osrm
|
||||||
docker run -t -v "${PWD}:/data" osrm/osrm-backend osrm-customize /data/berlin-latest.osrm
|
docker run -t -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-customize /data/berlin-latest.osrm
|
||||||
|
|
||||||
Note there is no `berlin-latest.osrm` file, but multiple `berlin-latest.osrm.*` files, i.e. `berlin-latest.osrm` is not file path, but "base" path referring to set of files and there is an option to omit this `.osrm` suffix completely(e.g. `osrm-partition /data/berlin-latest`).
|
Note there is no `berlin-latest.osrm` file, but multiple `berlin-latest.osrm.*` files, i.e. `berlin-latest.osrm` is not file path, but "base" path referring to set of files and there is an option to omit this `.osrm` suffix completely(e.g. `osrm-partition /data/berlin-latest`).
|
||||||
|
|
||||||
docker run -t -i -p 5000:5000 -v "${PWD}:/data" osrm/osrm-backend osrm-routed --algorithm mld /data/berlin-latest.osrm
|
docker run -t -i -p 5000:5000 -v "${PWD}:/data" ghcr.io/project-osrm/osrm-backend osrm-routed --algorithm mld /data/berlin-latest.osrm
|
||||||
|
|
||||||
Make requests against the HTTP server
|
Make requests against the HTTP server
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ Feature: Bike - Surfaces
|
|||||||
| cycleway | cobblestone:flattened | 72 s |
|
| cycleway | cobblestone:flattened | 72 s |
|
||||||
| cycleway | paving_stones | 72 s |
|
| cycleway | paving_stones | 72 s |
|
||||||
| cycleway | wood | 72 s |
|
| cycleway | wood | 72 s |
|
||||||
|
| cycleway | metal | 72 s |
|
||||||
| cycleway | compacted | 72 s |
|
| cycleway | compacted | 72 s |
|
||||||
| cycleway | fine_gravel | 72 s |
|
| cycleway | fine_gravel | 72 s |
|
||||||
| cycleway | ground | 72 s |
|
| cycleway | ground | 72 s |
|
||||||
@@ -22,11 +23,13 @@ Feature: Bike - Surfaces
|
|||||||
| cycleway | cobblestone | 102.9 s |
|
| cycleway | cobblestone | 102.9 s |
|
||||||
| cycleway | gravel | 120 s |
|
| cycleway | gravel | 120 s |
|
||||||
| cycleway | pebblestone | 120 s |
|
| cycleway | pebblestone | 120 s |
|
||||||
|
| cycleway | grass_paver | 120 s |
|
||||||
| cycleway | dirt | 90 s |
|
| cycleway | dirt | 90 s |
|
||||||
| cycleway | earth | 120 s |
|
| cycleway | earth | 120 s |
|
||||||
| cycleway | grass | 120 s |
|
| cycleway | grass | 120 s |
|
||||||
| cycleway | mud | 240 s |
|
| cycleway | mud | 240 s |
|
||||||
| cycleway | sand | 240 s |
|
| cycleway | sand | 240 s |
|
||||||
|
| cycleway | woodchips | 240 s |
|
||||||
| cycleway | sett | 80 s |
|
| cycleway | sett | 80 s |
|
||||||
|
|
||||||
Scenario: Bicycle - Good surfaces on small paths
|
Scenario: Bicycle - Good surfaces on small paths
|
||||||
|
|||||||
@@ -115,6 +115,36 @@ Feature: Car - Turn restrictions
|
|||||||
| c | a | cj,aj,aj |
|
| c | a | cj,aj,aj |
|
||||||
| c | b | cj,bj,bj |
|
| c | b | cj,bj,bj |
|
||||||
|
|
||||||
|
@no_turning
|
||||||
|
Scenario: Car - No u-turn
|
||||||
|
# https://www.openstreetmap.org/edit?node=54878482#map=19/34.05242/-117.19067
|
||||||
|
Given the node map
|
||||||
|
"""
|
||||||
|
c
|
||||||
|
3
|
||||||
|
a 1 x 2 b
|
||||||
|
4
|
||||||
|
d
|
||||||
|
"""
|
||||||
|
|
||||||
|
And the ways
|
||||||
|
| nodes |
|
||||||
|
| ax |
|
||||||
|
| xb |
|
||||||
|
| cx |
|
||||||
|
| xd |
|
||||||
|
|
||||||
|
And the relations
|
||||||
|
| type | way:from | way:to | node:via | restriction |
|
||||||
|
| restriction | ax | ax | x | no_u_turn |
|
||||||
|
| restriction | bx | bx | x | no_u_turn |
|
||||||
|
| restriction | cx | cx | x | no_u_turn |
|
||||||
|
| restriction | dx | dx | x | no_u_turn |
|
||||||
|
|
||||||
|
When I route I should get
|
||||||
|
| waypoints | route | turns |
|
||||||
|
| a,x,a | ax,xb,xb,xb,ax,ax | depart,new name straight,continue uturn,arrive,depart,arrive |
|
||||||
|
|
||||||
@no_turning
|
@no_turning
|
||||||
Scenario: Car - Handle any no_* relation
|
Scenario: Car - Handle any no_* relation
|
||||||
Given the node map
|
Given the node map
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module.exports = function () {
|
|||||||
this.When(/^I request \/(.*)$/, (path, callback) => {
|
this.When(/^I request \/(.*)$/, (path, callback) => {
|
||||||
this.reprocessAndLoadData((e) => {
|
this.reprocessAndLoadData((e) => {
|
||||||
if (e) return callback(e);
|
if (e) return callback(e);
|
||||||
this.requestPath(path, {}, (err, res, body) => {
|
this.requestUrl(path, (err, res, body) => {
|
||||||
this.response = res;
|
this.response = res;
|
||||||
callback(err, res, body);
|
callback(err, res, body);
|
||||||
});
|
});
|
||||||
@@ -23,13 +23,13 @@ module.exports = function () {
|
|||||||
this.ShouldBeWellFormed();
|
this.ShouldBeWellFormed();
|
||||||
});
|
});
|
||||||
|
|
||||||
this.Then(/^status code should be (\d+)$/, (code, callback) => {
|
this.Then(/^status code should be (.+)$/, (code, callback) => {
|
||||||
try {
|
try {
|
||||||
this.json = JSON.parse(this.response.body);
|
this.json = JSON.parse(this.response.body);
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
return callback(e);
|
return callback(e);
|
||||||
}
|
}
|
||||||
assert.equal(this.json.status, parseInt(code));
|
assert.equal(this.json.code, code);
|
||||||
callback();
|
callback();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -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));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
File diff suppressed because one or more lines are too long
+2
-1
@@ -38,7 +38,8 @@ 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})
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#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,15 +4,14 @@
|
|||||||
#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
|
||||||
@@ -48,7 +47,6 @@ 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.
|
||||||
@@ -62,13 +60,11 @@ 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;
|
||||||
std::optional<RequestParser> http_request_parser;
|
RequestParser request_parser;
|
||||||
boost::array<char, 8192> incoming_data_buffer;
|
boost::array<char, 8192> incoming_data_buffer;
|
||||||
http::request current_request;
|
http::request current_request;
|
||||||
http::reply current_reply;
|
http::reply current_reply;
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
#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.0-unreleased",
|
"version": "5.27.1",
|
||||||
"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": {
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ function setup()
|
|||||||
concrete = default_speed,
|
concrete = default_speed,
|
||||||
concrete_lanes = default_speed,
|
concrete_lanes = default_speed,
|
||||||
wood = 10,
|
wood = 10,
|
||||||
|
metal = 10,
|
||||||
["cobblestone:flattened"] = 10,
|
["cobblestone:flattened"] = 10,
|
||||||
paving_stones = 10,
|
paving_stones = 10,
|
||||||
compacted = 10,
|
compacted = 10,
|
||||||
@@ -186,12 +187,14 @@ function setup()
|
|||||||
fine_gravel = 10,
|
fine_gravel = 10,
|
||||||
gravel = 6,
|
gravel = 6,
|
||||||
pebblestone = 6,
|
pebblestone = 6,
|
||||||
|
grass_paver = 6,
|
||||||
ground = 10,
|
ground = 10,
|
||||||
dirt = 8,
|
dirt = 8,
|
||||||
earth = 6,
|
earth = 6,
|
||||||
grass = 6,
|
grass = 6,
|
||||||
mud = 3,
|
mud = 3,
|
||||||
sand = 3,
|
sand = 3,
|
||||||
|
woodchips = 3,
|
||||||
sett = 9
|
sett = 9
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
+30
-64
@@ -1,10 +1,12 @@
|
|||||||
#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,32 +16,12 @@ namespace server
|
|||||||
|
|
||||||
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), http_request_parser(std::make_optional<RequestParser>())
|
request_handler(handler)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
{
|
{
|
||||||
@@ -78,45 +60,20 @@ 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, bytes_transferred), 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);
|
||||||
|
|
||||||
if (ec)
|
// the request has been parsed
|
||||||
|
if (result == RequestParser::RequestStatus::valid)
|
||||||
{
|
{
|
||||||
if (ec == boost::beast::http::error::need_more)
|
|
||||||
{
|
|
||||||
// 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));
|
|
||||||
}
|
|
||||||
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();
|
||||||
@@ -170,6 +127,25 @@ 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.
|
||||||
@@ -182,7 +158,7 @@ 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();
|
||||||
http_request_parser.emplace();
|
request_parser = RequestParser();
|
||||||
incoming_data_buffer = boost::array<char, 8192>();
|
incoming_data_buffer = boost::array<char, 8192>();
|
||||||
output_buffer.clear();
|
output_buffer.clear();
|
||||||
this->start();
|
this->start();
|
||||||
@@ -244,15 +220,5 @@ 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
|
||||||
|
|||||||
@@ -0,0 +1,302 @@
|
|||||||
|
#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
|
||||||
Reference in New Issue
Block a user