#include "server/request_handler.hpp" #include "server/service_handler.hpp" #include "server/api/url_parser.hpp" #include "server/http/reply.hpp" #include "server/http/request.hpp" #include "util/json_renderer.hpp" #include "util/log.hpp" #include "util/string_util.hpp" #include "util/timing_util.hpp" #include "engine/status.hpp" #include "osrm/osrm.hpp" #include "util/json_container.hpp" #include #include #include #include #include #include namespace osrm::server { void RequestHandler::RegisterServiceHandler( std::unique_ptr service_handler_) { service_handler = std::move(service_handler_); } void SendResponse(ServiceHandler::ResultT &result, http::reply ¤t_reply) { current_reply.headers.emplace_back("Access-Control-Allow-Origin", "*"); current_reply.headers.emplace_back("Access-Control-Allow-Methods", "GET"); current_reply.headers.emplace_back("Access-Control-Allow-Headers", "X-Requested-With, Content-Type"); if (std::holds_alternative(result)) { current_reply.headers.emplace_back("Content-Type", "application/json; charset=UTF-8"); current_reply.headers.emplace_back("Content-Disposition", "inline; filename=\"response.json\""); util::json::render(current_reply.content, std::get(result)); } else if (std::holds_alternative(result)) { auto &buffer = std::get(result); current_reply.content.resize(buffer.GetSize()); std::copy(buffer.GetBufferPointer(), buffer.GetBufferPointer() + buffer.GetSize(), current_reply.content.begin()); current_reply.headers.emplace_back( "Content-Type", "application/x-flatbuffers;schema=osrm.engine.api.fbresult"); } else { BOOST_ASSERT(std::holds_alternative(result)); current_reply.content.resize(std::get(result).size()); std::copy(std::get(result).cbegin(), std::get(result).cend(), current_reply.content.begin()); current_reply.headers.emplace_back("Content-Type", "application/x-protobuf"); } // set headers current_reply.headers.emplace_back("Content-Length", std::to_string(current_reply.content.size())); } void RequestHandler::HandleRequest(const http::request ¤t_request, http::reply ¤t_reply) { if (!service_handler) { current_reply = http::reply::stock_reply(http::reply::internal_server_error); util::Log(logWARNING) << "No service handler registered." << std::endl; return; } const auto tid = std::this_thread::get_id(); // parse command try { TIMER_START(request_duration); std::string request_string; util::URIDecode(current_request.uri, request_string); util::Log(logDEBUG) << "[req][" << tid << "] " << request_string; auto api_iterator = request_string.begin(); auto maybe_parsed_url = api::parseURL(api_iterator, request_string.end()); ServiceHandler::ResultT result; // check if the was an error with the request if (maybe_parsed_url && api_iterator == request_string.end()) { const engine::Status status = service_handler->RunQuery(*std::move(maybe_parsed_url), result); if (status != engine::Status::Ok) { // 4xx bad request return code current_reply.status = http::reply::bad_request; } else { BOOST_ASSERT(status == engine::Status::Ok); } } else { const auto position = std::distance(request_string.begin(), api_iterator); BOOST_ASSERT(position >= 0); const auto context_begin = request_string.begin() + ((position < 3) ? 0 : (position - 3UL)); BOOST_ASSERT(context_begin >= request_string.begin()); const auto context_end = request_string.begin() + std::min(position + 3UL, request_string.size()); BOOST_ASSERT(context_end <= request_string.end()); std::string context(context_begin, context_end); current_reply.status = http::reply::bad_request; result = util::json::Object(); auto &json_result = std::get(result); json_result.values["code"] = "InvalidUrl"; json_result.values["message"] = "URL string malformed close to position " + std::to_string(position) + ": \"" + context + "\""; } SendResponse(result, current_reply); if (!std::getenv("DISABLE_ACCESS_LOGGING")) { // deactivated as GCC apparently does not implement that, not even in 4.9 // std::time_t t = std::time(nullptr); // util::Log() << std::put_time(std::localtime(&t), "%m-%d-%Y // %H:%M:%S") << // " " << current_request.endpoint.to_string() << " " << // current_request.referrer << ( 0 == current_request.referrer.length() ? "- " :" ") // << // current_request.agent << ( 0 == current_request.agent.length() ? "- " :" ") << // request; time_t ltime; struct tm *time_stamp; TIMER_STOP(request_duration); ltime = time(nullptr); time_stamp = localtime(<ime); // log timestamp util::Log() << (time_stamp->tm_mday < 10 ? "0" : "") << time_stamp->tm_mday << "-" << (time_stamp->tm_mon + 1 < 10 ? "0" : "") << (time_stamp->tm_mon + 1) << "-" << 1900 + time_stamp->tm_year << " " << (time_stamp->tm_hour < 10 ? "0" : "") << time_stamp->tm_hour << ":" << (time_stamp->tm_min < 10 ? "0" : "") << time_stamp->tm_min << ":" << (time_stamp->tm_sec < 10 ? "0" : "") << time_stamp->tm_sec << " " << TIMER_MSEC(request_duration) << "ms " << current_request.endpoint.to_string() << " " << current_request.referrer << (0 == current_request.referrer.length() ? "- " : " ") << current_request.agent << (0 == current_request.agent.length() ? "- " : " ") << current_reply.status << " " // << request_string; } } catch (const util::DisabledDatasetException &e) { current_reply.status = http::reply::bad_request; ServiceHandler::ResultT result = util::json::Object(); auto &json_result = std::get(result); json_result.values["code"] = "DisabledDataset"; json_result.values["message"] = e.what(); SendResponse(result, current_reply); util::Log(logWARNING) << "[disabled dataset error][" << tid << "] code: DisabledDataset_" << e.Dataset() << ", uri: " << current_request.uri; } catch (const std::exception &e) { current_reply = http::reply::stock_reply(http::reply::internal_server_error); util::Log(logWARNING) << "[server error][" << tid << "] code: " << e.what() << ", uri: " << current_request.uri; } } } // namespace osrm::server