Auto merge of #8828 - Ronak6892:docResp, r=eefriedman

M1503/M1504 : Support for missing XMLHttpRequestAPIs and Document response handling

Hi,
This is for NCSU Fall 15 project M1503 and M1504:
M1503: Integrate XML Parser (Step 3 of 4): Support for Document response handling and calling the appropriate parser.
M1504: Support for missing XMLHttpRequest APIs
https://github.com/servo/servo/wiki/Integrate-xml5ever
It includes changes to handle document response for XMLHttpRequest.
Kindly review.

<!-- Reviewable:start -->
[<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8828)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2015-12-10 09:00:19 +05:30
commit bd8af8e234
17 changed files with 166 additions and 106 deletions

View file

@ -72,5 +72,6 @@ interface XMLHttpRequest : XMLHttpRequestEventTarget {
readonly attribute any response;
[Throws]
readonly attribute DOMString responseText;
[Throws]
/*[Exposed=Window]*/ readonly attribute Document? responseXML;
};

View file

@ -4,8 +4,10 @@
use cors::CORSResponse;
use cors::{AsyncCORSResponseListener, CORSRequest, RequestMode, allow_cross_origin_request};
use document_loader::DocumentLoader;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::EventHandlerBinding::EventHandlerNonNull;
use dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use dom::bindings::codegen::Bindings::XMLHttpRequestBinding;
use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestMethods;
use dom::bindings::codegen::Bindings::XMLHttpRequestBinding::XMLHttpRequestResponseType;
@ -16,12 +18,13 @@ use dom::bindings::conversions::{ToJSValConvertible};
use dom::bindings::error::{Error, ErrorResult, Fallible};
use dom::bindings::global::{GlobalField, GlobalRef, GlobalRoot};
use dom::bindings::inheritance::Castable;
use dom::bindings::js::Root;
use dom::bindings::js::{JS, MutNullableHeap};
use dom::bindings::js::{Root, RootedReference};
use dom::bindings::refcounted::Trusted;
use dom::bindings::reflector::{Reflectable, reflect_dom_object};
use dom::bindings::str::ByteString;
use dom::document::Document;
use dom::document::DocumentSource;
use dom::document::{Document, IsHTMLDocument};
use dom::event::{Event, EventBubbles, EventCancelable};
use dom::eventtarget::EventTarget;
use dom::progressevent::ProgressEvent;
@ -45,6 +48,8 @@ use net_traits::ControlMsg::Load;
use net_traits::{AsyncResponseListener, AsyncResponseTarget, Metadata};
use net_traits::{LoadConsumer, LoadData, ResourceCORSData, ResourceTask};
use network_listener::{NetworkListener, PreInvoke};
use parse::html::{ParseContext, parse_html};
use parse::xml::{self, parse_xml};
use script_task::{ScriptChan, ScriptPort};
use std::ascii::AsciiExt;
use std::borrow::ToOwned;
@ -701,6 +706,14 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
_ if self.ready_state.get() != XMLHttpRequestState::Done => {
return NullValue()
},
XMLHttpRequestResponseType::Document => {
let op_doc = self.GetResponseXML();
if let Ok(Some(doc)) = op_doc {
doc.to_jsval(cx, rval.handle_mut());
} else {
return NullValue();
}
},
Json => {
let decoded = UTF_8.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned();
let decoded: Vec<u16> = decoded.utf16_units().collect();
@ -735,8 +748,25 @@ impl XMLHttpRequestMethods for XMLHttpRequest {
}
// https://xhr.spec.whatwg.org/#the-responsexml-attribute
fn GetResponseXML(&self) -> Option<Root<Document>> {
self.response_xml.get()
fn GetResponseXML(&self) -> Fallible<Option<Root<Document>>> {
match self.response_type.get() {
_empty | XMLHttpRequestResponseType::Document => {
match self.ready_state.get() {
XMLHttpRequestState::Done => {
match self.response_xml.get() {
Some(response) => Ok(Some(response)),
None => {
let response = self.document_response();
self.response_xml.set(response.r());
Ok(response)
}
}
},
_ => Ok(None)
}
},
_ => { Err(Error::InvalidState) }
}
}
}
@ -1006,6 +1036,87 @@ impl XMLHttpRequest {
// the result should be fine. XXXManishearth have a closer look at this later
encoding.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned()
}
fn document_response(&self) -> Option<Root<Document>> {
let mime_type = self.final_mime_type();
//TODO: prescan the response to determine encoding if final charset is null
let charset = self.final_charset().unwrap_or(UTF_8);
let temp_doc: Root<Document>;
match mime_type {
Some(Mime(mime::TopLevel::Text, mime::SubLevel::Html, _)) => {
if self.response_type.get() == XMLHttpRequestResponseType::_empty {
return None;
}
else {
temp_doc = self.document_text_html();
}
},
Some(Mime(mime::TopLevel::Text, mime::SubLevel::Xml, _)) |
Some(Mime(mime::TopLevel::Application, mime::SubLevel::Xml, _)) |
None => {
temp_doc = self.handle_xml();
},
Some(Mime(_, mime::SubLevel::Ext(sub), _)) => {
if sub.ends_with("+xml") {
temp_doc = self.handle_xml();
}
else {
return None;
}
},
_ => { return None; }
}
temp_doc.set_encoding_name(DOMString::from(charset.name()));
Some(temp_doc)
}
fn document_text_html(&self) -> Root<Document>{
let charset = self.final_charset().unwrap_or(UTF_8);
let wr = self.global.root();
let wr = wr.r();
let decoded = charset.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned();
let document = self.new_doc(IsHTMLDocument::HTMLDocument);
// TODO: Disable scripting while parsing
parse_html(document.r(), DOMString::from(decoded), wr.get_url(), ParseContext::Owner(Some(wr.pipeline())));
document
}
fn handle_xml(&self) -> Root<Document> {
let charset = self.final_charset().unwrap_or(UTF_8);
let wr = self.global.root();
let wr = wr.r();
let decoded = charset.decode(&self.response.borrow(), DecoderTrap::Replace).unwrap().to_owned();
let document = self.new_doc(IsHTMLDocument::NonHTMLDocument);
// TODO: Disable scripting while parsing
parse_xml(document.r(), DOMString::from(decoded), wr.get_url(), xml::ParseContext::Owner(Some(wr.pipeline())));
document
}
fn new_doc(&self, is_html_document: IsHTMLDocument) -> Root<Document> {
let wr = self.global.root();
let wr = wr.r();
let win = wr.as_window();
let doc = win.Document();
let doc = doc.r();
let docloader = DocumentLoader::new(&*doc.loader());
let base = self.global.root().r().get_url();
let parsed_url = match UrlParser::new().base_url(&base).parse(&self.ResponseURL()) {
Ok(parsed) => Some(parsed),
Err(_) => None // Step 7
};
let mime_type = self.final_mime_type();
let content_type = mime_type.map(|mime|{
DOMString::from(format!("{}", mime))
});
let document = Document::new(win,
parsed_url,
is_html_document,
content_type,
None,
DocumentSource::FromParser, docloader);
document
}
fn filter_response_headers(&self) -> Headers {
// https://fetch.spec.whatwg.org/#concept-response-header-list
use hyper::error::Result;