diff --git a/components/net/fetch/request.rs b/components/net/fetch/request.rs index 90a282746222..39af7aeb68b1 100644 --- a/components/net/fetch/request.rs +++ b/components/net/fetch/request.rs @@ -116,7 +116,7 @@ pub struct Request { pub origin: Option, // FIXME: Use Url::Origin pub force_origin_header: bool, pub omit_origin_header: bool, - pub same_origin_data: bool, + pub same_origin_data: Cell, pub referer: Referer, pub authentication: bool, pub sync: bool, @@ -145,7 +145,7 @@ impl Request { origin: None, force_origin_header: false, omit_origin_header: false, - same_origin_data: false, + same_origin_data: Cell::new(false), referer: Referer::Client, authentication: false, sync: false, @@ -235,8 +235,8 @@ pub fn fetch(request: Rc, cors_flag: bool) -> Response { /// [Main fetch](https://fetch.spec.whatwg.org/#concept-main-fetch) fn main_fetch(request: Rc, _cors_flag: bool) -> Response { // TODO: Implement main fetch spec - let _ = basic_fetch(request); - Response::network_error() + let response = basic_fetch(request); + response } /// [Basic fetch](https://fetch.spec.whatwg.org#basic-fetch) @@ -305,6 +305,7 @@ fn http_fetch(request: Rc, if !request.skip_service_worker.get() && !request.is_service_worker_global_scope { // TODO: Substep 1 (handle fetch unimplemented) + if let Some(ref res) = response { // Substep 2 @@ -361,7 +362,7 @@ fn http_fetch(request: Rc, destination: url.clone(), credentials: credentials }, view.name()) && !is_simple_header(&view) - ); + ); if method_mismatch || header_mismatch { let preflight_result = preflight_fetch(request.clone()); @@ -396,10 +397,11 @@ fn http_fetch(request: Rc, actual_response = response.clone(); } - // Step 5 - let actual_response = Rc::try_unwrap(actual_response.unwrap()).ok().unwrap(); - let mut response = Rc::try_unwrap(response.unwrap()).ok().unwrap(); + // response and actual_response are guaranteed to be something by now + let mut response = response.unwrap(); + let actual_response = actual_response.unwrap(); + // Step 5 match actual_response.status.unwrap() { // Code 301, 302, 303, 307, 308 @@ -411,13 +413,16 @@ fn http_fetch(request: Rc, return Response::network_error(); } - // Step 2-4 + // Step 3 if !actual_response.headers.has::() { - return actual_response; + drop(actual_response); + return Rc::try_unwrap(response).ok().unwrap(); } + // Step 2 let location = match actual_response.headers.get::() { Some(&Location(ref location)) => location.clone(), + // Step 4 _ => return Response::network_error(), }; @@ -426,7 +431,6 @@ fn http_fetch(request: Rc, // Step 6 let location_url = match location_url { - Ok(ref url) if url.scheme == "data" => { return Response::network_error(); } Ok(url) => url, _ => { return Response::network_error(); } }; @@ -439,14 +443,17 @@ fn http_fetch(request: Rc, // Step 8 request.redirect_count.set(request.redirect_count.get() + 1); + // Step 9 + request.same_origin_data.set(false); + match request.redirect_mode { - // Step 9 + // Step 10 RedirectMode::Manual => { - response = actual_response.to_filtered(ResponseType::Opaque); + response = Rc::new(Response::to_filtered(actual_response, ResponseType::Opaque)); } - // Step 10 + // Step 11 RedirectMode::Follow => { // Substep 1 @@ -493,7 +500,8 @@ fn http_fetch(request: Rc, // Step 1 // FIXME: Figure out what to do with request window objects if cors_flag { - return response; + drop(actual_response); + return Rc::try_unwrap(response).ok().unwrap(); } // Step 2 @@ -526,7 +534,7 @@ fn http_fetch(request: Rc, authentication_fetch_flag); } - _ => { } + _ => drop(actual_response) } // Step 6 @@ -535,7 +543,7 @@ fn http_fetch(request: Rc, } // Step 7 - response + Rc::try_unwrap(response).ok().unwrap() } /// [HTTP network or cache fetch](https://fetch.spec.whatwg.org#http-network-or-cache-fetch) @@ -744,10 +752,7 @@ fn http_network_fetch(request: Rc, let cancellation_listener = CancellationListener::new(None); let wrapped_response = obtain_response(&factory, &url, &request.method.borrow(), - // TODO nikkisquared: use this line instead - // after merging with another branch - // &request.headers.borrow() - &mut *request.headers.borrow_mut(), + &request.headers.borrow(), &cancellation_listener, &None, &request.method.borrow(), &None, request.redirect_count.get(), &None, ""); diff --git a/components/net/fetch/response.rs b/components/net/fetch/response.rs index 42e5fe414abe..64200ae91de2 100644 --- a/components/net/fetch/response.rs +++ b/components/net/fetch/response.rs @@ -13,7 +13,7 @@ use url::Url; pub trait ResponseMethods { fn new() -> Response; - fn to_filtered(self, ResponseType) -> Response; + fn to_filtered(Rc, ResponseType) -> Response; } impl ResponseMethods for Response { @@ -34,17 +34,23 @@ impl ResponseMethods for Response { /// Convert to a filtered response, of type `filter_type`. /// Do not use with type Error or Default - fn to_filtered(self, filter_type: ResponseType) -> Response { + fn to_filtered(old_response: Rc, filter_type: ResponseType) -> Response { + assert!(filter_type != ResponseType::Error); assert!(filter_type != ResponseType::Default); - if self.is_network_error() { - return self; + + if Response::is_network_error(&old_response) { + return Response::network_error(); } - let old_headers = self.headers.clone(); - let mut response = self.clone(); - response.internal_response = Some(Rc::new(self)); + + let old_headers = old_response.headers.clone(); + let mut response = (*old_response).clone(); + response.internal_response = Some(old_response); + match filter_type { + ResponseType::Default | ResponseType::Error => unreachable!(), + ResponseType::Basic => { let headers = old_headers.iter().filter(|header| { match &*header.name().to_ascii_lowercase() { @@ -55,6 +61,7 @@ impl ResponseMethods for Response { response.headers = headers; response.response_type = filter_type; }, + ResponseType::CORS => { let headers = old_headers.iter().filter(|header| { match &*header.name().to_ascii_lowercase() { @@ -67,6 +74,7 @@ impl ResponseMethods for Response { response.headers = headers; response.response_type = filter_type; }, + ResponseType::Opaque | ResponseType::OpaqueRedirect => { response.headers = Headers::new(); @@ -74,6 +82,7 @@ impl ResponseMethods for Response { response.body = ResponseBody::Empty; } } + response } } diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 88ccd2868256..64c732446dbb 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -554,7 +554,7 @@ pub fn process_response_headers(response: &HttpResponse, pub fn obtain_response(request_factory: &HttpRequestFactory, url: &Url, method: &Method, - request_headers: &mut Headers, + request_headers: &Headers, cancel_listener: &CancellationListener, data: &Option>, load_data_method: &Method, @@ -706,7 +706,7 @@ pub fn load(load_data: LoadData, modify_request_headers(&mut request_headers, &doc_url, &user_agent, &cookie_jar, &load_data); - let response = try!(obtain_response(request_factory, &url, &method, &mut request_headers, + let response = try!(obtain_response(request_factory, &url, &method, &request_headers, &cancel_listener, &load_data.data, &load_data.method, &load_data.pipeline_id, iters, &devtools_chan, &request_id)); diff --git a/tests/unit/net/fetch.rs b/tests/unit/net/fetch.rs new file mode 100644 index 000000000000..85dccf716f6c --- /dev/null +++ b/tests/unit/net/fetch.rs @@ -0,0 +1,44 @@ +/* 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/. */ + +use hyper::server::{Listening, Server}; +use hyper::server::{Request as HyperRequest, Response as HyperResponse}; +use net::fetch::request::{Context, fetch, Referer, Request}; +use net_traits::response::{Response}; +use std::rc::Rc; +use url::Url; + +fn make_server(message: &'static [u8]) -> (Listening, Url) { + + let handler = move |_: HyperRequest, response: HyperResponse| { + response.send(message).unwrap(); + }; + + // this is a Listening server because of handle_threads() + let server = Server::http("0.0.0.0:0").unwrap().handle_threads(handler, 1).unwrap(); + let port = server.socket.port().to_string(); + let mut url_string = "http://localhost:".to_owned(); + url_string.push_str(&port); + let url = Url::parse(&url_string).unwrap(); + (server, url) +} + + +#[test] +fn test_fetch_response_is_not_network_error() { + + static MESSAGE: &'static [u8] = b""; + let (mut server, url) = make_server(MESSAGE); + + let mut request = Request::new(url, Context::Fetch, false); + request.referer = Referer::NoReferer; + let wrapped_request = Rc::new(request); + + let fetch_response = fetch(wrapped_request, false); + let _ = server.close(); + + if Response::is_network_error(&fetch_response) { + panic!("fetch response shouldn't be a network error"); + } +} diff --git a/tests/unit/net/lib.rs b/tests/unit/net/lib.rs index 7cc340dc3ca2..1e4d522b7899 100644 --- a/tests/unit/net/lib.rs +++ b/tests/unit/net/lib.rs @@ -19,6 +19,7 @@ extern crate util; #[cfg(test)] mod cookie; #[cfg(test)] mod data_loader; +#[cfg(test)] mod fetch; #[cfg(test)] mod mime_classifier; #[cfg(test)] mod resource_thread; #[cfg(test)] mod hsts;