Support for extension methods, getResponseHeader(), and an extra error

This commit is contained in:
Manish Goregaokar 2014-06-07 23:05:59 +05:30
parent 1184b500e5
commit e8de5f2f55
6 changed files with 51 additions and 27 deletions

View file

@ -2622,7 +2622,7 @@ use js::jsapi::JSContext;
use js::jsval::JSVal;
#[repr(uint)]
#[deriving(Encodable)]
#[deriving(Encodable, Eq)]
pub enum valuelist {
%s
}

View file

@ -26,6 +26,7 @@ pub enum Error {
InvalidState,
Syntax,
NamespaceError,
InvalidAccess,
Security,
Network
}

View file

@ -2,7 +2,9 @@
* 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 std::from_str::FromStr;
use std::hash::{Hash, sip};
use std::path::BytesContainer;
use std::str;
#[deriving(Encodable,Clone,TotalEq,Eq)]
@ -113,4 +115,10 @@ impl Hash for ByteString {
let ByteString(ref vec) = *self;
vec.hash(state);
}
}
impl FromStr for ByteString {
fn from_str(s: &str) -> Option<ByteString> {
Some(ByteString::new(s.container_into_owned_bytes()))
}
}

View file

@ -46,8 +46,9 @@ impl DOMErrorName {
error::InvalidCharacter => InvalidCharacterError,
error::NotSupported => NotSupportedError,
error::InvalidState => InvalidStateError,
error::NamespaceError => NamespaceError,
error::Syntax => SyntaxError,
error::NamespaceError => NamespaceError,
error::InvalidAccess => InvalidAccessError,
error::Security => SecurityError,
error::Network => NetworkError,
error::FailureUnknown => fail!(),

View file

@ -56,7 +56,7 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
readonly attribute DOMString responseURL;
readonly attribute unsigned short status;
readonly attribute ByteString statusText;
// ByteString? getResponseHeader(ByteString name);
ByteString? getResponseHeader(ByteString name);
ByteString getAllResponseHeaders();
// void overrideMimeType(DOMString mime);
[SetterThrows]

View file

@ -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::InheritTypes::{EventCast, EventTargetCast, XMLHttpRequestDerived};
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::str::ByteString;
use dom::bindings::trace::Untraceable;
@ -30,7 +30,7 @@ use RequestHeaderCollection = http::headers::request::HeaderCollection;
use http::headers::content_type::MediaType;
use http::headers::{HeaderEnum, HeaderValueByteIterator};
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 js::jsapi::{JS_AddObjectRoot, JS_ParseJSON, JS_RemoveObjectRoot, JSContext};
@ -241,7 +241,7 @@ pub trait XMLHttpRequestMethods<'a> {
fn ResponseURL(&self) -> DOMString;
fn Status(&self) -> u16;
fn StatusText(&self) -> ByteString;
fn GetResponseHeader(&self, _name: ByteString) -> Option<ByteString>;
fn GetResponseHeader(&self, name: ByteString) -> Option<ByteString>;
fn GetAllResponseHeaders(&self) -> ByteString;
fn OverrideMimeType(&self, _mime: DOMString);
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 {
let maybe_method: Option<Method> = method.as_str().and_then(|s| {
FromStr::from_str(s.to_ascii_upper().as_slice()) // rust-http tests against the uppercase versions
let uppercase_method = method.as_str().map(|s| {
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
let base: Option<Url> = Some(self.global.root().get_url());
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();
@ -282,8 +299,14 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
Ok(parsed) => parsed,
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 environmet is a document environment
if self.timeout != 0 || self.with_credentials || self.response_type != _empty {
return Err(InvalidAccess)
}
}
// XXXManishearth abort existing requests
// Step 12
*self.request_url = parsed_url;
*self.request_headers = RequestHeaderCollection::new();
@ -295,22 +318,9 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
if self.ready_state != Opened {
self.change_ready_state(Opened);
}
//XXXManishearth fire a progressevent
Ok(())
},
// XXXManishearth Handle other standard methods
Some(Connect) | Some(Trace) => {
// XXXManishearth Track isn't in rust-http, but it should end up in this match arm.
Err(Security) // Step 4
},
None => Err(Syntax), // Step 3
_ => {
if method.is_token() {
Ok(()) // XXXManishearth handle extension methods
} else {
Err(Syntax) // Step 3
}
}
_ => Err(Syntax), // Step 3
}
}
fn Open_(&mut self, method: ByteString, url: DOMString, async: bool,
@ -491,8 +501,12 @@ impl<'a> XMLHttpRequestMethods<'a> for JSRef<'a, XMLHttpRequest> {
fn StatusText(&self) -> ByteString {
self.status_text.clone()
}
fn GetResponseHeader(&self, _name: ByteString) -> Option<ByteString> {
None
fn GetResponseHeader(&self, name: ByteString) -> Option<ByteString> {
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 {
let mut writer = MemWriter::new();