author | Sam Giles <sam.e.giles@gmail.com> |
Thu, 09 Mar 2017 22:15:11 -0800 | |
changeset 346907 | 9c29dd17051ec2db36577c463449a87eb4255ea9 |
parent 346906 | b3eb8484454007d3a44be3a1d63cc15790d4fc09 |
child 346908 | 349830b775ae00c179133c8a9256b6338507f379 |
push id | 31480 |
push user | cbook@mozilla.com |
push date | Fri, 10 Mar 2017 10:37:06 +0000 |
treeherder | mozilla-central@e18d3dd20e8d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | Wafflespeanut |
milestone | 55.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
servo/components/net/http_loader.rs | file | annotate | diff | comparison | revisions | |
servo/tests/unit/net/http_loader.rs | file | annotate | diff | comparison | revisions |
--- a/servo/components/net/http_loader.rs +++ b/servo/components/net/http_loader.rs @@ -17,16 +17,17 @@ use hyper::LanguageTag; use hyper::client::{Pool, Request as HyperRequest, Response as HyperResponse}; use hyper::header::{AcceptEncoding, AcceptLanguage, AccessControlAllowCredentials}; use hyper::header::{AccessControlAllowOrigin, AccessControlAllowHeaders, AccessControlAllowMethods}; use hyper::header::{AccessControlRequestHeaders, AccessControlMaxAge, AccessControlRequestMethod}; use hyper::header::{Authorization, Basic, CacheControl, CacheDirective, ContentEncoding}; use hyper::header::{ContentLength, Encoding, Header, Headers, Host, IfMatch, IfRange}; use hyper::header::{IfUnmodifiedSince, IfModifiedSince, IfNoneMatch, Location, Pragma, Quality}; use hyper::header::{QualityItem, Referer, SetCookie, UserAgent, qitem}; +use hyper::header::Origin as HyperOrigin; use hyper::method::Method; use hyper::net::Fresh; use hyper::status::StatusCode; use hyper_serde::Serde; use log; use msg::constellation_msg::PipelineId; use net_traits::{CookieSource, FetchMetadata, NetworkError, ReferrerPolicy}; use net_traits::hosts::replace_hosts; @@ -780,16 +781,25 @@ fn http_redirect_fetch(request: Rc<Reque // Step 12 // TODO implement referrer policy // Step 13 main_fetch(request, cache, cors_flag, true, target, done_chan, context) } +fn try_immutable_origin_to_hyper_origin(url_origin: &ImmutableOrigin) -> Option<HyperOrigin> { + match *url_origin { + // TODO (servo/servo#15569) Set "Origin: null" when hyper supports it + ImmutableOrigin::Opaque(_) => None, + ImmutableOrigin::Tuple(ref scheme, ref host, ref port) => + Some(HyperOrigin::new(scheme.clone(), host.to_string(), Some(port.clone()))) + } +} + /// [HTTP network or cache fetch](https://fetch.spec.whatwg.org#http-network-or-cache-fetch) fn http_network_or_cache_fetch(request: Rc<Request>, authentication_fetch_flag: bool, cors_flag: bool, done_chan: &mut DoneChannel, context: &FetchContext) -> Response { // TODO: Implement Window enum for Request @@ -838,20 +848,26 @@ fn http_network_or_cache_fetch(request: http_request.headers.borrow_mut().set(Referer(http_request_referrer.to_string())), Referrer::Client => // it should be impossible for referrer to be anything else during fetching // https://fetch.spec.whatwg.org/#concept-request-referrer unreachable!() }; // Step 9 - if cors_flag || - (*http_request.method.borrow() != Method::Get && *http_request.method.borrow() != Method::Head) { - // TODO update this when https://github.com/hyperium/hyper/pull/691 is finished - // http_request.headers.borrow_mut().set_raw("origin", origin); + if !http_request.omit_origin_header.get() { + let method = http_request.method.borrow(); + if cors_flag || (*method != Method::Get && *method != Method::Head) { + debug_assert!(*http_request.origin.borrow() != Origin::Client); + if let Origin::Origin(ref url_origin) = *http_request.origin.borrow() { + if let Some(hyper_origin) = try_immutable_origin_to_hyper_origin(url_origin) { + http_request.headers.borrow_mut().set(hyper_origin) + } + } + } } // Step 10 if !http_request.headers.borrow().has::<UserAgent>() { let user_agent = context.user_agent.clone().into_owned(); http_request.headers.borrow_mut().set(UserAgent(user_agent)); }
--- a/servo/tests/unit/net/http_loader.rs +++ b/servo/tests/unit/net/http_loader.rs @@ -7,37 +7,38 @@ use devtools_traits::{ChromeToDevtoolsCo use devtools_traits::HttpRequest as DevtoolsHttpRequest; use devtools_traits::HttpResponse as DevtoolsHttpResponse; use fetch; use fetch_with_context; use flate2::Compression; use flate2::write::{DeflateEncoder, GzEncoder}; use hyper::LanguageTag; use hyper::header::{Accept, AcceptEncoding, ContentEncoding, ContentLength, Cookie as CookieHeader}; -use hyper::header::{AcceptLanguage, Authorization, Basic, Date}; -use hyper::header::{Encoding, Headers, Host, Location, Quality, QualityItem, SetCookie, qitem}; +use hyper::header::{AcceptLanguage, AccessControlAllowOrigin, Authorization, Basic, Date}; +use hyper::header::{Encoding, Headers, Host, Location, Origin, Quality, QualityItem, SetCookie, qitem}; use hyper::header::{StrictTransportSecurity, UserAgent}; use hyper::method::Method; use hyper::mime::{Mime, SubLevel, TopLevel}; use hyper::server::{Request as HyperRequest, Response as HyperResponse}; use hyper::status::StatusCode; use hyper::uri::RequestUri; use make_server; use msg::constellation_msg::TEST_PIPELINE_ID; use net::cookie::Cookie; use net::cookie_storage::CookieStorage; use net::resource_thread::AuthCacheEntry; use net_traits::{CookieSource, NetworkError}; use net_traits::hosts::replace_host_table; -use net_traits::request::{Request, RequestInit, CredentialsMode, Destination}; +use net_traits::request::{Request, RequestInit, RequestMode, CredentialsMode, Destination}; use net_traits::response::ResponseBody; use new_fetch_context; use servo_url::ServoUrl; use std::collections::HashMap; use std::io::{Read, Write}; +use std::str::FromStr; use std::sync::{Arc, Mutex, RwLock, mpsc}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::Receiver; fn read_response(reader: &mut Read) -> String { let mut buf = vec![0; 1024]; match reader.read(&mut buf) { Ok(len) if len > 0 => { @@ -140,18 +141,23 @@ fn test_check_default_headers_loaded_in_ origin: url.clone(), pipeline_id: Some(TEST_PIPELINE_ID), .. RequestInit::default() }); let response = fetch(request, None); assert!(response.status.unwrap().is_success()); // Testing for method.POST - headers.set(ContentLength(0 as u64)); - *expected_headers.lock().unwrap() = Some(headers.clone()); + let mut post_headers = headers.clone(); + post_headers.set(ContentLength(0 as u64)); + let url_str = url.as_str(); + // request gets header "Origin: http://example.com" but expected_headers has + // "Origin: http://example.com/" which do not match for equality so strip trailing '/' + post_headers.set(Origin::from_str(&url_str[..url_str.len()-1]).unwrap()); + *expected_headers.lock().unwrap() = Some(post_headers); let request = Request::from_init(RequestInit { url: url.clone(), method: Method::Post, destination: Destination::Document, origin: url.clone(), pipeline_id: Some(TEST_PIPELINE_ID), .. RequestInit::default() }); @@ -1112,8 +1118,66 @@ fn test_auth_ui_needs_www_auth() { }); let response = fetch(request, None); let _ = server.close(); assert_eq!(response.status.unwrap(), StatusCode::Unauthorized); } + +#[test] +fn test_origin_set() { + let origin_header = Arc::new(Mutex::new(None)); + let origin_header_clone = origin_header.clone(); + let handler = move |request: HyperRequest, mut resp: HyperResponse| { + let origin_header_clone = origin_header.clone(); + resp.headers_mut().set(AccessControlAllowOrigin::Any); + match request.headers.get::<Origin>() { + None => assert_eq!(origin_header_clone.lock().unwrap().take(), None), + Some(h) => assert_eq!(*h, origin_header_clone.lock().unwrap().take().unwrap()), + } + }; + let (mut server, url) = make_server(handler); + + let mut origin = Origin::new(url.scheme(), url.host_str().unwrap(), url.port()); + *origin_header_clone.lock().unwrap() = Some(origin.clone()); + let request = Request::from_init(RequestInit { + url: url.clone(), + method: Method::Post, + body: None, + origin: url.clone(), + .. RequestInit::default() + }); + let response = fetch(request, None); + assert!(response.status.unwrap().is_success()); + + let origin_url = ServoUrl::parse("http://example.com").unwrap(); + origin = Origin::new(origin_url.scheme(), origin_url.host_str().unwrap(), origin_url.port()); + // Test Origin header is set on Get request with CORS mode + let request = Request::from_init(RequestInit { + url: url.clone(), + method: Method::Get, + mode: RequestMode::CorsMode, + body: None, + origin: origin_url.clone(), + .. RequestInit::default() + }); + + *origin_header_clone.lock().unwrap() = Some(origin.clone()); + let response = fetch(request, None); + assert!(response.status.unwrap().is_success()); + + // Test Origin header is not set on method Head + let request = Request::from_init(RequestInit { + url: url.clone(), + method: Method::Head, + body: None, + origin: url.clone(), + .. RequestInit::default() + }); + + *origin_header_clone.lock().unwrap() = None; + let response = fetch(request, None); + assert!(response.status.unwrap().is_success()); + + let _ = server.close(); +}