diff --git a/Ladybird/RequestServer/CMakeLists.txt b/Ladybird/RequestServer/CMakeLists.txt index 3738198d27b..fb579ba24b3 100644 --- a/Ladybird/RequestServer/CMakeLists.txt +++ b/Ladybird/RequestServer/CMakeLists.txt @@ -27,7 +27,7 @@ target_link_libraries(RequestServer PRIVATE requestserverservice) target_include_directories(requestserverservice PRIVATE ${LADYBIRD_SOURCE_DIR}/Userland/Services/) target_include_directories(requestserverservice PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..) -target_link_libraries(requestserverservice PUBLIC LibCore LibMain LibCrypto LibFileSystem LibIPC LibMain LibTLS LibWebView LibWebSocket LibURL LibThreading CURL::libcurl) +target_link_libraries(requestserverservice PUBLIC LibCore LibMain LibCrypto LibFileSystem LibIPC LibMain LibTLS LibWebView LibWebSocket LibURL LibTextCodec LibThreading CURL::libcurl) if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") # Solaris has socket and networking related functions in two extra libraries target_link_libraries(requestserverservice PUBLIC nsl socket) diff --git a/Userland/Services/RequestServer/ConnectionFromClient.cpp b/Userland/Services/RequestServer/ConnectionFromClient.cpp index fb8823c18e1..6811e3a927e 100644 --- a/Userland/Services/RequestServer/ConnectionFromClient.cpp +++ b/Userland/Services/RequestServer/ConnectionFromClient.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -37,6 +38,7 @@ struct ConnectionFromClient::ActiveRequest { bool got_all_headers { false }; size_t downloaded_so_far { 0 }; String url; + Optional reason_phrase; ByteBuffer body; ActiveRequest(ConnectionFromClient& client, CURLM* multi, CURL* easy, i32 request_id, int writer_fd) @@ -64,7 +66,7 @@ struct ConnectionFromClient::ActiveRequest { long http_status_code = 0; auto result = curl_easy_getinfo(easy, CURLINFO_RESPONSE_CODE, &http_status_code); VERIFY(result == CURLE_OK); - client->async_headers_became_available(request_id, headers, http_status_code); + client->async_headers_became_available(request_id, headers, http_status_code, reason_phrase); } }; @@ -73,11 +75,30 @@ size_t ConnectionFromClient::on_header_received(void* buffer, size_t size, size_ auto* request = static_cast(user_data); size_t total_size = size * nmemb; auto header_line = StringView { static_cast(buffer), total_size }; + + // NOTE: We need to extract the HTTP reason phrase since it can be a custom value. + // Fetching infrastructure needs this value for setting the status message. + if (!request->reason_phrase.has_value() && header_line.starts_with("HTTP/"sv)) { + if (auto const space_positions = header_line.find_all(" "sv); space_positions.size() > 1) { + auto const second_space_offset = space_positions.at(1); + auto const reason_phrase_string_view = header_line.substring_view(second_space_offset + 1).trim_whitespace(); + + if (!reason_phrase_string_view.is_empty()) { + auto decoder = TextCodec::decoder_for_exact_name("ISO-8859-1"sv); + VERIFY(decoder.has_value()); + + request->reason_phrase = MUST(decoder->to_utf8(reason_phrase_string_view)); + return total_size; + } + } + } + if (auto colon_index = header_line.find(':'); colon_index.has_value()) { auto name = header_line.substring_view(0, colon_index.value()).trim_whitespace(); auto value = header_line.substring_view(colon_index.value() + 1, header_line.length() - colon_index.value() - 1).trim_whitespace(); request->headers.set(name, value); } + return total_size; } diff --git a/Userland/Services/RequestServer/RequestClient.ipc b/Userland/Services/RequestServer/RequestClient.ipc index 4e72fe61e76..29624811788 100644 --- a/Userland/Services/RequestServer/RequestClient.ipc +++ b/Userland/Services/RequestServer/RequestClient.ipc @@ -6,7 +6,7 @@ endpoint RequestClient { request_started(i32 request_id, IPC::File fd) =| request_finished(i32 request_id, u64 total_size, Optional network_error) =| - headers_became_available(i32 request_id, HTTP::HeaderMap response_headers, Optional status_code) =| + headers_became_available(i32 request_id, HTTP::HeaderMap response_headers, Optional status_code, Optional reason_phrase) =| // Websocket API // FIXME: See if this can be merged with the regular APIs