void RequestParser::Test() { assert(ExtractMethod("GET / HTTP1.1") == GET); assert(ExtractMethod("HEAD / HTTP1.1") == HEAD); assert(ExtractMethod("POST / HTTP1.1") == POST); assert(ExtractMethod("Error / HTTP1.1") == UNKNOWN); assert(ExtractTarget("GET / HTTP1.1") == ""); assert(ExtractTarget("GET // HTTP1.1") == ""); assert(ExtractTarget("GET /// HTTP1.1") == ""); assert(ExtractTarget("GET /dir/file.txt HTTP1.1") == "dir/file.txt"); assert(ExtractTarget("GET /dir/file.txt?params HTTP1.1") == "dir/file.txt"); assert(ExtractTarget("GET /?params HTTP1.1") == ""); assert(ExtractTarget("GET //?params HTTP1.1") == ""); assert(Flatten(ExtractQueryParams("GET / HTTP1.1")) == ""); assert(Flatten(ExtractQueryParams("GET // HTTP1.1")) == ""); assert(Flatten(ExtractQueryParams("GET /// HTTP1.1")) == ""); assert(Flatten(ExtractQueryParams("GET /dir/file.txt HTTP1.1")) == ""); assert(Flatten(ExtractQueryParams("GET /dir/file.txt? HTTP1.1")) == ""); assert(Flatten(ExtractQueryParams("GET /dir/file.txt?params HTTP1.1")) == "params=''"); assert(Flatten(ExtractQueryParams("GET /dir/file.txt?param1¶m2¶m3 HTTP1.1")) == "param1='' param2='' param3=''"); assert(Flatten(ExtractQueryParams("GET /dir/file.txt?param1=val1¶m2=val2¶m3=val3 HTTP1.1")) == "param1='val1' param2='val2' param3='val3'"); assert(Flatten(ExtractQueryParams("GET /?params HTTP1.1")) == "params=''"); assert(Flatten(ExtractQueryParams("GET /? HTTP1.1")) == ""); assert(Flatten(ExtractQueryParams("GET //?params HTTP1.1")) == "params=''"); assert(TestRange(true, "Range: bytes=0-1024", 0, 1024)); assert(TestRange(false, "Range: time=0-1024", 0, 0)); assert(TestRange(true, "Range: bytes=0-", 0, -1)); assert(TestRange(true, "Range: bytes=1024-", 1024, -1)); assert(TestRange(true, "Range: bytes=232128512-", 232128512, -1)); }
void RequestParser::ParseRequestLine(const string& request) { // Extract method. method = ExtractMethod(request); target = ExtractTarget(request); params = ExtractQueryParams(request); //printf("Target: '%s'\n", target.c_str()); //printf("Params: '%s'\n", Flatten(params).c_str()); }
static void InternalCallback(struct mg_connection *connection, const struct mg_request_info *request) { MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data); MongooseOutputStream stream(connection); HttpOutput output(stream, that->IsKeepAliveEnabled()); // Check remote calls if (!that->IsRemoteAccessAllowed() && request->remote_ip != LOCALHOST) { output.SendUnauthorized(ORTHANC_REALM); return; } // Extract the HTTP headers IHttpHandler::Arguments headers; for (int i = 0; i < request->num_headers; i++) { std::string name = request->http_headers[i].name; std::transform(name.begin(), name.end(), name.begin(), ::tolower); headers.insert(std::make_pair(name, request->http_headers[i].value)); } // Extract the GET arguments IHttpHandler::GetArguments argumentsGET; if (!strcmp(request->request_method, "GET")) { HttpToolbox::ParseGetArguments(argumentsGET, request->query_string); } // Compute the HTTP method, taking method faking into consideration HttpMethod method = HttpMethod_Get; if (!ExtractMethod(method, request, headers, argumentsGET)) { output.SendStatus(HttpStatus_400_BadRequest); return; } // Authenticate this connection if (that->IsAuthenticationEnabled() && !IsAccessGranted(*that, headers)) { output.SendUnauthorized(ORTHANC_REALM); return; } // Apply the filter, if it is installed const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter(); if (filter != NULL) { std::string username = GetAuthenticatedUsername(headers); char remoteIp[24]; sprintf(remoteIp, "%d.%d.%d.%d", reinterpret_cast<const uint8_t*>(&request->remote_ip) [3], reinterpret_cast<const uint8_t*>(&request->remote_ip) [2], reinterpret_cast<const uint8_t*>(&request->remote_ip) [1], reinterpret_cast<const uint8_t*>(&request->remote_ip) [0]); if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str())) { output.SendUnauthorized(ORTHANC_REALM); return; } } // Extract the body of the request for PUT and POST // TODO Avoid unneccessary memcopy of the body std::string body; if (method == HttpMethod_Post || method == HttpMethod_Put) { PostDataStatus status; IHttpHandler::Arguments::const_iterator ct = headers.find("content-type"); if (ct == headers.end()) { // No content-type specified. Assume no multi-part content occurs at this point. status = ReadBody(body, connection, headers); } else { std::string contentType = ct->second; if (contentType.size() >= multipartLength && !memcmp(contentType.c_str(), multipart, multipartLength)) { status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore()); } else { status = ReadBody(body, connection, headers); } } switch (status) { case PostDataStatus_NoLength: output.SendStatus(HttpStatus_411_LengthRequired); return; case PostDataStatus_Failure: output.SendStatus(HttpStatus_400_BadRequest); return; case PostDataStatus_Pending: output.SendBody(); return; default: break; } } // Decompose the URI into its components UriComponents uri; try { Toolbox::SplitUriComponents(uri, request->uri); } catch (OrthancException) { output.SendStatus(HttpStatus_400_BadRequest); return; } LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri); bool found = false; try { if (that->HasHandler()) { found = that->GetHandler().Handle(output, method, uri, headers, argumentsGET, body.c_str(), body.size()); } } catch (OrthancException& e) { // Using this candidate handler results in an exception LOG(ERROR) << "Exception in the HTTP handler: " << e.What(); try { switch (e.GetErrorCode()) { case ErrorCode_InexistentFile: case ErrorCode_InexistentItem: case ErrorCode_UnknownResource: output.SendStatus(HttpStatus_404_NotFound); break; case ErrorCode_BadRequest: case ErrorCode_UriSyntax: output.SendStatus(HttpStatus_400_BadRequest); break; default: output.SendStatus(HttpStatus_500_InternalServerError); } } catch (OrthancException&) { // An exception here reflects the fact that an exception was // triggered after the status code was sent by the HTTP handler. } return; } catch (boost::bad_lexical_cast&) { LOG(ERROR) << "Exception in the HTTP handler: Bad lexical cast"; output.SendStatus(HttpStatus_400_BadRequest); return; } catch (std::runtime_error&) { LOG(ERROR) << "Exception in the HTTP handler: Presumably a bad JSON request"; output.SendStatus(HttpStatus_400_BadRequest); return; } if (!found) { output.SendStatus(HttpStatus_404_NotFound); } }