int Jupiter::HTTP::Server::Data::process_request(HTTPSession &session) { Jupiter::ReadableString::TokenizeResult<Jupiter::Reference_String> lines = Jupiter::ReferenceString::tokenize(session.request, STRING_LITERAL_AS_REFERENCE(ENDL)); HTTPCommand command = HTTPCommand::NONE_SPECIFIED; Content *content = nullptr; Jupiter::ReferenceString query_string; Jupiter::ReferenceString first_token; size_t index = 0; size_t span; auto get_line_offset = [&session, &lines](size_t index) { size_t offset = 0; while (index != 0) offset += lines.tokens[--index].size() + 2; return offset; }; while (index != lines.token_count) { Jupiter::ReferenceString &line = lines.tokens[index++]; // trim front-end spaces. span = line.span(" "_jrs); if (span != 0) line.shiftRight(span); if (line.isEmpty()) // end of http request { Jupiter::String result(256); switch (command) { case HTTPCommand::GET: case HTTPCommand::HEAD: if (content != nullptr) { // 200 (success) Jupiter::ReadableString *content_result = content->execute(query_string); switch (session.version) { default: case HTTPVersion::HTTP_1_0: result = "HTTP/1.0 200 OK"_jrs ENDL; break; case HTTPVersion::HTTP_1_1: result = "HTTP/1.1 200 OK"_jrs ENDL; break; } result += "Date: "_jrs; char *time_header = html_time(); result += time_header; delete[] time_header; result += ENDL; result += "Server: "_jrs JUPITER_VERSION ENDL; result += Jupiter::StringS::Format("Content-Length: %u" ENDL, content_result->size()); if (session.keep_alive) result += "Connection: keep-alive"_jrs ENDL; else result += "Connection: close"_jrs ENDL; result += "Content-Type: "_jrs; if (content->type == nullptr) result += Jupiter::HTTP::Content::Type::Text::PLAIN; else result += *content->type; if (content->charset != nullptr) { result += "; charset="_jrs; result += *content->charset; } result += ENDL; if (content->language != nullptr) { result += "Content-Language: "_jrs; result += *content->language; result += ENDL; } result += ENDL; if (command == HTTPCommand::GET) result += *content_result; if (content->free_result) delete content_result; session.sock.send(result); } else { // 404 (not found) switch (session.version) { default: case HTTPVersion::HTTP_1_0: result = "HTTP/1.0 404 Not Found"_jrs ENDL; break; case HTTPVersion::HTTP_1_1: result = "HTTP/1.1 404 Not Found"_jrs ENDL; break; } char *time_header = html_time(); result += "Date: "_jrs ENDL; result += time_header; delete[] time_header; result += "Server: "_jrs JUPITER_VERSION ENDL; result += "Content-Length: 0"_jrs ENDL; if (session.keep_alive) result += "Connection: keep-alive"_jrs ENDL; else result += "Connection: close"_jrs ENDL; result += ENDL ENDL; session.sock.send(result); } break; default: break; } if (session.keep_alive == false) // not keep-alive -- will be destroyed on return break; if (index == lines.token_count) // end of packet session.request.erase(); else // end of request -- another request is following session.request.shiftRight(get_line_offset(index)); if (session.request.find(HTTP_REQUEST_ENDING) != Jupiter::INVALID_INDEX) // there's another full request already received return Jupiter::HTTP::Server::Data::process_request(session); break; } // Not empty first_token = line.getToken(0, ' '); if (first_token.get(first_token.size() - 1) == ':') // header field { first_token.truncate(1); // trim trailing ':' if (first_token.equalsi("HOST"_jrs)) session.host = Jupiter::HTTP::Server::Data::find_host(line.getWord(1, " ")); else if (first_token.equalsi("CONNECTION"_jrs)) { Jupiter::ReferenceString connection_type = line.getWord(1, " "); if (connection_type.equalsi("keep-alive"_jrs)) session.keep_alive = Jupiter::HTTP::Server::Data::permit_keept_alive; } } else // command { if (first_token.equals("GET"_jrs)) { command = HTTPCommand::GET; query_string = line.getWord(1, " "); span = query_string.find('?'); // repurposing 'span' if (span == Jupiter::INVALID_INDEX) { if (session.host == nullptr) content = Jupiter::HTTP::Server::Data::find(query_string); else content = session.host->find(query_string); query_string.erase(); } else { if (session.host == nullptr) content = Jupiter::HTTP::Server::Data::find(query_string.substring(size_t{ 0 }, span)); else content = session.host->find(query_string.substring(size_t{ 0 }, span)); query_string.shiftRight(span + 1); // decode query_string here } Jupiter::ReferenceString protocol_str = line.getWord(2, " "); if (protocol_str.equalsi("http/1.0"_jrs)) session.version = HTTPVersion::HTTP_1_0; else if (protocol_str.equalsi("http/1.1"_jrs)) { session.version = HTTPVersion::HTTP_1_1; session.keep_alive = Jupiter::HTTP::Server::Data::permit_keept_alive; } } else if (first_token.equals("HEAD"_jrs)) { command = HTTPCommand::HEAD; query_string = line.getWord(1, " "); span = query_string.find('?'); // repurposing 'span' if (span == Jupiter::INVALID_INDEX) { if (session.host == nullptr) content = Jupiter::HTTP::Server::Data::find(query_string); else content = session.host->find(query_string); query_string.erase(); } else { if (session.host == nullptr) content = Jupiter::HTTP::Server::Data::find(query_string.substring(size_t{ 0 }, span)); else content = session.host->find(query_string.substring(size_t{ 0 }, span)); query_string.shiftRight(span + 1); // decode query_string here } Jupiter::ReferenceString protocol_str = line.getWord(2, " "); if (protocol_str.equalsi("http/1.0"_jrs)) session.version = HTTPVersion::HTTP_1_0; else if (protocol_str.equalsi("http/1.1"_jrs)) { session.version = HTTPVersion::HTTP_1_1; session.keep_alive = Jupiter::HTTP::Server::Data::permit_keept_alive; } } else command = HTTPCommand::UNKNOWN; } } return 0; }