Navigation Menu

Skip to content

Commit

Permalink
convert net crate to use hyper
Browse files Browse the repository at this point in the history
  • Loading branch information
seanmonstar authored and Manishearth committed Dec 4, 2014
1 parent 92a8c7a commit 12727d4
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 93 deletions.
4 changes: 2 additions & 2 deletions components/net/Cargo.toml
Expand Up @@ -13,8 +13,8 @@ path = "../util"
[dependencies.geom]
git = "https://github.com/servo/rust-geom"

[dependencies.http]
git = "https://github.com/servo/rust-http"
[dependencies.hyper]
git = "https://github.com/hyperium/hyper"
branch = "servo"

[dependencies.png]
Expand Down
4 changes: 2 additions & 2 deletions components/net/about_loader.rs
Expand Up @@ -7,7 +7,7 @@ use file_loader;

use std::io::fs::PathExtensions;
use url::Url;
use http::status::Ok as StatusOk;
use hyper::http::RawStatus;
use servo_util::resource_files::resources_dir_path;


Expand All @@ -23,7 +23,7 @@ pub fn factory(mut load_data: LoadData, start_chan: Sender<TargetedLoadResponse>
content_type: Some(("text".to_string(), "html".to_string())),
charset: Some("utf-8".to_string()),
headers: None,
status: Some(StatusOk),
status: Some(RawStatus(200, "OK".into_string()))
});
chan.send(Done(Ok(())));
return
Expand Down
7 changes: 3 additions & 4 deletions components/net/data_loader.rs
Expand Up @@ -6,8 +6,7 @@ use resource_task::{Done, Payload, Metadata, LoadData, TargetedLoadResponse, sta

use serialize::base64::FromBase64;

use http::headers::test_utils::from_stream_with_str;
use http::headers::content_type::MediaType;
use hyper::mime::Mime;
use url::{percent_decode, NonRelativeSchemeData};


Expand Down Expand Up @@ -59,8 +58,8 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {

// Parse the content type using rust-http.
// FIXME: this can go into an infinite loop! (rust-http #25)
let content_type: Option<MediaType> = from_stream_with_str(ct_str);
metadata.set_content_type(&content_type);
let content_type: Option<Mime> = from_str(ct_str);
metadata.set_content_type(content_type.as_ref());

let progress_chan = start_sending(senders, metadata);
let bytes = percent_decode(parts[1].as_bytes());
Expand Down
2 changes: 1 addition & 1 deletion components/net/fetch/cors_cache.rs
Expand Up @@ -9,7 +9,7 @@
//! This library will eventually become the core of the Fetch crate
//! with CORSRequest being expanded into FetchRequest (etc)

use http::method::Method;
use hyper::method::Method;
use std::ascii::AsciiExt;
use std::comm::{Sender, Receiver, channel};
use time;
Expand Down
12 changes: 7 additions & 5 deletions components/net/fetch/request.rs
Expand Up @@ -3,8 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use url::Url;
use http::method::{Get, Method};
use http::headers::request::HeaderCollection;
use hyper::method::{Get, Method};
use hyper::mime::{Mime, Text, Html, Charset, Utf8};
use hyper::header::Headers;
use hyper::header::common::ContentType;
use fetch::cors_cache::CORSCache;
use fetch::response::Response;

Expand Down Expand Up @@ -58,7 +60,7 @@ pub enum ResponseTainting {
pub struct Request {
pub method: Method,
pub url: Url,
pub headers: HeaderCollection,
pub headers: Headers,
pub unsafe_request: bool,
pub body: Option<Vec<u8>>,
pub preserve_content_codings: bool,
Expand Down Expand Up @@ -87,7 +89,7 @@ impl Request {
Request {
method: Get,
url: url,
headers: HeaderCollection::new(),
headers: Headers::new(),
unsafe_request: false,
body: None,
preserve_content_codings: false,
Expand Down Expand Up @@ -116,7 +118,7 @@ impl Request {
"about" => match self.url.non_relative_scheme_data() {
Some(s) if s.as_slice() == "blank" => {
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::network_error()
Expand Down
48 changes: 23 additions & 25 deletions components/net/fetch/response.rs
Expand Up @@ -3,11 +3,10 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use url::Url;
use http::status::{Status, UnregisteredStatus};
use http::status::Ok as StatusOk;
use http::headers::HeaderEnum;
use http::headers::response::HeaderCollection;
use std::ascii::OwnedAsciiExt;
use hyper::status::StatusCode;
use hyper::status::Ok as StatusOk;
use hyper::header::Headers;
use std::ascii::AsciiExt;
use std::comm::Receiver;

/// [Response type](http://fetch.spec.whatwg.org/#concept-response-type)
Expand Down Expand Up @@ -57,8 +56,9 @@ pub struct Response {
pub response_type: ResponseType,
pub termination_reason: Option<TerminationReason>,
pub url: Option<Url>,
pub status: Status,
pub headers: HeaderCollection,
/// `None` can be considered a StatusCode of `0`.
pub status: Option<StatusCode>,
pub headers: Headers,
pub body: ResponseBody,
/// [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>>,
Expand All @@ -70,8 +70,8 @@ impl Response {
response_type: Default,
termination_reason: None,
url: None,
status: StatusOk,
headers: HeaderCollection::new(),
status: Some(StatusOk),
headers: Headers::new(),
body: Empty,
internal_response: None
}
Expand All @@ -82,8 +82,8 @@ impl Response {
response_type: Error,
termination_reason: None,
url: None,
status: UnregisteredStatus(0, "".to_string()),
headers: HeaderCollection::new(),
status: None,
headers: Headers::new(),
body: Empty,
internal_response: None
}
Expand All @@ -110,32 +110,30 @@ impl Response {
match filter_type {
Default | Error => unreachable!(),
Basic => {
let mut headers = HeaderCollection::new();
for h in old_headers.iter() {
match h.header_name().into_ascii_lower().as_slice() {
"set-cookie" | "set-cookie2" => {},
_ => headers.insert(h)
let headers = old_headers.iter().filter(|header| {
match header.name().to_ascii_lower().as_slice() {
"set-cookie" | "set-cookie2" => false,
_ => true
}
}
}).collect();
response.headers = headers;
response.response_type = filter_type;
},
CORS => {
let mut headers = HeaderCollection::new();
for h in old_headers.iter() {
match h.header_name().into_ascii_lower().as_slice() {
let headers = old_headers.iter().filter(|header| {
match header.name().to_ascii_lower().as_slice() {
"cache-control" | "content-language" |
"content-type" | "expires" | "last-modified" | "Pragma" => {},
"content-type" | "expires" | "last-modified" | "Pragma" => false,
// XXXManishearth handle Access-Control-Expose-Headers
_ => headers.insert(h)
_ => true
}
}
}).collect();
response.headers = headers;
response.response_type = filter_type;
},
Opaque => {
response.headers = HeaderCollection::new();
response.status = UnregisteredStatus(0, "".to_string());
response.headers = Headers::new();
response.status = None;
response.body = Empty;
}
}
Expand Down
92 changes: 62 additions & 30 deletions components/net/http_loader.rs
Expand Up @@ -6,11 +6,13 @@ use resource_task::{Metadata, Payload, Done, TargetedLoadResponse, LoadData, sta

use log;
use std::collections::HashSet;
use http::client::{RequestWriter, NetworkStream};
use http::headers::HeaderEnum;
use hyper::client::Request;
use hyper::header::common::{ContentLength, ContentType, Host, Location};
use hyper::method::{Get, Head};
use hyper::status::Redirection;
use std::io::Reader;
use servo_util::task::spawn_named;
use url::Url;
use url::{Url, UrlParser};

pub fn factory(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
spawn_named("http_loader", proc() load(load_data, start_chan))
Expand Down Expand Up @@ -67,55 +69,75 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {

info!("requesting {:s}", url.serialize());

let request = RequestWriter::<NetworkStream>::new(load_data.method.clone(), url.clone());
let mut writer = match request {
Ok(w) => box w,
let mut req = match Request::new(load_data.method.clone(), url.clone()) {
Ok(req) => req,
Err(e) => {
send_error(url, e.desc.to_string(), senders);
send_error(url, e.to_string(), senders);
return;
}
};

// Preserve the `host` header set automatically by RequestWriter.
let host = writer.headers.host.clone();
writer.headers = load_data.headers.clone();
writer.headers.host = host;
if writer.headers.accept_encoding.is_none() {
// Preserve the `host` header set automatically by Request.
let host = req.headers().get::<Host>().unwrap().clone();
*req.headers_mut() = load_data.headers.clone();
req.headers_mut().set(host);
// FIXME(seanmonstar): use AcceptEncoding from Hyper once available
//if !req.headers.has::<AcceptEncoding>() {
// We currently don't support HTTP Compression (FIXME #2587)
writer.headers.accept_encoding = Some(String::from_str("identity".as_slice()))
}
match load_data.data {
req.headers_mut().set_raw("Accept-Encoding", vec![b"identity".to_vec()]);
//}
let writer = match load_data.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()) {
Err(e) => {
send_error(url, e.desc.to_string(), senders);
return;
}
_ => {}
}
};
writer
},
_ => {}
}
let mut response = match writer.read_response() {
None => {
match load_data.method {
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,
Err((_, e)) => {
send_error(url, e.desc.to_string(), senders);
Err(e) => {
send_error(url, e.to_string(), senders);
return;
}
};

// 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) {
for header in response.headers.iter() {
info!(" - {:s}: {:s}", header.header_name(), header.header_value());
info!(" - {}", header);
}
}

if 3 == (response.status.code() / 100) {
match response.headers.location {
Some(new_url) => {
if response.status.class() == Redirection {
match response.headers.get::<Location>() {
Some(&Location(ref new_url)) => {
// CORS (http://fetch.spec.whatwg.org/#http-fetch, status section, point 9, 10)
match load_data.cors {
Some(ref c) => {
Expand All @@ -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;
continue;
}
Expand All @@ -139,9 +168,12 @@ fn load(load_data: LoadData, start_chan: Sender<TargetedLoadResponse>) {
}

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.status = Some(response.status.clone());
metadata.status = Some(response.status_raw().clone());

let progress_chan = match start_sending_opt(senders, metadata) {
Ok(p) => p,
Expand Down
2 changes: 1 addition & 1 deletion components/net/lib.rs
Expand Up @@ -9,7 +9,7 @@

extern crate collections;
extern crate geom;
extern crate http;
extern crate hyper;
extern crate png;
#[phase(plugin, link)]
extern crate log;
Expand Down

0 comments on commit 12727d4

Please sign in to comment.