convert net crate to use hyper

This commit is contained in:
Sean McArthur 2014-11-14 11:57:32 -08:00 committed by Manish Goregaokar
parent 92a8c7a80c
commit 12727d4dd0
10 changed files with 164 additions and 93 deletions

View file

@ -13,8 +13,8 @@ path = "../util"
[dependencies.geom] [dependencies.geom]
git = "https://github.com/servo/rust-geom" git = "https://github.com/servo/rust-geom"
[dependencies.http] [dependencies.hyper]
git = "https://github.com/servo/rust-http" git = "https://github.com/hyperium/hyper"
branch = "servo" branch = "servo"
[dependencies.png] [dependencies.png]

View file

@ -7,7 +7,7 @@ use file_loader;
use std::io::fs::PathExtensions; use std::io::fs::PathExtensions;
use url::Url; use url::Url;
use http::status::Ok as StatusOk; use hyper::http::RawStatus;
use servo_util::resource_files::resources_dir_path; use servo_util::resource_files::resources_dir_path;
@ -23,7 +23,7 @@ pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>
content_type: Some(("text".to_string(), "html".to_string())), content_type: Some(("text".to_string(), "html".to_string())),
charset: Some("utf-8".to_string()), charset: Some("utf-8".to_string()),
headers: None, headers: None,
status: Some(StatusOk), status: Some(RawStatus(200, "OK".into_string()))
}); });
chan.send(Done(Ok(()))); chan.send(Done(Ok(())));
return return

View file

@ -6,8 +6,7 @@ use resource_task::{Done, Payload, Metadata, LoadData, TargetedLoadResponse, sta
use serialize::base64::FromBase64; use serialize::base64::FromBase64;
use http::headers::test_utils::from_stream_with_str; use hyper::mime::Mime;
use http::headers::content_type::MediaType;
use url::{percent_decode, NonRelativeSchemeData}; use url::{percent_decode, NonRelativeSchemeData};
@ -59,8 +58,8 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
// Parse the content type using rust-http. // Parse the content type using rust-http.
// FIXME: this can go into an infinite loop! (rust-http #25) // FIXME: this can go into an infinite loop! (rust-http #25)
let content_type: Option<MediaType> = from_stream_with_str(ct_str); let content_type: Option<Mime> = from_str(ct_str);
metadata.set_content_type(&content_type); metadata.set_content_type(content_type.as_ref());
let progress_chan = start_sending(senders, metadata); let progress_chan = start_sending(senders, metadata);
let bytes = percent_decode(parts[1].as_bytes()); let bytes = percent_decode(parts[1].as_bytes());

View file

@ -9,7 +9,7 @@
//! This library will eventually become the core of the Fetch crate //! This library will eventually become the core of the Fetch crate
//! with CORSRequest being expanded into FetchRequest (etc) //! with CORSRequest being expanded into FetchRequest (etc)
use http::method::Method; use hyper::method::Method;
use std::ascii::AsciiExt; use std::ascii::AsciiExt;
use std::comm::{Sender, Receiver, channel}; use std::comm::{Sender, Receiver, channel};
use time; use time;

View file

@ -3,8 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use url::Url; use url::Url;
use http::method::{Get, Method}; use hyper::method::{Get, Method};
use http::headers::request::HeaderCollection; use hyper::mime::{Mime, Text, Html, Charset, Utf8};
use hyper::header::Headers;
use hyper::header::common::ContentType;
use fetch::cors_cache::CORSCache; use fetch::cors_cache::CORSCache;
use fetch::response::Response; use fetch::response::Response;
@ -58,7 +60,7 @@ pub enum ResponseTainting {
pub struct Request { pub struct Request {
pub method: Method, pub method: Method,
pub url: Url, pub url: Url,
pub headers: HeaderCollection, pub headers: Headers,
pub unsafe_request: bool, pub unsafe_request: bool,
pub body: Option<Vec<u8>>, pub body: Option<Vec<u8>>,
pub preserve_content_codings: bool, pub preserve_content_codings: bool,
@ -87,7 +89,7 @@ impl Request {
Request { Request {
method: Get, method: Get,
url: url, url: url,
headers: HeaderCollection::new(), headers: Headers::new(),
unsafe_request: false, unsafe_request: false,
body: None, body: None,
preserve_content_codings: false, preserve_content_codings: false,
@ -116,7 +118,7 @@ impl Request {
"about" => match self.url.non_relative_scheme_data() { "about" => match self.url.non_relative_scheme_data() {
Some(s) if s.as_slice() == "blank" => { Some(s) if s.as_slice() == "blank" => {
let mut response = Response::new(); let mut response = Response::new();
let _ = response.headers.insert_raw("Content-Type".to_string(), b"text/html;charset=utf-8"); response.headers.set(ContentType(Mime(Text, Html, vec![(Charset, Utf8)])));
response response
}, },
_ => Response::network_error() _ => Response::network_error()

View file

@ -3,11 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use url::Url; use url::Url;
use http::status::{Status, UnregisteredStatus}; use hyper::status::StatusCode;
use http::status::Ok as StatusOk; use hyper::status::Ok as StatusOk;
use http::headers::HeaderEnum; use hyper::header::Headers;
use http::headers::response::HeaderCollection; use std::ascii::AsciiExt;
use std::ascii::OwnedAsciiExt;
use std::comm::Receiver; use std::comm::Receiver;
/// [Response type](http://fetch.spec.whatwg.org/#concept-response-type) /// [Response type](http://fetch.spec.whatwg.org/#concept-response-type)
@ -57,8 +56,9 @@ pub struct Response {
pub response_type: ResponseType, pub response_type: ResponseType,
pub termination_reason: Option<TerminationReason>, pub termination_reason: Option<TerminationReason>,
pub url: Option<Url>, pub url: Option<Url>,
pub status: Status, /// `None` can be considered a StatusCode of `0`.
pub headers: HeaderCollection, pub status: Option<StatusCode>,
pub headers: Headers,
pub body: ResponseBody, pub body: ResponseBody,
/// [Internal response](http://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response is a filtered response /// [Internal response](http://fetch.spec.whatwg.org/#concept-internal-response), only used if the Response is a filtered response
pub internal_response: Option<Box<Response>>, pub internal_response: Option<Box<Response>>,
@ -70,8 +70,8 @@ impl Response {
response_type: Default, response_type: Default,
termination_reason: None, termination_reason: None,
url: None, url: None,
status: StatusOk, status: Some(StatusOk),
headers: HeaderCollection::new(), headers: Headers::new(),
body: Empty, body: Empty,
internal_response: None internal_response: None
} }
@ -82,8 +82,8 @@ impl Response {
response_type: Error, response_type: Error,
termination_reason: None, termination_reason: None,
url: None, url: None,
status: UnregisteredStatus(0, "".to_string()), status: None,
headers: HeaderCollection::new(), headers: Headers::new(),
body: Empty, body: Empty,
internal_response: None internal_response: None
} }
@ -110,32 +110,30 @@ impl Response {
match filter_type { match filter_type {
Default | Error => unreachable!(), Default | Error => unreachable!(),
Basic => { Basic => {
let mut headers = HeaderCollection::new(); let headers = old_headers.iter().filter(|header| {
for h in old_headers.iter() { match header.name().to_ascii_lower().as_slice() {
match h.header_name().into_ascii_lower().as_slice() { "set-cookie" | "set-cookie2" => false,
"set-cookie" | "set-cookie2" => {}, _ => true
_ => headers.insert(h)
} }
} }).collect();
response.headers = headers; response.headers = headers;
response.response_type = filter_type; response.response_type = filter_type;
}, },
CORS => { CORS => {
let mut headers = HeaderCollection::new(); let headers = old_headers.iter().filter(|header| {
for h in old_headers.iter() { match header.name().to_ascii_lower().as_slice() {
match h.header_name().into_ascii_lower().as_slice() {
"cache-control" | "content-language" | "cache-control" | "content-language" |
"content-type" | "expires" | "last-modified" | "Pragma" => {}, "content-type" | "expires" | "last-modified" | "Pragma" => false,
// XXXManishearth handle Access-Control-Expose-Headers // XXXManishearth handle Access-Control-Expose-Headers
_ => headers.insert(h) _ => true
} }
} }).collect();
response.headers = headers; response.headers = headers;
response.response_type = filter_type; response.response_type = filter_type;
}, },
Opaque => { Opaque => {
response.headers = HeaderCollection::new(); response.headers = Headers::new();
response.status = UnregisteredStatus(0, "".to_string()); response.status = None;
response.body = Empty; response.body = Empty;
} }
} }

View file

@ -6,11 +6,13 @@ use resource_task::{Metadata, Payload, Done, TargetedLoadResponse, LoadData, sta
use log; use log;
use std::collections::HashSet; use std::collections::HashSet;
use http::client::{RequestWriter, NetworkStream}; use hyper::client::Request;
use http::headers::HeaderEnum; use hyper::header::common::{ContentLength, ContentType, Host, Location};
use hyper::method::{Get, Head};
use hyper::status::Redirection;
use std::io::Reader; use std::io::Reader;
use servo_util::task::spawn_named; use servo_util::task::spawn_named;
use url::Url; use url::{Url, UrlParser};
pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) { pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
spawn_named("http_loader", proc() load(load_data, start_chan)) spawn_named("http_loader", proc() load(load_data, start_chan))
@ -67,55 +69,75 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
info!("requesting {:s}", url.serialize()); info!("requesting {:s}", url.serialize());
let request = RequestWriter::<NetworkStream>::new(load_data.method.clone(), url.clone()); let mut req = match Request::new(load_data.method.clone(), url.clone()) {
let mut writer = match request { Ok(req) => req,
Ok(w) => box w,
Err(e) => { Err(e) => {
send_error(url, e.desc.to_string(), senders); send_error(url, e.to_string(), senders);
return; return;
} }
}; };
// Preserve the `host` header set automatically by RequestWriter. // Preserve the `host` header set automatically by Request.
let host = writer.headers.host.clone(); let host = req.headers().get::<Host>().unwrap().clone();
writer.headers = load_data.headers.clone(); *req.headers_mut() = load_data.headers.clone();
writer.headers.host = host; req.headers_mut().set(host);
if writer.headers.accept_encoding.is_none() { // FIXME(seanmonstar): use AcceptEncoding from Hyper once available
//if !req.headers.has::<AcceptEncoding>() {
// We currently don't support HTTP Compression (FIXME #2587) // We currently don't support HTTP Compression (FIXME #2587)
writer.headers.accept_encoding = Some(String::from_str("identity".as_slice())) req.headers_mut().set_raw("Accept-Encoding", vec![b"identity".to_vec()]);
} //}
match load_data.data { let writer = match load_data.data {
Some(ref data) => { Some(ref data) => {
writer.headers.content_length = Some(data.len()); req.headers_mut().set(ContentLength(data.len()));
let mut writer = match req.start() {
Ok(w) => w,
Err(e) => {
send_error(url, e.to_string(), senders);
return;
}
};
match writer.write(data.as_slice()) { match writer.write(data.as_slice()) {
Err(e) => { Err(e) => {
send_error(url, e.desc.to_string(), senders); send_error(url, e.desc.to_string(), senders);
return; return;
} }
_ => {} _ => {}
} };
writer
}, },
_ => {} None => {
} match load_data.method {
let mut response = match writer.read_response() { Get | Head => (),
_ => req.headers_mut().set(ContentLength(0))
}
match req.start() {
Ok(w) => w,
Err(e) => {
send_error(url, e.to_string(), senders);
return;
}
}
}
};
let mut response = match writer.send() {
Ok(r) => r, Ok(r) => r,
Err((_, e)) => { Err(e) => {
send_error(url, e.desc.to_string(), senders); send_error(url, e.to_string(), senders);
return; return;
} }
}; };
// Dump headers, but only do the iteration if info!() is enabled. // Dump headers, but only do the iteration if info!() is enabled.
info!("got HTTP response {:s}, headers:", response.status.to_string()); info!("got HTTP response {}, headers:", response.status);
if log_enabled!(log::INFO) { if log_enabled!(log::INFO) {
for header in response.headers.iter() { for header in response.headers.iter() {
info!(" - {:s}: {:s}", header.header_name(), header.header_value()); info!(" - {}", header);
} }
} }
if 3 == (response.status.code() / 100) { if response.status.class() == Redirection {
match response.headers.location { match response.headers.get::<Location>() {
Some(new_url) => { Some(&Location(ref new_url)) => {
// CORS (http://fetch.spec.whatwg.org/#http-fetch, status section, point 9, 10) // CORS (http://fetch.spec.whatwg.org/#http-fetch, status section, point 9, 10)
match load_data.cors { match load_data.cors {
Some(ref c) => { Some(ref c) => {
@ -130,7 +152,14 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
} }
_ => {} _ => {}
} }
info!("redirecting to {:s}", new_url.serialize()); let new_url = match UrlParser::new().base_url(&url).parse(new_url.as_slice()) {
Ok(u) => u,
Err(e) => {
send_error(url, e.to_string(), senders);
return;
}
};
info!("redirecting to {}", new_url);
url = new_url; url = new_url;
continue; continue;
} }
@ -139,9 +168,12 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
} }
let mut metadata = Metadata::default(url); let mut metadata = Metadata::default(url);
metadata.set_content_type(&response.headers.content_type); metadata.set_content_type(match response.headers.get() {
Some(&ContentType(ref mime)) => Some(mime),
None => None
});
metadata.headers = Some(response.headers.clone()); metadata.headers = Some(response.headers.clone());
metadata.status = Some(response.status.clone()); metadata.status = Some(response.status_raw().clone());
let progress_chan = match start_sending_opt(senders, metadata) { let progress_chan = match start_sending_opt(senders, metadata) {
Ok(p) => p, Ok(p) => p,

View file

@ -9,7 +9,7 @@
extern crate collections; extern crate collections;
extern crate geom; extern crate geom;
extern crate http; extern crate hyper;
extern crate png; extern crate png;
#[phase(plugin, link)] #[phase(plugin, link)]
extern crate log; extern crate log;

View file

@ -12,14 +12,13 @@ use sniffer_task;
use sniffer_task::SnifferTask; use sniffer_task::SnifferTask;
use std::comm::{channel, Receiver, Sender}; use std::comm::{channel, Receiver, Sender};
use http::headers::content_type::MediaType; use hyper::mime::{Mime, Charset};
use http::headers::response::HeaderCollection as ResponseHeaderCollection; use hyper::header::Headers;
use http::headers::request::HeaderCollection as RequestHeaderCollection; use hyper::header::common::UserAgent;
use http::method::{Method, Get}; use hyper::method::{Method, Get};
use url::Url; use url::Url;
use http::status::Ok as StatusOk; use hyper::http::RawStatus;
use http::status::Status;
use servo_util::task::spawn_named; use servo_util::task::spawn_named;
@ -33,7 +32,7 @@ pub enum ControlMsg {
pub struct LoadData { pub struct LoadData {
pub url: Url, pub url: Url,
pub method: Method, pub method: Method,
pub headers: RequestHeaderCollection, pub headers: Headers,
pub data: Option<Vec<u8>>, pub data: Option<Vec<u8>>,
pub cors: Option<ResourceCORSData>, pub cors: Option<ResourceCORSData>,
pub consumer: Sender<LoadResponse>, pub consumer: Sender<LoadResponse>,
@ -44,7 +43,7 @@ impl LoadData {
LoadData { LoadData {
url: url, url: url,
method: Get, method: Get,
headers: RequestHeaderCollection::new(), headers: Headers::new(),
data: None, data: None,
cors: None, cors: None,
consumer: consumer, consumer: consumer,
@ -72,10 +71,10 @@ pub struct Metadata {
pub charset: Option<String>, pub charset: Option<String>,
/// Headers /// Headers
pub headers: Option<ResponseHeaderCollection>, pub headers: Option<Headers>,
/// HTTP Status /// HTTP Status
pub status: Option<Status> pub status: Option<RawStatus>
} }
impl Metadata { impl Metadata {
@ -86,21 +85,19 @@ impl Metadata {
content_type: None, content_type: None,
charset: None, charset: None,
headers: None, headers: None,
status: Some(StatusOk) // http://fetch.spec.whatwg.org/#concept-response-status-message status: Some(RawStatus(200, "OK".into_string())) // http://fetch.spec.whatwg.org/#concept-response-status-message
} }
} }
/// Extract the parts of a MediaType that we care about. /// Extract the parts of a Mime that we care about.
pub fn set_content_type(&mut self, content_type: &Option<MediaType>) { pub fn set_content_type(&mut self, content_type: Option<&Mime>) {
match *content_type { match content_type {
None => (), None => (),
Some(MediaType { ref type_, Some(&Mime(ref type_, ref subtype, ref parameters)) => {
ref subtype, self.content_type = Some((type_.to_string(), subtype.to_string()));
ref parameters }) => {
self.content_type = Some((type_.clone(), subtype.clone()));
for &(ref k, ref v) in parameters.iter() { for &(ref k, ref v) in parameters.iter() {
if "charset" == k.as_slice() { if &Charset == k {
self.charset = Some(v.clone()); self.charset = Some(v.to_string());
} }
} }
} }
@ -224,7 +221,7 @@ impl ResourceManager {
fn load(&self, load_data: LoadData) { fn load(&self, load_data: LoadData) {
let mut load_data = load_data; let mut load_data = load_data;
load_data.headers.user_agent = self.user_agent.clone(); self.user_agent.map(|ref ua| load_data.headers.set(UserAgent(ua.clone())));
let senders = ResponseSenders { let senders = ResponseSenders {
immediate_consumer: self.sniffer_task.clone(), immediate_consumer: self.sniffer_task.clone(),
eventual_consumer: load_data.consumer.clone(), eventual_consumer: load_data.consumer.clone(),

View file

@ -87,6 +87,15 @@ dependencies = [
"util 0.0.1", "util 0.0.1",
] ]
[[package]]
name = "cookie"
version = "0.0.1"
source = "git+https://github.com/alexcrichton/cookie-rs#9b579dd9b8cf0624eee1d013e9b48577acd3c40e"
dependencies = [
"openssl 0.0.0 (git+https://github.com/sfackler/rust-openssl.git)",
"url 0.1.0 (git+https://github.com/servo/rust-url)",
]
[[package]] [[package]]
name = "core_foundation" name = "core_foundation"
version = "0.1.0" version = "0.1.0"
@ -353,6 +362,20 @@ dependencies = [
"url 0.1.0 (git+https://github.com/servo/rust-url)", "url 0.1.0 (git+https://github.com/servo/rust-url)",
] ]
[[package]]
name = "hyper"
version = "0.0.1"
source = "git+https://github.com/hyperium/hyper?ref=servo#414a302f6333abd4b2ae38ea328bc41f8ca8fdbe"
dependencies = [
"cookie 0.0.1 (git+https://github.com/alexcrichton/cookie-rs)",
"mime 0.0.1 (git+https://github.com/hyperium/mime.rs)",
"move-acceptor 0.0.1 (git+https://github.com/reem/rust-move-acceptor)",
"openssl 0.0.0 (git+https://github.com/sfackler/rust-openssl.git)",
"typeable 0.0.1 (git+https://github.com/reem/rust-typeable)",
"unsafe-any 0.1.0 (git+https://github.com/reem/rust-unsafe-any)",
"url 0.1.0 (git+https://github.com/servo/rust-url)",
]
[[package]] [[package]]
name = "io_surface" name = "io_surface"
version = "0.1.0" version = "0.1.0"
@ -427,6 +450,16 @@ name = "lazy_static"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/Kimundi/lazy-static.rs#62976cb611c5396e11315ae64c9c389576240eb7" source = "git+https://github.com/Kimundi/lazy-static.rs#62976cb611c5396e11315ae64c9c389576240eb7"
[[package]]
name = "mime"
version = "0.0.1"
source = "git+https://github.com/hyperium/mime.rs#467c271814d51659f12de88f87dcd3dc3280ee9b"
[[package]]
name = "move-acceptor"
version = "0.0.1"
source = "git+https://github.com/reem/rust-move-acceptor#25c5c33a83f605fdd0f3d37d2589e2b0b4e6cbd1"
[[package]] [[package]]
name = "mozjs-sys" name = "mozjs-sys"
version = "0.0.0" version = "0.0.0"
@ -451,7 +484,7 @@ name = "net"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"geom 0.1.0 (git+https://github.com/servo/rust-geom)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
"http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo)", "hyper 0.0.1 (git+https://github.com/hyperium/hyper?ref=servo)",
"png 0.1.0 (git+https://github.com/servo/rust-png)", "png 0.1.0 (git+https://github.com/servo/rust-png)",
"stb_image 0.1.0 (git+https://github.com/servo/rust-stb-image)", "stb_image 0.1.0 (git+https://github.com/servo/rust-stb-image)",
"url 0.1.0 (git+https://github.com/servo/rust-url)", "url 0.1.0 (git+https://github.com/servo/rust-url)",
@ -512,7 +545,7 @@ dependencies = [
"geom 0.1.0 (git+https://github.com/servo/rust-geom)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)",
"gfx 0.0.1", "gfx 0.0.1",
"html5ever 0.0.0 (git+https://github.com/servo/html5ever?ref=servo)", "html5ever 0.0.0 (git+https://github.com/servo/html5ever?ref=servo)",
"http 0.1.0-pre (git+https://github.com/servo/rust-http?ref=servo)", "hyper 0.0.1 (git+https://github.com/hyperium/hyper?ref=servo)",
"js 0.1.0 (git+https://github.com/servo/rust-mozjs)", "js 0.1.0 (git+https://github.com/servo/rust-mozjs)",
"msg 0.0.1", "msg 0.0.1",
"net 0.0.1", "net 0.0.1",
@ -596,6 +629,16 @@ dependencies = [
name = "task_info" name = "task_info"
version = "0.0.1" version = "0.0.1"
name = "typeable"
version = "0.0.1"
source = "git+https://github.com/reem/rust-typeable#55154e1809db8ceec8f8519bdbb638c2fbd712f5"
[[package]]
name = "unsafe-any"
version = "0.1.0"
source = "git+https://github.com/reem/rust-unsafe-any#2863af363bbd83079b6773920bba5b736408db33"
[[package]] [[package]]
name = "url" name = "url"
version = "0.1.0" version = "0.1.0"