diff --git a/features/step_definitions/data.rb b/features/step_definitions/data.rb index f1e58bae2..524fd322c 100644 --- a/features/step_definitions/data.rb +++ b/features/step_definitions/data.rb @@ -174,3 +174,7 @@ end Given /^data is loaded with datastore$/ do @load_method = 'datastore' end + +Given /^the HTTP method "([^"]*)"$/ do |method| + @http_method = method +end diff --git a/features/step_definitions/locate.rb b/features/step_definitions/locate.rb index 190795c26..2fd8e627b 100644 --- a/features/step_definitions/locate.rb +++ b/features/step_definitions/locate.rb @@ -9,7 +9,7 @@ When /^I request locate I should get$/ do |table| out_node = find_node_by_name row['out'] raise "*** unknown out-node '#{row['out']}" unless out_node - response = request_locate("#{in_node.lat},#{in_node.lon}") + response = request_locate(in_node) if response.code == "200" && response.body.empty? == false json = JSON.parse response.body if json['status'] == 0 diff --git a/features/step_definitions/nearest.rb b/features/step_definitions/nearest.rb index 099f4e06f..481c74167 100644 --- a/features/step_definitions/nearest.rb +++ b/features/step_definitions/nearest.rb @@ -9,7 +9,7 @@ When /^I request nearest I should get$/ do |table| out_node = find_node_by_name row['out'] raise "*** unknown out-node '#{row['out']}" unless out_node - response = request_nearest("#{in_node.lat},#{in_node.lon}") + response = request_nearest(in_node) if response.code == "200" && response.body.empty? == false json = JSON.parse response.body if json['status'] == 0 diff --git a/features/support/http.rb b/features/support/http.rb new file mode 100644 index 000000000..80dad8a85 --- /dev/null +++ b/features/support/http.rb @@ -0,0 +1,34 @@ +require 'net/http' + +def generate_request_url path + if @http_method.eql? "POST" + pos = path.index('?') - 1 + service = path[0..pos] + uri = URI.parse "#{HOST}/#{service}" + else + uri = URI.parse "#{HOST}/#{path}" + end +end + +def send_request uri, waypoints=[], options={}, timestamps=[] + @query = uri.to_s + Timeout.timeout(OSRM_TIMEOUT) do + if @http_method.eql? "POST" + datas = {} + if waypoints.length > 0 + datas[:loc] = waypoints.compact.map { |w| "#{w.lat},#{w.lon}" } + end + if timestamps.length > 0 + datas[:t] = timestamps.compact.map { |t| "#{t}" } + end + datas.merge! options + response = Net::HTTP.post_form uri, datas + else + response = Net::HTTP.get_response uri + end + end +rescue Errno::ECONNREFUSED => e + raise "*** osrm-routed is not running." +rescue Timeout::Error + raise "*** osrm-routed did not respond." +end diff --git a/features/support/locate.rb b/features/support/locate.rb index 900724703..a62e53aa9 100644 --- a/features/support/locate.rb +++ b/features/support/locate.rb @@ -1,17 +1,12 @@ require 'net/http' -def request_locate_url path +def request_locate_url path, node @query = path - uri = URI.parse "#{HOST}/#{path}" - Timeout.timeout(OSRM_TIMEOUT) do - Net::HTTP.get_response uri - end -rescue Errno::ECONNREFUSED => e - raise "*** osrm-routed is not running." -rescue Timeout::Error - raise "*** osrm-routed did not respond." + + uri = generate_request_url path + response = send_request uri, [node] end -def request_locate a - request_locate_url "locate?loc=#{a}" +def request_locate node + request_locate_url "locate?loc=#{node.lat},#{node.lon}", node end diff --git a/features/support/match.rb b/features/support/match.rb index bf51189a4..8bcf7a2c6 100644 --- a/features/support/match.rb +++ b/features/support/match.rb @@ -13,14 +13,8 @@ def request_matching trace=[], timestamps=[], options={} end params = (trace_params + defaults.merge(options).to_param).join('&') params = nil if params=="" - uri = URI.parse ["#{HOST}/match", params].compact.join('?') - @query = uri.to_s - Timeout.timeout(OSRM_TIMEOUT) do - Net::HTTP.get_response uri - end -rescue Errno::ECONNREFUSED => e - raise "*** osrm-routed is not running." -rescue Timeout::Error - raise "*** osrm-routed did not respond." + + uri = generate_request_url ("match" + '?' + params) + response = send_request uri, trace, options, timestamps end diff --git a/features/support/nearest.rb b/features/support/nearest.rb index 77fc351a9..af52b49e0 100644 --- a/features/support/nearest.rb +++ b/features/support/nearest.rb @@ -1,17 +1,12 @@ require 'net/http' -def request_nearest_url path +def request_nearest_url path, node @query = path - uri = URI.parse "#{HOST}/#{path}" - Timeout.timeout(OSRM_TIMEOUT) do - Net::HTTP.get_response uri - end -rescue Errno::ECONNREFUSED => e - raise "*** osrm-routed is not running." -rescue Timeout::Error - raise "*** osrm-routed did not respond." + + uri = generate_request_url path + response = send_request uri, [node] end -def request_nearest a - request_nearest_url "nearest?loc=#{a}" +def request_nearest node + request_nearest_url "nearest?loc=#{node.lat},#{node.lon}", node end diff --git a/features/support/route.rb b/features/support/route.rb index a8c78227e..ca353d6e6 100644 --- a/features/support/route.rb +++ b/features/support/route.rb @@ -15,15 +15,13 @@ def request_path path, waypoints=[], options={} locs = waypoints.compact.map { |w| "loc=#{w.lat},#{w.lon}" } params = (locs + options.to_param).join('&') params = nil if params=="" - uri = URI.parse ["#{HOST}/#{path}", params].compact.join('?') - @query = uri.to_s - Timeout.timeout(OSRM_TIMEOUT) do - Net::HTTP.get_response uri + + if params == nil + uri = generate_request_url (path) + else + uri = generate_request_url (path + '?' + params) end -rescue Errno::ECONNREFUSED => e - raise "*** osrm-routed is not running." -rescue Timeout::Error - raise "*** osrm-routed did not respond." + response = send_request uri, waypoints, options end def request_url path diff --git a/features/testbot/post.feature b/features/testbot/post.feature new file mode 100644 index 000000000..ff2282406 --- /dev/null +++ b/features/testbot/post.feature @@ -0,0 +1,100 @@ +@post @testbot +Feature: POST request + + Background: + Given the profile "testbot" + And the HTTP method "POST" + + Scenario: Testbot - viaroute POST request + Given the node locations + | node | lat | lon | + | a | 55.68740 | 12.52430 | + | b | 55.68745 | 12.52409 | + | c | 55.68711 | 12.52383 | + | x | -55.68740 | 12.52430 | + | y | -55.68745 | 12.52409 | + | z | -55.68711 | 12.52383 | + + And the ways + | nodes | + | ab | + | bc | + | xy | + | yz | + + When I route I should get + | from | to | route | turns | + | a | c | ab,bc | head,left,destination | + | c | a | bc,ab | head,right,destination | + | x | z | xy,yz | head,right,destination | + | z | x | yz,xy | head,left,destination | + + Scenario: Testbot - match POST request + Given the node map + | a | b | c | d | + | e | f | g | h | + + And the ways + | nodes | oneway | + | abcd | yes | + | hgfe | yes | + + When I match I should get + | trace | matchings | + | dcba | hgfe | + + Scenario: Testbot - table POST request + Given the node map + | x | a | b | y | + | | d | e | | + + And the ways + | nodes | oneway | + | abeda | yes | + | xa | | + | by | | + + When I request a travel time matrix I should get + | | x | y | d | e | + | x | 0 | 300 | 400 | 300 | + | y | 500 | 0 | 300 | 200 | + | d | 200 | 300 | 0 | 300 | + | e | 300 | 400 | 100 | 0 | + + Scenario: Testbot - locate POST request + Given the node locations + | node | lat | lon | + | a | -85 | -180 | + | b | 0 | 0 | + | c | 85 | 180 | + | x | -84 | -180 | + | y | 84 | 180 | + + And the ways + | nodes | + | abc | + + When I request locate I should get + | in | out | + | x | a | + | y | c | + + Scenario: Testbot - nearest POST request + Given the node locations + | node | lat | lon | + | a | -85 | -180 | + | b | -85 | -160 | + | c | -85 | -140 | + | x | -84.999 | -180 | + | y | -84.999 | -160 | + | z | -84.999 | -140 | + + And the ways + | nodes | + | abc | + + When I request nearest I should get + | in | out | + | x | a | + | y | b | + | z | c | diff --git a/server/request_parser.cpp b/server/request_parser.cpp index 584dcbeeb..502e6e0b8 100644 --- a/server/request_parser.cpp +++ b/server/request_parser.cpp @@ -42,7 +42,8 @@ namespace http RequestParser::RequestParser() : state(internal_state::method_start), current_header({"", ""}), - selected_compression(no_compression) + selected_compression(no_compression), is_post_header(false), + content_length(0) { } @@ -58,6 +59,11 @@ RequestParser::parse(request ¤t_request, char *begin, char *end) } } osrm::tribool result = osrm::tribool::indeterminate; + + if(state == internal_state::post_request && content_length <= 0) + { + result = osrm::tribool::yes; + } return std::make_tuple(result, selected_compression); } @@ -70,8 +76,39 @@ osrm::tribool RequestParser::consume(request ¤t_request, const char input) { return osrm::tribool::no; } + if(input == 'P') + { + state = internal_state::post_O; + return osrm::tribool::indeterminate; + } state = internal_state::method; return osrm::tribool::indeterminate; + case internal_state::post_O: + if(input == 'O') + { + state = internal_state::post_S; + return osrm::tribool::indeterminate; + } + return osrm::tribool::no; + case internal_state::post_S: + if(input == 'S') + { + state = internal_state::post_T; + return osrm::tribool::indeterminate; + } + return osrm::tribool::no; + case internal_state::post_T: + if(input == 'T') + { + is_post_header = true; + state = internal_state::method; + return osrm::tribool::indeterminate; + } + return osrm::tribool::no; + case internal_state::post_request: + current_request.uri.push_back(input); + --content_length; + return osrm::tribool::indeterminate; case internal_state::method: if (input == ' ') { @@ -204,6 +241,24 @@ osrm::tribool RequestParser::consume(request ¤t_request, const char input) { current_request.agent = current_header.value; } + if (boost::iequals(current_header.name, "Content-Length")) + { + try + { + content_length = std::stoi(current_header.value); + } + catch (const std::exception &e) + { + // Ignore the header if the parameter isn't an int + } + } + if (boost::iequals(current_header.name, "Content-Type")) + { + if (!boost::icontains(current_header.value, "application/x-www-form-urlencoded")) + { + return osrm::tribool::no; + } + } if (input == '\r') { @@ -272,7 +327,19 @@ osrm::tribool RequestParser::consume(request ¤t_request, const char input) return osrm::tribool::indeterminate; } return osrm::tribool::no; - default: // expecting_newline_3 + case internal_state::expecting_newline_3: + if(input == '\n') + { + if(is_post_header) + { + current_request.uri.push_back('?'); + state = internal_state::post_request; + return osrm::tribool::indeterminate; + } + return osrm::tribool::yes; + } + return osrm::tribool::no; + default: // should never be reached return input == '\n' ? osrm::tribool::yes : osrm::tribool::no; } } diff --git a/server/request_parser.hpp b/server/request_parser.hpp index 2b6bf6944..3724613a7 100644 --- a/server/request_parser.hpp +++ b/server/request_parser.hpp @@ -80,11 +80,17 @@ class RequestParser space_before_header_value, header_value, expecting_newline_2, - expecting_newline_3 + expecting_newline_3, + post_O, + post_S, + post_T, + post_request } state; header current_header; compression_type selected_compression; + bool is_post_header; + int content_length; }; } // namespace http