forked from mirrors/gecko-dev
		
	Fixes #19327 Source-Repo: https://github.com/servo/servo Source-Revision: 78fb3c206d30da8e7b16ea941268b733b21059ed --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : e76d89bd5fee0f74bc9592960a3c220bb6c37436
		
			
				
	
	
		
			544 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			544 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
/* 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/. */
 | 
						|
 | 
						|
 | 
						|
#![deny(unsafe_code)]
 | 
						|
 | 
						|
extern crate cookie as cookie_rs;
 | 
						|
extern crate hyper;
 | 
						|
extern crate hyper_serde;
 | 
						|
extern crate image as piston_image;
 | 
						|
extern crate ipc_channel;
 | 
						|
#[macro_use] extern crate lazy_static;
 | 
						|
#[macro_use] extern crate log;
 | 
						|
#[macro_use] extern crate malloc_size_of;
 | 
						|
#[macro_use] extern crate malloc_size_of_derive;
 | 
						|
extern crate msg;
 | 
						|
extern crate num_traits;
 | 
						|
#[macro_use] extern crate serde;
 | 
						|
extern crate servo_config;
 | 
						|
extern crate servo_url;
 | 
						|
extern crate url;
 | 
						|
extern crate uuid;
 | 
						|
extern crate webrender_api;
 | 
						|
 | 
						|
use cookie_rs::Cookie;
 | 
						|
use filemanager_thread::FileManagerThreadMsg;
 | 
						|
use hyper::Error as HyperError;
 | 
						|
use hyper::header::{ContentType, Headers, ReferrerPolicy as ReferrerPolicyHeader};
 | 
						|
use hyper::http::RawStatus;
 | 
						|
use hyper::mime::{Attr, Mime};
 | 
						|
use hyper_serde::Serde;
 | 
						|
use ipc_channel::Error as IpcError;
 | 
						|
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
 | 
						|
use ipc_channel::router::ROUTER;
 | 
						|
use request::{Request, RequestInit};
 | 
						|
use response::{HttpsState, Response, ResponseInit};
 | 
						|
use servo_url::ServoUrl;
 | 
						|
use std::error::Error;
 | 
						|
use storage_thread::StorageThreadMsg;
 | 
						|
 | 
						|
pub mod blob_url_store;
 | 
						|
pub mod filemanager_thread;
 | 
						|
pub mod image_cache;
 | 
						|
pub mod net_error_list;
 | 
						|
pub mod pub_domains;
 | 
						|
pub mod request;
 | 
						|
pub mod response;
 | 
						|
pub mod storage_thread;
 | 
						|
 | 
						|
/// Image handling.
 | 
						|
///
 | 
						|
/// It may be surprising that this goes in the network crate as opposed to the graphics crate.
 | 
						|
/// However, image handling is generally very integrated with the network stack (especially where
 | 
						|
/// caching is involved) and as a result it must live in here.
 | 
						|
pub mod image {
 | 
						|
    pub mod base;
 | 
						|
}
 | 
						|
 | 
						|
/// A loading context, for context-specific sniffing, as defined in
 | 
						|
/// <https://mimesniff.spec.whatwg.org/#context-specific-sniffing>
 | 
						|
#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
 | 
						|
pub enum LoadContext {
 | 
						|
    Browsing,
 | 
						|
    Image,
 | 
						|
    AudioVideo,
 | 
						|
    Plugin,
 | 
						|
    Style,
 | 
						|
    Script,
 | 
						|
    Font,
 | 
						|
    TextTrack,
 | 
						|
    CacheManifest,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
 | 
						|
pub struct CustomResponse {
 | 
						|
    #[ignore_malloc_size_of = "Defined in hyper"]
 | 
						|
    #[serde(deserialize_with = "::hyper_serde::deserialize",
 | 
						|
            serialize_with = "::hyper_serde::serialize")]
 | 
						|
    pub headers: Headers,
 | 
						|
    #[ignore_malloc_size_of = "Defined in hyper"]
 | 
						|
    #[serde(deserialize_with = "::hyper_serde::deserialize",
 | 
						|
            serialize_with = "::hyper_serde::serialize")]
 | 
						|
    pub raw_status: RawStatus,
 | 
						|
    pub body: Vec<u8>,
 | 
						|
}
 | 
						|
 | 
						|
impl CustomResponse {
 | 
						|
    pub fn new(headers: Headers, raw_status: RawStatus, body: Vec<u8>) -> CustomResponse {
 | 
						|
        CustomResponse {
 | 
						|
            headers: headers,
 | 
						|
            raw_status: raw_status,
 | 
						|
            body: body,
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Deserialize, Serialize)]
 | 
						|
pub struct CustomResponseMediator {
 | 
						|
    pub response_chan: IpcSender<Option<CustomResponse>>,
 | 
						|
    pub load_url: ServoUrl,
 | 
						|
}
 | 
						|
 | 
						|
/// [Policies](https://w3c.github.io/webappsec-referrer-policy/#referrer-policy-states)
 | 
						|
/// for providing a referrer header for a request
 | 
						|
#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
 | 
						|
pub enum ReferrerPolicy {
 | 
						|
    /// "no-referrer"
 | 
						|
    NoReferrer,
 | 
						|
    /// "no-referrer-when-downgrade"
 | 
						|
    NoReferrerWhenDowngrade,
 | 
						|
    /// "origin"
 | 
						|
    Origin,
 | 
						|
    /// "same-origin"
 | 
						|
    SameOrigin,
 | 
						|
    /// "origin-when-cross-origin"
 | 
						|
    OriginWhenCrossOrigin,
 | 
						|
    /// "unsafe-url"
 | 
						|
    UnsafeUrl,
 | 
						|
    /// "strict-origin"
 | 
						|
    StrictOrigin,
 | 
						|
    /// "strict-origin-when-cross-origin"
 | 
						|
    StrictOriginWhenCrossOrigin,
 | 
						|
}
 | 
						|
 | 
						|
impl<'a> From<&'a ReferrerPolicyHeader> for ReferrerPolicy {
 | 
						|
    fn from(policy: &'a ReferrerPolicyHeader) -> Self {
 | 
						|
        match *policy {
 | 
						|
            ReferrerPolicyHeader::NoReferrer =>
 | 
						|
                ReferrerPolicy::NoReferrer,
 | 
						|
            ReferrerPolicyHeader::NoReferrerWhenDowngrade =>
 | 
						|
                ReferrerPolicy::NoReferrerWhenDowngrade,
 | 
						|
            ReferrerPolicyHeader::SameOrigin =>
 | 
						|
                ReferrerPolicy::SameOrigin,
 | 
						|
            ReferrerPolicyHeader::Origin =>
 | 
						|
                ReferrerPolicy::Origin,
 | 
						|
            ReferrerPolicyHeader::OriginWhenCrossOrigin =>
 | 
						|
                ReferrerPolicy::OriginWhenCrossOrigin,
 | 
						|
            ReferrerPolicyHeader::UnsafeUrl =>
 | 
						|
                ReferrerPolicy::UnsafeUrl,
 | 
						|
            ReferrerPolicyHeader::StrictOrigin =>
 | 
						|
                ReferrerPolicy::StrictOrigin,
 | 
						|
            ReferrerPolicyHeader::StrictOriginWhenCrossOrigin =>
 | 
						|
                ReferrerPolicy::StrictOriginWhenCrossOrigin,
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[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<FetchMetadata, NetworkError>),
 | 
						|
    ProcessResponseChunk(Vec<u8>),
 | 
						|
    ProcessResponseEOF(Result<(), NetworkError>),
 | 
						|
}
 | 
						|
 | 
						|
pub trait FetchTaskTarget {
 | 
						|
    /// <https://fetch.spec.whatwg.org/#process-request-body>
 | 
						|
    ///
 | 
						|
    /// Fired when a chunk of the request body is transmitted
 | 
						|
    fn process_request_body(&mut self, request: &Request);
 | 
						|
 | 
						|
    /// <https://fetch.spec.whatwg.org/#process-request-end-of-file>
 | 
						|
    ///
 | 
						|
    /// Fired when the entire request finishes being transmitted
 | 
						|
    fn process_request_eof(&mut self, request: &Request);
 | 
						|
 | 
						|
    /// <https://fetch.spec.whatwg.org/#process-response>
 | 
						|
    ///
 | 
						|
    /// Fired when headers are received
 | 
						|
    fn process_response(&mut self, response: &Response);
 | 
						|
 | 
						|
    /// Fired when a chunk of response content is received
 | 
						|
    fn process_response_chunk(&mut self, chunk: Vec<u8>);
 | 
						|
 | 
						|
    /// <https://fetch.spec.whatwg.org/#process-response-end-of-file>
 | 
						|
    ///
 | 
						|
    /// Fired when the response is fully fetched
 | 
						|
    fn process_response_eof(&mut self, response: &Response);
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Deserialize, Serialize)]
 | 
						|
pub enum FilteredMetadata {
 | 
						|
    Basic(Metadata),
 | 
						|
    Cors(Metadata),
 | 
						|
    Opaque,
 | 
						|
    OpaqueRedirect
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Deserialize, Serialize)]
 | 
						|
pub enum FetchMetadata {
 | 
						|
    Unfiltered(Metadata),
 | 
						|
    Filtered {
 | 
						|
        filtered: FilteredMetadata,
 | 
						|
        unsafe_: Metadata,
 | 
						|
    },
 | 
						|
}
 | 
						|
 | 
						|
pub trait FetchResponseListener {
 | 
						|
    fn process_request_body(&mut self);
 | 
						|
    fn process_request_eof(&mut self);
 | 
						|
    fn process_response(&mut self, metadata: Result<FetchMetadata, NetworkError>);
 | 
						|
    fn process_response_chunk(&mut self, chunk: Vec<u8>);
 | 
						|
    fn process_response_eof(&mut self, response: Result<(), NetworkError>);
 | 
						|
}
 | 
						|
 | 
						|
impl FetchTaskTarget for IpcSender<FetchResponseMsg> {
 | 
						|
    fn process_request_body(&mut self, _: &Request) {
 | 
						|
        let _ = self.send(FetchResponseMsg::ProcessRequestBody);
 | 
						|
    }
 | 
						|
 | 
						|
    fn process_request_eof(&mut self, _: &Request) {
 | 
						|
        let _ = self.send(FetchResponseMsg::ProcessRequestEOF);
 | 
						|
    }
 | 
						|
 | 
						|
    fn process_response(&mut self, response: &Response) {
 | 
						|
        let _ = self.send(FetchResponseMsg::ProcessResponse(response.metadata()));
 | 
						|
    }
 | 
						|
 | 
						|
    fn process_response_chunk(&mut self, chunk: Vec<u8>) {
 | 
						|
        let _ = self.send(FetchResponseMsg::ProcessResponseChunk(chunk));
 | 
						|
    }
 | 
						|
 | 
						|
    fn process_response_eof(&mut self, response: &Response) {
 | 
						|
        if let Some(e) = response.get_network_error() {
 | 
						|
            let _ = self.send(FetchResponseMsg::ProcessResponseEOF(Err(e.clone())));
 | 
						|
        } else {
 | 
						|
            let _ = self.send(FetchResponseMsg::ProcessResponseEOF(Ok(())));
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
pub trait Action<Listener> {
 | 
						|
    fn process(self, listener: &mut Listener);
 | 
						|
}
 | 
						|
 | 
						|
impl<T: FetchResponseListener> Action<T> for FetchResponseMsg {
 | 
						|
    /// Execute the default action on a provided listener.
 | 
						|
    fn process(self, listener: &mut T) {
 | 
						|
        match self {
 | 
						|
            FetchResponseMsg::ProcessRequestBody => listener.process_request_body(),
 | 
						|
            FetchResponseMsg::ProcessRequestEOF => listener.process_request_eof(),
 | 
						|
            FetchResponseMsg::ProcessResponse(meta) => listener.process_response(meta),
 | 
						|
            FetchResponseMsg::ProcessResponseChunk(data) => listener.process_response_chunk(data),
 | 
						|
            FetchResponseMsg::ProcessResponseEOF(data) => listener.process_response_eof(data),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Handle to a resource thread
 | 
						|
pub type CoreResourceThread = IpcSender<CoreResourceMsg>;
 | 
						|
 | 
						|
pub type IpcSendResult = Result<(), IpcError>;
 | 
						|
 | 
						|
/// Abstraction of the ability to send a particular type of message,
 | 
						|
/// used by net_traits::ResourceThreads to ease the use its IpcSender sub-fields
 | 
						|
/// XXX: If this trait will be used more in future, some auto derive might be appealing
 | 
						|
pub trait IpcSend<T>
 | 
						|
    where T: serde::Serialize + for<'de> serde::Deserialize<'de>,
 | 
						|
{
 | 
						|
    /// send message T
 | 
						|
    fn send(&self, T) -> IpcSendResult;
 | 
						|
    /// get underlying sender
 | 
						|
    fn sender(&self) -> IpcSender<T>;
 | 
						|
}
 | 
						|
 | 
						|
// FIXME: Originally we will construct an Arc<ResourceThread> from ResourceThread
 | 
						|
// in script_thread to avoid some performance pitfall. Now we decide to deal with
 | 
						|
// the "Arc" hack implicitly in future.
 | 
						|
// See discussion: http://logs.glob.uno/?c=mozilla%23servo&s=16+May+2016&e=16+May+2016#c430412
 | 
						|
// See also: https://github.com/servo/servo/blob/735480/components/script/script_thread.rs#L313
 | 
						|
#[derive(Clone, Deserialize, Serialize)]
 | 
						|
pub struct ResourceThreads {
 | 
						|
    core_thread: CoreResourceThread,
 | 
						|
    storage_thread: IpcSender<StorageThreadMsg>,
 | 
						|
}
 | 
						|
 | 
						|
impl ResourceThreads {
 | 
						|
    pub fn new(c: CoreResourceThread, s: IpcSender<StorageThreadMsg>) -> ResourceThreads {
 | 
						|
        ResourceThreads {
 | 
						|
            core_thread: c,
 | 
						|
            storage_thread: s,
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl IpcSend<CoreResourceMsg> for ResourceThreads {
 | 
						|
    fn send(&self, msg: CoreResourceMsg) -> IpcSendResult {
 | 
						|
        self.core_thread.send(msg)
 | 
						|
    }
 | 
						|
 | 
						|
    fn sender(&self) -> IpcSender<CoreResourceMsg> {
 | 
						|
        self.core_thread.clone()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
impl IpcSend<StorageThreadMsg> for ResourceThreads {
 | 
						|
    fn send(&self, msg: StorageThreadMsg) -> IpcSendResult {
 | 
						|
        self.storage_thread.send(msg)
 | 
						|
    }
 | 
						|
 | 
						|
    fn sender(&self) -> IpcSender<StorageThreadMsg> {
 | 
						|
        self.storage_thread.clone()
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
// Ignore the sub-fields
 | 
						|
malloc_size_of_is_0!(ResourceThreads);
 | 
						|
 | 
						|
#[derive(Clone, Copy, Deserialize, PartialEq, Serialize)]
 | 
						|
pub enum IncludeSubdomains {
 | 
						|
    Included,
 | 
						|
    NotIncluded,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize, MallocSizeOf, Serialize)]
 | 
						|
pub enum MessageData {
 | 
						|
    Text(String),
 | 
						|
    Binary(Vec<u8>),
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize, Serialize)]
 | 
						|
pub enum WebSocketDomAction {
 | 
						|
    SendMessage(MessageData),
 | 
						|
    Close(Option<u16>, Option<String>),
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize, Serialize)]
 | 
						|
pub enum WebSocketNetworkEvent {
 | 
						|
    ConnectionEstablished {
 | 
						|
        protocol_in_use: Option<String>,
 | 
						|
    },
 | 
						|
    MessageReceived(MessageData),
 | 
						|
    Close(Option<u16>, String),
 | 
						|
    Fail,
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize, Serialize)]
 | 
						|
/// IPC channels to communicate with the script thread about network or DOM events.
 | 
						|
pub enum FetchChannels {
 | 
						|
    ResponseMsg(IpcSender<FetchResponseMsg>, /* cancel_chan */ Option<IpcReceiver<()>>),
 | 
						|
    WebSocket {
 | 
						|
        event_sender: IpcSender<WebSocketNetworkEvent>,
 | 
						|
        action_receiver: IpcReceiver<WebSocketDomAction>,
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Deserialize, Serialize)]
 | 
						|
pub enum CoreResourceMsg {
 | 
						|
    Fetch(RequestInit, FetchChannels),
 | 
						|
    /// Initiate a fetch in response to processing a redirection
 | 
						|
    FetchRedirect(RequestInit, ResponseInit, IpcSender<FetchResponseMsg>, /* cancel_chan */ Option<IpcReceiver<()>>),
 | 
						|
    /// Store a cookie for a given originating URL
 | 
						|
    SetCookieForUrl(ServoUrl, Serde<Cookie<'static>>, CookieSource),
 | 
						|
    /// Store a set of cookies for a given originating URL
 | 
						|
    SetCookiesForUrl(ServoUrl, Vec<Serde<Cookie<'static>>>, CookieSource),
 | 
						|
    /// Retrieve the stored cookies for a given URL
 | 
						|
    GetCookiesForUrl(ServoUrl, IpcSender<Option<String>>, CookieSource),
 | 
						|
    /// Get a cookie by name for a given originating URL
 | 
						|
    GetCookiesDataForUrl(ServoUrl, IpcSender<Vec<Serde<Cookie<'static>>>>, CookieSource),
 | 
						|
    /// Synchronization message solely for knowing the state of the ResourceChannelManager loop
 | 
						|
    Synchronize(IpcSender<()>),
 | 
						|
    /// Send the network sender in constellation to CoreResourceThread
 | 
						|
    NetworkMediator(IpcSender<CustomResponseMediator>),
 | 
						|
    /// Message forwarded to file manager's handler
 | 
						|
    ToFileManager(FileManagerThreadMsg),
 | 
						|
    /// Break the load handler loop, send a reply when done cleaning up local resources
 | 
						|
    /// and exit
 | 
						|
    Exit(IpcSender<()>),
 | 
						|
}
 | 
						|
 | 
						|
/// Instruct the resource thread to make a new request.
 | 
						|
pub fn fetch_async<F>(request: RequestInit, core_resource_thread: &CoreResourceThread, f: F)
 | 
						|
    where F: Fn(FetchResponseMsg) + Send + 'static,
 | 
						|
{
 | 
						|
    let (action_sender, action_receiver) = ipc::channel().unwrap();
 | 
						|
    ROUTER.add_route(action_receiver.to_opaque(),
 | 
						|
                     Box::new(move |message| f(message.to().unwrap())));
 | 
						|
    core_resource_thread.send(
 | 
						|
        CoreResourceMsg::Fetch(request, FetchChannels::ResponseMsg(action_sender, None))).unwrap();
 | 
						|
}
 | 
						|
 | 
						|
#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
 | 
						|
pub struct ResourceCorsData {
 | 
						|
    /// CORS Preflight flag
 | 
						|
    pub preflight: bool,
 | 
						|
    /// Origin of CORS Request
 | 
						|
    pub origin: ServoUrl,
 | 
						|
}
 | 
						|
 | 
						|
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
 | 
						|
#[derive(Clone, Deserialize, MallocSizeOf, Serialize)]
 | 
						|
pub struct Metadata {
 | 
						|
    /// Final URL after redirects.
 | 
						|
    pub final_url: ServoUrl,
 | 
						|
 | 
						|
    /// Location URL from the response headers.
 | 
						|
    pub location_url: Option<Result<ServoUrl, String>>,
 | 
						|
 | 
						|
    #[ignore_malloc_size_of = "Defined in hyper"]
 | 
						|
    /// MIME type / subtype.
 | 
						|
    pub content_type: Option<Serde<ContentType>>,
 | 
						|
 | 
						|
    /// Character set.
 | 
						|
    pub charset: Option<String>,
 | 
						|
 | 
						|
    #[ignore_malloc_size_of = "Defined in hyper"]
 | 
						|
    /// Headers
 | 
						|
    pub headers: Option<Serde<Headers>>,
 | 
						|
 | 
						|
    /// HTTP Status
 | 
						|
    pub status: Option<(u16, Vec<u8>)>,
 | 
						|
 | 
						|
    /// Is successful HTTPS connection
 | 
						|
    pub https_state: HttpsState,
 | 
						|
 | 
						|
    /// Referrer Url
 | 
						|
    pub referrer: Option<ServoUrl>,
 | 
						|
 | 
						|
    /// Referrer Policy of the Request used to obtain Response
 | 
						|
    pub referrer_policy: Option<ReferrerPolicy>,
 | 
						|
}
 | 
						|
 | 
						|
impl Metadata {
 | 
						|
    /// Metadata with defaults for everything optional.
 | 
						|
    pub fn default(url: ServoUrl) -> Self {
 | 
						|
        Metadata {
 | 
						|
            final_url: url,
 | 
						|
            location_url: None,
 | 
						|
            content_type: None,
 | 
						|
            charset: None,
 | 
						|
            headers: None,
 | 
						|
            // https://fetch.spec.whatwg.org/#concept-response-status-message
 | 
						|
            status: Some((200, b"OK".to_vec())),
 | 
						|
            https_state: HttpsState::None,
 | 
						|
            referrer: None,
 | 
						|
            referrer_policy: None,
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /// Extract the parts of a Mime that we care about.
 | 
						|
    pub fn set_content_type(&mut self, content_type: Option<&Mime>) {
 | 
						|
        if self.headers.is_none() {
 | 
						|
            self.headers = Some(Serde(Headers::new()));
 | 
						|
        }
 | 
						|
 | 
						|
        if let Some(mime) = content_type {
 | 
						|
            self.headers.as_mut().unwrap().set(ContentType(mime.clone()));
 | 
						|
            self.content_type = Some(Serde(ContentType(mime.clone())));
 | 
						|
            let Mime(_, _, ref parameters) = *mime;
 | 
						|
            for &(ref k, ref v) in parameters {
 | 
						|
                if Attr::Charset == *k {
 | 
						|
                    self.charset = Some(v.to_string());
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// The creator of a given cookie
 | 
						|
#[derive(Clone, Copy, Deserialize, PartialEq, Serialize)]
 | 
						|
pub enum CookieSource {
 | 
						|
    /// An HTTP API
 | 
						|
    HTTP,
 | 
						|
    /// A non-HTTP API
 | 
						|
    NonHTTP,
 | 
						|
}
 | 
						|
 | 
						|
/// Convenience function for synchronously loading a whole resource.
 | 
						|
pub fn load_whole_resource(request: RequestInit,
 | 
						|
                           core_resource_thread: &CoreResourceThread)
 | 
						|
                           -> Result<(Metadata, Vec<u8>), NetworkError> {
 | 
						|
    let (action_sender, action_receiver) = ipc::channel().unwrap();
 | 
						|
    core_resource_thread.send(
 | 
						|
        CoreResourceMsg::Fetch(request, FetchChannels::ResponseMsg(action_sender, None))).unwrap();
 | 
						|
 | 
						|
    let mut buf = vec![];
 | 
						|
    let mut metadata = None;
 | 
						|
    loop {
 | 
						|
        match action_receiver.recv().unwrap() {
 | 
						|
            FetchResponseMsg::ProcessRequestBody |
 | 
						|
            FetchResponseMsg::ProcessRequestEOF => (),
 | 
						|
            FetchResponseMsg::ProcessResponse(Ok(m)) => {
 | 
						|
                metadata = Some(match m {
 | 
						|
                    FetchMetadata::Unfiltered(m) => m,
 | 
						|
                    FetchMetadata::Filtered { unsafe_, .. } => unsafe_,
 | 
						|
                })
 | 
						|
            },
 | 
						|
            FetchResponseMsg::ProcessResponseChunk(data) => buf.extend_from_slice(&data),
 | 
						|
            FetchResponseMsg::ProcessResponseEOF(Ok(())) => return Ok((metadata.unwrap(), buf)),
 | 
						|
            FetchResponseMsg::ProcessResponse(Err(e)) |
 | 
						|
            FetchResponseMsg::ProcessResponseEOF(Err(e)) => return Err(e),
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Network errors that have to be exported out of the loaders
 | 
						|
#[derive(Clone, Debug, Deserialize, Eq, MallocSizeOf, PartialEq, Serialize)]
 | 
						|
pub enum NetworkError {
 | 
						|
    /// Could be any of the internal errors, like unsupported scheme, connection errors, etc.
 | 
						|
    Internal(String),
 | 
						|
    LoadCancelled,
 | 
						|
    /// SSL validation error that has to be handled in the HTML parser
 | 
						|
    SslValidation(ServoUrl, String),
 | 
						|
}
 | 
						|
 | 
						|
impl NetworkError {
 | 
						|
    pub fn from_hyper_error(url: &ServoUrl, error: HyperError) -> Self {
 | 
						|
        if let HyperError::Ssl(ref ssl_error) = error {
 | 
						|
            return NetworkError::from_ssl_error(url, &**ssl_error);
 | 
						|
        }
 | 
						|
        NetworkError::Internal(error.description().to_owned())
 | 
						|
    }
 | 
						|
 | 
						|
    pub fn from_ssl_error(url: &ServoUrl, error: &Error) -> Self {
 | 
						|
        NetworkError::SslValidation(url.clone(), error.description().to_owned())
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
/// Normalize `slice`, as defined by
 | 
						|
/// [the Fetch Spec](https://fetch.spec.whatwg.org/#concept-header-value-normalize).
 | 
						|
pub fn trim_http_whitespace(mut slice: &[u8]) -> &[u8] {
 | 
						|
    const HTTP_WS_BYTES: &'static [u8] = b"\x09\x0A\x0D\x20";
 | 
						|
 | 
						|
    loop {
 | 
						|
        match slice.split_first() {
 | 
						|
            Some((first, remainder)) if HTTP_WS_BYTES.contains(first) => slice = remainder,
 | 
						|
            _ => break,
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    loop {
 | 
						|
        match slice.split_last() {
 | 
						|
            Some((last, remainder)) if HTTP_WS_BYTES.contains(last) => slice = remainder,
 | 
						|
            _ => break,
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    slice
 | 
						|
}
 |