Skip to content

Commit

Permalink
LibRequests+LibWeb: Propagate HTTP reason phrase
Browse files Browse the repository at this point in the history
  • Loading branch information
rmg-x committed Oct 23, 2024
1 parent 259aad1 commit 8fba95b
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 42 deletions.
8 changes: 5 additions & 3 deletions Userland/Libraries/LibRequests/Request.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ void Request::set_buffered_request_finished_callback(BufferedRequestFinished on_

m_internal_buffered_data = make<InternalBufferedData>();

on_headers_received = [this](auto& headers, auto response_code) {
on_headers_received = [this](auto& headers, auto response_code, auto const& reason_phrase) {
m_internal_buffered_data->response_headers = headers;
m_internal_buffered_data->response_code = move(response_code);
m_internal_buffered_data->reason_phrase = reason_phrase;
};

on_finish = [this, on_buffered_request_finished = move(on_buffered_request_finished)](auto total_size, auto network_error) {
Expand All @@ -61,6 +62,7 @@ void Request::set_buffered_request_finished_callback(BufferedRequestFinished on_
network_error,
m_internal_buffered_data->response_headers,
m_internal_buffered_data->response_code,
m_internal_buffered_data->reason_phrase,
output_buffer);
};

Expand All @@ -87,10 +89,10 @@ void Request::did_finish(Badge<RequestClient>, u64 total_size, Optional<NetworkE
on_finish(total_size, network_error);
}

void Request::did_receive_headers(Badge<RequestClient>, HTTP::HeaderMap const& response_headers, Optional<u32> response_code)
void Request::did_receive_headers(Badge<RequestClient>, HTTP::HeaderMap const& response_headers, Optional<u32> response_code, Optional<String> const& reason_phrase)
{
if (on_headers_received)
on_headers_received(response_headers, response_code);
on_headers_received(response_headers, response_code, reason_phrase);
}

void Request::did_request_certificates(Badge<RequestClient>)
Expand Down
7 changes: 4 additions & 3 deletions Userland/Libraries/LibRequests/Request.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ class Request : public RefCounted<Request> {
int fd() const { return m_fd; }
bool stop();

using BufferedRequestFinished = Function<void(u64 total_size, Optional<NetworkError> const& network_error, HTTP::HeaderMap const& response_headers, Optional<u32> response_code, ReadonlyBytes payload)>;
using BufferedRequestFinished = Function<void(u64 total_size, Optional<NetworkError> const& network_error, HTTP::HeaderMap const& response_headers, Optional<u32> response_code, Optional<String> reason_phrase, ReadonlyBytes payload)>;

// Configure the request such that the entirety of the response data is buffered. The callback receives that data and
// the response headers all at once. Using this method is mutually exclusive with `set_unbuffered_data_received_callback`.
void set_buffered_request_finished_callback(BufferedRequestFinished);

using HeadersReceived = Function<void(HTTP::HeaderMap const& response_headers, Optional<u32> response_code)>;
using HeadersReceived = Function<void(HTTP::HeaderMap const& response_headers, Optional<u32> response_code, Optional<String> const& reason_phrase)>;
using DataReceived = Function<void(ReadonlyBytes data)>;
using RequestFinished = Function<void(u64 total_size, Optional<NetworkError> network_error)>;

Expand All @@ -55,7 +55,7 @@ class Request : public RefCounted<Request> {
Function<CertificateAndKey()> on_certificate_requested;

void did_finish(Badge<RequestClient>, u64 total_size, Optional<NetworkError> const& network_error);
void did_receive_headers(Badge<RequestClient>, HTTP::HeaderMap const& response_headers, Optional<u32> response_code);
void did_receive_headers(Badge<RequestClient>, HTTP::HeaderMap const& response_headers, Optional<u32> response_code, Optional<String> const& reason_phrase);
void did_request_certificates(Badge<RequestClient>);

RefPtr<Core::Notifier>& write_notifier(Badge<RequestClient>) { return m_write_notifier; }
Expand Down Expand Up @@ -85,6 +85,7 @@ class Request : public RefCounted<Request> {
AllocatingMemoryStream payload_stream;
HTTP::HeaderMap response_headers;
Optional<u32> response_code;
Optional<String> reason_phrase;
};

struct InternalStreamData {
Expand Down
4 changes: 2 additions & 2 deletions Userland/Libraries/LibRequests/RequestClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,14 +77,14 @@ void RequestClient::request_finished(i32 request_id, u64 total_size, Optional<Ne
m_requests.remove(request_id);
}

void RequestClient::headers_became_available(i32 request_id, HTTP::HeaderMap const& response_headers, Optional<u32> const& status_code)
void RequestClient::headers_became_available(i32 request_id, HTTP::HeaderMap const& response_headers, Optional<u32> const& status_code, Optional<String> const& reason_phrase)
{
auto request = const_cast<Request*>(m_requests.get(request_id).value_or(nullptr));
if (!request) {
warnln("Received headers for non-existent request {}", request_id);
return;
}
request->did_receive_headers({}, response_headers, status_code);
request->did_receive_headers({}, response_headers, status_code, reason_phrase);
}

void RequestClient::certificate_requested(i32 request_id)
Expand Down
2 changes: 1 addition & 1 deletion Userland/Libraries/LibRequests/RequestClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class RequestClient final
virtual void request_started(i32, IPC::File const&) override;
virtual void request_finished(i32, u64, Optional<NetworkError> const&) override;
virtual void certificate_requested(i32) override;
virtual void headers_became_available(i32, HTTP::HeaderMap const&, Optional<u32> const&) override;
virtual void headers_became_available(i32, HTTP::HeaderMap const&, Optional<u32> const&, Optional<String> const&) override;

virtual void websocket_connected(i64 websocket_id) override;
virtual void websocket_received(i64 websocket_id, bool, ByteBuffer const&) override;
Expand Down
19 changes: 13 additions & 6 deletions Userland/Libraries/LibWeb/Fetch/Fetching/Fetching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2207,7 +2207,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
// 13. Set up stream with byte reading support with pullAlgorithm set to pullAlgorithm, cancelAlgorithm set to cancelAlgorithm.
Streams::set_up_readable_stream_controller_with_byte_reading_support(stream, pull_algorithm, cancel_algorithm);

auto on_headers_received = [&vm, request, pending_response, stream](auto const& response_headers, Optional<u32> status_code) {
auto on_headers_received = [&vm, request, pending_response, stream](auto const& response_headers, Optional<u32> status_code, Optional<String> const& reason_phrase) {
if (pending_response->is_resolved()) {
// RequestServer will send us the response headers twice, the second time being for HTTP trailers. This
// fetch algorithm is not interested in trailers, so just drop them here.
Expand All @@ -2216,7 +2216,9 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load

auto response = Infrastructure::Response::create(vm);
response->set_status(status_code.value_or(200));
// FIXME: Set response status message

if (reason_phrase.has_value())
response->set_status_message(MUST(ByteBuffer::copy(reason_phrase.value().bytes())));

if constexpr (WEB_FETCH_DEBUG) {
dbgln("Fetch: ResourceLoader load for '{}' {}: (status {})",
Expand Down Expand Up @@ -2283,7 +2285,7 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load

ResourceLoader::the().load_unbuffered(load_request, move(on_headers_received), move(on_data_received), move(on_complete));
} else {
auto on_load_success = [&realm, &vm, request, pending_response](auto data, auto& response_headers, auto status_code) {
auto on_load_success = [&realm, &vm, request, pending_response](auto data, auto& response_headers, auto status_code, auto reason_phrase) {
dbgln_if(WEB_FETCH_DEBUG, "Fetch: ResourceLoader load for '{}' complete", request->url());
if constexpr (WEB_FETCH_DEBUG)
log_response(status_code, response_headers, data);
Expand All @@ -2295,11 +2297,14 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
auto header = Infrastructure::Header::from_string_pair(name, value);
response->header_list()->append(move(header));
}
// FIXME: Set response status message

if (reason_phrase.has_value())
response->set_status_message(MUST(ByteBuffer::copy(reason_phrase.value().bytes())));

pending_response->resolve(response);
};

auto on_load_error = [&realm, &vm, request, pending_response](auto& error, auto status_code, auto data, auto& response_headers) {
auto on_load_error = [&realm, &vm, request, pending_response](auto& error, auto status_code, auto reason_phrase, auto data, auto& response_headers) {
dbgln_if(WEB_FETCH_DEBUG, "Fetch: ResourceLoader load for '{}' failed: {} (status {})", request->url(), error, status_code.value_or(0));
if constexpr (WEB_FETCH_DEBUG)
log_response(status_code, response_headers, data);
Expand All @@ -2316,7 +2321,9 @@ WebIDL::ExceptionOr<JS::NonnullGCPtr<PendingResponse>> nonstandard_resource_load
auto header = Infrastructure::Header::from_string_pair(name, value);
response->header_list()->append(move(header));
}
// FIXME: Set response status message

if (reason_phrase.has_value())
response->set_status_message(MUST(ByteBuffer::copy(reason_phrase.value().bytes())));
}
pending_response->resolve(response);
};
Expand Down
48 changes: 24 additions & 24 deletions Userland/Libraries/LibWeb/Loader/ResourceLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ RefPtr<Resource> ResourceLoader::load_resource(Resource::Type type, LoadRequest&

load(
request,
[=](auto data, auto& headers, auto status_code) {
[=](auto data, auto& headers, auto status_code, auto const&) {
const_cast<Resource&>(*resource).did_load({}, data, headers, status_code);
},
[=](auto& error, auto status_code, auto data, auto& headers) {
[=](auto& error, auto status_code, auto const&, auto data, auto& headers) {
const_cast<Resource&>(*resource).did_fail({}, error, data, headers, status_code);
});

Expand Down Expand Up @@ -237,7 +237,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
request.start_timer();

if (should_block_request(request)) {
error_callback("Request was blocked", {}, {}, {});
error_callback("Request was blocked", {}, {}, {}, {});
return;
}

Expand All @@ -246,14 +246,14 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
if (maybe_response.is_error()) {
log_failure(request, maybe_response.error());
if (error_callback)
error_callback(ByteString::formatted("{}", maybe_response.error()), 500u, {}, {});
error_callback(ByteString::formatted("{}", maybe_response.error()), 500u, {}, {}, {});
return;
}

log_success(request);
HTTP::HeaderMap response_headers;
response_headers.set("Content-Type"sv, "text/html"sv);
success_callback(maybe_response.release_value().bytes(), response_headers, {});
success_callback(maybe_response.release_value().bytes(), response_headers, {}, {});
};

if (url.scheme() == "about") {
Expand All @@ -265,20 +265,20 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback

// About version page
if (url.path_segment_at_index(0) == "version") {
success_callback(MUST(load_about_version_page()).bytes(), response_headers, {});
success_callback(MUST(load_about_version_page()).bytes(), response_headers, {}, {});
return;
}

// Other about static HTML pages
auto resource = Core::Resource::load_from_uri(MUST(String::formatted("resource://ladybird/{}.html", url.path_segment_at_index(0))));
if (!resource.is_error()) {
auto data = resource.value()->data();
success_callback(data, response_headers, {});
success_callback(data, response_headers, {}, {});
return;
}

Platform::EventLoopPlugin::the().deferred_invoke([success_callback = move(success_callback), response_headers = move(response_headers)] {
success_callback(ByteString::empty().to_byte_buffer(), response_headers, {});
success_callback(ByteString::empty().to_byte_buffer(), response_headers, {}, {});
});
return;
}
Expand All @@ -288,7 +288,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
if (data_url_or_error.is_error()) {
auto error_message = data_url_or_error.error().string_literal();
log_failure(request, error_message);
error_callback(error_message, {}, {}, {});
error_callback(error_message, {}, {}, {}, {});
return;
}
auto data_url = data_url_or_error.release_value();
Expand All @@ -303,7 +303,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
log_success(request);

Platform::EventLoopPlugin::the().deferred_invoke([data = move(data_url.body), response_headers = move(response_headers), success_callback = move(success_callback)] {
success_callback(data, response_headers, {});
success_callback(data, response_headers, {}, {});
});
return;
}
Expand All @@ -313,7 +313,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
if (resource.is_error()) {
log_failure(request, resource.error());
if (error_callback)
error_callback(ByteString::formatted("{}", resource.error()), {}, {}, {});
error_callback(ByteString::formatted("{}", resource.error()), {}, {}, {}, {});
return;
}

Expand All @@ -327,7 +327,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
auto response_headers = response_headers_for_file(URL::percent_decode(url.serialize_path()), resource.value()->modified_time());

log_success(request);
success_callback(data, response_headers, {});
success_callback(data, response_headers, {}, {});

return;
}
Expand All @@ -349,7 +349,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
if (file_or_error.is_error()) {
log_failure(request, file_or_error.error());
if (error_callback)
error_callback(ByteString::formatted("{}", file_or_error.error()), {}, {}, {});
error_callback(ByteString::formatted("{}", file_or_error.error()), {}, {}, {}, {});
return;
}

Expand All @@ -366,7 +366,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
if (st_or_error.is_error()) {
log_failure(request, st_or_error.error());
if (error_callback)
error_callback(ByteString::formatted("{}", st_or_error.error()), {}, {}, {});
error_callback(ByteString::formatted("{}", st_or_error.error()), {}, {}, {}, {});
return;
}

Expand All @@ -375,7 +375,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
if (maybe_file.is_error()) {
log_failure(request, maybe_file.error());
if (error_callback)
error_callback(ByteString::formatted("{}", maybe_file.error()), {}, {}, {});
error_callback(ByteString::formatted("{}", maybe_file.error()), {}, {}, {}, {});
return;
}

Expand All @@ -384,15 +384,15 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
if (maybe_data.is_error()) {
log_failure(request, maybe_data.error());
if (error_callback)
error_callback(ByteString::formatted("{}", maybe_data.error()), {}, {}, {});
error_callback(ByteString::formatted("{}", maybe_data.error()), {}, {}, {}, {});
return;
}

auto data = maybe_data.release_value();
auto response_headers = response_headers_for_file(URL::percent_decode(request.url().serialize_path()), st_or_error.value().st_mtime);

log_success(request);
success_callback(data, response_headers, {});
success_callback(data, response_headers, {}, {});
});

(*m_page)->client().request_file(move(file_request));
Expand All @@ -408,7 +408,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
auto protocol_request = start_network_request(request);
if (!protocol_request) {
if (error_callback)
error_callback("Failed to start network request"sv, {}, {}, {});
error_callback("Failed to start network request"sv, {}, {}, {}, {});
return;
}

Expand All @@ -422,7 +422,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
timer->start();
}

auto on_buffered_request_finished = [this, success_callback = move(success_callback), error_callback = move(error_callback), request, &protocol_request = *protocol_request](auto, auto const& network_error, auto& response_headers, auto status_code, ReadonlyBytes payload) mutable {
auto on_buffered_request_finished = [this, success_callback = move(success_callback), error_callback = move(error_callback), request, &protocol_request = *protocol_request](auto, auto const& network_error, auto& response_headers, auto status_code, auto reason_phrase, ReadonlyBytes payload) mutable {
handle_network_response_headers(request, response_headers);
finish_network_request(protocol_request);

Expand All @@ -438,12 +438,12 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback

log_failure(request, error_builder.string_view());
if (error_callback)
error_callback(error_builder.to_byte_string(), status_code, payload, response_headers);
error_callback(error_builder.to_byte_string(), status_code, reason_phrase, payload, response_headers);
return;
}

log_success(request);
success_callback(payload, response_headers, status_code);
success_callback(payload, response_headers, status_code, reason_phrase);
};

protocol_request->set_buffered_request_finished_callback(move(on_buffered_request_finished));
Expand All @@ -453,7 +453,7 @@ void ResourceLoader::load(LoadRequest& request, SuccessCallback success_callback
auto not_implemented_error = ByteString::formatted("Protocol not implemented: {}", url.scheme());
log_failure(request, not_implemented_error);
if (error_callback)
error_callback(not_implemented_error, {}, {}, {});
error_callback(not_implemented_error, {}, {}, {}, {});
}

void ResourceLoader::load_unbuffered(LoadRequest& request, OnHeadersReceived on_headers_received, OnDataReceived on_data_received, OnComplete on_complete)
Expand All @@ -480,9 +480,9 @@ void ResourceLoader::load_unbuffered(LoadRequest& request, OnHeadersReceived on_
return;
}

auto protocol_headers_received = [this, on_headers_received = move(on_headers_received), request](auto const& response_headers, auto status_code) {
auto protocol_headers_received = [this, on_headers_received = move(on_headers_received), request](auto const& response_headers, auto status_code, auto const& reason_phrase) {
handle_network_response_headers(request, response_headers);
on_headers_received(response_headers, move(status_code));
on_headers_received(response_headers, move(status_code), reason_phrase);
};

auto protocol_data_received = [on_data_received = move(on_data_received)](auto data) {
Expand Down
Loading

0 comments on commit 8fba95b

Please sign in to comment.