mirror of
https://github.com/servo/servo.git
synced 2025-07-16 11:53:39 +01:00
Net side of XHR fetch integration
This commit is contained in:
parent
b5255f011e
commit
2cbc8dee25
5 changed files with 107 additions and 6 deletions
|
@ -847,6 +847,7 @@ fn http_network_fetch(request: Rc<Request>,
|
||||||
Ok((mut res, _)) => {
|
Ok((mut res, _)) => {
|
||||||
response.url = Some(res.response.url.clone());
|
response.url = Some(res.response.url.clone());
|
||||||
response.status = Some(res.response.status);
|
response.status = Some(res.response.status);
|
||||||
|
response.raw_status = Some(res.response.status_raw().clone());
|
||||||
response.headers = res.response.headers.clone();
|
response.headers = res.response.headers.clone();
|
||||||
|
|
||||||
let res_body = response.body.clone();
|
let res_body = response.body.clone();
|
||||||
|
|
|
@ -11,6 +11,7 @@ use cookie;
|
||||||
use cookie_storage::CookieStorage;
|
use cookie_storage::CookieStorage;
|
||||||
use data_loader;
|
use data_loader;
|
||||||
use devtools_traits::DevtoolsControlMsg;
|
use devtools_traits::DevtoolsControlMsg;
|
||||||
|
use fetch::methods::fetch;
|
||||||
use file_loader;
|
use file_loader;
|
||||||
use filemanager_thread::FileManagerThreadFactory;
|
use filemanager_thread::FileManagerThreadFactory;
|
||||||
use hsts::HstsList;
|
use hsts::HstsList;
|
||||||
|
@ -23,8 +24,10 @@ use mime_classifier::{ApacheBugFlag, MIMEClassifier, NoSniffFlag};
|
||||||
use net_traits::LoadContext;
|
use net_traits::LoadContext;
|
||||||
use net_traits::ProgressMsg::Done;
|
use net_traits::ProgressMsg::Done;
|
||||||
use net_traits::{AsyncResponseTarget, Metadata, ProgressMsg, ResponseAction, CoreResourceThread};
|
use net_traits::{AsyncResponseTarget, Metadata, ProgressMsg, ResponseAction, CoreResourceThread};
|
||||||
use net_traits::{CoreResourceMsg, CookieSource, LoadConsumer, LoadData, LoadResponse, ResourceId};
|
use net_traits::{CoreResourceMsg, CookieSource, FetchResponseMsg, LoadConsumer};
|
||||||
use net_traits::{NetworkError, WebSocketCommunicate, WebSocketConnectData, ResourceThreads};
|
use net_traits::{LoadData, LoadResponse, NetworkError, ResourceId};
|
||||||
|
use net_traits::{WebSocketCommunicate, WebSocketConnectData, ResourceThreads};
|
||||||
|
use net_traits::request::{Referer, Request};
|
||||||
use profile_traits::time::ProfilerChan;
|
use profile_traits::time::ProfilerChan;
|
||||||
use rustc_serialize::json;
|
use rustc_serialize::json;
|
||||||
use rustc_serialize::{Decodable, Encodable};
|
use rustc_serialize::{Decodable, Encodable};
|
||||||
|
@ -36,6 +39,7 @@ use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::sync::mpsc::{Receiver, Sender, channel};
|
use std::sync::mpsc::{Receiver, Sender, channel};
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use storage_thread::StorageThreadFactory;
|
use storage_thread::StorageThreadFactory;
|
||||||
|
@ -193,6 +197,8 @@ impl ResourceChannelManager {
|
||||||
match self.from_client.recv().unwrap() {
|
match self.from_client.recv().unwrap() {
|
||||||
CoreResourceMsg::Load(load_data, consumer, id_sender) =>
|
CoreResourceMsg::Load(load_data, consumer, id_sender) =>
|
||||||
self.resource_manager.load(load_data, consumer, id_sender, control_sender.clone()),
|
self.resource_manager.load(load_data, consumer, id_sender, control_sender.clone()),
|
||||||
|
CoreResourceMsg::Fetch(load_data, sender) =>
|
||||||
|
self.resource_manager.fetch(load_data, sender),
|
||||||
CoreResourceMsg::WebsocketConnect(connect, connect_data) =>
|
CoreResourceMsg::WebsocketConnect(connect, connect_data) =>
|
||||||
self.resource_manager.websocket_connect(connect, connect_data),
|
self.resource_manager.websocket_connect(connect, connect_data),
|
||||||
CoreResourceMsg::SetCookiesForUrl(request, cookie_list, source) =>
|
CoreResourceMsg::SetCookiesForUrl(request, cookie_list, source) =>
|
||||||
|
@ -480,6 +486,35 @@ impl CoreResourceManager {
|
||||||
cancel_listener));
|
cancel_listener));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fetch(&self, load_data: LoadData, sender: IpcSender<FetchResponseMsg>) {
|
||||||
|
spawn_named(format!("fetch thread for {}", load_data.url), move || {
|
||||||
|
let mut request = Request::new(load_data.url,
|
||||||
|
None, false);
|
||||||
|
// todo handle origin
|
||||||
|
// todo consider replacing LoadData with a direct mapping
|
||||||
|
// to a subset of Request
|
||||||
|
// todo set is_service_worker_global_scope
|
||||||
|
*request.method.borrow_mut() = load_data.method;
|
||||||
|
*request.headers.borrow_mut() = load_data.headers;
|
||||||
|
*request.body.borrow_mut() = load_data.data.clone();
|
||||||
|
if let Some(cors) = load_data.cors {
|
||||||
|
request.use_cors_preflight = cors.preflight;
|
||||||
|
}
|
||||||
|
// XXXManishearth: Check origin against pipeline id
|
||||||
|
request.use_url_credentials = load_data.credentials_flag;
|
||||||
|
// todo load context / mimesniff in fetch
|
||||||
|
// todo referrer policy?
|
||||||
|
if let Some(referer) = load_data.referrer_url {
|
||||||
|
request.referer = Referer::RefererUrl(referer);
|
||||||
|
}
|
||||||
|
// todo worker stuff
|
||||||
|
|
||||||
|
|
||||||
|
fetch(Rc::new(request), Some(Box::new(sender)));
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
fn websocket_connect(&self,
|
fn websocket_connect(&self,
|
||||||
connect: WebSocketCommunicate,
|
connect: WebSocketCommunicate,
|
||||||
connect_data: WebSocketConnectData) {
|
connect_data: WebSocketConnectData) {
|
||||||
|
|
|
@ -112,6 +112,7 @@ pub struct LoadData {
|
||||||
pub headers: Headers,
|
pub headers: Headers,
|
||||||
#[ignore_heap_size_of = "Defined in hyper"]
|
#[ignore_heap_size_of = "Defined in hyper"]
|
||||||
/// Headers that will apply to the initial request and any redirects
|
/// Headers that will apply to the initial request and any redirects
|
||||||
|
/// Unused in fetch
|
||||||
pub preserved_headers: Headers,
|
pub preserved_headers: Headers,
|
||||||
pub data: Option<Vec<u8>>,
|
pub data: Option<Vec<u8>>,
|
||||||
pub cors: Option<ResourceCORSData>,
|
pub cors: Option<ResourceCORSData>,
|
||||||
|
@ -154,6 +155,16 @@ pub trait LoadOrigin {
|
||||||
fn pipeline_id(&self) -> Option<PipelineId>;
|
fn pipeline_id(&self) -> Option<PipelineId>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
pub enum FetchResponseMsg {
|
||||||
|
// todo: should have fields for transmitted/total bytes
|
||||||
|
ProcessRequestBody,
|
||||||
|
ProcessRequestEOF,
|
||||||
|
// todo: send more info about the response (or perhaps the entire Response)
|
||||||
|
ProcessResponse(Result<Metadata, NetworkError>),
|
||||||
|
ProcessResponseEOF(Result<Vec<u8>, NetworkError>),
|
||||||
|
}
|
||||||
|
|
||||||
pub trait FetchTaskTarget {
|
pub trait FetchTaskTarget {
|
||||||
/// https://fetch.spec.whatwg.org/#process-request-body
|
/// https://fetch.spec.whatwg.org/#process-request-body
|
||||||
///
|
///
|
||||||
|
@ -176,6 +187,36 @@ pub trait FetchTaskTarget {
|
||||||
fn process_response_eof(&mut self, response: &response::Response);
|
fn process_response_eof(&mut self, response: &response::Response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl FetchTaskTarget for IpcSender<FetchResponseMsg> {
|
||||||
|
fn process_request_body(&mut self, _: &request::Request) {
|
||||||
|
let _ = self.send(FetchResponseMsg::ProcessRequestBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_request_eof(&mut self, _: &request::Request) {
|
||||||
|
let _ = self.send(FetchResponseMsg::ProcessRequestEOF);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_response(&mut self, response: &response::Response) {
|
||||||
|
let _ = self.send(FetchResponseMsg::ProcessResponse(response.metadata()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn process_response_eof(&mut self, response: &response::Response) {
|
||||||
|
if response.is_network_error() {
|
||||||
|
// todo: finer grained errors
|
||||||
|
let _ = self.send(FetchResponseMsg::ProcessResponse(Err(NetworkError::Internal("Network error".into()))));
|
||||||
|
}
|
||||||
|
if let Ok(ref guard) = response.body.lock() {
|
||||||
|
if let response::ResponseBody::Done(ref vec) = **guard {
|
||||||
|
let _ = self.send(FetchResponseMsg::ProcessResponseEOF(Ok(vec.clone())));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If something goes wrong, log it instead of crashing the resource thread
|
||||||
|
let _ = self.send(FetchResponseMsg::ProcessResponseEOF(Err(NetworkError::Internal("Incomplete body".into()))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A listener for asynchronous network events. Cancelling the underlying request is unsupported.
|
/// A listener for asynchronous network events. Cancelling the underlying request is unsupported.
|
||||||
pub trait AsyncResponseListener {
|
pub trait AsyncResponseListener {
|
||||||
/// The response headers for a request have been received.
|
/// The response headers for a request have been received.
|
||||||
|
@ -348,6 +389,7 @@ pub struct WebSocketConnectData {
|
||||||
pub enum CoreResourceMsg {
|
pub enum CoreResourceMsg {
|
||||||
/// Request the data associated with a particular URL
|
/// Request the data associated with a particular URL
|
||||||
Load(LoadData, LoadConsumer, Option<IpcSender<ResourceId>>),
|
Load(LoadData, LoadConsumer, Option<IpcSender<ResourceId>>),
|
||||||
|
Fetch(LoadData, 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 set of cookies for a given originating URL
|
/// Store a set of cookies for a given originating URL
|
||||||
|
|
|
@ -43,6 +43,7 @@ pub enum Origin {
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum Referer {
|
pub enum Referer {
|
||||||
NoReferer,
|
NoReferer,
|
||||||
|
/// Default referer if nothing is specified
|
||||||
Client,
|
Client,
|
||||||
RefererUrl(Url)
|
RefererUrl(Url)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,15 +4,17 @@
|
||||||
|
|
||||||
//! 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 hyper::header::{AccessControlExposeHeaders, Headers};
|
use hyper::header::{AccessControlExposeHeaders, ContentType, Headers};
|
||||||
|
use hyper::http::RawStatus;
|
||||||
use hyper::status::StatusCode;
|
use hyper::status::StatusCode;
|
||||||
|
use {Metadata, NetworkError};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
|
/// [Response type](https://fetch.spec.whatwg.org/#concept-response-type)
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
#[derive(Clone, PartialEq, Copy, Debug, Deserialize, Serialize)]
|
||||||
pub enum ResponseType {
|
pub enum ResponseType {
|
||||||
Basic,
|
Basic,
|
||||||
CORS,
|
CORS,
|
||||||
|
@ -23,7 +25,7 @@ pub enum ResponseType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// [Response termination reason](https://fetch.spec.whatwg.org/#concept-response-termination-reason)
|
/// [Response termination reason](https://fetch.spec.whatwg.org/#concept-response-termination-reason)
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Deserialize, Serialize)]
|
||||||
pub enum TerminationReason {
|
pub enum TerminationReason {
|
||||||
EndUserAbort,
|
EndUserAbort,
|
||||||
Fatal,
|
Fatal,
|
||||||
|
@ -50,7 +52,7 @@ impl ResponseBody {
|
||||||
|
|
||||||
|
|
||||||
/// [Cache state](https://fetch.spec.whatwg.org/#concept-response-cache-state)
|
/// [Cache state](https://fetch.spec.whatwg.org/#concept-response-cache-state)
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||||
pub enum CacheState {
|
pub enum CacheState {
|
||||||
None,
|
None,
|
||||||
Local,
|
Local,
|
||||||
|
@ -81,6 +83,7 @@ pub struct Response {
|
||||||
pub url_list: RefCell<Vec<Url>>,
|
pub url_list: RefCell<Vec<Url>>,
|
||||||
/// `None` can be considered a StatusCode of `0`.
|
/// `None` can be considered a StatusCode of `0`.
|
||||||
pub status: Option<StatusCode>,
|
pub status: Option<StatusCode>,
|
||||||
|
pub raw_status: Option<RawStatus>,
|
||||||
pub headers: Headers,
|
pub headers: Headers,
|
||||||
pub body: Arc<Mutex<ResponseBody>>,
|
pub body: Arc<Mutex<ResponseBody>>,
|
||||||
pub cache_state: CacheState,
|
pub cache_state: CacheState,
|
||||||
|
@ -100,6 +103,7 @@ impl Response {
|
||||||
url: None,
|
url: None,
|
||||||
url_list: RefCell::new(Vec::new()),
|
url_list: RefCell::new(Vec::new()),
|
||||||
status: Some(StatusCode::Ok),
|
status: Some(StatusCode::Ok),
|
||||||
|
raw_status: Some(RawStatus(200, "OK".into())),
|
||||||
headers: Headers::new(),
|
headers: Headers::new(),
|
||||||
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
||||||
cache_state: CacheState::None,
|
cache_state: CacheState::None,
|
||||||
|
@ -116,6 +120,7 @@ impl Response {
|
||||||
url: None,
|
url: None,
|
||||||
url_list: RefCell::new(vec![]),
|
url_list: RefCell::new(vec![]),
|
||||||
status: None,
|
status: None,
|
||||||
|
raw_status: None,
|
||||||
headers: Headers::new(),
|
headers: Headers::new(),
|
||||||
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
body: Arc::new(Mutex::new(ResponseBody::Empty)),
|
||||||
cache_state: CacheState::None,
|
cache_state: CacheState::None,
|
||||||
|
@ -216,4 +221,21 @@ impl Response {
|
||||||
|
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn metadata(&self) -> Result<Metadata, NetworkError> {
|
||||||
|
let mut metadata = if let Some(ref url) = self.url {
|
||||||
|
Metadata::default(url.clone())
|
||||||
|
} else {
|
||||||
|
return Err(NetworkError::Internal("No url found".to_string()));
|
||||||
|
};
|
||||||
|
|
||||||
|
metadata.set_content_type(match self.headers.get() {
|
||||||
|
Some(&ContentType(ref mime)) => Some(mime),
|
||||||
|
None => None
|
||||||
|
});
|
||||||
|
metadata.headers = Some(self.headers.clone());
|
||||||
|
metadata.status = self.raw_status.clone();
|
||||||
|
metadata.https_state = self.https_state;
|
||||||
|
return Ok(metadata);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue