Skip to content

Commit

Permalink
Redirect document loads manually
Browse files Browse the repository at this point in the history
  • Loading branch information
nikhilshagri committed May 31, 2017
1 parent 779edd7 commit 541baaf
Show file tree
Hide file tree
Showing 17 changed files with 376 additions and 52 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions components/constellation/Cargo.toml
Expand Up @@ -20,6 +20,7 @@ devtools_traits = {path = "../devtools_traits"}
euclid = "0.11"
gfx = {path = "../gfx"}
gfx_traits = {path = "../gfx_traits"}
hyper = "0.10"
ipc-channel = "0.7"
itertools = "0.5"
layout_traits = {path = "../layout_traits"}
Expand Down
55 changes: 54 additions & 1 deletion components/constellation/constellation.rs
Expand Up @@ -90,9 +90,11 @@ use log::{Log, LogLevel, LogLevelFilter, LogMetadata, LogRecord};
use msg::constellation_msg::{BrowsingContextId, TopLevelBrowsingContextId, FrameType, PipelineId};
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
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::request::RequestInit;
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
use network_listener::NetworkListener;
use offscreen_gl_context::{GLContextAttributes, GLLimits};
use pipeline::{InitialPipelineState, Pipeline};
use profile_traits::mem;
Expand Down Expand Up @@ -158,6 +160,12 @@ pub struct Constellation<Message, LTF, STF> {
/// This is the constellation's view of `layout_sender`.
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.
compositor_receiver: Receiver<FromCompositorMsg>,

Expand Down Expand Up @@ -498,6 +506,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
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 (network_listener_sender, network_listener_receiver) = channel();

let swmanager_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(swmanager_receiver);

PipelineNamespace::install(PipelineNamespaceId(0));
Expand All @@ -508,6 +518,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
script_receiver: script_receiver,
compositor_receiver: compositor_receiver,
layout_receiver: layout_receiver,
network_listener_sender: network_listener_sender,
network_listener_receiver: network_listener_receiver,
compositor_proxy: state.compositor_proxy,
debugger_chan: state.debugger_chan,
devtools_chan: state.devtools_chan,
Expand Down Expand Up @@ -782,6 +794,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Script(FromScriptMsg),
Compositor(FromCompositorMsg),
Layout(FromLayoutMsg),
NetworkListener((PipelineId, FetchResponseMsg)),
FromSWManager(SWManagerMsg),
}

Expand All @@ -800,6 +813,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let receiver_from_script = &self.script_receiver;
let receiver_from_compositor = &self.compositor_receiver;
let receiver_from_layout = &self.layout_receiver;
let receiver_from_network_listener = &self.network_listener_receiver;
let receiver_from_swmanager = &self.swmanager_receiver;
select! {
msg = receiver_from_script.recv() =>
Expand All @@ -808,6 +822,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Ok(Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation"))),
msg = receiver_from_layout.recv() =>
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.expect("Unexpected panic channel panic in constellation").map(Request::FromSWManager)
}
Expand All @@ -834,12 +852,31 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
Request::Layout(message) => {
self.handle_request_from_layout(message);
},
Request::NetworkListener(message) => {
self.handle_request_from_network_listener(message);
},
Request::FromSWManager(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) {
match message {
SWManagerMsg::OwnSender(sw_sender) => {
Expand Down Expand Up @@ -941,6 +978,10 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::PipelineExited(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) => {
debug!("constellation got iframe URL load message {:?} {:?} {:?}",
load_info.info.parent_pipeline_id,
Expand Down Expand Up @@ -1454,6 +1495,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
// 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
Expand Down
2 changes: 2 additions & 0 deletions components/constellation/lib.rs
Expand Up @@ -19,6 +19,7 @@ extern crate euclid;
extern crate gaol;
extern crate gfx;
extern crate gfx_traits;
extern crate hyper;
extern crate ipc_channel;
extern crate itertools;
extern crate layout_traits;
Expand All @@ -44,6 +45,7 @@ extern crate webvr_traits;
mod browsingcontext;
mod constellation;
mod event_loop;
mod network_listener;
mod pipeline;
#[cfg(not(target_os = "windows"))]
mod sandboxing;
Expand Down
133 changes: 133 additions & 0 deletions components/constellation/network_listener.rs
@@ -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);
}
}
}
}
21 changes: 12 additions & 9 deletions components/net/http_loader.rs
Expand Up @@ -674,14 +674,14 @@ pub fn http_fetch(request: &mut Request,
}

/// [HTTP redirect fetch](https://fetch.spec.whatwg.org#http-redirect-fetch)
fn http_redirect_fetch(request: &mut Request,
cache: &mut CorsCache,
response: Response,
cors_flag: bool,
target: Target,
done_chan: &mut DoneChannel,
context: &FetchContext)
-> Response {
pub fn http_redirect_fetch(request: &mut Request,
cache: &mut CorsCache,
response: Response,
cors_flag: bool,
target: Target,
done_chan: &mut DoneChannel,
context: &FetchContext)
-> Response {
// Step 1
assert!(response.return_internal);

Expand Down Expand Up @@ -749,8 +749,10 @@ fn http_redirect_fetch(request: &mut Request,
// Step 12
// TODO implement referrer policy

let recursive_flag = request.redirect_mode != RedirectMode::Manual;

// 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> {
Expand Down Expand Up @@ -1108,6 +1110,7 @@ fn http_network_fetch(request: &Request,
res.response.status_raw().1.as_bytes().to_vec()));
response.headers = res.response.headers.clone();
response.referrer = request.referrer.to_url().cloned();
response.referrer_policy = request.referrer_policy.clone();

let res_body = response.body.clone();

Expand Down
2 changes: 1 addition & 1 deletion components/net/lib.rs
Expand Up @@ -52,7 +52,7 @@ mod data_loader;
pub mod filemanager_thread;
mod hosts;
pub mod hsts;
mod http_loader;
pub mod http_loader;
pub mod image_cache;
pub mod mime_classifier;
pub mod resource_thread;
Expand Down

0 comments on commit 541baaf

Please sign in to comment.