diff --git a/src/overpass_api/frontend/cgi-helper.cc b/src/overpass_api/frontend/cgi-helper.cc index 186e0456c..42fd5b4a8 100644 --- a/src/overpass_api/frontend/cgi-helper.cc +++ b/src/overpass_api/frontend/cgi-helper.cc @@ -16,6 +16,7 @@ * along with Overpass_API. If not, see . */ +#include #include #include #include @@ -61,14 +62,21 @@ std::string cgi_get_to_text() return ""; } -std::string cgi_post_to_text() +std::string cgi_post_to_text(std::string::size_type max_input_size) { - std::string raw, buf; - while (!std::cin.eof()) + std::string raw; + const std::streamsize chunk_size = 65536; + char chunk[chunk_size]; + + while (raw.size() <= max_input_size) { - getline(std::cin, buf); - raw += buf + '\n'; + std::cin.read(chunk, chunk_size); + std::streamsize count = std::cin.gcount(); + if (count <= 0) + break; + raw.append(chunk, count); } + return raw; } @@ -79,10 +87,8 @@ std::string replace_cgi(const std::string& raw) while (pos < raw.size()) { - if (raw[pos] == '%') + if (raw[pos] == '%' && pos + 2 < raw.size()) { - if (pos >= raw.size()+2) - return (result + raw.substr(0, pos)); char a(hex_digit(raw[pos+1])), b(hex_digit(raw[pos+2])); if ((a < 16) && (b < 16)) { @@ -115,8 +121,8 @@ std::map< std::string, std::string > decode_cgi_to_plain(const std::string& raw) if (delim_pos == std::string::npos) delim_pos = raw.size(); - std::string::size_type middle_pos = raw.find('=', pos); - if (middle_pos != std::string::npos && middle_pos < delim_pos) + std::string::size_type middle_pos = std::find(raw.begin() + pos, raw.begin() + delim_pos, '=') - raw.begin(); + if (middle_pos != delim_pos) { std::string::size_type end_pos = delim_pos; while (end_pos > 0 && isspace(raw[end_pos-1])) diff --git a/src/overpass_api/frontend/cgi-helper.h b/src/overpass_api/frontend/cgi-helper.h index 983cbd804..a731da91b 100644 --- a/src/overpass_api/frontend/cgi-helper.h +++ b/src/overpass_api/frontend/cgi-helper.h @@ -25,7 +25,7 @@ std::string cgi_get_to_text(); -std::string cgi_post_to_text(); +std::string cgi_post_to_text(std::string::size_type max_input_size); std::map< std::string, std::string > decode_cgi_to_plain(const std::string& raw); diff --git a/src/overpass_api/frontend/user_interface.cc b/src/overpass_api/frontend/user_interface.cc index 8b6fe764b..54e973cef 100644 --- a/src/overpass_api/frontend/user_interface.cc +++ b/src/overpass_api/frontend/user_interface.cc @@ -29,6 +29,7 @@ #include "cgi-helper.h" #include "../../expat/expat_justparse_interface.h" +#include "../data/utils.h" #include "user_interface.h" @@ -37,7 +38,7 @@ namespace std::string autocomplete (std::string& input, Error_Output* error_output, uint32 max_input_size) { - unsigned int pos(0), line_number(1); + std::size_t pos(0), line_number(1); while ((pos < input.size()) && (isspace(input[pos]))) { if (input[pos] == '\n') @@ -124,10 +125,10 @@ std::map< std::string, std::string > get_xml_cgi( char* origin = getenv("HTTP_ORIGIN"); has_origin = ((origin) && strnlen(origin, 1) > 0); - int line_number(1); + std::size_t line_number(1); // If there is nonempty input from GET method, use GET std::string input(cgi_get_to_text()); - unsigned int pos(0); + std::size_t pos(0); while ((pos < input.size()) && (isspace(input[pos]))) { if (input[pos] == '\n') @@ -159,7 +160,7 @@ std::map< std::string, std::string > get_xml_cgi( error_output->add_encoding_remark("Only whitespace found from GET method. Trying to retrieve input by POST method."); } - input = cgi_post_to_text(); + input = cgi_post_to_text(max_input_size); pos = 0; line_number = 1; while ((pos < input.size()) && (isspace(input[pos]))) @@ -217,20 +218,44 @@ std::map< std::string, std::string > get_xml_cgi( } coords.push_back(lonlat.substr(pos)); - if (coords.size() == 4) + bool numeric = coords.size() == 4; + for (std::size_t i = 0; numeric && i < coords.size(); ++i) { - std::string latlon = coords[1] + "," + coords[0] + "," + coords[3] + "," + coords[2]; - - pos = input.find("(bbox)"); - while (pos != std::string::npos) - { - input = input.substr(0, pos) + "(" + latlon + ")" + input.substr(pos + 6); - pos = input.find("(bbox)"); - } - - pos = input.find("[bbox]"); - if (pos != std::string::npos) - input = input.substr(0, pos) + "[bbox:" + latlon + "]" + input.substr(pos + 6); + double value = 0; + if (try_double(coords[i], value)) + coords[i] = to_string(value); + else + numeric = false; + } + + if (numeric) + { + std::string bbox_global = "[bbox:" + coords[1] + ',' + coords[0] + ',' + coords[3] + ',' + coords[2] + ']'; + std::string bbox_filter = '(' + coords[1] + ',' + coords[0] + ',' + coords[3] + ',' + coords[2] + ')'; + + std::string modified; + std::string::size_type last = 0; + std::string::size_type paren = input.find("(bbox)"); + std::string::size_type bracket = input.find("[bbox]"); + while (paren != std::string::npos || bracket != std::string::npos) + { + if (bracket < paren) + { + modified.append(input, last, bracket - last); + modified += bbox_global; + last = bracket + 6; + bracket = std::string::npos; + } + else + { + modified.append(input, last, paren - last); + modified += bbox_filter; + last = paren + 6; + paren = input.find("(bbox)", last); + } + } + modified.append(input, last); + input.swap(modified); } } } @@ -253,7 +278,7 @@ std::string get_xml_console(Error_Output* error_output, uint32 max_input_size) // If there is nonempty input from GET method, use GET std::string input(""); - input = cgi_post_to_text(); + input = cgi_post_to_text(max_input_size); input = autocomplete(input, error_output, max_input_size); return input; } diff --git a/src/overpass_api/output_formats/output_custom_factory.cc b/src/overpass_api/output_formats/output_custom_factory.cc index a99dbc543..d10e4e48e 100644 --- a/src/overpass_api/output_formats/output_custom_factory.cc +++ b/src/overpass_api/output_formats/output_custom_factory.cc @@ -53,6 +53,13 @@ Output_Handler* Output_Custom_Generator::new_output_handler(const std::map< std: error_output->add_encoding_error("Parameter \"template\" must not contain slashes."); template_name = ""; } + // sanity check for url + if (url.find('\r') != std::string::npos || url.find('\n') != std::string::npos) + { + if (error_output) + error_output->add_encoding_error("Parameter \"url\" must not contain line breaks."); + url = ""; + } return new Output_Custom(redirect_it == input_params.end() || redirect_it->second != "no", template_name, url); diff --git a/src/pt_diagrams/processed_input.cc b/src/pt_diagrams/processed_input.cc index 9d1e0b82f..4ba8438e4 100644 --- a/src/pt_diagrams/processed_input.cc +++ b/src/pt_diagrams/processed_input.cc @@ -765,20 +765,20 @@ void start(const char *el, const char **attr) is_route = true; if ((key == "route") && (value == "ferry")) is_route = true; - if (key == "operates_Mo_Fr") + if (key == "operates_Mo_Fr" && value.size() >= 9) { for (unsigned int i(0); i < 5; ++i) relation.opening_hours.push_back(Timespan (i, atoi(value.substr(0, 2).c_str()), atoi(value.substr(2, 2).c_str()), i, atoi(value.substr(5, 2).c_str()), atoi(value.substr(7, 2).c_str()))); } - if (key == "operates_Sa") + if (key == "operates_Sa" && value.size() >= 9) { relation.opening_hours.push_back(Timespan (5, atoi(value.substr(0, 2).c_str()), atoi(value.substr(2, 2).c_str()), 5, atoi(value.substr(5, 2).c_str()), atoi(value.substr(7, 2).c_str()))); } - if (key == "operates_Su") + if (key == "operates_Su" && value.size() >= 9) { relation.opening_hours.push_back(Timespan (6, atoi(value.substr(0, 2).c_str()), atoi(value.substr(2, 2).c_str()),