mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
auto merge of #2613 : Manishearth/servo/xhr-wpt-methods, r=Ms2ger
For [XMLHttpRequest/open-method-case-sensitive.htm](https://github.com/w3c/web-platform-tests/blob/master/XMLHttpRequest/open-method-case-sensitive.htm), [XMLHttpRequest/XMLHttpRequest/open-method-insecure.htm](https://github.com/w3c/web-platform-tests/blob/master/XMLHttpRequest/open-method-insecure.htm), [XMLHttpRequest/XMLHttpRequest/open-method-responsetype-set-sync.htm ](https://github.com/w3c/web-platform-tests/blob/master/XMLHttpRequest/open-method-responsetype-set-sync.htm) in particular. `getResponseHeader()` is used by a lot of other tests (the harness echoes most of the metadata in the response headers, which is tested on this side) The sync changes fixes half of the timeouts to give meaningful results. Blocks #2525
This commit is contained in:
commit
1f41eda321
6 changed files with 58 additions and 28 deletions
|
@ -2627,7 +2627,7 @@ use js::jsapi::JSContext;
|
||||||
use js::jsval::JSVal;
|
use js::jsval::JSVal;
|
||||||
|
|
||||||
#[repr(uint)]
|
#[repr(uint)]
|
||||||
#[deriving(Encodable)]
|
#[deriving(Encodable, Eq)]
|
||||||
pub enum valuelist {
|
pub enum valuelist {
|
||||||
%s
|
%s
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ pub enum Error {
|
||||||
InvalidState,
|
InvalidState,
|
||||||
Syntax,
|
Syntax,
|
||||||
NamespaceError,
|
NamespaceError,
|
||||||
|
InvalidAccess,
|
||||||
Security,
|
Security,
|
||||||
Network
|
Network
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
use std::from_str::FromStr;
|
||||||
use std::hash::{Hash, sip};
|
use std::hash::{Hash, sip};
|
||||||
|
use std::path::BytesContainer;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
#[deriving(Encodable,Clone,TotalEq,Eq)]
|
#[deriving(Encodable,Clone,TotalEq,Eq)]
|
||||||
|
@ -45,6 +47,9 @@ impl ByteString {
|
||||||
|
|
||||||
pub fn is_token(&self) -> bool {
|
pub fn is_token(&self) -> bool {
|
||||||
let ByteString(ref vec) = *self;
|
let ByteString(ref vec) = *self;
|
||||||
|
if vec.len() == 0 {
|
||||||
|
return false; // A token must be at least a single character
|
||||||
|
}
|
||||||
vec.iter().all(|&x| {
|
vec.iter().all(|&x| {
|
||||||
// http://tools.ietf.org/html/rfc2616#section-2.2
|
// http://tools.ietf.org/html/rfc2616#section-2.2
|
||||||
match x {
|
match x {
|
||||||
|
@ -53,6 +58,7 @@ impl ByteString {
|
||||||
44 | 59 | 58 | 92 | 34 |
|
44 | 59 | 58 | 92 | 34 |
|
||||||
47 | 91 | 93 | 63 | 61 |
|
47 | 91 | 93 | 63 | 61 |
|
||||||
123 | 125 | 32 => false, // separators
|
123 | 125 | 32 => false, // separators
|
||||||
|
x if x > 127 => false, // non-CHARs
|
||||||
_ => true
|
_ => true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -113,4 +119,10 @@ impl Hash for ByteString {
|
||||||
let ByteString(ref vec) = *self;
|
let ByteString(ref vec) = *self;
|
||||||
vec.hash(state);
|
vec.hash(state);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for ByteString {
|
||||||
|
fn from_str(s: &str) -> Option<ByteString> {
|
||||||
|
Some(ByteString::new(s.container_into_owned_bytes()))
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -46,8 +46,9 @@ impl DOMErrorName {
|
||||||
error::InvalidCharacter => InvalidCharacterError,
|
error::InvalidCharacter => InvalidCharacterError,
|
||||||
error::NotSupported => NotSupportedError,
|
error::NotSupported => NotSupportedError,
|
||||||
error::InvalidState => InvalidStateError,
|
error::InvalidState => InvalidStateError,
|
||||||
error::NamespaceError => NamespaceError,
|
|
||||||
error::Syntax => SyntaxError,
|
error::Syntax => SyntaxError,
|
||||||
|
error::NamespaceError => NamespaceError,
|
||||||
|
error::InvalidAccess => InvalidAccessError,
|
||||||
error::Security => SecurityError,
|
error::Security => SecurityError,
|
||||||
error::Network => NetworkError,
|
error::Network => NetworkError,
|
||||||
error::FailureUnknown => fail!(),
|
error::FailureUnknown => fail!(),
|
||||||
|
|
|
@ -56,7 +56,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
|
||||||
readonly attribute DOMString responseURL;
|
readonly attribute DOMString responseURL;
|
||||||
readonly attribute unsigned short status;
|
readonly attribute unsigned short status;
|
||||||
readonly attribute ByteString statusText;
|
readonly attribute ByteString statusText;
|
||||||
// ByteString? getResponseHeader(ByteString name);
|
ByteString? getResponseHeader(ByteString name);
|
||||||
ByteString getAllResponseHeaders();
|
ByteString getAllResponseHeaders();
|
||||||
// void overrideMimeType(DOMString mime);
|
// void overrideMimeType(DOMString mime);
|
||||||
[SetterThrows]
|
[SetterThrows]
|
||||||
|
|
|
@ -8,7 +8,7 @@ use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestRespo
|
||||||
use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestResponseTypeValues::{_empty, Json, Text};
|
use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestResponseTypeValues::{_empty, Json, Text};
|
||||||
use dom::bindings::codegen::InheritTypes::{EventCast, EventTargetCast, XMLHttpRequestDerived};
|
use dom::bindings::codegen::InheritTypes::{EventCast, EventTargetCast, XMLHttpRequestDerived};
|
||||||
use dom::bindings::conversions::ToJSValConvertible;
|
use dom::bindings::conversions::ToJSValConvertible;
|
||||||
use dom::bindings::error::{ErrorResult, Fallible, InvalidState, Network, Syntax, Security};
|
use dom::bindings::error::{ErrorResult, Fallible, InvalidState, InvalidAccess, Network, Syntax, Security};
|
||||||
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, OptionalRootedRootable};
|
use dom::bindings::js::{JS, JSRef, Temporary, OptionalSettable, OptionalRootedRootable};
|
||||||
use dom::bindings::str::ByteString;
|
use dom::bindings::str::ByteString;
|
||||||
use dom::bindings::trace::Untraceable;
|
use dom::bindings::trace::Untraceable;
|
||||||
|
@ -30,7 +30,7 @@ use RequestHeaderCollection = http::headers::request::HeaderCollection;
|
||||||
use http::headers::content_type::MediaType;
|
use http::headers::content_type::MediaType;
|
||||||
use http::headers::{HeaderEnum, HeaderValueByteIterator};
|
use http::headers::{HeaderEnum, HeaderValueByteIterator};
|
||||||
use http::headers::request::Header;
|
use http::headers::request::Header;
|
||||||
use http::method::{Method, Get, Head, Post, Connect, Trace};
|
use http::method::{Method, Get, Head, Connect, Trace, ExtensionMethod};
|
||||||
use http::status::Status;
|
use http::status::Status;
|
||||||
|
|
||||||
use js::jsapi::{JS_AddObjectRoot, JS_ParseJSON, JS_RemoveObjectRoot, JSContext};
|
use js::jsapi::{JS_AddObjectRoot, JS_ParseJSON, JS_RemoveObjectRoot, JSContext};
|
||||||
|
@ -95,7 +95,7 @@ enum SyncOrAsync<'a, 'b> {
|
||||||
impl<'a,'b> SyncOrAsync<'a,'b> {
|
impl<'a,'b> SyncOrAsync<'a,'b> {
|
||||||
fn is_async(&self) -> bool {
|
fn is_async(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
Sync(_) => true,
|
Async(_,_) => true,
|
||||||
_ => false
|
_ => false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ pub trait XMLHttpRequestMethods<'a> {
|
||||||
fn ResponseURL(&self) -> DOMString;
|
fn ResponseURL(&self) -> DOMString;
|
||||||
fn Status(&self) -> u16;
|
fn Status(&self) -> u16;
|
||||||
fn StatusText(&self) -> ByteString;
|
fn StatusText(&self) -> ByteString;
|
||||||
fn GetResponseHeader(&self, _name: ByteString) -> Option<ByteString>;
|
fn GetResponseHeader(&self, name: ByteString) -> Option<ByteString>;
|
||||||
fn GetAllResponseHeaders(&self) -> ByteString;
|
fn GetAllResponseHeaders(&self) -> ByteString;
|
||||||
fn OverrideMimeType(&self, _mime: DOMString);
|
fn OverrideMimeType(&self, _mime: DOMString);
|
||||||
fn ResponseType(&self) -> XMLHttpRequestResponseType;
|
fn ResponseType(&self) -> XMLHttpRequestResponseType;
|
||||||
|
@ -267,13 +267,30 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Open(&mut self, method: ByteString, url: DOMString) -> ErrorResult {
|
fn Open(&mut self, method: ByteString, url: DOMString) -> ErrorResult {
|
||||||
let maybe_method: Option<Method> = method.as_str().and_then(|s| {
|
let uppercase_method = method.as_str().map(|s| {
|
||||||
FromStr::from_str(s.to_ascii_upper().as_slice()) // rust-http tests against the uppercase versions
|
let upper = s.to_ascii_upper();
|
||||||
|
match upper.as_slice() {
|
||||||
|
"DELETE" | "GET" | "HEAD" | "OPTIONS" |
|
||||||
|
"POST" | "PUT" | "CONNECT" | "TRACE" |
|
||||||
|
"TRACK" => upper,
|
||||||
|
_ => s.to_string()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
let maybe_method: Option<Method> = uppercase_method.and_then(|s| {
|
||||||
|
// Note: rust-http tests against the uppercase versions
|
||||||
|
// Since we want to pass methods not belonging to the short list above
|
||||||
|
// without changing capitalization, this will actually sidestep rust-http's type system
|
||||||
|
// since methods like "patch" or "PaTcH" will be considered extension methods
|
||||||
|
// despite the there being a rust-http method variant for them
|
||||||
|
Method::from_str_or_new(s.as_slice())
|
||||||
});
|
});
|
||||||
// Step 2
|
// Step 2
|
||||||
let base: Option<Url> = Some(self.global.root().get_url());
|
let base: Option<Url> = Some(self.global.root().get_url());
|
||||||
match maybe_method {
|
match maybe_method {
|
||||||
Some(Get) | Some(Post) | Some(Head) => {
|
// Step 4
|
||||||
|
Some(Connect) | Some(Trace) => Err(Security),
|
||||||
|
Some(ExtensionMethod(ref t)) if t.as_slice() == "TRACK" => Err(Security),
|
||||||
|
Some(_) if method.is_token() => {
|
||||||
|
|
||||||
*self.request_method = maybe_method.unwrap();
|
*self.request_method = maybe_method.unwrap();
|
||||||
|
|
||||||
|
@ -282,8 +299,14 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
|
||||||
Ok(parsed) => parsed,
|
Ok(parsed) => parsed,
|
||||||
Err(_) => return Err(Syntax) // Step 7
|
Err(_) => return Err(Syntax) // Step 7
|
||||||
};
|
};
|
||||||
// XXXManishearth Do some handling of username/passwords, and abort existing requests
|
// XXXManishearth Do some handling of username/passwords
|
||||||
|
if self.sync {
|
||||||
|
// FIXME: This should only happen if the global environment is a document environment
|
||||||
|
if self.timeout != 0 || self.with_credentials || self.response_type != _empty {
|
||||||
|
return Err(InvalidAccess)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// XXXManishearth abort existing requests
|
||||||
// Step 12
|
// Step 12
|
||||||
*self.request_url = parsed_url;
|
*self.request_url = parsed_url;
|
||||||
*self.request_headers = RequestHeaderCollection::new();
|
*self.request_headers = RequestHeaderCollection::new();
|
||||||
|
@ -295,22 +318,11 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
|
||||||
if self.ready_state != Opened {
|
if self.ready_state != Opened {
|
||||||
self.change_ready_state(Opened);
|
self.change_ready_state(Opened);
|
||||||
}
|
}
|
||||||
//XXXManishearth fire a progressevent
|
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
// XXXManishearth Handle other standard methods
|
// This includes cases where as_str() returns None, and when is_token() returns false,
|
||||||
Some(Connect) | Some(Trace) => {
|
// both of which indicate invalid extension method names
|
||||||
// XXXManishearth Track isn't in rust-http, but it should end up in this match arm.
|
_ => Err(Syntax), // Step 3
|
||||||
Err(Security) // Step 4
|
|
||||||
},
|
|
||||||
None => Err(Syntax), // Step 3
|
|
||||||
_ => {
|
|
||||||
if method.is_token() {
|
|
||||||
Ok(()) // XXXManishearth handle extension methods
|
|
||||||
} else {
|
|
||||||
Err(Syntax) // Step 3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn Open_(&mut self, method: ByteString, url: DOMString, async: bool,
|
fn Open_(&mut self, method: ByteString, url: DOMString, async: bool,
|
||||||
|
@ -491,8 +503,12 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
|
||||||
fn StatusText(&self) -> ByteString {
|
fn StatusText(&self) -> ByteString {
|
||||||
self.status_text.clone()
|
self.status_text.clone()
|
||||||
}
|
}
|
||||||
fn GetResponseHeader(&self, _name: ByteString) -> Option<ByteString> {
|
fn GetResponseHeader(&self, name: ByteString) -> Option<ByteString> {
|
||||||
None
|
self.response_headers.deref().iter().find(|h| {
|
||||||
|
name.eq_ignore_case(&FromStr::from_str(h.header_name().as_slice()).unwrap())
|
||||||
|
}).map(|h| {
|
||||||
|
FromStr::from_str(h.header_value().as_slice()).unwrap()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
fn GetAllResponseHeaders(&self) -> ByteString {
|
fn GetAllResponseHeaders(&self) -> ByteString {
|
||||||
let mut writer = MemWriter::new();
|
let mut writer = MemWriter::new();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue