diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 7c32c5e9015..b8d6002c1d8 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -70,6 +70,7 @@ use servo_atoms::Atom; use servo_url::ServoUrl; use std::borrow::ToOwned; use std::cell::Cell; +use std::cmp; use std::default::Default; use std::ptr; use std::ptr::NonNull; @@ -95,7 +96,6 @@ pub struct GenerationId(u32); struct XHRContext { xhr: TrustedXHRAddress, gen_id: GenerationId, - buf: DomRefCell>, sync_status: DomRefCell>, resource_timing: ResourceFetchTiming, } @@ -105,7 +105,7 @@ pub enum XHRProgress { /// Notify that headers have been received HeadersReceived(GenerationId, Option, Option<(u16, Vec)>), /// Partial progress (after receiving headers), containing portion of the response - Loading(GenerationId, ByteString), + Loading(GenerationId, Vec), /// Loading is done Done(GenerationId), /// There was an error (only Error::Abort, Error::Timeout or Error::Network is used) @@ -133,7 +133,7 @@ pub struct XMLHttpRequest { response_url: DomRefCell, status: Cell, status_text: DomRefCell, - response: DomRefCell, + response: DomRefCell>, response_type: Cell, response_xml: MutNullableDom, response_blob: MutNullableDom, @@ -185,7 +185,7 @@ impl XMLHttpRequest { response_url: DomRefCell::new(String::new()), status: Cell::new(0), status_text: DomRefCell::new(ByteString::new(vec![])), - response: DomRefCell::new(ByteString::new(vec![])), + response: DomRefCell::new(vec![]), response_type: Cell::new(XMLHttpRequestResponseType::_empty), response_xml: Default::default(), response_blob: Default::default(), @@ -253,11 +253,8 @@ impl XMLHttpRequest { } } - fn process_response_chunk(&mut self, mut chunk: Vec) { - self.buf.borrow_mut().append(&mut chunk); - self.xhr - .root() - .process_data_available(self.gen_id, self.buf.borrow().clone()); + fn process_response_chunk(&mut self, chunk: Vec) { + self.xhr.root().process_data_available(self.gen_id, chunk); } fn process_response_eof( @@ -1008,7 +1005,7 @@ impl XMLHttpRequest { } fn process_data_available(&self, gen_id: GenerationId, payload: Vec) { - self.process_partial_response(XHRProgress::Loading(gen_id, ByteString::new(payload))); + self.process_partial_response(XHRProgress::Loading(gen_id, payload)); } fn process_response_complete( @@ -1077,18 +1074,34 @@ impl XMLHttpRequest { headers .as_ref() .map(|h| *self.response_headers.borrow_mut() = h.clone()); + { + let len = headers.and_then(|h| h.typed_get::()); + let mut response = self.response.borrow_mut(); + response.clear(); + if let Some(len) = len { + // don't attempt to prereserve more than 4 MB of memory, + // to avoid giving servers the ability to DOS the client by + // providing arbitrarily large content-lengths. + // + // this number is arbitrary, it's basically big enough that most + // XHR requests won't hit it, but not so big that it allows for DOS + let size = cmp::min(0b100_0000000000_0000000000, len.0 as usize); + // preallocate the buffer + response.reserve(size); + } + } // Substep 3 if !self.sync.get() { self.change_ready_state(XMLHttpRequestState::HeadersReceived); } }, - XHRProgress::Loading(_, partial_response) => { + XHRProgress::Loading(_, mut partial_response) => { // For synchronous requests, this should not fire any events, and just store data // Part of step 11, send() (processing response body) // XXXManishearth handle errors, if any (substep 2) - *self.response.borrow_mut() = partial_response; + self.response.borrow_mut().append(&mut partial_response); if !self.sync.get() { if self.ready_state.get() == XMLHttpRequestState::HeadersReceived { self.ready_state.set(XMLHttpRequestState::Loading); @@ -1451,7 +1464,6 @@ impl XMLHttpRequest { let context = Arc::new(Mutex::new(XHRContext { xhr: xhr, gen_id: self.generation_id.get(), - buf: DomRefCell::new(vec![]), sync_status: DomRefCell::new(None), resource_timing: ResourceFetchTiming::new(ResourceTimingType::Resource), }));