diff --git a/components/net/http_loader.rs b/components/net/http_loader.rs index e21ade1b2ad..cad5cef6999 100644 --- a/components/net/http_loader.rs +++ b/components/net/http_loader.rs @@ -14,6 +14,7 @@ use hsts::{HSTSEntry, HSTSList, secure_url}; use hyper::Error as HttpError; use hyper::client::{Pool, Request, Response}; use hyper::header::{Accept, AcceptEncoding, ContentLength, ContentType, Host}; +use hyper::header::{Authorization, Basic}; use hyper::header::{ContentEncoding, Encoding, Header, Headers, Quality, QualityItem}; use hyper::header::{Location, SetCookie, StrictTransportSecurity, UserAgent, qitem}; use hyper::http::RawStatus; @@ -529,6 +530,25 @@ pub fn modify_request_headers(headers: &mut Headers, // https://fetch.spec.whatwg.org/#concept-http-network-or-cache-fetch step 11 if load_data.credentials_flag { set_request_cookies(doc_url.clone(), headers, cookie_jar); + + // https://fetch.spec.whatwg.org/#http-network-or-cache-fetch step 12 + if !headers.has::>() { + if let Some(auth) = auth_from_url(doc_url) { + headers.set(auth); + } + } + } +} + +fn auth_from_url(doc_url: &Url) -> Option> { + match doc_url.username() { + Some(username) if username != "" => { + Some(Authorization(Basic { + username: username.to_owned(), + password: Some(doc_url.password().unwrap_or("").to_owned()) + })) + }, + _ => None } } diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 42d1dc18ef1..8f1e8ade718 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -62,6 +62,7 @@ use string_cache::Atom; use time; use timers::{ScheduledCallback, TimerHandle}; use url::Url; +use url::percent_encoding::{utf8_percent_encode, USERNAME_ENCODE_SET, PASSWORD_ENCODE_SET}; use util::str::DOMString; pub type SendParam = BlobOrStringOrURLSearchParams; @@ -300,7 +301,9 @@ impl XMLHttpRequestMethods for XMLHttpRequest { } // https://xhr.spec.whatwg.org/#the-open()-method - fn Open(&self, method: ByteString, url: USVString) -> ErrorResult { + fn Open_(&self, method: ByteString, url: USVString, async: bool, + username: Option, password: Option) -> ErrorResult { + self.sync.set(!async); //FIXME(seanmonstar): use a Trie instead? let maybe_method = method.as_str().and_then(|s| { // Note: hyper tests against the uppercase versions @@ -331,10 +334,11 @@ impl XMLHttpRequestMethods for XMLHttpRequest { // Step 6 let base = self.global().r().get_url(); - let parsed_url = match base.join(&url.0) { + let mut parsed_url = match base.join(&url.0) { Ok(parsed) => parsed, Err(_) => return Err(Error::Syntax) // Step 7 }; + // XXXManishearth Do some handling of username/passwords if self.sync.get() { // FIXME: This should only happen if the global environment is a document environment @@ -343,6 +347,21 @@ impl XMLHttpRequestMethods for XMLHttpRequest { return Err(Error::InvalidAccess) } } + + if parsed_url.host().is_some() { + if let Some(scheme_data) = parsed_url.relative_scheme_data_mut() { + if let Some(user_str) = username { + scheme_data.username = utf8_percent_encode(&user_str.0, USERNAME_ENCODE_SET); + + // ensure that the password is mutated when a username is provided + scheme_data.password = match password { + Some(pass_str) => Some(utf8_percent_encode(&pass_str.0, PASSWORD_ENCODE_SET)), + None => None + } + } + } + } + // abort existing requests self.terminate_ongoing_fetch(); @@ -366,10 +385,8 @@ impl XMLHttpRequestMethods for XMLHttpRequest { } // https://xhr.spec.whatwg.org/#the-open()-method - fn Open_(&self, method: ByteString, url: USVString, async: bool, - _username: Option, _password: Option) -> ErrorResult { - self.sync.set(!async); - self.Open(method, url) + fn Open(&self, method: ByteString, url: USVString) -> ErrorResult { + self.Open_(method, url, true, None, None) } // https://xhr.spec.whatwg.org/#the-setrequestheader()-method diff --git a/tests/wpt/metadata/XMLHttpRequest/send-authentication-competing-names-passwords.htm.ini b/tests/wpt/metadata/XMLHttpRequest/send-authentication-competing-names-passwords.htm.ini deleted file mode 100644 index b74829cdec5..00000000000 --- a/tests/wpt/metadata/XMLHttpRequest/send-authentication-competing-names-passwords.htm.ini +++ /dev/null @@ -1,20 +0,0 @@ -[send-authentication-competing-names-passwords.htm] - type: testharness - [XMLHttpRequest: send() - "Basic" authenticated requests with competing user name/password options user/pass in open() call] - expected: FAIL - - [XMLHttpRequest: send() - "Basic" authenticated requests with competing user name/password options another user/pass in open() call - must override cached credentials from previous test] - expected: FAIL - - [XMLHttpRequest: send() - "Basic" authenticated requests with competing user name/password options user/pass both in URL userinfo AND open() call - expexted that open() wins] - expected: FAIL - - [XMLHttpRequest: send() - "Basic" authenticated requests with competing user name/password options user/pass *only* in URL userinfo] - expected: FAIL - - [XMLHttpRequest: send() - "Basic" authenticated requests with competing user name/password options user name in URL userinfo, password in open() call: user name wins and password is thrown away] - expected: FAIL - - [XMLHttpRequest: send() - "Basic" authenticated requests with competing user name/password options user name and password in URL userinfo, only user name in open() call: user name in open() wins] - expected: FAIL -