mirror of
https://github.com/LadybirdBrowser/ladybird
synced 2026-04-25 17:25:08 +02:00
LibDevTools: Add Firefox DevTools network monitoring support
Hook ResourceLoader to emit network request lifecycle events through IPC to the UI process, where FrameActor creates NetworkEventActor instances that serialize requests using Firefox's Remote Debug Protocol. The Network panel now shows requests with method, URL, status, MIME type, size, and timing information. Several features remain stubbed (POST data, response content, cause detection) marked with FIXMEs.
This commit is contained in:
committed by
Andreas Kling
parent
affad6c85d
commit
cf010885d5
Notes:
github-actions[bot]
2026-01-15 19:12:01 +00:00
Author: https://github.com/awesomekling Commit: https://github.com/LadybirdBrowser/ladybird/commit/cf010885d57 Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/7472 Reviewed-by: https://github.com/trflynn89
@@ -12,6 +12,7 @@
|
||||
#include <LibDevTools/Actors/ConsoleActor.h>
|
||||
#include <LibDevTools/Actors/FrameActor.h>
|
||||
#include <LibDevTools/Actors/InspectorActor.h>
|
||||
#include <LibDevTools/Actors/NetworkEventActor.h>
|
||||
#include <LibDevTools/Actors/StyleSheetsActor.h>
|
||||
#include <LibDevTools/Actors/TabActor.h>
|
||||
#include <LibDevTools/Actors/ThreadActor.h>
|
||||
@@ -53,13 +54,30 @@ FrameActor::FrameActor(DevToolsServer& devtools, String name, WeakPtr<TabActor>
|
||||
async_handler<FrameActor>({}, [](auto& self, auto style_sheets, auto& response) {
|
||||
self.style_sheets_available(response, move(style_sheets));
|
||||
}));
|
||||
|
||||
devtools.delegate().listen_for_network_events(
|
||||
tab->description(),
|
||||
[weak_self = make_weak_ptr<FrameActor>()](DevToolsDelegate::NetworkRequestData data) {
|
||||
if (auto self = weak_self.strong_ref())
|
||||
self->on_network_request_started(move(data));
|
||||
},
|
||||
[weak_self = make_weak_ptr<FrameActor>()](DevToolsDelegate::NetworkResponseData data) {
|
||||
if (auto self = weak_self.strong_ref())
|
||||
self->on_network_response_headers_received(move(data));
|
||||
},
|
||||
[weak_self = make_weak_ptr<FrameActor>()](DevToolsDelegate::NetworkRequestCompleteData data) {
|
||||
if (auto self = weak_self.strong_ref())
|
||||
self->on_network_request_finished(move(data));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
FrameActor::~FrameActor()
|
||||
{
|
||||
if (auto tab = m_tab.strong_ref())
|
||||
if (auto tab = m_tab.strong_ref()) {
|
||||
devtools().delegate().stop_listening_for_console_messages(tab->description());
|
||||
devtools().delegate().stop_listening_for_network_events(tab->description());
|
||||
}
|
||||
}
|
||||
|
||||
void FrameActor::handle_message(Message const& message)
|
||||
@@ -348,4 +366,129 @@ void FrameActor::request_console_messages()
|
||||
}
|
||||
}
|
||||
|
||||
void FrameActor::on_network_request_started(DevToolsDelegate::NetworkRequestData data)
|
||||
{
|
||||
auto& actor = devtools().register_actor<NetworkEventActor>(data.request_id);
|
||||
actor.set_request_info(move(data.url), move(data.method), data.start_time, move(data.request_headers));
|
||||
m_network_events.set(data.request_id, actor);
|
||||
|
||||
JsonArray events;
|
||||
events.must_append(actor.serialize_initial_event());
|
||||
|
||||
JsonArray network_event;
|
||||
network_event.must_append("network-event"sv);
|
||||
network_event.must_append(move(events));
|
||||
|
||||
JsonArray array;
|
||||
array.must_append(move(network_event));
|
||||
|
||||
JsonObject message;
|
||||
message.set("type"sv, "resources-available-array"sv);
|
||||
message.set("array"sv, move(array));
|
||||
send_message(move(message));
|
||||
}
|
||||
|
||||
void FrameActor::on_network_response_headers_received(DevToolsDelegate::NetworkResponseData data)
|
||||
{
|
||||
auto it = m_network_events.find(data.request_id);
|
||||
if (it == m_network_events.end())
|
||||
return;
|
||||
|
||||
auto& actor = *it->value;
|
||||
actor.set_response_start(data.status_code, data.reason_phrase);
|
||||
|
||||
// Extract Content-Type before moving headers
|
||||
String mime_type;
|
||||
i64 headers_size = 0;
|
||||
for (auto const& header : data.response_headers) {
|
||||
headers_size += static_cast<i64>(header.name.bytes().size() + header.value.bytes().size() + 4);
|
||||
if (header.name.equals_ignoring_ascii_case("content-type"sv))
|
||||
mime_type = MUST(String::from_byte_string(header.value));
|
||||
}
|
||||
|
||||
actor.set_response_headers(move(data.response_headers));
|
||||
|
||||
// Build resource updates object
|
||||
JsonObject resource_updates;
|
||||
resource_updates.set("status"sv, String::number(data.status_code));
|
||||
resource_updates.set("statusText"sv, data.reason_phrase.value_or(String {}));
|
||||
resource_updates.set("headersSize"sv, headers_size);
|
||||
resource_updates.set("mimeType"sv, mime_type);
|
||||
// FIXME: Get actual HTTP version from response
|
||||
resource_updates.set("httpVersion"sv, "HTTP/1.1"sv);
|
||||
// FIXME: Get actual remote address and port from connection
|
||||
resource_updates.set("remoteAddress"sv, String {});
|
||||
resource_updates.set("remotePort"sv, 0);
|
||||
// FIXME: Calculate actual waiting time (time between request sent and first byte received)
|
||||
resource_updates.set("waitingTime"sv, 0);
|
||||
// Mark headers as available
|
||||
resource_updates.set("responseHeadersAvailable"sv, true);
|
||||
|
||||
JsonObject update_entry;
|
||||
update_entry.set("resourceId"sv, static_cast<i64>(data.request_id));
|
||||
update_entry.set("resourceType"sv, "network-event"sv);
|
||||
update_entry.set("resourceUpdates"sv, move(resource_updates));
|
||||
update_entry.set("browsingContextID"sv, 1);
|
||||
update_entry.set("innerWindowId"sv, 1);
|
||||
|
||||
JsonArray updates;
|
||||
updates.must_append(move(update_entry));
|
||||
|
||||
JsonArray network_event_updates;
|
||||
network_event_updates.must_append("network-event"sv);
|
||||
network_event_updates.must_append(move(updates));
|
||||
|
||||
JsonArray array;
|
||||
array.must_append(move(network_event_updates));
|
||||
|
||||
JsonObject message;
|
||||
message.set("type"sv, "resources-updated-array"sv);
|
||||
message.set("array"sv, move(array));
|
||||
send_message(move(message));
|
||||
}
|
||||
|
||||
void FrameActor::on_network_request_finished(DevToolsDelegate::NetworkRequestCompleteData data)
|
||||
{
|
||||
auto it = m_network_events.find(data.request_id);
|
||||
if (it == m_network_events.end())
|
||||
return;
|
||||
|
||||
auto& actor = *it->value;
|
||||
actor.set_request_complete(data.body_size, data.timing_info, data.network_error);
|
||||
|
||||
// Calculate total time in milliseconds
|
||||
auto total_time = (data.timing_info.response_end_microseconds - data.timing_info.request_start_microseconds) / 1000;
|
||||
|
||||
// Build resource updates object with content and timing info
|
||||
JsonObject resource_updates;
|
||||
resource_updates.set("contentSize"sv, static_cast<i64>(data.body_size));
|
||||
resource_updates.set("transferredSize"sv, static_cast<i64>(data.body_size));
|
||||
resource_updates.set("totalTime"sv, total_time);
|
||||
// Mark as complete
|
||||
resource_updates.set("responseContentAvailable"sv, true);
|
||||
resource_updates.set("eventTimingsAvailable"sv, true);
|
||||
|
||||
JsonObject update_entry;
|
||||
update_entry.set("resourceId"sv, static_cast<i64>(data.request_id));
|
||||
update_entry.set("resourceType"sv, "network-event"sv);
|
||||
update_entry.set("resourceUpdates"sv, move(resource_updates));
|
||||
update_entry.set("browsingContextID"sv, 1);
|
||||
update_entry.set("innerWindowId"sv, 1);
|
||||
|
||||
JsonArray updates;
|
||||
updates.must_append(move(update_entry));
|
||||
|
||||
JsonArray network_event_updates;
|
||||
network_event_updates.must_append("network-event"sv);
|
||||
network_event_updates.must_append(move(updates));
|
||||
|
||||
JsonArray array;
|
||||
array.must_append(move(network_event_updates));
|
||||
|
||||
JsonObject message;
|
||||
message.set("type"sv, "resources-updated-array"sv);
|
||||
message.set("array"sv, move(array));
|
||||
send_message(move(message));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,10 +6,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Types.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibDevTools/Actor.h>
|
||||
#include <LibDevTools/DevToolsDelegate.h>
|
||||
#include <LibDevTools/Forward.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWebView/Forward.h>
|
||||
@@ -38,6 +40,10 @@ private:
|
||||
void console_messages_received(i32 start_index, Vector<WebView::ConsoleOutput>);
|
||||
void request_console_messages();
|
||||
|
||||
void on_network_request_started(DevToolsDelegate::NetworkRequestData);
|
||||
void on_network_response_headers_received(DevToolsDelegate::NetworkResponseData);
|
||||
void on_network_request_finished(DevToolsDelegate::NetworkRequestCompleteData);
|
||||
|
||||
WeakPtr<TabActor> m_tab;
|
||||
|
||||
WeakPtr<CSSPropertiesActor> m_css_properties;
|
||||
@@ -50,6 +56,8 @@ private:
|
||||
i32 m_highest_notified_message_index { -1 };
|
||||
i32 m_highest_received_message_index { -1 };
|
||||
bool m_waiting_for_messages { false };
|
||||
|
||||
HashMap<u64, NonnullRefPtr<NetworkEventActor>> m_network_events;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
259
Libraries/LibDevTools/Actors/NetworkEventActor.cpp
Normal file
259
Libraries/LibDevTools/Actors/NetworkEventActor.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2025, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/JsonArray.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <LibDevTools/Actors/NetworkEventActor.h>
|
||||
#include <LibDevTools/DevToolsServer.h>
|
||||
|
||||
namespace DevTools {
|
||||
|
||||
NonnullRefPtr<NetworkEventActor> NetworkEventActor::create(DevToolsServer& devtools, String name, u64 request_id)
|
||||
{
|
||||
return adopt_ref(*new NetworkEventActor(devtools, move(name), request_id));
|
||||
}
|
||||
|
||||
NetworkEventActor::NetworkEventActor(DevToolsServer& devtools, String name, u64 request_id)
|
||||
: Actor(devtools, move(name))
|
||||
, m_request_id(request_id)
|
||||
{
|
||||
}
|
||||
|
||||
NetworkEventActor::~NetworkEventActor() = default;
|
||||
|
||||
void NetworkEventActor::set_request_info(String url, String method, UnixDateTime start_time, Vector<HTTP::Header> request_headers)
|
||||
{
|
||||
m_url = move(url);
|
||||
m_method = move(method);
|
||||
m_start_time = start_time;
|
||||
m_request_headers = move(request_headers);
|
||||
}
|
||||
|
||||
void NetworkEventActor::set_response_start(u32 status_code, Optional<String> reason_phrase)
|
||||
{
|
||||
m_status_code = status_code;
|
||||
m_reason_phrase = move(reason_phrase);
|
||||
}
|
||||
|
||||
void NetworkEventActor::set_response_headers(Vector<HTTP::Header> response_headers)
|
||||
{
|
||||
m_response_headers = move(response_headers);
|
||||
}
|
||||
|
||||
void NetworkEventActor::set_request_complete(u64 body_size, Requests::RequestTimingInfo timing_info, Optional<Requests::NetworkError> network_error)
|
||||
{
|
||||
m_body_size = body_size;
|
||||
m_timing_info = timing_info;
|
||||
m_network_error = network_error;
|
||||
m_complete = true;
|
||||
}
|
||||
|
||||
JsonObject NetworkEventActor::serialize_initial_event() const
|
||||
{
|
||||
// FIXME: Detect actual cause type (xhr, fetch, script, stylesheet, image, etc.)
|
||||
JsonObject cause;
|
||||
cause.set("type"sv, "document"sv);
|
||||
|
||||
JsonObject event;
|
||||
event.set("resourceType"sv, "network-event"sv);
|
||||
event.set("resourceId"sv, static_cast<i64>(m_request_id));
|
||||
event.set("actor"sv, name());
|
||||
event.set("startedDateTime"sv, MUST(m_start_time.to_string("%Y-%m-%dT%H:%M:%S.000Z"sv)));
|
||||
event.set("timeStamp"sv, m_start_time.milliseconds_since_epoch());
|
||||
event.set("url"sv, m_url);
|
||||
event.set("method"sv, m_method);
|
||||
// FIXME: Detect if request is XHR/fetch
|
||||
event.set("isXHR"sv, false);
|
||||
event.set("cause"sv, move(cause));
|
||||
event.set("private"sv, false);
|
||||
// FIXME: Detect if response is from cache
|
||||
event.set("fromCache"sv, false);
|
||||
event.set("fromServiceWorker"sv, false);
|
||||
event.set("isThirdPartyTrackingResource"sv, false);
|
||||
// FIXME: Get actual referrer policy from request
|
||||
event.set("referrerPolicy"sv, "strict-origin-when-cross-origin"sv);
|
||||
event.set("blockedReason"sv, 0);
|
||||
event.set("blockingExtension"sv, JsonValue {});
|
||||
event.set("channelId"sv, static_cast<i64>(m_request_id));
|
||||
// FIXME: Get actual browsing context ID from the page
|
||||
event.set("browsingContextID"sv, 1);
|
||||
// FIXME: Get actual inner window ID
|
||||
event.set("innerWindowId"sv, 1);
|
||||
// FIXME: Get request priority
|
||||
event.set("priority"sv, 0);
|
||||
// FIXME: Detect if this is a navigation request
|
||||
event.set("isNavigationRequest"sv, false);
|
||||
event.set("chromeContext"sv, false);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
void NetworkEventActor::handle_message(Message const& message)
|
||||
{
|
||||
if (message.type == "getRequestHeaders"sv) {
|
||||
get_request_headers(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getRequestCookies"sv) {
|
||||
get_request_cookies(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getRequestPostData"sv) {
|
||||
get_request_post_data(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getResponseHeaders"sv) {
|
||||
get_response_headers(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getResponseCookies"sv) {
|
||||
get_response_cookies(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getResponseContent"sv) {
|
||||
get_response_content(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getEventTimings"sv) {
|
||||
get_event_timings(message);
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getSecurityInfo"sv) {
|
||||
get_security_info(message);
|
||||
return;
|
||||
}
|
||||
|
||||
send_unrecognized_packet_type_error(message);
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_request_headers(Message const& message)
|
||||
{
|
||||
JsonArray headers;
|
||||
i64 header_size = 0;
|
||||
|
||||
for (auto const& header : m_request_headers) {
|
||||
JsonObject header_obj;
|
||||
header_obj.set("name"sv, MUST(String::from_byte_string(header.name)));
|
||||
header_obj.set("value"sv, MUST(String::from_byte_string(header.value)));
|
||||
headers.must_append(move(header_obj));
|
||||
header_size += static_cast<i64>(header.name.bytes().size() + header.value.bytes().size() + 4); // ": " and "\r\n"
|
||||
}
|
||||
|
||||
JsonObject response;
|
||||
response.set("headers"sv, move(headers));
|
||||
response.set("headersSize"sv, header_size);
|
||||
response.set("rawHeaders"sv, String {});
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_request_cookies(Message const& message)
|
||||
{
|
||||
JsonObject response;
|
||||
response.set("cookies"sv, JsonArray {});
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_request_post_data(Message const& message)
|
||||
{
|
||||
JsonObject post_data;
|
||||
post_data.set("text"sv, String {});
|
||||
|
||||
JsonObject response;
|
||||
response.set("postData"sv, move(post_data));
|
||||
response.set("postDataDiscarded"sv, false);
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_response_headers(Message const& message)
|
||||
{
|
||||
JsonArray headers;
|
||||
i64 header_size = 0;
|
||||
|
||||
for (auto const& header : m_response_headers) {
|
||||
JsonObject header_obj;
|
||||
header_obj.set("name"sv, MUST(String::from_byte_string(header.name)));
|
||||
header_obj.set("value"sv, MUST(String::from_byte_string(header.value)));
|
||||
headers.must_append(move(header_obj));
|
||||
header_size += static_cast<i64>(header.name.bytes().size() + header.value.bytes().size() + 4);
|
||||
}
|
||||
|
||||
JsonObject response;
|
||||
response.set("headers"sv, move(headers));
|
||||
response.set("headersSize"sv, header_size);
|
||||
response.set("rawHeaders"sv, String {});
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_response_cookies(Message const& message)
|
||||
{
|
||||
JsonObject response;
|
||||
response.set("cookies"sv, JsonArray {});
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_response_content(Message const& message)
|
||||
{
|
||||
// FIXME: Store and return actual response body content
|
||||
JsonObject content;
|
||||
content.set("text"sv, String {});
|
||||
// FIXME: Get actual MIME type from response headers
|
||||
content.set("mimeType"sv, "text/html"sv);
|
||||
content.set("size"sv, static_cast<i64>(m_body_size));
|
||||
|
||||
JsonObject response;
|
||||
response.set("content"sv, move(content));
|
||||
response.set("contentDiscarded"sv, true);
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_event_timings(Message const& message)
|
||||
{
|
||||
// Convert microseconds to milliseconds for HAR format
|
||||
auto dns_time = (m_timing_info.domain_lookup_end_microseconds - m_timing_info.domain_lookup_start_microseconds) / 1000;
|
||||
auto connect_time = (m_timing_info.connect_end_microseconds - m_timing_info.connect_start_microseconds) / 1000;
|
||||
auto ssl_time = m_timing_info.secure_connect_start_microseconds > 0
|
||||
? (m_timing_info.connect_end_microseconds - m_timing_info.secure_connect_start_microseconds) / 1000
|
||||
: 0;
|
||||
auto send_time = (m_timing_info.response_start_microseconds - m_timing_info.request_start_microseconds) / 1000;
|
||||
// FIXME: Calculate actual time waiting for server response (TTFB)
|
||||
auto wait_time = 0;
|
||||
auto receive_time = (m_timing_info.response_end_microseconds - m_timing_info.response_start_microseconds) / 1000;
|
||||
|
||||
JsonObject timings;
|
||||
timings.set("blocked"sv, 0);
|
||||
timings.set("dns"sv, dns_time);
|
||||
timings.set("connect"sv, connect_time);
|
||||
timings.set("ssl"sv, ssl_time);
|
||||
timings.set("send"sv, send_time);
|
||||
timings.set("wait"sv, wait_time);
|
||||
timings.set("receive"sv, receive_time);
|
||||
|
||||
auto total_time = dns_time + connect_time + send_time + wait_time + receive_time;
|
||||
|
||||
JsonObject response;
|
||||
response.set("timings"sv, move(timings));
|
||||
response.set("totalTime"sv, total_time);
|
||||
response.set("offsets"sv, JsonObject {});
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
void NetworkEventActor::get_security_info(Message const& message)
|
||||
{
|
||||
// FIXME: Get actual TLS/SSL security information from the connection
|
||||
JsonObject response;
|
||||
response.set("securityInfo"sv, JsonObject {});
|
||||
response.set("state"sv, "insecure"sv);
|
||||
send_response(message, move(response));
|
||||
}
|
||||
|
||||
}
|
||||
65
Libraries/LibDevTools/Actors/NetworkEventActor.h
Normal file
65
Libraries/LibDevTools/Actors/NetworkEventActor.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2025, the Ladybird developers.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/NonnullRefPtr.h>
|
||||
#include <AK/Time.h>
|
||||
#include <LibDevTools/Actor.h>
|
||||
#include <LibDevTools/Forward.h>
|
||||
#include <LibHTTP/Header.h>
|
||||
#include <LibRequests/NetworkError.h>
|
||||
#include <LibRequests/RequestTimingInfo.h>
|
||||
|
||||
namespace DevTools {
|
||||
|
||||
class DEVTOOLS_API NetworkEventActor final : public Actor {
|
||||
public:
|
||||
static constexpr auto base_name = "netEvent"sv;
|
||||
|
||||
static NonnullRefPtr<NetworkEventActor> create(DevToolsServer&, String name, u64 request_id);
|
||||
virtual ~NetworkEventActor() override;
|
||||
|
||||
u64 request_id() const { return m_request_id; }
|
||||
|
||||
void set_request_info(String url, String method, UnixDateTime start_time, Vector<HTTP::Header> request_headers);
|
||||
void set_response_start(u32 status_code, Optional<String> reason_phrase);
|
||||
void set_response_headers(Vector<HTTP::Header> response_headers);
|
||||
void set_request_complete(u64 body_size, Requests::RequestTimingInfo timing_info, Optional<Requests::NetworkError> network_error);
|
||||
|
||||
JsonObject serialize_initial_event() const;
|
||||
|
||||
private:
|
||||
NetworkEventActor(DevToolsServer&, String name, u64 request_id);
|
||||
|
||||
virtual void handle_message(Message const&) override;
|
||||
|
||||
void get_request_headers(Message const&);
|
||||
void get_request_cookies(Message const&);
|
||||
void get_request_post_data(Message const&);
|
||||
void get_response_headers(Message const&);
|
||||
void get_response_cookies(Message const&);
|
||||
void get_response_content(Message const&);
|
||||
void get_event_timings(Message const&);
|
||||
void get_security_info(Message const&);
|
||||
|
||||
u64 m_request_id { 0 };
|
||||
String m_url;
|
||||
String m_method;
|
||||
UnixDateTime m_start_time;
|
||||
Vector<HTTP::Header> m_request_headers;
|
||||
|
||||
Optional<u32> m_status_code;
|
||||
Optional<String> m_reason_phrase;
|
||||
Vector<HTTP::Header> m_response_headers;
|
||||
|
||||
u64 m_body_size { 0 };
|
||||
Requests::RequestTimingInfo m_timing_info {};
|
||||
Optional<Requests::NetworkError> m_network_error;
|
||||
bool m_complete { false };
|
||||
};
|
||||
|
||||
}
|
||||
98
Libraries/LibDevTools/Actors/NetworkParentActor.cpp
Normal file
98
Libraries/LibDevTools/Actors/NetworkParentActor.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/JsonArray.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <LibDevTools/Actors/NetworkParentActor.h>
|
||||
#include <LibDevTools/DevToolsServer.h>
|
||||
|
||||
namespace DevTools {
|
||||
|
||||
NonnullRefPtr<NetworkParentActor> NetworkParentActor::create(DevToolsServer& devtools, String name)
|
||||
{
|
||||
return adopt_ref(*new NetworkParentActor(devtools, move(name)));
|
||||
}
|
||||
|
||||
NetworkParentActor::NetworkParentActor(DevToolsServer& devtools, String name)
|
||||
: Actor(devtools, move(name))
|
||||
{
|
||||
}
|
||||
|
||||
NetworkParentActor::~NetworkParentActor() = default;
|
||||
|
||||
void NetworkParentActor::handle_message(Message const& message)
|
||||
{
|
||||
JsonObject response;
|
||||
|
||||
if (message.type == "setPersist"sv) {
|
||||
// FIXME: Implement persist functionality
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "setNetworkThrottling"sv) {
|
||||
// FIXME: Implement network throttling
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getNetworkThrottling"sv) {
|
||||
response.set("state"sv, JsonValue {});
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "clearNetworkThrottling"sv) {
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "setSaveRequestAndResponseBodies"sv) {
|
||||
// FIXME: Implement saving request/response bodies
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "setBlockedUrls"sv) {
|
||||
// FIXME: Implement URL blocking
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getBlockedUrls"sv) {
|
||||
response.set("urls"sv, JsonArray {});
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "blockRequest"sv) {
|
||||
// FIXME: Implement request blocking
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "unblockRequest"sv) {
|
||||
// FIXME: Implement request unblocking
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "override"sv) {
|
||||
// FIXME: Implement request override
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "removeOverride"sv) {
|
||||
// FIXME: Implement remove override
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
send_unrecognized_packet_type_error(message);
|
||||
}
|
||||
|
||||
}
|
||||
26
Libraries/LibDevTools/Actors/NetworkParentActor.h
Normal file
26
Libraries/LibDevTools/Actors/NetworkParentActor.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibDevTools/Actor.h>
|
||||
|
||||
namespace DevTools {
|
||||
|
||||
class DEVTOOLS_API NetworkParentActor final : public Actor {
|
||||
public:
|
||||
static constexpr auto base_name = "networkParent"sv;
|
||||
|
||||
static NonnullRefPtr<NetworkParentActor> create(DevToolsServer&, String name);
|
||||
|
||||
private:
|
||||
NetworkParentActor(DevToolsServer&, String name);
|
||||
virtual ~NetworkParentActor() override;
|
||||
|
||||
virtual void handle_message(Message const&) override;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -25,7 +25,7 @@ NonnullRefPtr<RootActor> RootActor::create(DevToolsServer& devtools, String name
|
||||
traits.set("sources"sv, false);
|
||||
traits.set("highlightable"sv, true);
|
||||
traits.set("customHighlighters"sv, true);
|
||||
traits.set("networkMonitor"sv, false);
|
||||
traits.set("networkMonitor"sv, true);
|
||||
|
||||
JsonObject message;
|
||||
message.set("applicationType"sv, "browser"sv);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <LibDevTools/Actors/ConsoleActor.h>
|
||||
#include <LibDevTools/Actors/FrameActor.h>
|
||||
#include <LibDevTools/Actors/InspectorActor.h>
|
||||
#include <LibDevTools/Actors/NetworkParentActor.h>
|
||||
#include <LibDevTools/Actors/StyleSheetsActor.h>
|
||||
#include <LibDevTools/Actors/TabActor.h>
|
||||
#include <LibDevTools/Actors/TargetConfigurationActor.h>
|
||||
@@ -39,6 +40,15 @@ void WatcherActor::handle_message(Message const& message)
|
||||
{
|
||||
JsonObject response;
|
||||
|
||||
if (message.type == "getNetworkParentActor"sv) {
|
||||
if (!m_network_parent)
|
||||
m_network_parent = devtools().register_actor<NetworkParentActor>();
|
||||
|
||||
response.set("network"sv, m_network_parent->name());
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "getParentBrowsingContextID"sv) {
|
||||
auto browsing_context_id = get_required_parameter<u64>(message, "browsingContextID"sv);
|
||||
if (!browsing_context_id.has_value())
|
||||
@@ -66,7 +76,6 @@ void WatcherActor::handle_message(Message const& message)
|
||||
send_response(message, move(response));
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.type == "watchResources"sv) {
|
||||
auto resource_types = get_required_parameter<JsonArray>(message, "resourceTypes"sv);
|
||||
if (!resource_types.has_value())
|
||||
@@ -132,7 +141,7 @@ JsonObject WatcherActor::serialize_description() const
|
||||
resources.set("jstracer-trace"sv, false);
|
||||
resources.set("last-private-context-exit"sv, false);
|
||||
resources.set("local-storage"sv, false);
|
||||
resources.set("network-event"sv, false);
|
||||
resources.set("network-event"sv, true);
|
||||
resources.set("network-event-stacktrace"sv, false);
|
||||
resources.set("platform-message"sv, false);
|
||||
resources.set("reflow"sv, false);
|
||||
|
||||
@@ -30,6 +30,7 @@ private:
|
||||
WeakPtr<Actor> m_target;
|
||||
WeakPtr<TargetConfigurationActor> m_target_configuration;
|
||||
WeakPtr<ThreadConfigurationActor> m_thread_configuration;
|
||||
WeakPtr<NetworkParentActor> m_network_parent;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -10,6 +10,8 @@ set(SOURCES
|
||||
Actors/HighlighterActor.cpp
|
||||
Actors/InspectorActor.cpp
|
||||
Actors/LayoutInspectorActor.cpp
|
||||
Actors/NetworkEventActor.cpp
|
||||
Actors/NetworkParentActor.cpp
|
||||
Actors/NodeActor.cpp
|
||||
Actors/PageStyleActor.cpp
|
||||
Actors/ParentAccessibilityActor.cpp
|
||||
|
||||
@@ -9,11 +9,15 @@
|
||||
#include <AK/Error.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/JsonValue.h>
|
||||
#include <AK/Time.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibDevTools/Actors/CSSPropertiesActor.h>
|
||||
#include <LibDevTools/Actors/PageStyleActor.h>
|
||||
#include <LibDevTools/Actors/TabActor.h>
|
||||
#include <LibDevTools/Forward.h>
|
||||
#include <LibHTTP/Header.h>
|
||||
#include <LibRequests/NetworkError.h>
|
||||
#include <LibRequests/RequestTimingInfo.h>
|
||||
#include <LibWeb/CSS/Selector.h>
|
||||
#include <LibWeb/CSS/StyleSheetIdentifier.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
@@ -77,6 +81,34 @@ public:
|
||||
virtual void listen_for_console_messages(TabDescription const&, OnConsoleMessageAvailable, OnReceivedConsoleMessages) const { }
|
||||
virtual void stop_listening_for_console_messages(TabDescription const&) const { }
|
||||
virtual void request_console_messages(TabDescription const&, i32) const { }
|
||||
|
||||
struct NetworkRequestData {
|
||||
u64 request_id { 0 };
|
||||
String url;
|
||||
String method;
|
||||
UnixDateTime start_time;
|
||||
Vector<HTTP::Header> request_headers;
|
||||
};
|
||||
|
||||
struct NetworkResponseData {
|
||||
u64 request_id { 0 };
|
||||
u32 status_code { 0 };
|
||||
Optional<String> reason_phrase;
|
||||
Vector<HTTP::Header> response_headers;
|
||||
};
|
||||
|
||||
struct NetworkRequestCompleteData {
|
||||
u64 request_id { 0 };
|
||||
u64 body_size { 0 };
|
||||
Requests::RequestTimingInfo timing_info;
|
||||
Optional<Requests::NetworkError> network_error;
|
||||
};
|
||||
|
||||
using OnNetworkRequestStarted = Function<void(NetworkRequestData)>;
|
||||
using OnNetworkResponseHeadersReceived = Function<void(NetworkResponseData)>;
|
||||
using OnNetworkRequestFinished = Function<void(NetworkRequestCompleteData)>;
|
||||
virtual void listen_for_network_events(TabDescription const&, OnNetworkRequestStarted, OnNetworkResponseHeadersReceived, OnNetworkRequestFinished) const { }
|
||||
virtual void stop_listening_for_network_events(TabDescription const&) const { }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,8 @@ class FrameActor;
|
||||
class HighlighterActor;
|
||||
class InspectorActor;
|
||||
class LayoutInspectorActor;
|
||||
class NetworkEventActor;
|
||||
class NetworkParentActor;
|
||||
class NodeActor;
|
||||
class PageStyleActor;
|
||||
class ParentAccessibilityActor;
|
||||
|
||||
@@ -417,8 +417,12 @@ void ResourceLoader::load(LoadRequest& request, GC::Root<OnHeadersReceived> on_h
|
||||
return;
|
||||
}
|
||||
|
||||
auto protocol_headers_received = [this, on_headers_received = move(on_headers_received), request](auto const& response_headers, auto status_code, auto const& reason_phrase) {
|
||||
auto protocol_headers_received = [this, on_headers_received = move(on_headers_received), request, request_id = protocol_request->id()](auto const& response_headers, auto status_code, auto const& reason_phrase) {
|
||||
handle_network_response_headers(request, response_headers);
|
||||
|
||||
if (auto page = request.page())
|
||||
page->client().page_did_receive_network_response_headers(request_id, status_code.value_or(0), reason_phrase, response_headers->headers());
|
||||
|
||||
on_headers_received->function()(response_headers, move(status_code), reason_phrase);
|
||||
};
|
||||
|
||||
@@ -426,9 +430,12 @@ void ResourceLoader::load(LoadRequest& request, GC::Root<OnHeadersReceived> on_h
|
||||
on_data_received->function()(data);
|
||||
};
|
||||
|
||||
auto protocol_complete = [this, on_complete = move(on_complete), request, &protocol_request = *protocol_request](u64, Requests::RequestTimingInfo const& timing_info, Optional<Requests::NetworkError> const& network_error) {
|
||||
auto protocol_complete = [this, on_complete = move(on_complete), request, &protocol_request = *protocol_request](u64 total_size, Requests::RequestTimingInfo const& timing_info, Optional<Requests::NetworkError> const& network_error) {
|
||||
finish_network_request(protocol_request);
|
||||
|
||||
if (auto page = request.page())
|
||||
page->client().page_did_finish_network_request(protocol_request.id(), total_size, timing_info, network_error);
|
||||
|
||||
if (!network_error.has_value()) {
|
||||
log_success(request);
|
||||
on_complete->function()(true, timing_info, {});
|
||||
@@ -464,6 +471,9 @@ RefPtr<Requests::Request> ResourceLoader::start_network_request(LoadRequest cons
|
||||
return {};
|
||||
};
|
||||
|
||||
if (auto page = request.page())
|
||||
page->client().page_did_start_network_request(protocol_request->id(), request.url().value(), request.method(), request.headers().headers());
|
||||
|
||||
++m_pending_loads;
|
||||
if (on_load_counter_change)
|
||||
on_load_counter_change();
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
#include <LibGfx/Rect.h>
|
||||
#include <LibGfx/ShareableBitmap.h>
|
||||
#include <LibGfx/Size.h>
|
||||
#include <LibHTTP/Header.h>
|
||||
#include <LibIPC/Forward.h>
|
||||
#include <LibRequests/NetworkError.h>
|
||||
#include <LibRequests/RequestTimingInfo.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/Bindings/AgentType.h>
|
||||
#include <LibWeb/CSS/PreferredColorScheme.h>
|
||||
@@ -416,6 +419,10 @@ public:
|
||||
|
||||
virtual void page_did_change_audio_play_state(HTML::AudioPlayState) { }
|
||||
|
||||
virtual void page_did_start_network_request([[maybe_unused]] u64 request_id, [[maybe_unused]] URL::URL const& url, [[maybe_unused]] ByteString const& method, [[maybe_unused]] Vector<HTTP::Header> const& request_headers) { }
|
||||
virtual void page_did_receive_network_response_headers([[maybe_unused]] u64 request_id, [[maybe_unused]] u32 status_code, [[maybe_unused]] Optional<String> reason_phrase, [[maybe_unused]] Vector<HTTP::Header> const& response_headers) { }
|
||||
virtual void page_did_finish_network_request([[maybe_unused]] u64 request_id, [[maybe_unused]] u64 body_size, [[maybe_unused]] Requests::RequestTimingInfo const& timing_info, [[maybe_unused]] Optional<Requests::NetworkError> const& network_error) { }
|
||||
|
||||
virtual IPC::File request_worker_agent([[maybe_unused]] Web::Bindings::AgentType worker_type) { return IPC::File {}; }
|
||||
|
||||
virtual void page_did_mutate_dom([[maybe_unused]] FlyString const& type, [[maybe_unused]] DOM::Node const& target, [[maybe_unused]] DOM::NodeList& added_nodes, [[maybe_unused]] DOM::NodeList& removed_nodes, [[maybe_unused]] GC::Ptr<DOM::Node> previous_sibling, [[maybe_unused]] GC::Ptr<DOM::Node> next_sibling, [[maybe_unused]] Optional<String> const& attribute_name) { }
|
||||
|
||||
@@ -1307,4 +1307,34 @@ void Application::request_console_messages(DevTools::TabDescription const& descr
|
||||
view->js_console_request_messages(start_index);
|
||||
}
|
||||
|
||||
void Application::listen_for_network_events(DevTools::TabDescription const& description, OnNetworkRequestStarted on_request_started, OnNetworkResponseHeadersReceived on_response_headers, OnNetworkRequestFinished on_request_finished) const
|
||||
{
|
||||
auto view = ViewImplementation::find_view_by_id(description.id);
|
||||
if (!view.has_value())
|
||||
return;
|
||||
|
||||
view->on_network_request_started = [on_request_started = move(on_request_started)](u64 request_id, URL::URL const& url, ByteString const& method, Vector<HTTP::Header> const& headers) {
|
||||
on_request_started({ request_id, url.to_string(), MUST(String::from_byte_string(method)), UnixDateTime::now(), headers });
|
||||
};
|
||||
|
||||
view->on_network_response_headers_received = [on_response_headers = move(on_response_headers)](u64 request_id, u32 status_code, Optional<String> const& reason_phrase, Vector<HTTP::Header> const& headers) {
|
||||
on_response_headers({ request_id, status_code, reason_phrase, headers });
|
||||
};
|
||||
|
||||
view->on_network_request_finished = [on_request_finished = move(on_request_finished)](u64 request_id, u64 body_size, Requests::RequestTimingInfo const& timing_info, Optional<Requests::NetworkError> const& network_error) {
|
||||
on_request_finished({ request_id, body_size, timing_info, network_error });
|
||||
};
|
||||
}
|
||||
|
||||
void Application::stop_listening_for_network_events(DevTools::TabDescription const& description) const
|
||||
{
|
||||
auto view = ViewImplementation::find_view_by_id(description.id);
|
||||
if (!view.has_value())
|
||||
return;
|
||||
|
||||
view->on_network_request_started = nullptr;
|
||||
view->on_network_response_headers_received = nullptr;
|
||||
view->on_network_request_finished = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -191,6 +191,8 @@ private:
|
||||
virtual void listen_for_console_messages(DevTools::TabDescription const&, OnConsoleMessageAvailable, OnReceivedConsoleMessages) const override;
|
||||
virtual void stop_listening_for_console_messages(DevTools::TabDescription const&) const override;
|
||||
virtual void request_console_messages(DevTools::TabDescription const&, i32) const override;
|
||||
virtual void listen_for_network_events(DevTools::TabDescription const&, OnNetworkRequestStarted, OnNetworkResponseHeadersReceived, OnNetworkRequestFinished) const override;
|
||||
virtual void stop_listening_for_network_events(DevTools::TabDescription const&) const override;
|
||||
|
||||
static Application* s_the;
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
#include <LibCore/Promise.h>
|
||||
#include <LibGfx/Cursor.h>
|
||||
#include <LibGfx/Forward.h>
|
||||
#include <LibHTTP/Header.h>
|
||||
#include <LibRequests/Forward.h>
|
||||
#include <LibRequests/NetworkError.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
#include <LibWeb/HTML/ActivateTab.h>
|
||||
#include <LibWeb/HTML/AudioPlayState.h>
|
||||
@@ -201,6 +204,9 @@ public:
|
||||
Function<void(JsonValue)> on_received_js_console_result;
|
||||
Function<void(i32 message_id)> on_console_message_available;
|
||||
Function<void(i32 start_index, Vector<ConsoleOutput>)> on_received_console_messages;
|
||||
Function<void(u64 request_id, URL::URL const&, ByteString const&, Vector<HTTP::Header> const&)> on_network_request_started;
|
||||
Function<void(u64 request_id, u32 status_code, Optional<String> const&, Vector<HTTP::Header> const&)> on_network_response_headers_received;
|
||||
Function<void(u64 request_id, u64 body_size, Requests::RequestTimingInfo const&, Optional<Requests::NetworkError> const&)> on_network_request_finished;
|
||||
Function<void(i32 count_waiting)> on_resource_status_change;
|
||||
Function<void()> on_restore_window;
|
||||
Function<void(Gfx::IntPoint)> on_reposition_window;
|
||||
|
||||
@@ -434,6 +434,30 @@ void WebContentClient::did_get_js_console_messages(u64 page_id, i32 start_index,
|
||||
}
|
||||
}
|
||||
|
||||
void WebContentClient::did_start_network_request(u64 page_id, u64 request_id, URL::URL url, ByteString method, Vector<HTTP::Header> request_headers)
|
||||
{
|
||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||
if (view->on_network_request_started)
|
||||
view->on_network_request_started(request_id, url, method, request_headers);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContentClient::did_receive_network_response_headers(u64 page_id, u64 request_id, u32 status_code, Optional<String> reason_phrase, Vector<HTTP::Header> response_headers)
|
||||
{
|
||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||
if (view->on_network_response_headers_received)
|
||||
view->on_network_response_headers_received(request_id, status_code, reason_phrase, response_headers);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContentClient::did_finish_network_request(u64 page_id, u64 request_id, u64 body_size, Requests::RequestTimingInfo timing_info, Optional<Requests::NetworkError> network_error)
|
||||
{
|
||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||
if (view->on_network_request_finished)
|
||||
view->on_network_request_finished(request_id, body_size, timing_info, network_error);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContentClient::did_request_alert(u64 page_id, String message)
|
||||
{
|
||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||
|
||||
@@ -8,8 +8,11 @@
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/SourceLocation.h>
|
||||
#include <LibHTTP/Header.h>
|
||||
#include <LibIPC/ConnectionToServer.h>
|
||||
#include <LibIPC/Transport.h>
|
||||
#include <LibRequests/NetworkError.h>
|
||||
#include <LibRequests/RequestTimingInfo.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
#include <LibWeb/CSS/StyleSheetIdentifier.h>
|
||||
#include <LibWeb/HTML/ActivateTab.h>
|
||||
@@ -94,6 +97,9 @@ private:
|
||||
virtual void did_execute_js_console_input(u64 page_id, JsonValue) override;
|
||||
virtual void did_output_js_console_message(u64 page_id, i32 message_index) override;
|
||||
virtual void did_get_js_console_messages(u64 page_id, i32 start_index, Vector<ConsoleOutput>) override;
|
||||
virtual void did_start_network_request(u64 page_id, u64 request_id, URL::URL, ByteString method, Vector<HTTP::Header>) override;
|
||||
virtual void did_receive_network_response_headers(u64 page_id, u64 request_id, u32 status_code, Optional<String> reason_phrase, Vector<HTTP::Header>) override;
|
||||
virtual void did_finish_network_request(u64 page_id, u64 request_id, u64 body_size, Requests::RequestTimingInfo, Optional<Requests::NetworkError>) override;
|
||||
virtual void did_change_favicon(u64 page_id, Gfx::ShareableBitmap) override;
|
||||
virtual void did_request_alert(u64 page_id, String) override;
|
||||
virtual void did_request_confirm(u64 page_id, String) override;
|
||||
|
||||
@@ -30,7 +30,7 @@ target_include_directories(webcontentservice PUBLIC $<BUILD_INTERFACE:${CMAKE_CU
|
||||
target_include_directories(webcontentservice PUBLIC $<BUILD_INTERFACE:${LADYBIRD_SOURCE_DIR}>)
|
||||
target_include_directories(webcontentservice PUBLIC $<BUILD_INTERFACE:${LADYBIRD_SOURCE_DIR}/Services/>)
|
||||
|
||||
target_link_libraries(webcontentservice PUBLIC LibCore LibCrypto LibFileSystem LibGfx LibIPC LibJS LibMain LibMedia LibWeb LibWebSocket LibRequests LibWebView LibImageDecoderClient LibGC)
|
||||
target_link_libraries(webcontentservice PUBLIC LibCore LibCrypto LibFileSystem LibGfx LibHTTP LibIPC LibJS LibMain LibMedia LibWeb LibWebSocket LibRequests LibWebView LibImageDecoderClient LibGC)
|
||||
target_link_libraries(webcontentservice PRIVATE OpenSSL::Crypto OpenSSL::SSL)
|
||||
target_link_libraries(webcontentservice PRIVATE SDL3::SDL3)
|
||||
|
||||
|
||||
@@ -751,6 +751,21 @@ void PageClient::received_message_from_web_ui(String const& name, JS::Value data
|
||||
m_web_ui->received_message_from_web_ui(name, data);
|
||||
}
|
||||
|
||||
void PageClient::page_did_start_network_request(u64 request_id, URL::URL const& url, ByteString const& method, Vector<HTTP::Header> const& request_headers)
|
||||
{
|
||||
client().async_did_start_network_request(m_id, request_id, url, method, request_headers);
|
||||
}
|
||||
|
||||
void PageClient::page_did_receive_network_response_headers(u64 request_id, u32 status_code, Optional<String> reason_phrase, Vector<HTTP::Header> const& response_headers)
|
||||
{
|
||||
client().async_did_receive_network_response_headers(m_id, request_id, status_code, move(reason_phrase), response_headers);
|
||||
}
|
||||
|
||||
void PageClient::page_did_finish_network_request(u64 request_id, u64 body_size, Requests::RequestTimingInfo const& timing_info, Optional<Requests::NetworkError> const& network_error)
|
||||
{
|
||||
client().async_did_finish_network_request(m_id, request_id, body_size, timing_info, network_error);
|
||||
}
|
||||
|
||||
void PageClient::initialize_js_console(Web::DOM::Document& document)
|
||||
{
|
||||
if (document.is_temporary_document_for_fragment_parsing())
|
||||
|
||||
@@ -181,6 +181,9 @@ private:
|
||||
virtual void page_did_paint(Gfx::IntRect const& content_rect, i32 bitmap_id) override;
|
||||
virtual void page_did_take_screenshot(Gfx::ShareableBitmap const& screenshot) override;
|
||||
virtual void received_message_from_web_ui(String const& name, JS::Value data) override;
|
||||
virtual void page_did_start_network_request(u64 request_id, URL::URL const&, ByteString const&, Vector<HTTP::Header> const&) override;
|
||||
virtual void page_did_receive_network_response_headers(u64 request_id, u32 status_code, Optional<String>, Vector<HTTP::Header> const&) override;
|
||||
virtual void page_did_finish_network_request(u64 request_id, u64 body_size, Requests::RequestTimingInfo const&, Optional<Requests::NetworkError> const&) override;
|
||||
|
||||
void setup_palette();
|
||||
ConnectionFromClient& client() const;
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibGfx/Cursor.h>
|
||||
#include <LibGfx/ShareableBitmap.h>
|
||||
#include <LibHTTP/Header.h>
|
||||
#include <LibRequests/NetworkError.h>
|
||||
#include <LibRequests/RequestTimingInfo.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/Bindings/MainThreadVM.h>
|
||||
#include <LibWeb/Clipboard/SystemClipboard.h>
|
||||
@@ -113,6 +116,10 @@ endpoint WebContentClient
|
||||
did_output_js_console_message(u64 page_id, i32 message_index) =|
|
||||
did_get_js_console_messages(u64 page_id, i32 start_index, Vector<WebView::ConsoleOutput> console_output) =|
|
||||
|
||||
did_start_network_request(u64 page_id, u64 request_id, URL::URL url, ByteString method, Vector<HTTP::Header> request_headers) =|
|
||||
did_receive_network_response_headers(u64 page_id, u64 request_id, u32 status_code, Optional<String> reason_phrase, Vector<HTTP::Header> response_headers) =|
|
||||
did_finish_network_request(u64 page_id, u64 request_id, u64 body_size, Requests::RequestTimingInfo timing_info, Optional<Requests::NetworkError> network_error) =|
|
||||
|
||||
did_finish_test(u64 page_id, String text) =|
|
||||
did_set_test_timeout(u64 page_id, double milliseconds) =|
|
||||
did_receive_reference_test_metadata(u64 page_id, JsonValue result) =|
|
||||
|
||||
Reference in New Issue
Block a user