script: Move navigation fetching to the ScriptThread (#34919)

This allows reusing the asynchrnous fetch mechanism that we use for page
resources and is likely a step toward removing the `FetchThread`.

Benefits:
 - Reduces IPC traffic during navigation. Now instead of bouncing
   between the constellation and the `ScriptThread` responses are sent
   directly to the `ScriptThread`.
 - Allows cancelling loads after redirects, which was not possible
   before.

There is the question of what to do when a redirect is cross-origin
(#23037). This currently isn't handled properly as the `Constellation`
sends data to the same `Pipeline` that initiated the load. This change
doesn't fix this issue, but does make it more possible for the
`ScriptThread` to shut down the pipeline and ask the `Constellation` to
replace it with a new one.

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Martin Robinson 2025-01-10 13:19:40 +01:00 committed by GitHub
parent 73c0701c83
commit fbd77b4524
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 420 additions and 460 deletions

View file

@ -14,7 +14,7 @@ use base::id::HistoryStateId;
use cookie::Cookie;
use crossbeam_channel::{unbounded, Receiver, Sender};
use headers::{ContentType, HeaderMapExt, ReferrerPolicy as ReferrerPolicyHeader};
use http::{Error as HttpError, HeaderMap, StatusCode};
use http::{header, Error as HttpError, HeaderMap, HeaderValue, StatusCode};
use hyper_serde::Serde;
use hyper_util::client::legacy::Error as HyperError;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
@ -46,6 +46,10 @@ pub mod request;
pub mod response;
pub mod storage_thread;
/// <https://fetch.spec.whatwg.org/#document-accept-header-value>
pub const DOCUMENT_ACCEPT_HEADER_VALUE: HeaderValue =
HeaderValue::from_static("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
/// An implementation of the [Fetch specification](https://fetch.spec.whatwg.org/)
pub mod fetch {
pub mod headers;
@ -197,7 +201,7 @@ pub enum FetchResponseMsg {
}
impl FetchResponseMsg {
fn request_id(&self) -> RequestId {
pub fn request_id(&self) -> RequestId {
match self {
FetchResponseMsg::ProcessRequestBody(id) |
FetchResponseMsg::ProcessRequestEOF(id) |
@ -252,6 +256,15 @@ pub enum FetchMetadata {
},
}
impl FetchMetadata {
pub fn metadata(&self) -> &Metadata {
match self {
Self::Unfiltered(metadata) => metadata,
Self::Filtered { unsafe_, .. } => unsafe_,
}
}
}
pub trait FetchResponseListener {
fn process_request_body(&mut self, request_id: RequestId);
fn process_request_eof(&mut self, request_id: RequestId);
@ -511,6 +524,7 @@ pub enum CoreResourceMsg {
enum ToFetchThreadMessage {
StartFetch(
/* request_builder */ RequestBuilder,
/* response_init */ Option<ResponseInit>,
/* cancel_chan */ Option<IpcReceiver<()>>,
/* callback */ BoxedFetchCallback,
),
@ -570,14 +584,29 @@ impl FetchThread {
fn run(&mut self) {
loop {
match self.receiver.recv().unwrap() {
ToFetchThreadMessage::StartFetch(request_builder, canceller, callback) => {
ToFetchThreadMessage::StartFetch(
request_builder,
response_init,
canceller,
callback,
) => {
self.active_fetches.insert(request_builder.id, callback);
self.core_resource_thread
.send(CoreResourceMsg::Fetch(
// Only redirects have a `response_init` field.
let message = match response_init {
Some(response_init) => CoreResourceMsg::FetchRedirect(
request_builder,
response_init,
self.to_fetch_sender.clone(),
canceller,
),
None => CoreResourceMsg::Fetch(
request_builder,
FetchChannels::ResponseMsg(self.to_fetch_sender.clone(), canceller),
))
.unwrap();
),
};
self.core_resource_thread.send(message).unwrap();
},
ToFetchThreadMessage::FetchResponse(fetch_response_msg) => {
let request_id = fetch_response_msg.request_id();
@ -599,18 +628,23 @@ impl FetchThread {
}
}
/// Instruct the resource thread to make a new request.
static FETCH_THREAD: OnceLock<Sender<ToFetchThreadMessage>> = OnceLock::new();
/// Instruct the resource thread to make a new fetch request.
pub fn fetch_async(
core_resource_thread: &CoreResourceThread,
request: RequestBuilder,
response_init: Option<ResponseInit>,
canceller: Option<IpcReceiver<()>>,
callback: BoxedFetchCallback,
) {
static FETCH_THREAD: OnceLock<Sender<ToFetchThreadMessage>> = OnceLock::new();
let _ = FETCH_THREAD
.get_or_init(|| FetchThread::spawn(core_resource_thread))
.send(ToFetchThreadMessage::StartFetch(
request, canceller, callback,
request,
response_init,
canceller,
callback,
));
}
@ -945,5 +979,17 @@ pub fn http_percent_encode(bytes: &[u8]) -> String {
percent_encoding::percent_encode(bytes, HTTP_VALUE).to_string()
}
pub fn set_default_accept_language(headers: &mut HeaderMap) {
if headers.contains_key(header::ACCEPT_LANGUAGE) {
return;
}
// TODO(eijebong): Change this once typed headers are done
headers.insert(
header::ACCEPT_LANGUAGE,
HeaderValue::from_static("en-US,en;q=0.5"),
);
}
pub static PRIVILEGED_SECRET: LazyLock<u32> =
LazyLock::new(|| servo_rand::ServoRng::default().next_u32());