Split subresource fetch handling by lifecycle

This commit is contained in:
ldm0
2026-09-28 11:58:22 +08:00
parent 317270f49c
commit ea5fdcc804
6 changed files with 5650 additions and 5702 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,333 @@
use super::*;
impl ScriptVm {
#[cfg(test)]
pub(crate) fn current_document_write_external_script_fetch_target(
&self,
) -> Option<crate::types::DocumentWriteExternalScriptFetchTarget> {
let target = self
.document_runtime
.pending_document_write_external_script_fetch_target()?;
self.document_write_external_script_fetch_target_is_current(target)
.then_some(target)
}
pub(crate) fn document_write_external_script_fetch_target_is_current(
&self,
expected: crate::types::DocumentWriteExternalScriptFetchTarget,
) -> bool {
self.document_runtime
.has_document_write_external_script_fetch_target(expected)
&& self.current_main_document_task_owner() == Some(expected.task_owner())
}
pub(crate) fn apply_current_document_write_external_script_load_completion(
&mut self,
completion: crate::runtime::AuthorizedCurrentDocumentWriteExternalScriptLoadCompletion,
) -> Result<crate::document_runtime::DocumentWriteExternalScriptLoadApplication> {
let completion = completion.into_completion();
let document_runtime: *mut DocumentRuntime = &mut *self.document_runtime;
self.with_default_context_scope(|scope, host_ptr| {
Ok(unsafe { &mut *document_runtime }
.complete_document_write_external_script_load(scope, host_ptr, completion))
})
}
pub(crate) fn apply_current_child_document_load_completion(
&mut self,
authorization: AuthorizedCurrentChildDocumentLoadCompletion,
) -> Result<CurrentChildDocumentLoadApplication> {
self.apply_current_child_document_load_completion_inner(authorization.into_completion())
}
pub(super) fn apply_current_child_document_load_completion_inner(
&mut self,
completion: ChildDocumentLoadCompletion,
) -> Result<CurrentChildDocumentLoadApplication> {
let context_host = self._context_host.clone();
let application = self.with_default_context_scope(move |scope, _host_ptr| {
Ok(context_host
.borrow_mut()
.apply_current_child_document_load_completion(scope, completion))
})?;
let application = match application {
crate::native_bridge::ChildDocumentLoadApplication::Applied {
followup,
body_activity,
} => (followup.map(|application| *application), body_activity),
crate::native_bridge::ChildDocumentLoadApplication::SupersededDuringApplication {
completion,
body_activity,
} => {
let historical_network_recorded =
self.record_historical_child_document_load_network(&completion);
self.apply_pending_child_document_owner_retirements();
return Ok(
CurrentChildDocumentLoadApplication::SupersededDuringApplication {
historical_network_recorded,
body_activity,
},
);
}
};
self.apply_pending_child_document_owner_retirements();
let (application, body_activity) = application;
let Some(application) = application else {
return Ok(CurrentChildDocumentLoadApplication::Applied { body_activity });
};
let (work, parser_stop_action, owner_transition) = application.into_followups();
if let Some(transition) = owner_transition {
self.apply_child_document_owner_transition(transition);
}
if let Some(action) = parser_stop_action {
super::super::child_document_lifecycle::ChildDocumentLifecycleOwner::new(self)
.notify_parser_stop_action(action);
}
if let Some(work) = work {
super::super::child_document_script_scheduler::ChildDocumentScriptSchedulerOwner::new(
self,
)
.notify_parser_classic_next_owner_action(work);
}
Ok(CurrentChildDocumentLoadApplication::Applied { body_activity })
}
pub(crate) fn current_child_document_navigation_fetch_target(
&self,
child_handle: crate::document_runtime::DomHandle,
) -> Option<crate::frame_owner_model::ChildDocumentNavigationFetchTarget> {
self._context_host
.borrow()
.current_child_document_navigation_fetch_target(child_handle)
}
pub(crate) fn record_historical_child_document_load_network(
&mut self,
completion: &ChildDocumentLoadCompletion,
) -> bool {
self._context_host
.borrow_mut()
.record_historical_child_document_load_network(completion)
}
pub(crate) fn discard_stale_child_document_load_completion(
&mut self,
target: crate::frame_owner_model::ChildDocumentNavigationFetchTarget,
) {
self._context_host
.borrow_mut()
.discard_stale_child_document_load_completion(target);
}
pub(crate) fn apply_child_blocking_stylesheet_load_completion_from_page_turn(
&mut self,
completion: ChildBlockingStylesheetLoadCompletion,
) -> Result<()> {
let context_host = self._context_host.clone();
self.with_default_context_scope(move |scope, _host_ptr| {
context_host
.borrow_mut()
.apply_child_blocking_stylesheet_load_completion(scope, completion);
Ok(())
})
}
pub(crate) fn record_historical_child_blocking_stylesheet_network_results(
&mut self,
completion: &ChildBlockingStylesheetLoadCompletion,
) {
self._context_host
.borrow_mut()
.record_historical_child_blocking_stylesheet_network_results(completion);
}
pub(crate) fn current_child_document_task_owner(
&self,
child_handle: crate::document_runtime::DomHandle,
) -> Option<crate::frame_owner_model::FrameDocumentTaskOwner> {
self._context_host
.borrow()
.current_child_document_task_owner(child_handle)
}
pub(crate) fn current_child_document_module_fetch_target(
&self,
child_handle: crate::document_runtime::DomHandle,
) -> Option<crate::frame_owner_model::ChildDocumentModuleFetchTarget> {
self._context_host
.borrow()
.current_child_document_module_fetch_target(child_handle)
}
pub(crate) fn apply_child_classic_script_load_completion_from_page_turn(
&mut self,
completion: ChildClassicScriptLoadCompletion,
) -> Result<()> {
let context_host = self._context_host.clone();
let application = self.with_default_context_scope(move |_scope, _host_ptr| {
Ok(context_host
.borrow_mut()
.apply_child_classic_script_load_completion(completion))
})?;
if let Some(application) = application {
if let Some(work) = application.scheduler_work {
super::super::child_document_script_scheduler::ChildDocumentScriptSchedulerOwner::new(
self,
)
.notify_parser_classic_next_owner_action(work);
return Ok(());
}
let _ = application.queued_document_script_ready;
let _ = application.queued_document_lifecycle;
}
Ok(())
}
pub(crate) fn record_historical_child_classic_script_network_result(
&mut self,
completion: &ChildClassicScriptLoadCompletion,
) -> bool {
self._context_host
.borrow_mut()
.record_historical_child_classic_script_network_result(completion)
}
/// Applies a parser-module terminal only after the Page owner has proved
/// that its complete exact target is current.
pub(crate) fn apply_current_child_parser_module_root_fetch_completion(
&mut self,
authorization: AuthorizedCurrentChildModuleFetchCompletion<
ChildParserModuleRootFetchCompletion,
>,
) -> FrameDocumentModuleTerminalQueueFollowup {
self.finish_child_parser_module_root_fetch_completion(authorization.into_completion())
}
pub(super) fn finish_child_parser_module_root_fetch_completion(
&mut self,
completion: ChildParserModuleRootFetchCompletion,
) -> FrameDocumentModuleTerminalQueueFollowup {
let applied = self
._context_host
.borrow_mut()
.finish_child_parser_module_root_fetch_request(&completion);
if applied {
return self.apply_child_parser_module_root_fetch_completion_to_owner(completion);
}
FrameDocumentModuleTerminalQueueFollowup::none()
}
/// Applies a dependency terminal only after the Page owner has proved
/// that its complete exact target is current.
pub(crate) fn apply_current_child_module_dependency_fetch_completion(
&mut self,
authorization: AuthorizedCurrentChildModuleFetchCompletion<
ChildModuleDependencyFetchCompletion,
>,
) -> FrameDocumentModuleTerminalQueueFollowup {
self.finish_child_module_dependency_fetch_completion(authorization.into_completion())
}
/// Applies a child `modulepreload` terminal only after the Page owner has
/// proved its complete exact target is current.
pub(crate) fn apply_current_child_modulepreload_fetch_completion(
&mut self,
authorization: AuthorizedCurrentChildModuleFetchCompletion<
ChildModulepreloadFetchCompletion,
>,
) -> FrameDocumentModuleTerminalQueueFollowup {
super::super::child_module_fetch::ChildModuleFetchOwner::new(self)
.apply_current_modulepreload_fetch_completion(authorization.into_completion())
}
pub(super) fn finish_child_module_dependency_fetch_completion(
&mut self,
completion: ChildModuleDependencyFetchCompletion,
) -> FrameDocumentModuleTerminalQueueFollowup {
let applied = self
._context_host
.borrow_mut()
.finish_child_module_dependency_fetch_request(&completion);
if applied {
return self.apply_child_module_dependency_fetch_completion_to_owner(completion);
}
FrameDocumentModuleTerminalQueueFollowup::none()
}
pub(crate) fn record_current_child_module_fetch_network_result(
&mut self,
attribution: &crate::types::ChildModuleFetchNetworkAttribution,
network_result: Option<&crate::types::SharedNavigationResponseResult>,
) -> bool {
let Some(network_result) = network_result else {
return false;
};
self._context_host
.borrow_mut()
.record_current_child_module_fetch_network_result(attribution, network_result.as_ref());
true
}
pub(crate) fn record_historical_child_module_fetch_network_result(
&mut self,
attribution: &crate::types::ChildModuleFetchNetworkAttribution,
network_result: Option<&crate::types::SharedNavigationResponseResult>,
) -> bool {
let Some(network_result) = network_result else {
return false;
};
self._context_host
.borrow_mut()
.record_historical_child_module_fetch_network_result(
attribution,
network_result.as_ref(),
);
true
}
#[cfg(test)]
pub(crate) fn complete_popup_document_load(
&mut self,
completion: PopupDocumentLoadCompletion,
) -> Result<()> {
let target = completion.target();
if self.current_lightweight_popup_document_fetch_target(target.load_id()) != Some(target) {
return Ok(());
}
let _ = self.apply_popup_document_load_completion_inner(completion)?;
Ok(())
}
pub(crate) fn current_lightweight_popup_document_fetch_target(
&self,
load_id: u64,
) -> Option<crate::native_bridge::LightweightPopupDocumentFetchTarget> {
self._context_host
.borrow()
.current_lightweight_popup_document_fetch_target(load_id)
}
pub(crate) fn apply_current_popup_document_load_completion(
&mut self,
authorization: AuthorizedCurrentPopupDocumentLoadCompletion,
) -> Result<crate::native_bridge::PopupDocumentLoadApplication> {
self.apply_popup_document_load_completion_inner(authorization.into_completion())
}
pub(super) fn apply_popup_document_load_completion_inner(
&mut self,
completion: PopupDocumentLoadCompletion,
) -> Result<crate::native_bridge::PopupDocumentLoadApplication> {
let context_host = self._context_host.clone();
self.with_default_context_scope(move |scope, _host_ptr| {
let application = context_host
.borrow_mut()
.apply_lightweight_popup_document_load_completion(scope, completion);
Ok(application)
})
}
pub(crate) fn current_lightweight_popup_classic_script_fetch_target(
&self,
load_id: u64,
) -> Option<crate::native_bridge::LightweightPopupClassicScriptFetchTarget> {
self._context_host
.borrow()
.current_lightweight_popup_classic_script_fetch_target(load_id)
}
pub(crate) fn discard_stale_lightweight_popup_classic_script_completion(
&mut self,
target: crate::native_bridge::LightweightPopupClassicScriptFetchTarget,
) {
self._context_host
.borrow_mut()
.discard_stale_lightweight_popup_classic_script_completion(target);
}
pub(crate) fn apply_current_popup_classic_script_load_completion(
&mut self,
authorization: AuthorizedCurrentPopupClassicScriptLoadCompletion,
) -> Result<crate::native_bridge::PopupClassicScriptLoadApplication> {
let completion: PopupClassicScriptLoadCompletion = authorization.into_completion();
let context_host = self._context_host.clone();
self.with_default_context_scope(move |scope, _host_ptr| {
Ok(context_host
.borrow_mut()
.apply_lightweight_popup_classic_script_load_completion(scope, completion))
})
}
}
@@ -0,0 +1,955 @@
use super::*;
impl ScriptVm {
pub(super) fn resolve_network_only_subresource_fetch(
&mut self,
mut pending: PendingSubresourceFetchState,
request_url: Url,
request_method: String,
request_headers: moli_fetch::RequestHeaders,
request_body: Option<String>,
response_status_text: Option<String>,
skip_fetch_security_validation: bool,
network_error_text: Option<String>,
result: std::result::Result<crate::protocol_types::NavigationResponse, String>,
) -> Result<()> {
let detached_window_fetch = pending.continuation.is_detached_window_fetch();
debug_assert!(
detached_window_fetch || pending.execution_context.is_window_network_only(),
"network-only completion must be an accepted fire-and-forget request or detached Fetch"
);
self._context_host
.borrow_mut()
.record_deferred_pending_subresource_request_started(&mut pending);
let result = if detached_window_fetch {
result.and_then(|response| {
if !response.redirect_chain.is_empty()
&& let Some(message) = detached_window_fetch_csp_redirect_failure_message(
&self._context_host,
&pending,
&response.final_url,
)
{
return Err(message);
}
if !skip_fetch_security_validation {
crate::network_host::validate_fetch_response_security_policy_with_body(
&pending.request_origin,
&response.head(),
response.body_bytes(),
pending.request_mode,
pending.credentials_mode,
pending.policy_context,
)?;
}
Ok(response)
})
} else {
result
};
match result {
Ok(response) => {
let network_request_headers = response
.network_request_headers()
.map(|headers| headers.to_vec());
let request_cookie_report = response
.request_cookie_report
.clone()
.or_else(|| pending.info.request_cookie_report.clone());
let response_body = SubresourceResponseBody::from_navigation_response(&response);
let mut network_record = crate::types::SubresourceNetworkRecord::success_with_body(
pending.info.frame_id.clone(),
pending.info.document_url.clone(),
request_url,
request_method,
request_headers,
request_body,
pending.info.resource_type,
request_cookie_report,
response.redirect_chain,
response.final_url,
response.status,
response.headers,
response_body,
response.cookie_set_reports,
)
.with_from_cache(response.from_cache)
.with_negotiated_http_version(response.negotiated_http_version)
.with_network_request_headers(network_request_headers)
.with_request_initiator_type(SubresourceRequestInitiatorType::Script)
.with_request_body_bytes(pending.info.request_body_bytes.clone());
if let Some(status_text) = response_status_text.as_deref() {
network_record = network_record.with_response_status_text(status_text);
}
if let Some(handle) = pending.info.network_request_handle {
network_record = network_record.with_request_handle(handle);
}
self._context_host
.borrow_mut()
.record_subresource_network(network_record);
}
Err(error_text) => {
let error_text = network_error_text.as_deref().unwrap_or(&error_text);
let mut network_record = crate::types::SubresourceNetworkRecord::failure(
pending.info.frame_id.clone(),
pending.info.document_url.clone(),
request_url,
request_method,
request_headers,
request_body,
pending.info.resource_type,
error_text.to_owned(),
)
.with_request_initiator_type(SubresourceRequestInitiatorType::Script)
.with_request_body_bytes(pending.info.request_body_bytes.clone());
if let Some(handle) = pending.info.network_request_handle {
network_record = network_record.with_request_handle(handle);
}
self._context_host
.borrow_mut()
.record_subresource_network(network_record);
}
}
tracing::debug!(
internal_id = pending.info.internal_id,
detached_owner = ?pending.execution_context.detached_window_fetch_identity(),
accepted_context = ?pending.execution_context.window_network_only_identity(),
accepted_document = ?pending.execution_context.window_document_network_only_identity(),
"completed network-only subresource without entering V8"
);
Ok(())
}
#[allow(clippy::too_many_arguments)]
pub(super) fn resolve_pending_event_source_fetch(
&mut self,
mut pending: PendingSubresourceFetchState,
request_url: Url,
request_method: String,
request_headers: moli_fetch::RequestHeaders,
request_body: Option<String>,
response_status_text: Option<String>,
skip_fetch_security_validation: bool,
network_error_text: Option<String>,
result: std::result::Result<crate::protocol_types::NavigationResponse, String>,
) -> Result<AsyncSubresourceFetchBodyActivity> {
self._context_host
.borrow_mut()
.record_deferred_pending_subresource_request_started(&mut pending);
let context_host = self._context_host.clone();
self.renderer_document_isolate
.with_entered_renderer_document_isolate(|isolate| {
let scope = pin!(v8::HandleScope::new(isolate));
let scope = &mut scope.init();
let context = v8::Local::new(
scope,
pending
.execution_context
.context_global()
.expect("EventSource completion must retain its V8 context"),
);
let scope = &mut v8::ContextScope::new(scope, context);
if !window_subresource_realm_is_current(&context_host, scope, &pending) {
return Ok(AsyncSubresourceFetchBodyActivity::NoWindowRealmEntered);
}
let owner_async_scope = enter_subresource_owner_async_scope(
&context_host,
scope,
pending.execution_context.dispatch_scope(),
);
let event_source = match &pending.continuation {
PendingSubresourceContinuation::EventSource(event_source) => {
v8::Local::new(scope, event_source)
}
_ => unreachable!("EventSource completion requires EventSource continuation"),
};
let request_handle = pending.info.network_request_handle;
match result {
Err(error_text) => {
let error_text = network_error_text.unwrap_or(error_text);
let mut record = crate::types::SubresourceNetworkRecord::failure(
pending.info.frame_id.clone(),
pending.info.document_url.clone(),
request_url,
request_method,
request_headers,
request_body,
SubresourceResourceType::EventSource,
error_text,
);
if let Some(handle) = request_handle {
record = record.with_request_handle(handle);
}
context_host
.borrow_mut()
.record_subresource_network(record);
crate::network_host::fail_event_source_connection(
scope,
event_source,
crate::network_host::EventSourceTerminalMode::Reconnect,
);
}
Ok(response) => {
let security_error = if !response.redirect_chain.is_empty() {
document_connect_csp_redirect_failure_message(
scope,
&context_host,
&pending,
&response.final_url,
)
} else {
None
}
.or_else(|| {
(!skip_fetch_security_validation)
.then(|| {
crate::network_host::validate_fetch_response_security_policy_with_body(
&pending.request_origin,
&response.head(),
response.body_bytes(),
pending.request_mode,
pending.credentials_mode,
pending.policy_context,
)
.err()
})
.flatten()
});
if let Some(error_text) = security_error {
let mut record = crate::types::SubresourceNetworkRecord::failure(
pending.info.frame_id.clone(),
pending.info.document_url.clone(),
request_url,
request_method,
request_headers,
request_body,
SubresourceResourceType::EventSource,
error_text,
);
if let Some(handle) = request_handle {
record = record.with_request_handle(handle);
}
context_host
.borrow_mut()
.record_subresource_network(record);
crate::network_host::fail_event_source_connection(
scope,
event_source,
crate::network_host::EventSourceTerminalMode::Close,
);
} else {
let head = response.head();
if let Some(handle) = request_handle {
context_host
.borrow_mut()
.record_subresource_response_started(
crate::types::SubresourceResponseStarted::new(
handle,
response.redirect_chain.clone(),
response.final_url.clone(),
response.status,
response.headers.clone(),
response.cookie_set_reports.clone(),
)
.with_status_text(response_status_text)
.with_from_cache(response.from_cache)
.with_negotiated_http_version(
response.negotiated_http_version,
)
.with_network_request_headers(
response
.network_request_headers()
.map(|headers| headers.to_vec()),
),
);
}
if let Some(error_text) =
crate::network_host::event_source_response_error(&head)
{
if let Some(handle) = request_handle {
context_host
.borrow_mut()
.record_subresource_body_finished(
crate::types::SubresourceBodyFinished::failed(
handle, error_text,
),
);
}
crate::network_host::fail_event_source_connection(
scope,
event_source,
crate::network_host::EventSourceTerminalMode::Close,
);
} else {
crate::network_host::open_event_source_connection(
scope,
event_source,
&response.final_url,
);
let bytes = response.body_bytes();
if let Some(handle) = request_handle
&& !bytes.is_empty()
{
context_host.borrow_mut().record_subresource_data_received(
crate::types::SubresourceDataReceived::new(
handle,
bytes.len(),
bytes.len(),
),
);
}
let mut parser = crate::network_host::EventSourceParser::new(
crate::network_host::event_source_last_event_id(
scope,
event_source,
),
crate::network_host::event_source_reconnect_delay_ms(
scope,
event_source,
),
);
if crate::network_host::event_source_ready_state(scope, event_source)
!= crate::network_host::EVENT_SOURCE_CLOSED
{
let messages = parser.push(bytes);
dispatch_streaming_event_source_messages(
&context_host,
scope,
event_source,
request_handle,
&messages,
);
}
if crate::network_host::event_source_ready_state(scope, event_source)
!= crate::network_host::EVENT_SOURCE_CLOSED
{
crate::network_host::update_event_source_stream_state(
scope,
event_source,
parser.last_event_id(),
parser.reconnect_delay_ms(),
);
}
if let Some(handle) = request_handle {
context_host.borrow_mut().record_subresource_body_finished(
crate::types::SubresourceBodyFinished::ready_after_streaming(
handle,
SubresourceResponseBody::from_navigation_response(
&response,
),
),
);
}
if crate::network_host::event_source_ready_state(scope, event_source)
!= crate::network_host::EVENT_SOURCE_CLOSED
{
crate::network_host::fail_event_source_connection(
scope,
event_source,
crate::network_host::EventSourceTerminalMode::Reconnect,
);
}
}
}
}
}
defer_subresource_owner_async_scope(
&context_host,
scope,
pending.execution_context.dispatch_scope(),
owner_async_scope,
);
Ok(AsyncSubresourceFetchBodyActivity::WindowRealmEntered)
})
}
pub(super) fn resolve_pending_subresource_fetch_body(
&mut self,
pending: PendingSubresourceFetchState,
request_url: Url,
request_method: String,
request_headers: moli_fetch::RequestHeaders,
request_body: Option<String>,
response_status_text: Option<String>,
skip_fetch_security_validation: bool,
response_filter: Option<AsyncSubresourceFetchResponseFilter>,
network_error_text: Option<String>,
result: std::result::Result<crate::protocol_types::NavigationResponse, String>,
) -> Result<AsyncSubresourceFetchBodyActivity> {
self.resolve_pending_subresource_fetch_completion(
pending,
request_url,
request_method,
request_headers,
request_body,
response_status_text,
skip_fetch_security_validation,
response_filter,
network_error_text,
result.into(),
)
}
#[allow(clippy::too_many_arguments)]
pub(super) fn resolve_pending_subresource_fetch_completion(
&mut self,
mut pending: PendingSubresourceFetchState,
request_url: Url,
request_method: String,
request_headers: moli_fetch::RequestHeaders,
request_body: Option<String>,
response_status_text: Option<String>,
skip_fetch_security_validation: bool,
response_filter: Option<AsyncSubresourceFetchResponseFilter>,
network_error_text: Option<String>,
completion_result: AsyncSubresourceFetchResult,
) -> Result<AsyncSubresourceFetchBodyActivity> {
let (supplied_parkable_image, result) = match completion_result {
AsyncSubresourceFetchResult::Response(response) => (None, Ok(response)),
AsyncSubresourceFetchResult::Image { response, encoded } => {
(Some(encoded), Ok(response))
}
AsyncSubresourceFetchResult::Failure(error) => (None, Err(error)),
};
let trace_started = moli_trace::cdp_runtime_trace_enabled().then(Instant::now);
let trace_fields = async_subresource_trace_fields_for_pending(
"completion",
pending.info.internal_id,
&pending,
);
trace_async_subresource_stage(
"async_subresource_resolve_pending_start",
trace_fields,
trace_started,
);
if pending.continuation.is_detached_window_fetch()
|| pending.execution_context.is_window_network_only()
{
return self
.resolve_network_only_subresource_fetch(
pending,
request_url,
request_method,
request_headers,
request_body,
response_status_text,
skip_fetch_security_validation,
network_error_text,
result,
)
.map(|()| AsyncSubresourceFetchBodyActivity::NoWindowRealmEntered);
}
if !window_subresource_owner_is_current(&self._context_host, &pending) {
tracing::debug!(
internal_id = pending.info.internal_id,
owner = ?pending.execution_context.window_request_target().map(crate::native_bridge::WindowTaskTarget::owner),
"discarded subresource completion for retired Window execution context"
);
return Ok(AsyncSubresourceFetchBodyActivity::NoWindowRealmEntered);
}
if pending.continuation.is_window_event_source() {
return self.resolve_pending_event_source_fetch(
pending,
request_url,
request_method,
request_headers,
request_body,
response_status_text,
skip_fetch_security_validation,
network_error_text,
result,
);
}
self._context_host
.borrow_mut()
.record_deferred_pending_subresource_request_started(&mut pending);
let context_host = self._context_host.clone();
let mut completed_web_font = None;
let result = self.renderer_document_isolate.with_entered_renderer_document_isolate(|isolate| {
let scope = pin!(v8::HandleScope::new(isolate));
let scope = &mut scope.init();
let context = v8::Local::new(
scope,
pending
.execution_context
.context_global()
.expect("active subresource completion must retain its V8 context"),
);
let scope = &mut v8::ContextScope::new(scope, context);
if !window_subresource_realm_is_current(&context_host, scope, &pending) {
tracing::debug!(
internal_id = pending.info.internal_id,
expected_realm = ?pending.execution_context.realm_token(),
"discarded subresource completion for retired V8 realm"
);
return Ok(AsyncSubresourceFetchBodyActivity::NoWindowRealmEntered);
}
trace_async_subresource_stage(
"async_subresource_context_entered",
trace_fields,
trace_started,
);
let owner_async_scope =
enter_subresource_owner_async_scope(
&context_host,
scope,
pending.execution_context.dispatch_scope(),
);
let security_started = moli_trace::cdp_runtime_trace_enabled().then(Instant::now);
let mut opaque_response_blocked = false;
let result = result.and_then(|response| {
if !response.redirect_chain.is_empty()
&& let Some(message) = document_connect_csp_redirect_failure_message(
scope,
&context_host,
&pending,
&response.final_url,
)
{
return Err(message);
}
if !skip_fetch_security_validation
&& matches!(
pending.info.resource_type,
SubresourceResourceType::Audio
| SubresourceResourceType::Fetch
| SubresourceResourceType::Font
| SubresourceResourceType::Image
| SubresourceResourceType::Media
| SubresourceResourceType::TextTrack
| SubresourceResourceType::Video
| SubresourceResourceType::Xhr
) {
let supplied_snapshot = supplied_parkable_image
.as_ref()
.map(|image| {
image.snapshot().map_err(|error| {
format!("failed to read image response bytes: {error}")
})
})
.transpose()?;
let response_body = supplied_snapshot
.as_ref()
.map_or_else(|| response.body_bytes(), AsRef::as_ref);
let validation = crate::network_host::validate_fetch_response_security_policy_with_body_classified(
&pending.request_origin,
&response.head(),
response_body,
pending.request_mode,
pending.credentials_mode,
pending.policy_context,
);
match validation {
Ok(()) => {}
Err(crate::network_host::FetchResponseSecurityViolation::OpaqueResponseBlocked(_))
if pending.continuation.is_window_fetch() =>
{
opaque_response_blocked = true;
}
Err(violation) => return Err(violation.into_message()),
}
}
Ok(response)
});
trace_async_subresource_stage(
"async_subresource_security_checked",
trace_fields,
security_started,
);
let request_initiator_type = pending.continuation.request_initiator_type();
match result {
Ok(mut response) => {
let response_status = response.status;
let parkable_image = (!opaque_response_blocked
&& pending.info.resource_type == SubresourceResourceType::Image)
.then(|| {
supplied_parkable_image.clone().unwrap_or_else(|| {
let runner = pending.load.task_runner();
pending
.load
.request_client()
.parkable_image_manager(&runner)
.from_frozen_bytes(response.take_body_bytes())
})
});
let request_cookie_report = response
.request_cookie_report
.clone()
.or_else(|| pending.info.request_cookie_report.clone());
let record_started =
moli_trace::cdp_runtime_trace_enabled().then(Instant::now);
let mut network_record = if opaque_response_blocked {
crate::types::SubresourceNetworkRecord::failure(
pending.info.frame_id.clone(),
pending.info.document_url.clone(),
request_url.clone(),
request_method,
request_headers,
request_body,
pending.info.resource_type,
crate::network_host::ABORTED_ERROR_TEXT.to_owned(),
)
.with_request_initiator_type(request_initiator_type)
.with_request_body_bytes(pending.info.request_body_bytes.clone())
} else {
crate::types::SubresourceNetworkRecord::success_with_body(
pending.info.frame_id.clone(),
pending.info.document_url.clone(),
request_url.clone(),
request_method,
request_headers,
request_body,
pending.info.resource_type,
request_cookie_report,
response.redirect_chain.clone().into_iter().collect(),
response.final_url.clone(),
response.status,
response.headers.clone(),
parkable_image.as_ref().map_or_else(
|| SubresourceResponseBody::from_navigation_response(&response),
|image| {
SubresourceResponseBody::from_parkable_image(image.clone())
},
),
response.cookie_set_reports.clone(),
)
.with_from_cache(response.from_cache)
.with_negotiated_http_version(response.negotiated_http_version)
.with_network_request_headers(
response.network_request_headers().map(|headers| headers.to_vec()),
)
.with_request_initiator_type(request_initiator_type)
.with_request_body_bytes(pending.info.request_body_bytes.clone())
};
if !opaque_response_blocked
&& let Some(status_text) = response_status_text.as_deref()
{
network_record =
network_record.with_response_status_text(status_text);
}
if let Some(handle) = pending.info.network_request_handle {
network_record = network_record.with_request_handle(handle);
}
context_host
.borrow_mut()
.record_subresource_network(network_record);
trace_async_subresource_stage(
"async_subresource_network_recorded",
trace_fields,
record_started,
);
let mut observable_response = response;
if matches!(
pending.info.resource_type,
SubresourceResourceType::Fetch | SubresourceResourceType::Xhr
) && !response_filter.is_some_and(|filter| filter.is_readable()) {
observable_response.headers =
crate::network_host::filter_cors_exposed_response_headers(
&pending.request_origin,
&observable_response.head(),
pending.credentials_mode,
);
}
let continuation_started =
moli_trace::cdp_runtime_trace_enabled().then(Instant::now);
match pending.continuation {
PendingSubresourceContinuation::Fetch(fetch) => {
let resolver = fetch
.into_resolver()
.expect("detached keepalive completion is handled before V8 entry");
let resolver = v8::Local::new(scope, &resolver);
let (head, body) = observable_response.into_body();
let body = if opaque_response_blocked {
moli_fetch::ResponseBody::materialized_bytes(Vec::new())
} else {
body
};
let response_filter = opaque_response_blocked
.then_some(AsyncSubresourceFetchResponseFilter::Opaque)
.or(response_filter);
let response_obj =
crate::network_host::build_fetch_response_object_from_body_source_for_request_mode_with_filter(
scope,
&pending.request_origin,
pending.request_mode,
head,
body,
response_filter,
);
if let Some(status_text) = response_status_text.as_deref() {
crate::network_host::set_response_slot_string(
scope,
response_obj,
crate::network_host::RESPONSE_STATUS_TEXT_SLOT,
status_text,
);
}
resolver.resolve(scope, response_obj.into());
}
PendingSubresourceContinuation::Xhr(xhr) => {
crate::context_bootstrap::record_resource_performance_entry(
scope,
crate::context_bootstrap::ResourcePerformanceEntry::from_network_response(
pending.info.url.as_str(),
"xmlhttprequest",
None,
&observable_response,
),
);
let xhr = v8::Local::new(scope, &xhr);
let (head, body) = observable_response.into_body();
crate::network_host::apply_xhr_response_body_source_with_status_text(
scope,
xhr,
head,
body,
response_status_text.as_deref(),
);
}
PendingSubresourceContinuation::Image {
image_handle,
sequence,
..
} => {
let encoded = parkable_image
.as_ref()
.expect("an accepted image response must be parkable");
apply_image_subresource_terminal(
scope,
&context_host,
image_handle,
sequence,
pending.info.internal_id,
&pending.info.url,
ImageSubresourceTerminal::Response {
response: &observable_response,
encoded,
},
)
}
PendingSubresourceContinuation::Media {
media_handle,
sequence,
} => apply_media_subresource_terminal(
scope,
&context_host,
media_handle,
sequence,
pending.info.internal_id,
crate::network_host::media_response_status_is_successful(
response_status,
),
),
PendingSubresourceContinuation::TextTrack {
track_handle,
sequence,
} => apply_text_track_subresource_terminal(
scope,
&context_host,
track_handle,
sequence,
pending.info.internal_id,
crate::network_host::text_track_response_result(
response_status,
observable_response.body_text(),
),
),
PendingSubresourceContinuation::StylesheetSubresource {
binding,
web_font,
css_image,
} => {
if let Some(identity) = css_image.as_ref() {
let descriptor = crate::network_host::image_response_descriptor_from_parkable(
&observable_response,
parkable_image
.as_ref()
.expect("a CSS image response must be parkable"),
);
let _ = context_host
.borrow_mut()
.complete_stylesheet_css_image_response(
identity,
descriptor,
parkable_image
.as_ref()
.expect("a CSS image response must be parkable")
.clone(),
);
}
if binding.child_handle().is_none() {
completed_web_font = web_font.map(|font| {
if (200..=299).contains(&response_status)
&& !opaque_response_blocked
{
crate::css_resource_urls::CompletedStylesheetWebFont::response(
font,
observable_response.clone_body_bytes(),
)
} else {
crate::css_resource_urls::CompletedStylesheetWebFont::failure(
font,
)
}
});
}
apply_stylesheet_subresource_terminal(&context_host, binding);
}
PendingSubresourceContinuation::Beacon
| PendingSubresourceContinuation::CspReport { .. }
| PendingSubresourceContinuation::EventSource(_)
| PendingSubresourceContinuation::WebSocket(_)
| PendingSubresourceContinuation::WorkerFetch { .. }
| PendingSubresourceContinuation::WorkerXhr { .. }
| PendingSubresourceContinuation::WorkerCspReport { .. }
| PendingSubresourceContinuation::SharedWorkerFetch { .. }
| PendingSubresourceContinuation::SharedWorkerXhr { .. }
| PendingSubresourceContinuation::SharedWorkerCspReport { .. } => {}
}
trace_async_subresource_stage(
"async_subresource_continuation_delivered",
trace_fields,
continuation_started,
);
}
Err(error_text) => {
let network_error_text = network_error_text
.as_deref()
.or_else(|| {
crate::network_host::is_cors_policy_failure_message(&error_text)
.then_some(crate::network_host::FAILED_ERROR_TEXT)
})
.unwrap_or(&error_text);
let record_started =
moli_trace::cdp_runtime_trace_enabled().then(Instant::now);
let mut network_record = crate::types::SubresourceNetworkRecord::failure(
pending.info.frame_id.clone(),
pending.info.document_url.clone(),
request_url,
request_method,
request_headers,
request_body,
pending.info.resource_type,
network_error_text.to_owned(),
)
.with_request_initiator_type(request_initiator_type);
if let Some(handle) = pending.info.network_request_handle {
network_record = network_record.with_request_handle(handle);
}
context_host
.borrow_mut()
.record_subresource_network(network_record);
trace_async_subresource_stage(
"async_subresource_network_recorded",
trace_fields,
record_started,
);
let continuation_started =
moli_trace::cdp_runtime_trace_enabled().then(Instant::now);
match pending.continuation {
PendingSubresourceContinuation::Fetch(fetch) => {
let resolver = fetch
.into_resolver()
.expect("detached keepalive failure is handled before V8 entry");
let resolver = v8::Local::new(scope, &resolver);
let exception = v8_string(scope, &error_text)
.map(|message| v8::Exception::type_error(scope, message))
.unwrap_or_else(|| v8::undefined(scope).into());
resolver.reject(scope, exception);
}
PendingSubresourceContinuation::Xhr(xhr) => {
let xhr = v8::Local::new(scope, &xhr);
crate::network_host::apply_xhr_failure(scope, xhr);
}
PendingSubresourceContinuation::Image {
image_handle,
sequence,
..
} => apply_image_subresource_terminal(
scope,
&context_host,
image_handle,
sequence,
pending.info.internal_id,
&pending.info.url,
ImageSubresourceTerminal::Failure,
),
PendingSubresourceContinuation::Media {
media_handle,
sequence,
} => apply_media_subresource_terminal(
scope,
&context_host,
media_handle,
sequence,
pending.info.internal_id,
false,
),
PendingSubresourceContinuation::TextTrack {
track_handle,
sequence,
} => apply_text_track_subresource_terminal(
scope,
&context_host,
track_handle,
sequence,
pending.info.internal_id,
Err(error_text.clone()),
),
PendingSubresourceContinuation::StylesheetSubresource {
binding,
web_font,
css_image,
} => {
if let Some(identity) = css_image.as_ref() {
let _ = context_host
.borrow_mut()
.fail_stylesheet_css_image(identity);
}
if binding.child_handle().is_none() {
completed_web_font = web_font.map(
crate::css_resource_urls::CompletedStylesheetWebFont::failure,
);
}
apply_stylesheet_subresource_terminal(&context_host, binding);
}
PendingSubresourceContinuation::Beacon
| PendingSubresourceContinuation::CspReport { .. }
| PendingSubresourceContinuation::EventSource(_)
| PendingSubresourceContinuation::WebSocket(_)
| PendingSubresourceContinuation::WorkerFetch { .. }
| PendingSubresourceContinuation::WorkerXhr { .. }
| PendingSubresourceContinuation::WorkerCspReport { .. }
| PendingSubresourceContinuation::SharedWorkerFetch { .. }
| PendingSubresourceContinuation::SharedWorkerXhr { .. }
| PendingSubresourceContinuation::SharedWorkerCspReport { .. } => {}
}
trace_async_subresource_stage(
"async_subresource_continuation_delivered",
trace_fields,
continuation_started,
);
}
}
defer_subresource_owner_async_scope(
&context_host,
scope,
pending.execution_context.dispatch_scope(),
owner_async_scope,
);
Ok(AsyncSubresourceFetchBodyActivity::WindowRealmEntered)
});
if let Some(web_font) = completed_web_font {
self.complete_document_web_font(web_font);
}
trace_async_subresource_stage(
"async_subresource_resolve_pending_done",
trace_fields,
trace_started,
);
result
}
}
@@ -0,0 +1,440 @@
use super::*;
impl ScriptVm {
pub(crate) fn should_intercept_parser_script_source_fetch(
&self,
script: &crate::planning::PreparedScript,
) -> bool {
script.source_kind == crate::types::ScriptSourceKind::External
&& matches!(script.url.scheme(), "http" | "https")
&& self
._context_host
.borrow()
.should_intercept_subresource(SubresourceResourceType::Script)
}
pub(crate) fn start_parser_script_source_fetch_interception(
&mut self,
script: crate::planning::PreparedScript,
request_client: ResourceRequestClient,
task_runner: crate::network::RendererResourceTaskRunner,
browser_context_runtime: crate::runtime::RendererBrowserContextRuntime,
document_character_set: Option<String>,
) -> crate::planning::SharedScriptSourceLoad {
// Main-parser source completion is routed by the exact parser
// continuation registered on the returned load. The interception
// request itself is frozen into this Page turn's concrete output
// journal; it is never parked in browser-global state for a later
// protocol snapshot to rediscover.
let (load, completer) =
crate::planning::SharedScriptSourceLoad::pending_with_owner_wake(None);
let (info, continuation) = browser_context_runtime.prepare_detached_parser_script_fetch(
PendingSubresourceFetchInfo {
internal_id: 0,
network_request_handle: None,
frame_id: self.root_frame_id.clone(),
document_url: script.initiator_url.clone(),
url: script.url.clone(),
websocket_socket_id: None,
method: "GET".to_owned(),
request_headers: Default::default(),
request_body: None,
request_body_bytes: None,
resource_type: SubresourceResourceType::Script,
request_cookie_report: None,
},
script,
self.current_main_document_resource_loader()
.expect("parser interception requires its Document authority")
.fetch_context()
.request_origin(),
request_client,
task_runner,
document_character_set,
completer,
);
let source_document = self
._context_host
.borrow()
.root_document_lifecycle_identity()
.expect("parser fetch interception requires an active root Document");
let appended = self._context_host.borrow().append_live_turn_owner_action(
crate::runtime::RendererOwnerAction::DetachedParserScriptFetchPause {
source_document,
info: Box::new(info),
continuation,
},
);
assert!(
appended,
"parser fetch interception requires a concrete Page output journal"
);
load
}
pub(super) fn continue_worker_owned_fetch(
&self,
target: WorkerOwnedFetchTarget,
request: crate::worker::WorkerPendingFetchContinue,
) -> bool {
match target {
WorkerOwnedFetchTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.continue_worker_fetch(worker_id, request),
WorkerOwnedFetchTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.continue_shared_worker_fetch(instance_id, request),
}
}
pub(super) fn continue_worker_owned_xhr(
&self,
target: WorkerOwnedXhrTarget,
request: crate::worker::WorkerPendingXhrContinue,
) -> bool {
match target {
WorkerOwnedXhrTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.continue_worker_xhr(worker_id, request),
WorkerOwnedXhrTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.continue_shared_worker_xhr(instance_id, request),
}
}
pub(super) fn continue_worker_owned_csp_report(
&self,
target: WorkerOwnedCspReportTarget,
request: crate::worker::WorkerPendingFetchContinue,
) -> bool {
match target {
WorkerOwnedCspReportTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.continue_worker_csp_report(worker_id, request),
WorkerOwnedCspReportTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.continue_shared_worker_csp_report(instance_id, request),
}
}
pub(super) fn fail_worker_owned_fetch(
&self,
target: WorkerOwnedFetchTarget,
request: crate::worker::WorkerPendingFetchContinue,
error_text: String,
) -> bool {
match target {
WorkerOwnedFetchTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fail_worker_fetch(worker_id, request, error_text),
WorkerOwnedFetchTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fail_shared_worker_fetch(instance_id, request, error_text),
}
}
pub(super) fn fail_worker_owned_xhr(
&self,
target: WorkerOwnedXhrTarget,
request: crate::worker::WorkerPendingXhrContinue,
error_text: String,
) -> bool {
match target {
WorkerOwnedXhrTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fail_worker_xhr(worker_id, request, error_text),
WorkerOwnedXhrTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fail_shared_worker_xhr(instance_id, request, error_text),
}
}
pub(super) fn fail_worker_owned_csp_report(
&self,
target: WorkerOwnedCspReportTarget,
request: crate::worker::WorkerPendingFetchContinue,
error_text: String,
) -> bool {
match target {
WorkerOwnedCspReportTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fail_worker_csp_report(worker_id, request, error_text),
WorkerOwnedCspReportTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fail_shared_worker_csp_report(instance_id, request, error_text),
}
}
pub(super) fn fail_worker_owned_fetch_auth(
&self,
target: WorkerOwnedFetchTarget,
request: crate::worker::WorkerPendingFetchContinue,
error_text: String,
) -> bool {
match target {
WorkerOwnedFetchTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fail_worker_fetch_auth(worker_id, request, error_text),
WorkerOwnedFetchTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fail_shared_worker_fetch_auth(instance_id, request, error_text),
}
}
pub(super) fn fail_worker_owned_xhr_auth(
&self,
target: WorkerOwnedXhrTarget,
request: crate::worker::WorkerPendingXhrContinue,
error_text: String,
) -> bool {
match target {
WorkerOwnedXhrTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fail_worker_xhr_auth(worker_id, request, error_text),
WorkerOwnedXhrTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fail_shared_worker_xhr_auth(instance_id, request, error_text),
}
}
pub(super) fn continue_worker_owned_fetch_response(
&self,
target: WorkerOwnedFetchTarget,
request: crate::worker::WorkerPendingFetchContinue,
response_code: Option<u16>,
response_headers: Option<Vec<(String, Vec<u8>)>>,
) -> bool {
match target {
WorkerOwnedFetchTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.continue_worker_fetch_response(
worker_id,
request,
response_code,
response_headers,
),
WorkerOwnedFetchTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.continue_shared_worker_fetch_response(
instance_id,
request,
response_code,
response_headers,
),
}
}
pub(super) fn continue_worker_owned_xhr_response(
&self,
target: WorkerOwnedXhrTarget,
request: crate::worker::WorkerPendingXhrContinue,
response_code: Option<u16>,
response_headers: Option<Vec<(String, Vec<u8>)>>,
) -> bool {
match target {
WorkerOwnedXhrTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.continue_worker_xhr_response(worker_id, request, response_code, response_headers),
WorkerOwnedXhrTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.continue_shared_worker_xhr_response(
instance_id,
request,
response_code,
response_headers,
),
}
}
pub(super) fn fail_worker_owned_fetch_response(
&self,
target: WorkerOwnedFetchTarget,
request: crate::worker::WorkerPendingFetchContinue,
error_text: String,
) -> bool {
match target {
WorkerOwnedFetchTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fail_worker_fetch_response(worker_id, request, error_text),
WorkerOwnedFetchTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fail_shared_worker_fetch_response(instance_id, request, error_text),
}
}
pub(super) fn fail_worker_owned_xhr_response(
&self,
target: WorkerOwnedXhrTarget,
request: crate::worker::WorkerPendingXhrContinue,
error_text: String,
) -> bool {
match target {
WorkerOwnedXhrTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fail_worker_xhr_response(worker_id, request, error_text),
WorkerOwnedXhrTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fail_shared_worker_xhr_response(instance_id, request, error_text),
}
}
pub(super) fn fulfill_worker_owned_fetch(
&self,
target: WorkerOwnedFetchTarget,
request: crate::worker::WorkerPendingFetchContinue,
response_code: u16,
response_headers: Vec<(String, Vec<u8>)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
match target {
WorkerOwnedFetchTarget::Dedicated { worker_id, .. } => {
self._context_host.borrow_mut().fulfill_worker_fetch(
worker_id,
request,
response_code,
response_headers,
response_body,
)
}
WorkerOwnedFetchTarget::Shared { instance_id, .. } => {
self._context_host.borrow_mut().fulfill_shared_worker_fetch(
instance_id,
request,
response_code,
response_headers,
response_body,
)
}
}
}
pub(super) fn fulfill_worker_owned_xhr(
&self,
target: WorkerOwnedXhrTarget,
request: crate::worker::WorkerPendingXhrContinue,
response_code: u16,
response_headers: Vec<(String, Vec<u8>)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
match target {
WorkerOwnedXhrTarget::Dedicated { worker_id, .. } => {
self._context_host.borrow_mut().fulfill_worker_xhr(
worker_id,
request,
response_code,
response_headers,
response_body,
)
}
WorkerOwnedXhrTarget::Shared { instance_id, .. } => {
self._context_host.borrow_mut().fulfill_shared_worker_xhr(
instance_id,
request,
response_code,
response_headers,
response_body,
)
}
}
}
pub(super) fn fulfill_worker_owned_csp_report(
&self,
target: WorkerOwnedCspReportTarget,
request: crate::worker::WorkerPendingFetchContinue,
response_code: u16,
response_headers: Vec<(String, Vec<u8>)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
match target {
WorkerOwnedCspReportTarget::Dedicated { worker_id, .. } => {
self._context_host.borrow_mut().fulfill_worker_csp_report(
worker_id,
request,
response_code,
response_headers,
response_body,
)
}
WorkerOwnedCspReportTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fulfill_shared_worker_csp_report(
instance_id,
request,
response_code,
response_headers,
response_body,
),
}
}
pub(super) fn fulfill_worker_owned_fetch_response(
&self,
target: WorkerOwnedFetchTarget,
request: crate::worker::WorkerPendingFetchContinue,
response_code: u16,
response_headers: Vec<(String, Vec<u8>)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
match target {
WorkerOwnedFetchTarget::Dedicated { worker_id, .. } => self
._context_host
.borrow_mut()
.fulfill_worker_fetch_response(
worker_id,
request,
response_code,
response_headers,
response_body,
),
WorkerOwnedFetchTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fulfill_shared_worker_fetch_response(
instance_id,
request,
response_code,
response_headers,
response_body,
),
}
}
pub(super) fn fulfill_worker_owned_xhr_response(
&self,
target: WorkerOwnedXhrTarget,
request: crate::worker::WorkerPendingXhrContinue,
response_code: u16,
response_headers: Vec<(String, Vec<u8>)>,
response_body: RendererSyntheticResponseBody,
) -> bool {
match target {
WorkerOwnedXhrTarget::Dedicated { worker_id, .. } => {
self._context_host.borrow_mut().fulfill_worker_xhr_response(
worker_id,
request,
response_code,
response_headers,
response_body,
)
}
WorkerOwnedXhrTarget::Shared { instance_id, .. } => self
._context_host
.borrow_mut()
.fulfill_shared_worker_xhr_response(
instance_id,
request,
response_code,
response_headers,
response_body,
),
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff