diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index 91bf0b643f3..9ffc95b8620 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -22,6 +22,7 @@ use hyper::header::{Authorization, Basic, CacheControl, CacheDirective, ContentE 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; @@ -785,6 +786,15 @@ fn http_redirect_fetch(request: Rc, main_fetch(request, cache, cors_flag, true, target, done_chan, context) } +fn try_immutable_origin_to_hyper_origin(url_origin: &ImmutableOrigin) -> Option { + 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, authentication_fetch_flag: bool, @@ -843,10 +853,16 @@ fn http_network_or_cache_fetch(request: Rc, }; // 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 diff --git a/tests/unit/net/http_loader.rs b/tests/unit/net/http_loader.rs index a55b2e78eb6..0905a047413 100644 --- a/tests/unit/net/http_loader.rs +++ b/tests/unit/net/http_loader.rs @@ -12,8 +12,8 @@ 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}; @@ -27,12 +27,13 @@ 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; @@ -145,8 +146,13 @@ fn test_check_default_headers_loaded_in_every_request() { 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, @@ -1117,3 +1123,61 @@ fn test_auth_ui_needs_www_auth() { 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::() { + 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(); +} diff --git a/tests/wpt/metadata/XMLHttpRequest/open-url-worker-origin.htm.ini b/tests/wpt/metadata/XMLHttpRequest/open-url-worker-origin.htm.ini index be2ee0358af..78c84602472 100644 --- a/tests/wpt/metadata/XMLHttpRequest/open-url-worker-origin.htm.ini +++ b/tests/wpt/metadata/XMLHttpRequest/open-url-worker-origin.htm.ini @@ -3,6 +3,3 @@ [Referer header] expected: FAIL - [Origin header] - expected: FAIL - diff --git a/tests/wpt/metadata/cors/allow-headers.htm.ini b/tests/wpt/metadata/cors/allow-headers.htm.ini index c46e502e53c..cfba35521e9 100644 --- a/tests/wpt/metadata/cors/allow-headers.htm.ini +++ b/tests/wpt/metadata/cors/allow-headers.htm.ini @@ -1,14 +1,5 @@ [allow-headers.htm] type: testharness - [Allow origin: *] - expected: FAIL - - [Allow origin: _*__] - expected: FAIL - - [Allow origin: [tab\]*] - expected: FAIL - [Allow origin: undefined//undefined] expected: FAIL @@ -21,15 +12,6 @@ [Allow origin: [tab\]undefined//undefined] expected: FAIL - [Allow origin: http://web-platform.test:8000] - expected: FAIL - - [Allow origin: _http://web-platform.test:8000] - expected: FAIL - [Allow origin: _http://web-platform.test:8000___[tab\]_] expected: FAIL - [Allow origin: [tab\]http://web-platform.test:8000] - expected: FAIL - diff --git a/tests/wpt/metadata/cors/basic.htm.ini b/tests/wpt/metadata/cors/basic.htm.ini index 6b8c71e2f21..8653d98cf33 100644 --- a/tests/wpt/metadata/cors/basic.htm.ini +++ b/tests/wpt/metadata/cors/basic.htm.ini @@ -1,14 +1,5 @@ [basic.htm] type: testharness - [Cross domain basic usage] - expected: FAIL - - [Same domain different port] - expected: FAIL - - [Cross domain different port] - expected: FAIL - [Cross domain different protocol] expected: FAIL diff --git a/tests/wpt/metadata/cors/credentials-flag.htm.ini b/tests/wpt/metadata/cors/credentials-flag.htm.ini index 7c356c2eecc..ff476934a29 100644 --- a/tests/wpt/metadata/cors/credentials-flag.htm.ini +++ b/tests/wpt/metadata/cors/credentials-flag.htm.ini @@ -1,12 +1,8 @@ [credentials-flag.htm] type: testharness - expected: TIMEOUT - [Don't send cookie by default] - expected: TIMEOUT + [Access-Control-Allow-Credentials: True should be disallowed (async)] + expected: FAIL - [Don't send cookie part 2] - expected: TIMEOUT - - [Don't obey Set-Cookie when withCredentials=false] - expected: TIMEOUT + [Access-Control-Allow-Credentials: TRUE should be disallowed (async)] + expected: FAIL diff --git a/tests/wpt/metadata/cors/origin.htm.ini b/tests/wpt/metadata/cors/origin.htm.ini index 6b627bf7b8c..48eea9276cb 100644 --- a/tests/wpt/metadata/cors/origin.htm.ini +++ b/tests/wpt/metadata/cors/origin.htm.ini @@ -1,14 +1,5 @@ [origin.htm] type: testharness - [Allow origin: *] - expected: FAIL - - [Allow origin: _*__] - expected: FAIL - - [Allow origin: [tab\]*] - expected: FAIL - [Allow origin: undefined//undefined] expected: FAIL @@ -21,15 +12,6 @@ [Allow origin: [tab\]undefined//undefined] expected: FAIL - [Allow origin: http://web-platform.test:8000] - expected: FAIL - - [Allow origin: _http://web-platform.test:8000] - expected: FAIL - [Allow origin: _http://web-platform.test:8000___[tab\]_] expected: FAIL - [Allow origin: [tab\]http://web-platform.test:8000] - expected: FAIL - diff --git a/tests/wpt/metadata/cors/redirect-origin.htm.ini b/tests/wpt/metadata/cors/redirect-origin.htm.ini index ef3413cca5a..19365ee4d0b 100644 --- a/tests/wpt/metadata/cors/redirect-origin.htm.ini +++ b/tests/wpt/metadata/cors/redirect-origin.htm.ini @@ -56,24 +56,6 @@ [remote (undefined//undefined) to remote2 (null), expect origin=null] expected: FAIL - [local (*) to remote (*), expect origin=http://web-platform.test:8000] - expected: FAIL - - [local (*) to remote (http://web-platform.test:8000), expect origin=http://web-platform.test:8000] - expected: FAIL - - [local (http://web-platform.test:8000) to remote (*), expect origin=http://web-platform.test:8000] - expected: FAIL - - [local (http://web-platform.test:8000) to remote (http://web-platform.test:8000), expect origin=http://web-platform.test:8000] - expected: FAIL - - [local (null) to remote (*), expect origin=http://web-platform.test:8000] - expected: FAIL - - [local (none) to remote (*), expect origin=http://web-platform.test:8000] - expected: FAIL - [remote (http://web-platform.test:8000) to local (*), expect origin=null] expected: FAIL diff --git a/tests/wpt/metadata/cors/request-headers.htm.ini b/tests/wpt/metadata/cors/request-headers.htm.ini deleted file mode 100644 index 6cf0c04c833..00000000000 --- a/tests/wpt/metadata/cors/request-headers.htm.ini +++ /dev/null @@ -1,14 +0,0 @@ -[request-headers.htm] - type: testharness - [basic request header] - expected: FAIL - - [Simple request headers need not be in allow-headers] - expected: FAIL - - [Strange allowheaders (case insensitive)] - expected: FAIL - - [INVALID_STATE_ERR on setRequestHeader after send()] - expected: FAIL - diff --git a/tests/wpt/metadata/cors/status-async.htm.ini b/tests/wpt/metadata/cors/status-async.htm.ini deleted file mode 100644 index 37b5f558b8e..00000000000 --- a/tests/wpt/metadata/cors/status-async.htm.ini +++ /dev/null @@ -1,53 +0,0 @@ -[status-async.htm] - type: testharness - [Status on GET 200] - expected: FAIL - - [Status on GET 201] - expected: FAIL - - [Status on GET 202] - expected: FAIL - - [Status on GET 203] - expected: FAIL - - [Status on GET 204] - expected: FAIL - - [Status on GET 205] - expected: FAIL - - [Status on GET 206] - expected: FAIL - - [Status on GET 209] - expected: FAIL - - [Status on GET 299] - expected: FAIL - - [Status on POST 200] - expected: FAIL - - [Status on HEAD 200] - expected: FAIL - - [Status on PUT 200] - expected: FAIL - - [Status on CHICKEN 200] - expected: FAIL - - [Status on GET 400] - expected: FAIL - - [Status on HEAD 401] - expected: FAIL - - [Status on POST 404] - expected: FAIL - - [Status on POST 500] - expected: FAIL - diff --git a/tests/wpt/metadata/cors/status-preflight.htm.ini b/tests/wpt/metadata/cors/status-preflight.htm.ini deleted file mode 100644 index f6b79144a24..00000000000 --- a/tests/wpt/metadata/cors/status-preflight.htm.ini +++ /dev/null @@ -1,50 +0,0 @@ -[status-preflight.htm] - type: testharness - [CORS - status after preflight on GET 200] - expected: FAIL - - [CORS - status after preflight on GET 204] - expected: FAIL - - [CORS - status after preflight on GET 400] - expected: FAIL - - [CORS - status after preflight on GET 401] - expected: FAIL - - [CORS - status after preflight on HEAD 200] - expected: FAIL - - [CORS - status after preflight on HEAD 204] - expected: FAIL - - [CORS - status after preflight on HEAD 400] - expected: FAIL - - [CORS - status after preflight on HEAD 401] - expected: FAIL - - [CORS - status after preflight on HEAD 501] - expected: FAIL - - [CORS - status after preflight on HEAD 699] - expected: FAIL - - [CORS - status after preflight on POST 204] - expected: FAIL - - [CORS - status after preflight on POST 400] - expected: FAIL - - [CORS - status after preflight on POST 401] - expected: FAIL - - [CORS - status after preflight on POST 404] - expected: FAIL - - [CORS - status after preflight on PUT 699] - expected: FAIL - - [CORS - status after preflight on CHICKEN 501] - expected: FAIL - diff --git a/tests/wpt/metadata/cors/status.htm.ini b/tests/wpt/metadata/cors/status.htm.ini deleted file mode 100644 index f8ff634de40..00000000000 --- a/tests/wpt/metadata/cors/status.htm.ini +++ /dev/null @@ -1,8 +0,0 @@ -[status.htm] - type: testharness - [3. CORS allowed, response status 400.] - expected: FAIL - - [4. CORS allowed, preflight status 200, response status 400.] - expected: FAIL - diff --git a/tests/wpt/metadata/eventsource/eventsource-cross-origin.htm.ini b/tests/wpt/metadata/eventsource/eventsource-cross-origin.htm.ini index b8818892048..6861c6e524f 100644 --- a/tests/wpt/metadata/eventsource/eventsource-cross-origin.htm.ini +++ b/tests/wpt/metadata/eventsource/eventsource-cross-origin.htm.ini @@ -1,15 +1,9 @@ [eventsource-cross-origin.htm] type: testharness expected: TIMEOUT - [EventSource: cross-origin basic use] - expected: TIMEOUT - [EventSource: cross-origin redirect use] expected: TIMEOUT - [EventSource: cross-origin redirect use recon] - expected: TIMEOUT - [EventSource: cross-origin allow-origin: http://example.org should fail] expected: FAIL diff --git a/tests/wpt/metadata/eventsource/request-cache-control.htm.ini b/tests/wpt/metadata/eventsource/request-cache-control.htm.ini deleted file mode 100644 index 7ceb8e9c65c..00000000000 --- a/tests/wpt/metadata/eventsource/request-cache-control.htm.ini +++ /dev/null @@ -1,6 +0,0 @@ -[request-cache-control.htm] - type: testharness - expected: TIMEOUT - [EventSource: Cache-Control 1] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/eventsource/request-credentials.htm.ini b/tests/wpt/metadata/eventsource/request-credentials.htm.ini deleted file mode 100644 index 1ca9f95ac12..00000000000 --- a/tests/wpt/metadata/eventsource/request-credentials.htm.ini +++ /dev/null @@ -1,12 +0,0 @@ -[request-credentials.htm] - type: testharness - expected: TIMEOUT - [EventSource: credentials: credentials enabled] - expected: TIMEOUT - - [EventSource: credentials: credentials disabled] - expected: TIMEOUT - - [EventSource: credentials: credentials default] - expected: TIMEOUT - diff --git a/tests/wpt/metadata/fetch/api/basic/request-headers.html.ini b/tests/wpt/metadata/fetch/api/basic/request-headers.html.ini index 7aa360a8750..f6ead72b358 100644 --- a/tests/wpt/metadata/fetch/api/basic/request-headers.html.ini +++ b/tests/wpt/metadata/fetch/api/basic/request-headers.html.ini @@ -1,23 +1,14 @@ [request-headers.html] type: testharness - [Fetch with PUT without body] - expected: FAIL - [Fetch with PUT with body] expected: FAIL - [Fetch with POST without body] - expected: FAIL - [Fetch with POST with text body] expected: FAIL [Fetch with POST with FormData body] expected: FAIL - [Fetch with POST with Blob body] - expected: FAIL - [Fetch with POST with ArrayBuffer body] expected: FAIL @@ -48,15 +39,6 @@ [Fetch with POST with URLSearchParams body] expected: FAIL - [Fetch with POST and mode "same-origin" needs an Origin header] - expected: FAIL - - [Fetch with POST and mode "no-cors" needs an Origin header] - expected: FAIL - - [Fetch with PUT and mode "same-origin" needs an Origin header] - expected: FAIL - [Fetch with TacO and mode "same-origin" needs an Origin header] expected: FAIL