mirror of
https://github.com/servo/servo.git
synced 2025-06-18 05:14:28 +00:00
217 lines
6.2 KiB
Rust
217 lines
6.2 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/. */
|
|
|
|
#![feature(box_syntax)]
|
|
#![feature(collections)]
|
|
#![feature(core)]
|
|
#![feature(rustc_private)]
|
|
#![feature(std_misc)]
|
|
|
|
extern crate geom;
|
|
extern crate hyper;
|
|
#[macro_use]
|
|
extern crate log;
|
|
extern crate png;
|
|
extern crate profile;
|
|
extern crate stb_image;
|
|
extern crate url;
|
|
extern crate util;
|
|
|
|
use hyper::header::Headers;
|
|
use hyper::http::RawStatus;
|
|
use hyper::method::Method;
|
|
use hyper::mime::{Mime, Attr};
|
|
use url::Url;
|
|
|
|
use std::borrow::IntoCow;
|
|
use std::sync::mpsc::{channel, Receiver, Sender};
|
|
|
|
pub mod image_cache_task;
|
|
pub mod local_image_cache;
|
|
pub mod storage_task;
|
|
|
|
/// 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;
|
|
pub mod holder;
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct LoadData {
|
|
pub url: Url,
|
|
pub method: Method,
|
|
/// Headers that will apply to the initial request only
|
|
pub headers: Headers,
|
|
/// Headers that will apply to the initial request and any redirects
|
|
pub preserved_headers: Headers,
|
|
pub data: Option<Vec<u8>>,
|
|
pub cors: Option<ResourceCORSData>,
|
|
pub consumer: Sender<LoadResponse>,
|
|
}
|
|
|
|
impl LoadData {
|
|
pub fn new(url: Url, consumer: Sender<LoadResponse>) -> LoadData {
|
|
LoadData {
|
|
url: url,
|
|
method: Method::Get,
|
|
headers: Headers::new(),
|
|
preserved_headers: Headers::new(),
|
|
data: None,
|
|
cors: None,
|
|
consumer: consumer,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Handle to a resource task
|
|
pub type ResourceTask = Sender<ControlMsg>;
|
|
|
|
pub enum ControlMsg {
|
|
/// Request the data associated with a particular URL
|
|
Load(LoadData),
|
|
/// Store a set of cookies for a given originating URL
|
|
SetCookiesForUrl(Url, String, CookieSource),
|
|
/// Retrieve the stored cookies for a given URL
|
|
GetCookiesForUrl(Url, Sender<Option<String>>, CookieSource),
|
|
Exit
|
|
}
|
|
|
|
/// Message sent in response to `Load`. Contains metadata, and a port
|
|
/// for receiving the data.
|
|
///
|
|
/// Even if loading fails immediately, we send one of these and the
|
|
/// progress_port will provide the error.
|
|
pub struct LoadResponse {
|
|
/// Metadata, such as from HTTP headers.
|
|
pub metadata: Metadata,
|
|
/// Port for reading data.
|
|
pub progress_port: Receiver<ProgressMsg>,
|
|
}
|
|
|
|
#[derive(Clone)]
|
|
pub struct ResourceCORSData {
|
|
/// CORS Preflight flag
|
|
pub preflight: bool,
|
|
/// Origin of CORS Request
|
|
pub origin: Url
|
|
}
|
|
|
|
/// Metadata about a loaded resource, such as is obtained from HTTP headers.
|
|
#[derive(Clone)]
|
|
pub struct Metadata {
|
|
/// Final URL after redirects.
|
|
pub final_url: Url,
|
|
|
|
/// MIME type / subtype.
|
|
pub content_type: Option<(String, String)>,
|
|
|
|
/// Character set.
|
|
pub charset: Option<String>,
|
|
|
|
/// Headers
|
|
pub headers: Option<Headers>,
|
|
|
|
/// HTTP Status
|
|
pub status: Option<RawStatus>,
|
|
}
|
|
|
|
impl Metadata {
|
|
/// Metadata with defaults for everything optional.
|
|
pub fn default(url: Url) -> Self {
|
|
Metadata {
|
|
final_url: url,
|
|
content_type: None,
|
|
charset: None,
|
|
headers: None,
|
|
// http://fetch.spec.whatwg.org/#concept-response-status-message
|
|
status: Some(RawStatus(200, "OK".into_cow())),
|
|
}
|
|
}
|
|
|
|
/// Extract the parts of a Mime that we care about.
|
|
pub fn set_content_type(&mut self, content_type: Option<&Mime>) {
|
|
match content_type {
|
|
None => (),
|
|
Some(&Mime(ref type_, ref subtype, ref parameters)) => {
|
|
self.content_type = Some((type_.to_string(), subtype.to_string()));
|
|
for &(ref k, ref v) in parameters.iter() {
|
|
if &Attr::Charset == k {
|
|
self.charset = Some(v.to_string());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// The creator of a given cookie
|
|
#[derive(PartialEq, Copy)]
|
|
pub enum CookieSource {
|
|
/// An HTTP API
|
|
HTTP,
|
|
/// A non-HTTP API
|
|
NonHTTP,
|
|
}
|
|
|
|
/// Messages sent in response to a `Load` message
|
|
#[derive(PartialEq,Debug)]
|
|
pub enum ProgressMsg {
|
|
/// Binary data - there may be multiple of these
|
|
Payload(Vec<u8>),
|
|
/// Indicates loading is complete, either successfully or not
|
|
Done(Result<(), String>)
|
|
}
|
|
|
|
/// Convenience function for synchronously loading a whole resource.
|
|
pub fn load_whole_resource(resource_task: &ResourceTask, url: Url)
|
|
-> Result<(Metadata, Vec<u8>), String> {
|
|
let (start_chan, start_port) = channel();
|
|
resource_task.send(ControlMsg::Load(LoadData::new(url, start_chan))).unwrap();
|
|
let response = start_port.recv().unwrap();
|
|
|
|
let mut buf = vec!();
|
|
loop {
|
|
match response.progress_port.recv().unwrap() {
|
|
ProgressMsg::Payload(data) => buf.push_all(&data),
|
|
ProgressMsg::Done(Ok(())) => return Ok((response.metadata, buf)),
|
|
ProgressMsg::Done(Err(e)) => return Err(e)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Load a URL asynchronously and iterate over chunks of bytes from the response.
|
|
pub fn load_bytes_iter(resource_task: &ResourceTask, url: Url) -> (Metadata, ProgressMsgPortIterator) {
|
|
let (input_chan, input_port) = channel();
|
|
resource_task.send(ControlMsg::Load(LoadData::new(url, input_chan))).unwrap();
|
|
|
|
let response = input_port.recv().unwrap();
|
|
let iter = ProgressMsgPortIterator { progress_port: response.progress_port };
|
|
(response.metadata, iter)
|
|
}
|
|
|
|
/// Iterator that reads chunks of bytes from a ProgressMsg port
|
|
pub struct ProgressMsgPortIterator {
|
|
progress_port: Receiver<ProgressMsg>
|
|
}
|
|
|
|
impl Iterator for ProgressMsgPortIterator {
|
|
type Item = Vec<u8>;
|
|
|
|
fn next(&mut self) -> Option<Vec<u8>> {
|
|
match self.progress_port.recv().unwrap() {
|
|
ProgressMsg::Payload(data) => Some(data),
|
|
ProgressMsg::Done(Ok(())) => None,
|
|
ProgressMsg::Done(Err(e)) => {
|
|
error!("error receiving bytes: {}", e);
|
|
None
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|