mirror of
https://github.com/servo/servo.git
synced 2025-07-23 15:23:42 +01:00
Auto merge of #15354 - cynicaldevil:manual-redirect, r=jdm
Redirect document loads manually <!-- Please describe your changes on the following line: --> --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #14596 . r? @jdm I ran some tests at random from the `navigating-across-documents` folder, and they are passing. <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/15354) <!-- Reviewable:end -->
This commit is contained in:
commit
eac4f407e2
17 changed files with 376 additions and 52 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -489,6 +489,7 @@ dependencies = [
|
||||||
"gaol 0.0.1 (git+https://github.com/servo/gaol)",
|
"gaol 0.0.1 (git+https://github.com/servo/gaol)",
|
||||||
"gfx 0.0.1",
|
"gfx 0.0.1",
|
||||||
"gfx_traits 0.0.1",
|
"gfx_traits 0.0.1",
|
||||||
|
"hyper 0.10.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"ipc-channel 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
"itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"layout_traits 0.0.1",
|
"layout_traits 0.0.1",
|
||||||
|
|
|
@ -21,6 +21,7 @@ devtools_traits = {path = "../devtools_traits"}
|
||||||
euclid = "0.11"
|
euclid = "0.11"
|
||||||
gfx = {path = "../gfx"}
|
gfx = {path = "../gfx"}
|
||||||
gfx_traits = {path = "../gfx_traits"}
|
gfx_traits = {path = "../gfx_traits"}
|
||||||
|
hyper = "0.10"
|
||||||
ipc-channel = "0.7"
|
ipc-channel = "0.7"
|
||||||
itertools = "0.5"
|
itertools = "0.5"
|
||||||
layout_traits = {path = "../layout_traits"}
|
layout_traits = {path = "../layout_traits"}
|
||||||
|
|
|
@ -91,9 +91,11 @@ use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
|
||||||
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId};
|
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId};
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||||
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
|
||||||
use net_traits::{self, IpcSend, ResourceThreads};
|
use net_traits::{self, IpcSend, FetchResponseMsg, ResourceThreads};
|
||||||
use net_traits::pub_domains::reg_host;
|
use net_traits::pub_domains::reg_host;
|
||||||
|
use net_traits::request::RequestInit;
|
||||||
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
|
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
|
||||||
|
use network_listener::NetworkListener;
|
||||||
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
||||||
use pipeline::{InitialPipelineState, Pipeline};
|
use pipeline::{InitialPipelineState, Pipeline};
|
||||||
use profile_traits::mem;
|
use profile_traits::mem;
|
||||||
|
@ -159,6 +161,12 @@ pub struct Constellation<Message, LTF, STF> {
|
||||||
/// This is the constellation's view of `layout_sender`.
|
/// This is the constellation's view of `layout_sender`.
|
||||||
layout_receiver: Receiver<Result<FromLayoutMsg, IpcError>>,
|
layout_receiver: Receiver<Result<FromLayoutMsg, IpcError>>,
|
||||||
|
|
||||||
|
/// A channel for network listener to send messages to the constellation.
|
||||||
|
network_listener_sender: Sender<(PipelineId, FetchResponseMsg)>,
|
||||||
|
|
||||||
|
/// A channel for the constellation to receive messages from network listener.
|
||||||
|
network_listener_receiver: Receiver<(PipelineId, FetchResponseMsg)>,
|
||||||
|
|
||||||
/// A channel for the constellation to receive messages from the compositor thread.
|
/// A channel for the constellation to receive messages from the compositor thread.
|
||||||
compositor_receiver: Receiver<FromCompositorMsg>,
|
compositor_receiver: Receiver<FromCompositorMsg>,
|
||||||
|
|
||||||
|
@ -502,6 +510,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure");
|
let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure");
|
||||||
let layout_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_layout_receiver);
|
let layout_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_layout_receiver);
|
||||||
|
|
||||||
|
let (network_listener_sender, network_listener_receiver) = channel();
|
||||||
|
|
||||||
let swmanager_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);
|
let swmanager_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);
|
||||||
|
|
||||||
PipelineNamespace::install(PipelineNamespaceId(0));
|
PipelineNamespace::install(PipelineNamespaceId(0));
|
||||||
|
@ -512,6 +522,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
script_receiver: script_receiver,
|
script_receiver: script_receiver,
|
||||||
compositor_receiver: compositor_receiver,
|
compositor_receiver: compositor_receiver,
|
||||||
layout_receiver: layout_receiver,
|
layout_receiver: layout_receiver,
|
||||||
|
network_listener_sender: network_listener_sender,
|
||||||
|
network_listener_receiver: network_listener_receiver,
|
||||||
compositor_proxy: state.compositor_proxy,
|
compositor_proxy: state.compositor_proxy,
|
||||||
debugger_chan: state.debugger_chan,
|
debugger_chan: state.debugger_chan,
|
||||||
devtools_chan: state.devtools_chan,
|
devtools_chan: state.devtools_chan,
|
||||||
|
@ -797,6 +809,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
Script(FromScriptMsg),
|
Script(FromScriptMsg),
|
||||||
Compositor(FromCompositorMsg),
|
Compositor(FromCompositorMsg),
|
||||||
Layout(FromLayoutMsg),
|
Layout(FromLayoutMsg),
|
||||||
|
NetworkListener((PipelineId, FetchResponseMsg)),
|
||||||
FromSWManager(SWManagerMsg),
|
FromSWManager(SWManagerMsg),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -815,6 +828,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
let receiver_from_script = &self.script_receiver;
|
let receiver_from_script = &self.script_receiver;
|
||||||
let receiver_from_compositor = &self.compositor_receiver;
|
let receiver_from_compositor = &self.compositor_receiver;
|
||||||
let receiver_from_layout = &self.layout_receiver;
|
let receiver_from_layout = &self.layout_receiver;
|
||||||
|
let receiver_from_network_listener = &self.network_listener_receiver;
|
||||||
let receiver_from_swmanager = &self.swmanager_receiver;
|
let receiver_from_swmanager = &self.swmanager_receiver;
|
||||||
select! {
|
select! {
|
||||||
msg = receiver_from_script.recv() =>
|
msg = receiver_from_script.recv() =>
|
||||||
|
@ -823,6 +837,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
Ok(Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation"))),
|
Ok(Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation"))),
|
||||||
msg = receiver_from_layout.recv() =>
|
msg = receiver_from_layout.recv() =>
|
||||||
msg.expect("Unexpected layout channel panic in constellation").map(Request::Layout),
|
msg.expect("Unexpected layout channel panic in constellation").map(Request::Layout),
|
||||||
|
msg = receiver_from_network_listener.recv() =>
|
||||||
|
Ok(Request::NetworkListener(
|
||||||
|
msg.expect("Unexpected network listener channel panic in constellation")
|
||||||
|
)),
|
||||||
msg = receiver_from_swmanager.recv() =>
|
msg = receiver_from_swmanager.recv() =>
|
||||||
msg.expect("Unexpected panic channel panic in constellation").map(Request::FromSWManager)
|
msg.expect("Unexpected panic channel panic in constellation").map(Request::FromSWManager)
|
||||||
}
|
}
|
||||||
|
@ -849,12 +867,31 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
Request::Layout(message) => {
|
Request::Layout(message) => {
|
||||||
self.handle_request_from_layout(message);
|
self.handle_request_from_layout(message);
|
||||||
},
|
},
|
||||||
|
Request::NetworkListener(message) => {
|
||||||
|
self.handle_request_from_network_listener(message);
|
||||||
|
},
|
||||||
Request::FromSWManager(message) => {
|
Request::FromSWManager(message) => {
|
||||||
self.handle_request_from_swmanager(message);
|
self.handle_request_from_swmanager(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_request_from_network_listener(&mut self, message: (PipelineId, FetchResponseMsg)) {
|
||||||
|
let (id, message_) = message;
|
||||||
|
let result = match self.pipelines.get(&id) {
|
||||||
|
Some(pipeline) => {
|
||||||
|
let msg = ConstellationControlMsg::NavigationResponse(id, message_);
|
||||||
|
pipeline.event_loop.send(msg)
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
return warn!("Pipeline {:?} got fetch data after closure!", id);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if let Err(e) = result {
|
||||||
|
self.handle_send_error(id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_request_from_swmanager(&mut self, message: SWManagerMsg) {
|
fn handle_request_from_swmanager(&mut self, message: SWManagerMsg) {
|
||||||
match message {
|
match message {
|
||||||
SWManagerMsg::OwnSender(sw_sender) => {
|
SWManagerMsg::OwnSender(sw_sender) => {
|
||||||
|
@ -956,6 +993,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
FromScriptMsg::PipelineExited(pipeline_id) => {
|
FromScriptMsg::PipelineExited(pipeline_id) => {
|
||||||
self.handle_pipeline_exited(pipeline_id);
|
self.handle_pipeline_exited(pipeline_id);
|
||||||
}
|
}
|
||||||
|
FromScriptMsg::InitiateNavigateRequest(req_init, pipeline_id) => {
|
||||||
|
debug!("constellation got initiate navigate request message");
|
||||||
|
self.handle_navigate_request(req_init, pipeline_id);
|
||||||
|
}
|
||||||
FromScriptMsg::ScriptLoadedURLInIFrame(load_info) => {
|
FromScriptMsg::ScriptLoadedURLInIFrame(load_info) => {
|
||||||
debug!("constellation got iframe URL load message {:?} {:?} {:?}",
|
debug!("constellation got iframe URL load message {:?} {:?} {:?}",
|
||||||
load_info.info.parent_pipeline_id,
|
load_info.info.parent_pipeline_id,
|
||||||
|
@ -1484,6 +1525,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_navigate_request(&self,
|
||||||
|
req_init: RequestInit,
|
||||||
|
id: PipelineId) {
|
||||||
|
let listener = NetworkListener::new(
|
||||||
|
req_init,
|
||||||
|
id,
|
||||||
|
self.public_resource_threads.clone(),
|
||||||
|
self.network_listener_sender.clone());
|
||||||
|
|
||||||
|
listener.initiate_fetch();
|
||||||
|
}
|
||||||
|
|
||||||
// The script thread associated with pipeline_id has loaded a URL in an iframe via script. This
|
// The script thread associated with pipeline_id has loaded a URL in an iframe via script. This
|
||||||
// will result in a new pipeline being spawned and a child being added to
|
// will result in a new pipeline being spawned and a child being added to
|
||||||
// the parent pipeline. This message is never the result of a
|
// the parent pipeline. This message is never the result of a
|
||||||
|
|
|
@ -20,6 +20,7 @@ extern crate euclid;
|
||||||
extern crate gaol;
|
extern crate gaol;
|
||||||
extern crate gfx;
|
extern crate gfx;
|
||||||
extern crate gfx_traits;
|
extern crate gfx_traits;
|
||||||
|
extern crate hyper;
|
||||||
extern crate ipc_channel;
|
extern crate ipc_channel;
|
||||||
extern crate itertools;
|
extern crate itertools;
|
||||||
extern crate layout_traits;
|
extern crate layout_traits;
|
||||||
|
@ -45,6 +46,7 @@ extern crate webvr_traits;
|
||||||
mod browsingcontext;
|
mod browsingcontext;
|
||||||
mod constellation;
|
mod constellation;
|
||||||
mod event_loop;
|
mod event_loop;
|
||||||
|
mod network_listener;
|
||||||
mod pipeline;
|
mod pipeline;
|
||||||
#[cfg(not(target_os = "windows"))]
|
#[cfg(not(target_os = "windows"))]
|
||||||
mod sandboxing;
|
mod sandboxing;
|
||||||
|
|
133
components/constellation/network_listener.rs
Normal file
133
components/constellation/network_listener.rs
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! The listener that encapsulates all state for an in-progress document request.
|
||||||
|
//! Any redirects that are encountered are followed. Whenever a non-redirect
|
||||||
|
//! response is received, it is forwarded to the appropriate script thread.
|
||||||
|
|
||||||
|
use hyper::header::Location;
|
||||||
|
use ipc_channel::ipc;
|
||||||
|
use ipc_channel::router::ROUTER;
|
||||||
|
use msg::constellation_msg::PipelineId;
|
||||||
|
use net::http_loader::{set_default_accept, set_default_accept_language};
|
||||||
|
use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseMsg};
|
||||||
|
use net_traits::{IpcSend, NetworkError, ResourceThreads};
|
||||||
|
use net_traits::request::{Destination, RequestInit, Type};
|
||||||
|
use net_traits::response::ResponseInit;
|
||||||
|
use std::sync::mpsc::Sender;
|
||||||
|
|
||||||
|
pub struct NetworkListener {
|
||||||
|
res_init: Option<ResponseInit>,
|
||||||
|
req_init: RequestInit,
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
resource_threads: ResourceThreads,
|
||||||
|
sender: Sender<(PipelineId, FetchResponseMsg)>,
|
||||||
|
should_send: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkListener {
|
||||||
|
pub fn new(req_init: RequestInit,
|
||||||
|
pipeline_id: PipelineId,
|
||||||
|
resource_threads: ResourceThreads,
|
||||||
|
sender: Sender<(PipelineId, FetchResponseMsg)>) -> NetworkListener {
|
||||||
|
NetworkListener {
|
||||||
|
res_init: None,
|
||||||
|
req_init,
|
||||||
|
pipeline_id,
|
||||||
|
resource_threads,
|
||||||
|
sender,
|
||||||
|
should_send: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn initiate_fetch(&self) {
|
||||||
|
let (ipc_sender, ipc_receiver) = ipc::channel().expect("Failed to create IPC channel!");
|
||||||
|
|
||||||
|
let mut listener = NetworkListener {
|
||||||
|
res_init: self.res_init.clone(),
|
||||||
|
req_init: self.req_init.clone(),
|
||||||
|
resource_threads: self.resource_threads.clone(),
|
||||||
|
sender: self.sender.clone(),
|
||||||
|
pipeline_id: self.pipeline_id.clone(),
|
||||||
|
should_send: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
let msg = match self.res_init {
|
||||||
|
Some(ref res_init_) => CoreResourceMsg::FetchRedirect(
|
||||||
|
self.req_init.clone(),
|
||||||
|
res_init_.clone(),
|
||||||
|
ipc_sender),
|
||||||
|
None => {
|
||||||
|
set_default_accept(Type::None, Destination::Document, &mut listener.req_init.headers);
|
||||||
|
set_default_accept_language(&mut listener.req_init.headers);
|
||||||
|
|
||||||
|
CoreResourceMsg::Fetch(
|
||||||
|
listener.req_init.clone(),
|
||||||
|
ipc_sender)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ROUTER.add_route(ipc_receiver.to_opaque(), box move |message| {
|
||||||
|
let msg = message.to();
|
||||||
|
match msg {
|
||||||
|
Ok(FetchResponseMsg::ProcessResponse(res)) => listener.check_redirect(res),
|
||||||
|
Ok(msg_) => listener.send(msg_),
|
||||||
|
Err(e) => warn!("Error while receiving network listener message: {}", e),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Err(e) = self.resource_threads.sender().send(msg) {
|
||||||
|
warn!("Resource thread unavailable ({})", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_redirect(&mut self,
|
||||||
|
message: Result<(FetchMetadata), NetworkError>) {
|
||||||
|
match message {
|
||||||
|
Ok(res_metadata) => {
|
||||||
|
let metadata = match res_metadata {
|
||||||
|
FetchMetadata::Filtered { ref unsafe_, .. } => unsafe_,
|
||||||
|
FetchMetadata::Unfiltered(ref m) => m,
|
||||||
|
};
|
||||||
|
|
||||||
|
match metadata.headers {
|
||||||
|
Some(ref headers) if headers.has::<Location>() => {
|
||||||
|
if self.req_init.url_list.is_empty() {
|
||||||
|
self.req_init.url_list.push(self.req_init.url.clone());
|
||||||
|
}
|
||||||
|
self.req_init.url_list.push(metadata.final_url.clone());
|
||||||
|
|
||||||
|
self.req_init.referrer_url = metadata.referrer.clone();
|
||||||
|
self.req_init.referrer_policy = metadata.referrer_policy;
|
||||||
|
|
||||||
|
self.res_init = Some(ResponseInit {
|
||||||
|
url: metadata.final_url.clone(),
|
||||||
|
headers: headers.clone().into_inner(),
|
||||||
|
referrer: metadata.referrer.clone(),
|
||||||
|
});
|
||||||
|
|
||||||
|
self.initiate_fetch();
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
// Response should be processed by script thread.
|
||||||
|
self.should_send = true;
|
||||||
|
self.send(FetchResponseMsg::ProcessResponse(Ok(res_metadata.clone())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
self.should_send = true;
|
||||||
|
self.send(FetchResponseMsg::ProcessResponse(Err(e)))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send(&mut self, msg: FetchResponseMsg) {
|
||||||
|
if self.should_send {
|
||||||
|
if let Err(e) = self.sender.send((self.pipeline_id, msg)) {
|
||||||
|
warn!("Failed to forward network message to pipeline {}: {:?}", self.pipeline_id, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -674,7 +674,7 @@ pub fn http_fetch(request: &mut Request,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [HTTP redirect fetch](https://fetch.spec.whatwg.org#http-redirect-fetch)
|
/// [HTTP redirect fetch](https://fetch.spec.whatwg.org#http-redirect-fetch)
|
||||||
fn http_redirect_fetch(request: &mut Request,
|
pub fn http_redirect_fetch(request: &mut Request,
|
||||||
cache: &mut CorsCache,
|
cache: &mut CorsCache,
|
||||||
response: Response,
|
response: Response,
|
||||||
cors_flag: bool,
|
cors_flag: bool,
|
||||||
|
@ -749,8 +749,10 @@ fn http_redirect_fetch(request: &mut Request,
|
||||||
// Step 12
|
// Step 12
|
||||||
// TODO implement referrer policy
|
// TODO implement referrer policy
|
||||||
|
|
||||||
|
let recursive_flag = request.redirect_mode != RedirectMode::Manual;
|
||||||
|
|
||||||
// Step 13
|
// Step 13
|
||||||
main_fetch(request, cache, cors_flag, true, target, done_chan, context)
|
main_fetch(request, cache, cors_flag, recursive_flag, target, done_chan, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_immutable_origin_to_hyper_origin(url_origin: &ImmutableOrigin) -> Option<HyperOrigin> {
|
fn try_immutable_origin_to_hyper_origin(url_origin: &ImmutableOrigin) -> Option<HyperOrigin> {
|
||||||
|
@ -1108,6 +1110,7 @@ fn http_network_fetch(request: &Request,
|
||||||
res.response.status_raw().1.as_bytes().to_vec()));
|
res.response.status_raw().1.as_bytes().to_vec()));
|
||||||
response.headers = res.response.headers.clone();
|
response.headers = res.response.headers.clone();
|
||||||
response.referrer = request.referrer.to_url().cloned();
|
response.referrer = request.referrer.to_url().cloned();
|
||||||
|
response.referrer_policy = request.referrer_policy.clone();
|
||||||
|
|
||||||
let res_body = response.body.clone();
|
let res_body = response.body.clone();
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ mod data_loader;
|
||||||
pub mod filemanager_thread;
|
pub mod filemanager_thread;
|
||||||
mod hosts;
|
mod hosts;
|
||||||
pub mod hsts;
|
pub mod hsts;
|
||||||
mod http_loader;
|
pub mod http_loader;
|
||||||
pub mod image_cache;
|
pub mod image_cache;
|
||||||
pub mod mime_classifier;
|
pub mod mime_classifier;
|
||||||
pub mod resource_thread;
|
pub mod resource_thread;
|
||||||
|
|
|
@ -8,10 +8,11 @@ use cookie;
|
||||||
use cookie_rs;
|
use cookie_rs;
|
||||||
use cookie_storage::CookieStorage;
|
use cookie_storage::CookieStorage;
|
||||||
use devtools_traits::DevtoolsControlMsg;
|
use devtools_traits::DevtoolsControlMsg;
|
||||||
|
use fetch::cors_cache::CorsCache;
|
||||||
use fetch::methods::{FetchContext, fetch};
|
use fetch::methods::{FetchContext, fetch};
|
||||||
use filemanager_thread::{FileManager, TFDProvider};
|
use filemanager_thread::{FileManager, TFDProvider};
|
||||||
use hsts::HstsList;
|
use hsts::HstsList;
|
||||||
use http_loader::HttpState;
|
use http_loader::{HttpState, http_redirect_fetch};
|
||||||
use hyper_serde::Serde;
|
use hyper_serde::Serde;
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcReceiverSet, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcReceiverSet, IpcSender};
|
||||||
use net_traits::{CookieSource, CoreResourceThread};
|
use net_traits::{CookieSource, CoreResourceThread};
|
||||||
|
@ -19,6 +20,7 @@ use net_traits::{CoreResourceMsg, FetchResponseMsg};
|
||||||
use net_traits::{CustomResponseMediator, ResourceId};
|
use net_traits::{CustomResponseMediator, ResourceId};
|
||||||
use net_traits::{ResourceThreads, WebSocketCommunicate, WebSocketConnectData};
|
use net_traits::{ResourceThreads, WebSocketCommunicate, WebSocketConnectData};
|
||||||
use net_traits::request::{Request, RequestInit};
|
use net_traits::request::{Request, RequestInit};
|
||||||
|
use net_traits::response::{Response, ResponseInit};
|
||||||
use net_traits::storage_thread::StorageThreadMsg;
|
use net_traits::storage_thread::StorageThreadMsg;
|
||||||
use profile_traits::time::ProfilerChan;
|
use profile_traits::time::ProfilerChan;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
@ -153,8 +155,10 @@ impl ResourceChannelManager {
|
||||||
msg: CoreResourceMsg,
|
msg: CoreResourceMsg,
|
||||||
http_state: &Arc<HttpState>) -> bool {
|
http_state: &Arc<HttpState>) -> bool {
|
||||||
match msg {
|
match msg {
|
||||||
CoreResourceMsg::Fetch(init, sender) =>
|
CoreResourceMsg::Fetch(req_init, sender) =>
|
||||||
self.resource_manager.fetch(init, sender, http_state),
|
self.resource_manager.fetch(req_init, None, sender, http_state),
|
||||||
|
CoreResourceMsg::FetchRedirect(req_init, res_init, sender) =>
|
||||||
|
self.resource_manager.fetch(req_init, Some(res_init), sender, http_state),
|
||||||
CoreResourceMsg::WebsocketConnect(connect, connect_data) =>
|
CoreResourceMsg::WebsocketConnect(connect, connect_data) =>
|
||||||
self.resource_manager.websocket_connect(connect, connect_data, http_state),
|
self.resource_manager.websocket_connect(connect, connect_data, http_state),
|
||||||
CoreResourceMsg::SetCookieForUrl(request, cookie, source) =>
|
CoreResourceMsg::SetCookieForUrl(request, cookie, source) =>
|
||||||
|
@ -318,7 +322,8 @@ impl CoreResourceManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fetch(&self,
|
fn fetch(&self,
|
||||||
init: RequestInit,
|
req_init: RequestInit,
|
||||||
|
res_init_: Option<ResponseInit>,
|
||||||
mut sender: IpcSender<FetchResponseMsg>,
|
mut sender: IpcSender<FetchResponseMsg>,
|
||||||
http_state: &Arc<HttpState>) {
|
http_state: &Arc<HttpState>) {
|
||||||
let http_state = http_state.clone();
|
let http_state = http_state.clone();
|
||||||
|
@ -326,8 +331,8 @@ impl CoreResourceManager {
|
||||||
let dc = self.devtools_chan.clone();
|
let dc = self.devtools_chan.clone();
|
||||||
let filemanager = self.filemanager.clone();
|
let filemanager = self.filemanager.clone();
|
||||||
|
|
||||||
thread::Builder::new().name(format!("fetch thread for {}", init.url)).spawn(move || {
|
thread::Builder::new().name(format!("fetch thread for {}", req_init.url)).spawn(move || {
|
||||||
let mut request = Request::from_init(init);
|
let mut request = Request::from_init(req_init);
|
||||||
// XXXManishearth: Check origin against pipeline id (also ensure that the mode is allowed)
|
// XXXManishearth: Check origin against pipeline id (also ensure that the mode is allowed)
|
||||||
// todo load context / mimesniff in fetch
|
// todo load context / mimesniff in fetch
|
||||||
// todo referrer policy?
|
// todo referrer policy?
|
||||||
|
@ -338,7 +343,20 @@ impl CoreResourceManager {
|
||||||
devtools_chan: dc,
|
devtools_chan: dc,
|
||||||
filemanager: filemanager,
|
filemanager: filemanager,
|
||||||
};
|
};
|
||||||
fetch(&mut request, &mut sender, &context);
|
|
||||||
|
match res_init_ {
|
||||||
|
Some(res_init) => {
|
||||||
|
let response = Response::from_init(res_init);
|
||||||
|
http_redirect_fetch(&mut request,
|
||||||
|
&mut CorsCache::new(),
|
||||||
|
response,
|
||||||
|
true,
|
||||||
|
&mut sender,
|
||||||
|
&mut None,
|
||||||
|
&context);
|
||||||
|
},
|
||||||
|
None => fetch(&mut request, &mut sender, &context),
|
||||||
|
};
|
||||||
}).expect("Thread spawning failed");
|
}).expect("Thread spawning failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -42,7 +42,7 @@ use ipc_channel::Error as IpcError;
|
||||||
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
|
||||||
use ipc_channel::router::ROUTER;
|
use ipc_channel::router::ROUTER;
|
||||||
use request::{Request, RequestInit};
|
use request::{Request, RequestInit};
|
||||||
use response::{HttpsState, Response};
|
use response::{HttpsState, Response, ResponseInit};
|
||||||
use servo_url::ServoUrl;
|
use servo_url::ServoUrl;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use storage_thread::StorageThreadMsg;
|
use storage_thread::StorageThreadMsg;
|
||||||
|
@ -369,6 +369,8 @@ pub struct WebSocketConnectData {
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum CoreResourceMsg {
|
pub enum CoreResourceMsg {
|
||||||
Fetch(RequestInit, IpcSender<FetchResponseMsg>),
|
Fetch(RequestInit, IpcSender<FetchResponseMsg>),
|
||||||
|
/// Initiate a fetch in response to processing a redirection
|
||||||
|
FetchRedirect(RequestInit, ResponseInit, IpcSender<FetchResponseMsg>),
|
||||||
/// Try to make a websocket connection to a URL.
|
/// Try to make a websocket connection to a URL.
|
||||||
WebsocketConnect(WebSocketCommunicate, WebSocketConnectData),
|
WebsocketConnect(WebSocketCommunicate, WebSocketConnectData),
|
||||||
/// Store a cookie for a given originating URL
|
/// Store a cookie for a given originating URL
|
||||||
|
@ -435,6 +437,9 @@ pub struct Metadata {
|
||||||
|
|
||||||
/// Referrer Url
|
/// Referrer Url
|
||||||
pub referrer: Option<ServoUrl>,
|
pub referrer: Option<ServoUrl>,
|
||||||
|
|
||||||
|
/// Referrer Policy of the Request used to obtain Response
|
||||||
|
pub referrer_policy: Option<ReferrerPolicy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Metadata {
|
impl Metadata {
|
||||||
|
@ -449,6 +454,7 @@ impl Metadata {
|
||||||
status: Some((200, b"OK".to_vec())),
|
status: Some((200, b"OK".to_vec())),
|
||||||
https_state: HttpsState::None,
|
https_state: HttpsState::None,
|
||||||
referrer: None,
|
referrer: None,
|
||||||
|
referrer_policy: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub enum Origin {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
|
/// A [referer](https://fetch.spec.whatwg.org/#concept-request-referrer)
|
||||||
#[derive(Clone, PartialEq, HeapSizeOf)]
|
#[derive(Clone, PartialEq, Serialize, Deserialize, HeapSizeOf)]
|
||||||
pub enum Referrer {
|
pub enum Referrer {
|
||||||
NoReferrer,
|
NoReferrer,
|
||||||
/// Default referrer if nothing is specified
|
/// Default referrer if nothing is specified
|
||||||
|
@ -158,6 +158,8 @@ pub struct RequestInit {
|
||||||
pub pipeline_id: Option<PipelineId>,
|
pub pipeline_id: Option<PipelineId>,
|
||||||
pub redirect_mode: RedirectMode,
|
pub redirect_mode: RedirectMode,
|
||||||
pub integrity_metadata: String,
|
pub integrity_metadata: String,
|
||||||
|
// to keep track of redirects
|
||||||
|
pub url_list: Vec<ServoUrl>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for RequestInit {
|
impl Default for RequestInit {
|
||||||
|
@ -182,6 +184,7 @@ impl Default for RequestInit {
|
||||||
pipeline_id: None,
|
pipeline_id: None,
|
||||||
redirect_mode: RedirectMode::Follow,
|
redirect_mode: RedirectMode::Follow,
|
||||||
integrity_metadata: "".to_owned(),
|
integrity_metadata: "".to_owned(),
|
||||||
|
url_list: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,7 +293,7 @@ impl Request {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_init(init: RequestInit) -> Request {
|
pub fn from_init(init: RequestInit) -> Request {
|
||||||
let mut req = Request::new(init.url,
|
let mut req = Request::new(init.url.clone(),
|
||||||
Some(Origin::Origin(init.origin.origin())),
|
Some(Origin::Origin(init.origin.origin())),
|
||||||
false,
|
false,
|
||||||
init.pipeline_id);
|
init.pipeline_id);
|
||||||
|
@ -314,6 +317,12 @@ impl Request {
|
||||||
req.referrer_policy = init.referrer_policy;
|
req.referrer_policy = init.referrer_policy;
|
||||||
req.pipeline_id = init.pipeline_id;
|
req.pipeline_id = init.pipeline_id;
|
||||||
req.redirect_mode = init.redirect_mode;
|
req.redirect_mode = init.redirect_mode;
|
||||||
|
let mut url_list = init.url_list;
|
||||||
|
if url_list.is_empty() {
|
||||||
|
url_list.push(init.url);
|
||||||
|
}
|
||||||
|
req.redirect_count = url_list.len() as u32 - 1;
|
||||||
|
req.url_list = url_list;
|
||||||
req.integrity_metadata = init.integrity_metadata;
|
req.integrity_metadata = init.integrity_metadata;
|
||||||
req
|
req
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
//! The [Response](https://fetch.spec.whatwg.org/#responses) object
|
//! The [Response](https://fetch.spec.whatwg.org/#responses) object
|
||||||
//! resulting from a [fetch operation](https://fetch.spec.whatwg.org/#concept-fetch)
|
//! resulting from a [fetch operation](https://fetch.spec.whatwg.org/#concept-fetch)
|
||||||
use {FetchMetadata, FilteredMetadata, Metadata, NetworkError};
|
use {FetchMetadata, FilteredMetadata, Metadata, NetworkError, ReferrerPolicy};
|
||||||
use hyper::header::{AccessControlExposeHeaders, ContentType, Headers};
|
use hyper::header::{AccessControlExposeHeaders, ContentType, Headers};
|
||||||
use hyper::status::StatusCode;
|
use hyper::status::StatusCode;
|
||||||
use hyper_serde::Serde;
|
use hyper_serde::Serde;
|
||||||
|
@ -74,6 +74,16 @@ pub enum ResponseMsg {
|
||||||
Errored,
|
Errored,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone, HeapSizeOf)]
|
||||||
|
pub struct ResponseInit {
|
||||||
|
pub url: ServoUrl,
|
||||||
|
#[serde(deserialize_with = "::hyper_serde::deserialize",
|
||||||
|
serialize_with = "::hyper_serde::serialize")]
|
||||||
|
#[ignore_heap_size_of = "Defined in hyper"]
|
||||||
|
pub headers: Headers,
|
||||||
|
pub referrer: Option<ServoUrl>,
|
||||||
|
}
|
||||||
|
|
||||||
/// A [Response](https://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec
|
/// A [Response](https://fetch.spec.whatwg.org/#concept-response) as defined by the Fetch spec
|
||||||
#[derive(Debug, Clone, HeapSizeOf)]
|
#[derive(Debug, Clone, HeapSizeOf)]
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
|
@ -97,6 +107,7 @@ pub struct Response {
|
||||||
pub internal_response: Option<Box<Response>>,
|
pub internal_response: Option<Box<Response>>,
|
||||||
/// whether or not to try to return the internal_response when asked for actual_response
|
/// whether or not to try to return the internal_response when asked for actual_response
|
||||||
pub return_internal: bool,
|
pub return_internal: bool,
|
||||||
|
pub referrer_policy: Option<ReferrerPolicy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
|
@ -113,11 +124,19 @@ impl Response {
|
||||||
cache_state: CacheState::None,
|
cache_state: CacheState::None,
|
||||||
https_state: HttpsState::None,
|
https_state: HttpsState::None,
|
||||||
referrer: None,
|
referrer: None,
|
||||||
|
referrer_policy: None,
|
||||||
internal_response: None,
|
internal_response: None,
|
||||||
return_internal: true,
|
return_internal: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_init(init: ResponseInit) -> Response {
|
||||||
|
let mut res = Response::new(init.url);
|
||||||
|
res.headers = init.headers;
|
||||||
|
res.referrer = init.referrer;
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
pub fn network_error(e: NetworkError) -> Response {
|
pub fn network_error(e: NetworkError) -> Response {
|
||||||
Response {
|
Response {
|
||||||
response_type: ResponseType::Error(e),
|
response_type: ResponseType::Error(e),
|
||||||
|
@ -131,6 +150,7 @@ impl Response {
|
||||||
cache_state: CacheState::None,
|
cache_state: CacheState::None,
|
||||||
https_state: HttpsState::None,
|
https_state: HttpsState::None,
|
||||||
referrer: None,
|
referrer: None,
|
||||||
|
referrer_policy: None,
|
||||||
internal_response: None,
|
internal_response: None,
|
||||||
return_internal: true,
|
return_internal: true,
|
||||||
}
|
}
|
||||||
|
@ -263,6 +283,7 @@ impl Response {
|
||||||
metadata.status = response.raw_status.clone();
|
metadata.status = response.raw_status.clone();
|
||||||
metadata.https_state = response.https_state;
|
metadata.https_state = response.https_state;
|
||||||
metadata.referrer = response.referrer.clone();
|
metadata.referrer = response.referrer.clone();
|
||||||
|
metadata.referrer_policy = response.referrer_policy.clone();
|
||||||
metadata
|
metadata
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -527,6 +527,7 @@ impl Tokenizer {
|
||||||
|
|
||||||
/// The context required for asynchronously fetching a document
|
/// The context required for asynchronously fetching a document
|
||||||
/// and parsing it progressively.
|
/// and parsing it progressively.
|
||||||
|
#[derive(JSTraceable)]
|
||||||
pub struct ParserContext {
|
pub struct ParserContext {
|
||||||
/// The parser that initiated the request.
|
/// The parser that initiated the request.
|
||||||
parser: Option<Trusted<ServoParser>>,
|
parser: Option<Trusted<ServoParser>>,
|
||||||
|
|
|
@ -60,7 +60,7 @@ use dom::worklet::WorkletThreadPool;
|
||||||
use dom::workletglobalscope::WorkletGlobalScopeInit;
|
use dom::workletglobalscope::WorkletGlobalScopeInit;
|
||||||
use euclid::Rect;
|
use euclid::Rect;
|
||||||
use euclid::point::Point2D;
|
use euclid::point::Point2D;
|
||||||
use hyper::header::{ContentType, HttpDate, LastModified, Headers};
|
use hyper::header::{ContentType, HttpDate, Headers, LastModified};
|
||||||
use hyper::header::ReferrerPolicy as ReferrerPolicyHeader;
|
use hyper::header::ReferrerPolicy as ReferrerPolicyHeader;
|
||||||
use hyper::mime::{Mime, SubLevel, TopLevel};
|
use hyper::mime::{Mime, SubLevel, TopLevel};
|
||||||
use hyper_serde::Serde;
|
use hyper_serde::Serde;
|
||||||
|
@ -74,12 +74,11 @@ use js::rust::Runtime;
|
||||||
use mem::heap_size_of_self_and_children;
|
use mem::heap_size_of_self_and_children;
|
||||||
use microtask::{MicrotaskQueue, Microtask};
|
use microtask::{MicrotaskQueue, Microtask};
|
||||||
use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, PipelineNamespace, TopLevelBrowsingContextId};
|
use msg::constellation_msg::{BrowsingContextId, FrameType, PipelineId, PipelineNamespace, TopLevelBrowsingContextId};
|
||||||
use net_traits::{CoreResourceMsg, FetchMetadata, FetchResponseListener};
|
use net_traits::{FetchMetadata, FetchResponseListener, FetchResponseMsg};
|
||||||
use net_traits::{IpcSend, Metadata, ReferrerPolicy, ResourceThreads};
|
use net_traits::{Metadata, NetworkError, ReferrerPolicy, ResourceThreads};
|
||||||
use net_traits::image_cache::{ImageCache, PendingImageResponse};
|
use net_traits::image_cache::{ImageCache, PendingImageResponse};
|
||||||
use net_traits::request::{CredentialsMode, Destination, RequestInit};
|
use net_traits::request::{CredentialsMode, Destination, RedirectMode, RequestInit};
|
||||||
use net_traits::storage_thread::StorageType;
|
use net_traits::storage_thread::StorageType;
|
||||||
use network_listener::NetworkListener;
|
|
||||||
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
use profile_traits::mem::{self, OpaqueSender, Report, ReportKind, ReportsChan};
|
||||||
use profile_traits::time::{self, ProfilerCategory, profile};
|
use profile_traits::time::{self, ProfilerCategory, profile};
|
||||||
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
|
use script_layout_interface::message::{self, NewLayoutThreadInfo, ReflowQueryType};
|
||||||
|
@ -105,7 +104,7 @@ use std::option::Option;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::result::Result;
|
use std::result::Result;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::Arc;
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::sync::atomic::{AtomicBool, Ordering};
|
||||||
use std::sync::mpsc::{Receiver, Select, Sender, channel};
|
use std::sync::mpsc::{Receiver, Select, Sender, channel};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
@ -411,6 +410,8 @@ pub struct ScriptThread {
|
||||||
window_proxies: DOMRefCell<HashMap<BrowsingContextId, JS<WindowProxy>>>,
|
window_proxies: DOMRefCell<HashMap<BrowsingContextId, JS<WindowProxy>>>,
|
||||||
/// A list of data pertaining to loads that have not yet received a network response
|
/// A list of data pertaining to loads that have not yet received a network response
|
||||||
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
|
incomplete_loads: DOMRefCell<Vec<InProgressLoad>>,
|
||||||
|
/// A vector containing parser contexts which have not yet been fully processed
|
||||||
|
incomplete_parser_contexts: DOMRefCell<Vec<(PipelineId, ParserContext)>>,
|
||||||
/// A map to store service worker registrations for a given origin
|
/// A map to store service worker registrations for a given origin
|
||||||
registration_map: DOMRefCell<HashMap<ServoUrl, JS<ServiceWorkerRegistration>>>,
|
registration_map: DOMRefCell<HashMap<ServoUrl, JS<ServiceWorkerRegistration>>>,
|
||||||
/// A job queue for Service Workers keyed by their scope url
|
/// A job queue for Service Workers keyed by their scope url
|
||||||
|
@ -574,7 +575,7 @@ impl ScriptThreadFactory for ScriptThread {
|
||||||
let origin = MutableOrigin::new(load_data.url.origin());
|
let origin = MutableOrigin::new(load_data.url.origin());
|
||||||
let new_load = InProgressLoad::new(id, browsing_context_id, top_level_browsing_context_id, parent_info,
|
let new_load = InProgressLoad::new(id, browsing_context_id, top_level_browsing_context_id, parent_info,
|
||||||
layout_chan, window_size, load_data.url.clone(), origin);
|
layout_chan, window_size, load_data.url.clone(), origin);
|
||||||
script_thread.start_page_load(new_load, load_data);
|
script_thread.pre_page_load(new_load, load_data);
|
||||||
|
|
||||||
let reporter_name = format!("script-reporter-{}", id);
|
let reporter_name = format!("script-reporter-{}", id);
|
||||||
mem_profiler_chan.run_with_memory_reporting(|| {
|
mem_profiler_chan.run_with_memory_reporting(|| {
|
||||||
|
@ -758,6 +759,7 @@ impl ScriptThread {
|
||||||
documents: DOMRefCell::new(Documents::new()),
|
documents: DOMRefCell::new(Documents::new()),
|
||||||
window_proxies: DOMRefCell::new(HashMap::new()),
|
window_proxies: DOMRefCell::new(HashMap::new()),
|
||||||
incomplete_loads: DOMRefCell::new(vec!()),
|
incomplete_loads: DOMRefCell::new(vec!()),
|
||||||
|
incomplete_parser_contexts: DOMRefCell::new(vec!()),
|
||||||
registration_map: DOMRefCell::new(HashMap::new()),
|
registration_map: DOMRefCell::new(HashMap::new()),
|
||||||
job_queue_map: Rc::new(JobQueue::new()),
|
job_queue_map: Rc::new(JobQueue::new()),
|
||||||
|
|
||||||
|
@ -1105,6 +1107,14 @@ impl ScriptThread {
|
||||||
|
|
||||||
fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg) {
|
fn handle_msg_from_constellation(&self, msg: ConstellationControlMsg) {
|
||||||
match msg {
|
match msg {
|
||||||
|
ConstellationControlMsg::NavigationResponse(id, fetch_data) => {
|
||||||
|
match fetch_data {
|
||||||
|
FetchResponseMsg::ProcessResponse(metadata) => self.handle_fetch_metadata(id, metadata),
|
||||||
|
FetchResponseMsg::ProcessResponseChunk(chunk) => self.handle_fetch_chunk(id, chunk),
|
||||||
|
FetchResponseMsg::ProcessResponseEOF(eof) => self.handle_fetch_eof(id, eof),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
},
|
||||||
ConstellationControlMsg::Navigate(parent_pipeline_id, browsing_context_id, load_data, replace) =>
|
ConstellationControlMsg::Navigate(parent_pipeline_id, browsing_context_id, load_data, replace) =>
|
||||||
self.handle_navigate(parent_pipeline_id, Some(browsing_context_id), load_data, replace),
|
self.handle_navigate(parent_pipeline_id, Some(browsing_context_id), load_data, replace),
|
||||||
ConstellationControlMsg::SendEvent(id, event) =>
|
ConstellationControlMsg::SendEvent(id, event) =>
|
||||||
|
@ -1396,7 +1406,7 @@ impl ScriptThread {
|
||||||
if load_data.url.as_str() == "about:blank" {
|
if load_data.url.as_str() == "about:blank" {
|
||||||
self.start_page_load_about_blank(new_load);
|
self.start_page_load_about_blank(new_load);
|
||||||
} else {
|
} else {
|
||||||
self.start_page_load(new_load, load_data);
|
self.pre_page_load(new_load, load_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2225,45 +2235,67 @@ impl ScriptThread {
|
||||||
window.evaluate_media_queries_and_report_changes();
|
window.evaluate_media_queries_and_report_changes();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initiate a non-blocking fetch for a specified resource. Stores the InProgressLoad
|
/// Instructs the constellation to fetch the document that will be loaded. Stores the InProgressLoad
|
||||||
/// argument until a notification is received that the fetch is complete.
|
/// argument until a notification is received that the fetch is complete.
|
||||||
fn start_page_load(&self, incomplete: InProgressLoad, mut load_data: LoadData) {
|
fn pre_page_load(&self, incomplete: InProgressLoad, load_data: LoadData) {
|
||||||
let id = incomplete.pipeline_id.clone();
|
let id = incomplete.pipeline_id.clone();
|
||||||
|
let mut req_init = RequestInit {
|
||||||
let context = Arc::new(Mutex::new(ParserContext::new(id, load_data.url.clone())));
|
|
||||||
let (action_sender, action_receiver) = ipc::channel().unwrap();
|
|
||||||
let listener = NetworkListener {
|
|
||||||
context: context,
|
|
||||||
task_source: self.networking_task_source.clone(),
|
|
||||||
wrapper: None,
|
|
||||||
};
|
|
||||||
ROUTER.add_route(action_receiver.to_opaque(), box move |message| {
|
|
||||||
listener.notify_fetch(message.to().unwrap());
|
|
||||||
});
|
|
||||||
|
|
||||||
if load_data.url.scheme() == "javascript" {
|
|
||||||
load_data.url = ServoUrl::parse("about:blank").unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
let request = RequestInit {
|
|
||||||
url: load_data.url.clone(),
|
url: load_data.url.clone(),
|
||||||
method: load_data.method,
|
method: load_data.method,
|
||||||
destination: Destination::Document,
|
destination: Destination::Document,
|
||||||
credentials_mode: CredentialsMode::Include,
|
credentials_mode: CredentialsMode::Include,
|
||||||
use_url_credentials: true,
|
use_url_credentials: true,
|
||||||
origin: load_data.url,
|
origin: load_data.url.clone(),
|
||||||
pipeline_id: Some(id),
|
pipeline_id: Some(id),
|
||||||
referrer_url: load_data.referrer_url,
|
referrer_url: load_data.referrer_url,
|
||||||
referrer_policy: load_data.referrer_policy,
|
referrer_policy: load_data.referrer_policy,
|
||||||
headers: load_data.headers,
|
headers: load_data.headers,
|
||||||
body: load_data.data,
|
body: load_data.data,
|
||||||
|
redirect_mode: RedirectMode::Manual,
|
||||||
.. RequestInit::default()
|
.. RequestInit::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.resource_threads.send(CoreResourceMsg::Fetch(request, action_sender)).unwrap();
|
if req_init.url.scheme() == "javascript" {
|
||||||
|
req_init.url = ServoUrl::parse("about:blank").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let context = ParserContext::new(id, load_data.url);
|
||||||
|
self.incomplete_parser_contexts.borrow_mut().push((id, context));
|
||||||
|
|
||||||
|
self.constellation_chan.send(ConstellationMsg::InitiateNavigateRequest(req_init, id)).unwrap();
|
||||||
self.incomplete_loads.borrow_mut().push(incomplete);
|
self.incomplete_loads.borrow_mut().push(incomplete);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_fetch_metadata(&self, id: PipelineId, fetch_metadata: Result<FetchMetadata, NetworkError>) {
|
||||||
|
match fetch_metadata {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(ref e) => warn!("Network error: {:?}", e),
|
||||||
|
};
|
||||||
|
let mut incomplete_parser_contexts = self.incomplete_parser_contexts.borrow_mut();
|
||||||
|
let parser = incomplete_parser_contexts.iter_mut().find(|&&mut (pipeline_id, _)| pipeline_id == id);
|
||||||
|
if let Some(&mut (_, ref mut ctxt)) = parser {
|
||||||
|
ctxt.process_response(fetch_metadata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_fetch_chunk(&self, id: PipelineId, chunk: Vec<u8>) {
|
||||||
|
let mut incomplete_parser_contexts = self.incomplete_parser_contexts.borrow_mut();
|
||||||
|
let parser = incomplete_parser_contexts.iter_mut().find(|&&mut (pipeline_id, _)| pipeline_id == id);
|
||||||
|
if let Some(&mut (_, ref mut ctxt)) = parser {
|
||||||
|
ctxt.process_response_chunk(chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn handle_fetch_eof(&self, id: PipelineId, eof: Result<(), NetworkError>) {
|
||||||
|
let idx = self.incomplete_parser_contexts.borrow().iter().position(|&(pipeline_id, _)| {
|
||||||
|
pipeline_id == id
|
||||||
|
});
|
||||||
|
if let Some(idx) = idx {
|
||||||
|
let (_, mut ctxt) = self.incomplete_parser_contexts.borrow_mut().remove(idx);
|
||||||
|
ctxt.process_response_eof(eof);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Synchronously fetch `about:blank`. Stores the `InProgressLoad`
|
/// Synchronously fetch `about:blank`. Stores the `InProgressLoad`
|
||||||
/// argument until a notification is received that the fetch is complete.
|
/// argument until a notification is received that the fetch is complete.
|
||||||
fn start_page_load_about_blank(&self, incomplete: InProgressLoad) {
|
fn start_page_load_about_blank(&self, incomplete: InProgressLoad) {
|
||||||
|
|
|
@ -55,7 +55,7 @@ use ipc_channel::ipc::{IpcReceiver, IpcSender};
|
||||||
use libc::c_void;
|
use libc::c_void;
|
||||||
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, Key, KeyModifiers, KeyState};
|
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, Key, KeyModifiers, KeyState};
|
||||||
use msg::constellation_msg::{PipelineId, PipelineNamespaceId, TraversalDirection};
|
use msg::constellation_msg::{PipelineId, PipelineNamespaceId, TraversalDirection};
|
||||||
use net_traits::{ReferrerPolicy, ResourceThreads};
|
use net_traits::{FetchResponseMsg, ReferrerPolicy, ResourceThreads};
|
||||||
use net_traits::image::base::Image;
|
use net_traits::image::base::Image;
|
||||||
use net_traits::image_cache::ImageCache;
|
use net_traits::image_cache::ImageCache;
|
||||||
use net_traits::response::HttpsState;
|
use net_traits::response::HttpsState;
|
||||||
|
@ -232,6 +232,9 @@ pub enum UpdatePipelineIdReason {
|
||||||
/// Messages sent from the constellation or layout to the script thread.
|
/// Messages sent from the constellation or layout to the script thread.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum ConstellationControlMsg {
|
pub enum ConstellationControlMsg {
|
||||||
|
/// Sends the final response to script thread for fetching after all redirections
|
||||||
|
/// have been resolved
|
||||||
|
NavigationResponse(PipelineId, FetchResponseMsg),
|
||||||
/// Gives a channel and ID to a layout thread, as well as the ID of that layout's parent
|
/// Gives a channel and ID to a layout thread, as well as the ID of that layout's parent
|
||||||
AttachLayout(NewLayoutInfo),
|
AttachLayout(NewLayoutInfo),
|
||||||
/// Window resized. Sends a DOM event eventually, but first we combine events.
|
/// Window resized. Sends a DOM event eventually, but first we combine events.
|
||||||
|
@ -304,6 +307,7 @@ impl fmt::Debug for ConstellationControlMsg {
|
||||||
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||||
use self::ConstellationControlMsg::*;
|
use self::ConstellationControlMsg::*;
|
||||||
let variant = match *self {
|
let variant = match *self {
|
||||||
|
NavigationResponse(..) => "NavigationResponse",
|
||||||
AttachLayout(..) => "AttachLayout",
|
AttachLayout(..) => "AttachLayout",
|
||||||
Resize(..) => "Resize",
|
Resize(..) => "Resize",
|
||||||
ResizeInactive(..) => "ResizeInactive",
|
ResizeInactive(..) => "ResizeInactive",
|
||||||
|
|
|
@ -20,6 +20,7 @@ use ipc_channel::ipc::IpcSender;
|
||||||
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId, TraversalDirection};
|
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId, TraversalDirection};
|
||||||
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
|
||||||
use net_traits::CoreResourceMsg;
|
use net_traits::CoreResourceMsg;
|
||||||
|
use net_traits::request::RequestInit;
|
||||||
use net_traits::storage_thread::StorageType;
|
use net_traits::storage_thread::StorageType;
|
||||||
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
use offscreen_gl_context::{GLContextAttributes, GLLimits};
|
||||||
use servo_url::ImmutableOrigin;
|
use servo_url::ImmutableOrigin;
|
||||||
|
@ -67,6 +68,9 @@ pub enum LogEntry {
|
||||||
/// Messages from the script to the constellation.
|
/// Messages from the script to the constellation.
|
||||||
#[derive(Deserialize, Serialize)]
|
#[derive(Deserialize, Serialize)]
|
||||||
pub enum ScriptMsg {
|
pub enum ScriptMsg {
|
||||||
|
/// Requests are sent to constellation and fetches are checked manually
|
||||||
|
/// for cross-origin loads
|
||||||
|
InitiateNavigateRequest(RequestInit, PipelineId),
|
||||||
/// Broadcast a storage event to every same-origin pipeline.
|
/// Broadcast a storage event to every same-origin pipeline.
|
||||||
/// The strings are key, old value and new value.
|
/// The strings are key, old value and new value.
|
||||||
BroadcastStorageEvent(PipelineId, StorageType, ServoUrl, Option<String>, Option<String>, Option<String>),
|
BroadcastStorageEvent(PipelineId, StorageType, ServoUrl, Option<String>, Option<String>, Option<String>),
|
||||||
|
|
|
@ -13352,6 +13352,12 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"mozilla/multiple_redirects.html": [
|
||||||
|
[
|
||||||
|
"/_mozilla/mozilla/multiple_redirects.html",
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
],
|
||||||
"mozilla/navigator.html": [
|
"mozilla/navigator.html": [
|
||||||
[
|
[
|
||||||
"/_mozilla/mozilla/navigator.html",
|
"/_mozilla/mozilla/navigator.html",
|
||||||
|
@ -26021,6 +26027,10 @@
|
||||||
"f8f9adebe09f9473a52e5ec4f075540b10b32d7e",
|
"f8f9adebe09f9473a52e5ec4f075540b10b32d7e",
|
||||||
"testharness"
|
"testharness"
|
||||||
],
|
],
|
||||||
|
"mozilla/multiple_redirects.html": [
|
||||||
|
"db0ffd3db5b23204b91f332915d938cfc85ec46c",
|
||||||
|
"testharness"
|
||||||
|
],
|
||||||
"mozilla/navigator.html": [
|
"mozilla/navigator.html": [
|
||||||
"939f453fecfb28a36cb93057382b56439b00b136",
|
"939f453fecfb28a36cb93057382b56439b00b136",
|
||||||
"testharness"
|
"testharness"
|
||||||
|
|
26
tests/wpt/mozilla/tests/mozilla/multiple_redirects.html
Normal file
26
tests/wpt/mozilla/tests/mozilla/multiple_redirects.html
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Multiple redirects</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe src=""></iframe>
|
||||||
|
<script>
|
||||||
|
async_test(function(t) {
|
||||||
|
var iframe = document.getElementsByTagName("iframe")[0];
|
||||||
|
var base_url = "/common/redirect.py?location=/common/dummy.xhtml";
|
||||||
|
var second = "/common/redirect.py?location=" + base_url;
|
||||||
|
var third = "/common/redirect.py?location=" + second;
|
||||||
|
iframe.src = third;
|
||||||
|
iframe.onload = t.step_func(function() {
|
||||||
|
if(iframe.contentWindow.location.href === new URL('/common/dummy.xhtml', location.href).href) {
|
||||||
|
this.done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue