1use std::borrow::ToOwned;
6use std::cell::Cell;
7use std::cmp;
8use std::default::Default;
9use std::str::{self, FromStr};
10use std::sync::Arc;
11use std::time::{Duration, Instant};
12
13use atomic_refcell::AtomicRefCell;
14use bytes::{Bytes, BytesMut};
15use data_url::mime::Mime;
16use dom_struct::dom_struct;
17use encoding_rs::{Encoding, UTF_8};
18use headers::{ContentLength, ContentType, HeaderMapExt};
19use html5ever::serialize;
20use html5ever::serialize::SerializeOpts;
21use http::Method;
22use http::header::{self, HeaderMap, HeaderName, HeaderValue};
23use hyper_serde::Serde;
24use js::context::{JSContext, NoGC};
25use js::conversions::ToJSValConvertible;
26use js::jsapi::Heap;
27use js::jsval::{JSVal, NullValue};
28use js::rust::wrappers2::{JS_ClearPendingException, JS_ParseJSON};
29use js::rust::{HandleObject, MutableHandleValue};
30use js::typedarray::{ArrayBufferU8, HeapArrayBuffer};
31use net_traits::blob_url_store::UrlWithBlobClaim;
32use net_traits::fetch::fetch_controller::FetchController;
33use net_traits::fetch::headers::extract_mime_type_as_dataurl_mime;
34use net_traits::http_status::HttpStatus;
35use net_traits::request::{CredentialsMode, Referrer, RequestBuilder, RequestId, RequestMode};
36use net_traits::{
37 FetchMetadata, FilteredMetadata, NetworkError, ReferrerPolicy, ResourceFetchTiming,
38 trim_http_whitespace,
39};
40use script_bindings::cell::DomRefCell;
41use script_bindings::num::Finite;
42use script_bindings::reflector::reflect_dom_object_with_proto;
43use script_bindings::trace::RootedTraceableBox;
44use script_traits::DocumentActivity;
45use servo_constellation_traits::BlobImpl;
46use servo_url::ServoUrl;
47use stylo_atoms::Atom;
48use url::Position;
49
50use crate::dom::bindings::buffer_source::{HeapBufferSource, get_buffer_source_copy};
51use crate::dom::bindings::cell::AtomicSafeBorrowMut;
52use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
53use crate::dom::bindings::codegen::Bindings::XMLHttpRequestBinding::{
54 XMLHttpRequestMethods, XMLHttpRequestResponseType,
55};
56use crate::dom::bindings::codegen::UnionTypes::DocumentOrBlobOrArrayBufferViewOrArrayBufferOrFormDataOrStringOrURLSearchParams as DocumentOrXMLHttpRequestBodyInit;
57use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
58use crate::dom::bindings::inheritance::Castable;
59use crate::dom::bindings::refcounted::Trusted;
60use crate::dom::bindings::reflector::DomGlobal;
61use crate::dom::bindings::root::{Dom, DomRoot, MutNullableDom};
62use crate::dom::bindings::str::{ByteString, DOMString, USVString, is_token};
63use crate::dom::blob::{Blob, normalize_type_string};
64use crate::dom::csp::{GlobalCspReporting, Violation};
65use crate::dom::document::{Document, HasBrowsingContext, IsHTMLDocument};
66use crate::dom::event::{Event, EventBubbles, EventCancelable};
67use crate::dom::eventtarget::EventTarget;
68use crate::dom::globalscope::GlobalScope;
69use crate::dom::headers::is_forbidden_request_header;
70use crate::dom::node::Node;
71use crate::dom::performance::performanceresourcetiming::InitiatorType;
72use crate::dom::progressevent::ProgressEvent;
73use crate::dom::servoparser::ServoParser;
74use crate::dom::servoparser::html::HtmlSerialize;
75use crate::dom::stream::readablestream::ReadableStream;
76use crate::dom::window::Window;
77use crate::dom::workerglobalscope::WorkerGlobalScope;
78use crate::dom::xmlhttprequesteventtarget::XMLHttpRequestEventTarget;
79use crate::dom::xmlhttprequestupload::XMLHttpRequestUpload;
80use crate::event_loop::document_loader::DocumentLoader;
81use crate::event_loop::timers::{OneshotTimerCallback, OneshotTimerHandle};
82use crate::fetch::body::{
83 BodySource, Extractable, ExtractedBody, decode_to_utf16_with_bom_removal,
84};
85use crate::fetch::fetch::RequestWithGlobalScope;
86use crate::fetch::network_listener::{self, FetchResponseListener, ResourceTimingListener};
87use crate::mime::{APPLICATION, CHARSET, HTML, MimeExt, TEXT, XML};
88use crate::tasks::task_source::{SendableTaskSource, TaskSourceName};
89use crate::url::ensure_blob_referenced_by_url_is_kept_alive;
90
91#[derive(Clone, Copy, Debug, JSTraceable, MallocSizeOf, PartialEq)]
92enum XMLHttpRequestState {
93 Unsent = 0,
94 Opened = 1,
95 HeadersReceived = 2,
96 Loading = 3,
97 Done = 4,
98}
99
100#[derive(Clone, Copy)]
101enum ErrorType {
102 Abort,
103 Timeout,
104 Network,
105}
106
107#[derive(Clone, Copy, JSTraceable, MallocSizeOf, PartialEq)]
108pub(crate) struct GenerationId(u32);
109
110struct XHRContext {
113 xhr: TrustedXHRAddress,
114 gen_id: GenerationId,
115 sync_status: Arc<AtomicRefCell<Option<ErrorResult>>>,
116 url: ServoUrl,
117}
118
119impl FetchResponseListener for XHRContext {
120 fn process_request_body(&mut self, _: RequestId) {
121 }
123
124 fn process_response(
125 &mut self,
126 cx: &mut JSContext,
127 _: RequestId,
128 metadata: Result<FetchMetadata, NetworkError>,
129 ) {
130 let xhr = self.xhr.root();
131 let rv = xhr.process_headers_available(cx, self.gen_id, metadata);
132 if rv.is_err() {
133 *self.sync_status.safe_borrow_mut(cx.no_gc()) = Some(rv);
134 }
135 }
136
137 fn process_response_chunk(&mut self, cx: &mut JSContext, _: RequestId, chunk: Bytes) {
138 self.xhr
139 .root()
140 .process_data_available(cx, self.gen_id, chunk);
141 }
142
143 fn process_response_eof(
144 self,
145 cx: &mut JSContext,
146 _: RequestId,
147 response: Result<(), NetworkError>,
148 timing: ResourceFetchTiming,
149 ) {
150 network_listener::submit_timing(cx, &self, &response, &timing);
151
152 let rv = self
153 .xhr
154 .root()
155 .process_response_complete(cx, self.gen_id, response.map(|_| ()));
156 *self.sync_status.safe_borrow_mut(cx.no_gc()) = Some(rv);
157 }
158
159 fn process_csp_violations(
160 &mut self,
161 cx: &mut js::context::JSContext,
162 _request_id: RequestId,
163 violations: Vec<Violation>,
164 ) {
165 let global = &self.resource_timing_global();
166 global.report_csp_violations(cx, violations, None, None);
167 }
168
169 fn should_invoke(&self) -> bool {
170 self.xhr.root().generation_id.get() == self.gen_id
171 }
172}
173
174impl ResourceTimingListener for XHRContext {
175 fn resource_timing_information(&self) -> (InitiatorType, ServoUrl) {
176 (InitiatorType::XMLHttpRequest, self.url.clone())
177 }
178
179 fn resource_timing_global(&self) -> DomRoot<GlobalScope> {
180 self.xhr.root().global()
181 }
182}
183
184#[derive(Clone)]
185enum XHRProgress {
186 HeadersReceived(GenerationId, Option<HeaderMap>, HttpStatus),
188 Loading(GenerationId, Bytes),
190 Done(GenerationId),
192 Errored(GenerationId, ErrorType),
194}
195
196impl XHRProgress {
197 fn generation_id(&self) -> GenerationId {
198 match *self {
199 XHRProgress::HeadersReceived(id, _, _) |
200 XHRProgress::Loading(id, _) |
201 XHRProgress::Done(id) |
202 XHRProgress::Errored(id, _) => id,
203 }
204 }
205}
206
207#[dom_struct]
208pub(crate) struct XMLHttpRequest {
209 eventtarget: XMLHttpRequestEventTarget,
210 ready_state: Cell<XMLHttpRequestState>,
211 timeout: Cell<Duration>,
212 with_credentials: Cell<bool>,
213 upload: Dom<XMLHttpRequestUpload>,
214 response_url: DomRefCell<String>,
215 #[no_trace]
216 status: DomRefCell<HttpStatus>,
217 #[no_trace]
218 response: DomRefCell<BytesMut>,
219 response_type: Cell<XMLHttpRequestResponseType>,
220 response_xml: MutNullableDom<Document>,
221 response_blob: MutNullableDom<Blob>,
222 #[ignore_malloc_size_of = "mozjs"]
223 response_arraybuffer: HeapBufferSource<ArrayBufferU8>,
224 #[ignore_malloc_size_of = "Defined in rust-mozjs"]
225 response_json: Heap<JSVal>,
226 #[no_trace]
227 response_headers: DomRefCell<HeaderMap>,
228 #[no_trace]
229 override_mime_type: DomRefCell<Option<Mime>>,
230
231 #[no_trace]
233 request_method: DomRefCell<Method>,
234 #[no_trace]
235 request_url: DomRefCell<Option<UrlWithBlobClaim>>,
236 #[no_trace]
237 request_headers: DomRefCell<HeaderMap>,
238 request_body_len: Cell<usize>,
239 sync: Cell<bool>,
240 upload_complete: Cell<bool>,
241 upload_listener: Cell<bool>,
242 send_flag: Cell<bool>,
243
244 timeout_cancel: DomRefCell<Option<OneshotTimerHandle>>,
245 fetch_time: Cell<Instant>,
246 generation_id: Cell<GenerationId>,
247 response_status: Cell<Result<(), ()>>,
248 #[no_trace]
249 referrer: Referrer,
250 #[no_trace]
251 referrer_policy: ReferrerPolicy,
252 #[no_trace]
253 controller: DomRefCell<FetchController>,
254}
255
256impl XMLHttpRequest {
257 fn new_inherited(global: &GlobalScope, upload: &XMLHttpRequestUpload) -> XMLHttpRequest {
258 XMLHttpRequest {
259 eventtarget: XMLHttpRequestEventTarget::new_inherited(),
260 ready_state: Cell::new(XMLHttpRequestState::Unsent),
261 timeout: Cell::new(Duration::ZERO),
262 with_credentials: Cell::new(false),
263 upload: Dom::from_ref(upload),
264 response_url: DomRefCell::new(String::new()),
265 status: DomRefCell::new(HttpStatus::new_error()),
266 response: DomRefCell::new(BytesMut::new()),
267 response_type: Cell::new(XMLHttpRequestResponseType::_empty),
268 response_xml: Default::default(),
269 response_blob: Default::default(),
270 response_arraybuffer: HeapBufferSource::default(),
271 response_json: Heap::default(),
272 response_headers: DomRefCell::new(HeaderMap::new()),
273 override_mime_type: DomRefCell::new(None),
274
275 request_method: DomRefCell::new(Method::GET),
276 request_url: DomRefCell::new(None),
277 request_headers: DomRefCell::new(HeaderMap::new()),
278 request_body_len: Cell::new(0),
279 sync: Cell::new(false),
280 upload_complete: Cell::new(false),
281 upload_listener: Cell::new(false),
282 send_flag: Cell::new(false),
283
284 timeout_cancel: DomRefCell::new(None),
285 fetch_time: Cell::new(Instant::now()),
286 generation_id: Cell::new(GenerationId(0)),
287 response_status: Cell::new(Ok(())),
288 referrer: global.get_referrer(),
289 referrer_policy: global.get_referrer_policy(),
290 controller: DomRefCell::new(Default::default()),
291 }
292 }
293
294 fn new(
295 cx: &mut JSContext,
296 global: &GlobalScope,
297 proto: Option<HandleObject>,
298 ) -> DomRoot<XMLHttpRequest> {
299 let upload = XMLHttpRequestUpload::new(cx, global);
300 reflect_dom_object_with_proto(
301 cx,
302 Box::new(XMLHttpRequest::new_inherited(global, &upload)),
303 global,
304 proto,
305 )
306 }
307
308 fn sync_in_window(&self) -> bool {
309 self.sync.get() && self.global().is::<Window>()
310 }
311}
312
313impl XMLHttpRequestMethods<crate::DomTypeHolder> for XMLHttpRequest {
314 fn Constructor(
316 cx: &mut JSContext,
317 global: &GlobalScope,
318 proto: Option<HandleObject>,
319 ) -> Fallible<DomRoot<XMLHttpRequest>> {
320 Ok(XMLHttpRequest::new(cx, global, proto))
321 }
322
323 event_handler!(
325 readystatechange,
326 GetOnreadystatechange,
327 SetOnreadystatechange
328 );
329
330 fn ReadyState(&self) -> u16 {
332 self.ready_state.get() as u16
333 }
334
335 fn Open(&self, cx: &mut JSContext, method: ByteString, url: USVString) -> ErrorResult {
337 self.Open_(cx, method, url, true, None, None)
339 }
340
341 fn Open_(
343 &self,
344 cx: &mut JSContext,
345 method: ByteString,
346 url: USVString,
347 asynch: bool,
348 username: Option<USVString>,
349 password: Option<USVString>,
350 ) -> ErrorResult {
351 let global = self.global();
354 if let Some(window) = global.downcast::<Window>() &&
355 !window.Document().is_fully_active()
356 {
357 return Err(Error::InvalidState(Some(
358 "Document is not fully active".into(),
359 )));
360 }
361
362 let maybe_method = method.as_str().and_then(|s| {
365 let upper = s.to_ascii_uppercase();
371 match &*upper {
372 "DELETE" | "GET" | "HEAD" | "OPTIONS" | "POST" | "PUT" | "CONNECT" | "TRACE" |
373 "TRACK" => upper.parse().ok(),
374 _ => s.parse().ok(),
375 }
376 });
377
378 match maybe_method {
379 Some(Method::CONNECT) | Some(Method::TRACE) => {
381 Err(Error::Security(Some("Method is forbidden".into())))
382 },
383 Some(ref t) if t.as_str() == "TRACK" => {
384 Err(Error::Security(Some("Method is forbidden".into())))
385 },
386 Some(parsed_method) => {
387 if !is_token(&method) {
389 return Err(Error::Syntax(Some("Invalid method".into())));
390 }
391
392 let mut parsed_url = match self
395 .global()
396 .encoding_parse_a_url(&url.0)
397 .map(|url| ensure_blob_referenced_by_url_is_kept_alive(&global, url))
398 {
399 Ok(parsed) => parsed,
400 Err(_) => {
401 return Err(Error::Syntax(Some("Invalid URL".into())));
403 },
404 };
405
406 if parsed_url.host().is_some() {
408 if let Some(user_str) = username &&
410 let Err(error) = parsed_url.set_username(&user_str.0)
411 {
412 warn!("Could not set username on XMLHttpRequest: {error:?}");
413 }
414
415 if let Some(pass_str) = password &&
417 let Err(error) = parsed_url.set_password(Some(&pass_str.0))
418 {
419 warn!("Could not set password on XMLHttpRequest: {error:?}");
420 }
421 }
422
423 if !asynch {
427 if !self.timeout.get().is_zero() {
429 return Err(Error::InvalidAccess(Some(
430 "Nonzero timeout for synchronous request".into(),
431 )));
432 }
433 if self.response_type.get() != XMLHttpRequestResponseType::_empty {
434 return Err(Error::InvalidAccess(Some(
435 "Nonempty response type for synchronous request".into(),
436 )));
437 }
438 }
439
440 self.terminate_ongoing_fetch(cx.no_gc());
442
443 *self.request_method.safe_borrow_mut(cx.no_gc()) = parsed_method;
451 *self.request_url.safe_borrow_mut(cx.no_gc()) = Some(parsed_url);
452 self.sync.set(!asynch);
453 *self.request_headers.safe_borrow_mut(cx.no_gc()) = HeaderMap::new();
454 self.send_flag.set(false);
455 self.upload_listener.set(false);
456 *self.status.safe_borrow_mut(cx.no_gc()) = HttpStatus::new_error();
457
458 if self.ready_state.get() != XMLHttpRequestState::Opened {
460 self.change_ready_state(cx, XMLHttpRequestState::Opened);
461 }
462 Ok(())
463 },
464 _ => Err(Error::Syntax(Some("Invalid method".into()))),
468 }
469 }
470
471 fn SetRequestHeader(&self, no_gc: &NoGC, name: ByteString, value: ByteString) -> ErrorResult {
473 if self.ready_state.get() != XMLHttpRequestState::Opened {
475 return Err(Error::InvalidState(Some("Request not yet open".into())));
476 }
477 if self.send_flag.get() {
479 return Err(Error::InvalidState(Some("Request already sent".into())));
480 }
481
482 let value = trim_http_whitespace(&value);
484
485 if !is_token(&name) {
488 return Err(Error::Syntax(Some("Invalid header name".into())));
489 }
490 if !is_field_value(value) {
491 return Err(Error::Syntax(Some("Invalid header value".into())));
492 }
493
494 let name_str = name
496 .as_str()
497 .ok_or(Error::Syntax(Some("Non-UTF8 header name".into())))?;
498
499 if is_forbidden_request_header(name_str, value) {
501 return Ok(());
502 }
503
504 debug!(
505 "SetRequestHeader: name={:?}, value={:?}",
506 name_str,
507 str::from_utf8(value).ok()
508 );
509 let mut headers = self.request_headers.safe_borrow_mut(no_gc);
510
511 let value = match headers.get(name_str).map(HeaderValue::as_bytes) {
514 Some(raw) => {
515 let mut buf = raw.to_vec();
516 buf.extend_from_slice(b", ");
517 buf.extend_from_slice(value);
518 buf
519 },
520 None => value.into(),
521 };
522
523 if let (Ok(header_name), Ok(header_value)) = (
524 HeaderName::from_str(name_str),
525 HeaderValue::from_bytes(&value),
526 ) {
527 headers.insert(header_name, header_value);
528 } else {
529 warn!("Not setting header in XMLHttpRequest {name_str:?}: {value:?}");
530 }
531
532 Ok(())
533 }
534
535 fn Timeout(&self) -> u32 {
537 self.timeout.get().as_millis() as u32
538 }
539
540 fn SetTimeout(&self, no_gc: &NoGC, timeout: u32) -> ErrorResult {
542 if self.sync_in_window() {
544 return Err(Error::InvalidAccess(Some(
545 "Timeouts are not allowed for synchronous requests".into(),
546 )));
547 }
548
549 let timeout = Duration::from_millis(timeout as u64);
551 self.timeout.set(timeout);
552
553 if self.send_flag.get() {
554 if timeout.is_zero() {
555 self.cancel_timeout(no_gc);
556 return Ok(());
557 }
558 let progress = Instant::now() - self.fetch_time.get();
559 if timeout > progress {
560 self.set_timeout(no_gc, timeout - progress);
561 } else {
562 self.set_timeout(no_gc, Duration::ZERO);
564 }
565 }
566 Ok(())
567 }
568
569 fn WithCredentials(&self) -> bool {
571 self.with_credentials.get()
572 }
573
574 fn SetWithCredentials(&self, with_credentials: bool) -> ErrorResult {
576 match self.ready_state.get() {
577 XMLHttpRequestState::HeadersReceived |
579 XMLHttpRequestState::Loading |
580 XMLHttpRequestState::Done => {
581 Err(Error::InvalidState(Some("Response in progress".into())))
582 },
583 _ if self.send_flag.get() => {
585 Err(Error::InvalidState(Some("Request has been sent".into())))
586 },
587 _ => {
589 self.with_credentials.set(with_credentials);
590 Ok(())
591 },
592 }
593 }
594
595 fn Upload(&self) -> DomRoot<XMLHttpRequestUpload> {
597 DomRoot::from_ref(&*self.upload)
598 }
599
600 fn Send(
602 &self,
603 cx: &mut JSContext,
604 data: Option<DocumentOrXMLHttpRequestBodyInit>,
605 ) -> ErrorResult {
606 if self.ready_state.get() != XMLHttpRequestState::Opened || self.send_flag.get() {
609 return Err(Error::InvalidState(Some(
610 "XMLHttpRequest not open or already sent".into(),
611 )));
612 }
613 let Some(url) = self.request_url.borrow().clone() else {
614 return Err(Error::InvalidState(Some("XMLHttpRequest not open".into())));
615 };
616
617 let data = match *self.request_method.borrow() {
619 Method::GET | Method::HEAD => None,
620 _ => data,
621 };
622
623 let mut extracted_or_serialized = match data {
625 Some(DocumentOrXMLHttpRequestBodyInit::Document(ref doc)) => {
626 let bytes = Vec::from(&*serialize_document(doc)?.as_bytes(cx.no_gc()));
627 let content_type = if doc.is_html_document() {
628 "text/html;charset=UTF-8"
629 } else {
630 "application/xml;charset=UTF-8"
631 };
632 let total_bytes = bytes.len();
633 let global = self.global();
634 let stream = ReadableStream::new_from_bytes(cx, &global, bytes)?;
635 Some(ExtractedBody {
636 stream,
637 total_bytes: Some(total_bytes),
638 content_type: Some(DOMString::from(content_type)),
639 source: BodySource::Object,
640 })
641 },
642 Some(DocumentOrXMLHttpRequestBodyInit::Blob(ref b)) => {
643 let extracted_body = b
644 .extract(cx, &self.global(), false)
645 .expect("Couldn't extract body.");
646 if !extracted_body.in_memory() && self.sync.get() {
647 warn!("Sync XHR with not in-memory Blob as body not supported");
648 None
649 } else {
650 Some(extracted_body)
651 }
652 },
653 Some(DocumentOrXMLHttpRequestBodyInit::FormData(ref formdata)) => Some(
654 formdata
655 .extract(cx, &self.global(), false)
656 .expect("Couldn't extract body."),
657 ),
658 Some(DocumentOrXMLHttpRequestBodyInit::String(ref str)) => Some(
659 str.extract(cx, &self.global(), false)
660 .expect("Couldn't extract body."),
661 ),
662 Some(DocumentOrXMLHttpRequestBodyInit::URLSearchParams(ref urlsp)) => Some(
663 urlsp
664 .extract(cx, &self.global(), false)
665 .expect("Couldn't extract body."),
666 ),
667 Some(DocumentOrXMLHttpRequestBodyInit::ArrayBuffer(ref typedarray)) => {
668 let bytes = get_buffer_source_copy(typedarray.into());
669 let total_bytes = bytes.len();
670 let global = self.global();
671 let stream = ReadableStream::new_from_bytes(cx, &global, bytes)?;
672 Some(ExtractedBody {
673 stream,
674 total_bytes: Some(total_bytes),
675 content_type: None,
676 source: BodySource::Object,
677 })
678 },
679 Some(DocumentOrXMLHttpRequestBodyInit::ArrayBufferView(ref typedarray)) => {
680 let bytes = get_buffer_source_copy(typedarray.into());
681 let total_bytes = bytes.len();
682 let global = self.global();
683 let stream = ReadableStream::new_from_bytes(cx, &global, bytes)?;
684 Some(ExtractedBody {
685 stream,
686 total_bytes: Some(total_bytes),
687 content_type: None,
688 source: BodySource::Object,
689 })
690 },
691 None => None,
692 };
693
694 self.request_body_len.set(
695 extracted_or_serialized
696 .as_ref()
697 .map_or(0, |e| e.total_bytes.unwrap_or(0)),
698 );
699
700 let has_handlers = self.upload.upcast::<EventTarget>().has_handlers();
704 self.upload_listener.set(has_handlers && data.is_some());
705
706 self.upload_complete.set(false);
710
711 self.upload_complete.set(extracted_or_serialized.is_none());
716
717 self.send_flag.set(true);
719
720 if !self.sync.get() {
722 let gen_id = self.generation_id.get();
725
726 self.dispatch_response_progress_event(cx, atom!("loadstart"));
728 if self.generation_id.get() != gen_id {
729 return Ok(());
730 }
731
732 if !self.upload_complete.get() && self.upload_listener.get() {
736 self.dispatch_upload_progress_event(cx, atom!("loadstart"), Ok(Some(0)));
737 if self.generation_id.get() != gen_id {
738 return Ok(());
739 }
740 }
741 }
742
743 let credentials_mode = if self.with_credentials.get() {
746 CredentialsMode::Include
747 } else {
748 CredentialsMode::CredentialsSameOrigin
749 };
750 let use_url_credentials = !url.username().is_empty() || url.password().is_some();
751
752 let content_type = match extracted_or_serialized.as_mut() {
753 Some(body) => body.content_type.take(),
754 None => None,
755 };
756
757 let global = self.global();
758 let mut request = RequestBuilder::new(global.webview_id(), url, self.referrer.clone())
759 .method(self.request_method.borrow().clone())
760 .headers((*self.request_headers.borrow()).clone())
761 .unsafe_request(true)
762 .body(extracted_or_serialized.map(|e| e.into_net_request_body(cx).0))
764 .synchronous(self.sync.get())
765 .mode(RequestMode::CorsMode)
766 .use_cors_preflight(self.upload_listener.get())
767 .credentials_mode(credentials_mode)
768 .use_url_credentials(use_url_credentials)
769 .with_global_scope(&global)
770 .referrer_policy(self.referrer_policy);
771
772 if let Some(content_type) = content_type {
774 let encoding = match data {
775 Some(DocumentOrXMLHttpRequestBodyInit::String(_)) |
776 Some(DocumentOrXMLHttpRequestBodyInit::Document(_)) =>
777 {
781 Some("UTF-8")
782 },
783 _ => None,
784 };
785
786 let mut content_type_set = false;
789 if !request.headers.contains_key(header::CONTENT_TYPE) &&
790 let Ok(content_type_value) = HeaderValue::from_str(&content_type.str())
791 {
792 request
793 .headers
794 .insert(header::CONTENT_TYPE, content_type_value);
795 content_type_set = true;
796 }
797
798 if !content_type_set {
799 let content_type = request.headers.typed_get::<ContentType>();
800 if let Some(content_type) = content_type &&
801 let Some(encoding) = encoding &&
802 let Ok(mime) = content_type.to_string().parse::<Mime>()
803 {
804 for param in mime.parameters.iter() {
805 if param.0 == CHARSET && !param.1.as_str().eq_ignore_ascii_case(encoding) {
806 let new_params: Vec<_> =
807 mime.parameters.iter().filter(|p| p.0 != CHARSET).collect();
808
809 let new_mime = format!(
810 "{}/{};charset={encoding}{}{}",
811 mime.type_,
812 mime.subtype,
813 if new_params.is_empty() { "" } else { "; " },
814 new_params
815 .iter()
816 .map(|param| format!("{}={}", param.0, param.1))
817 .collect::<Vec<String>>()
818 .join("; ")
819 );
820
821 if let Ok(content_type_header) = HeaderValue::from_str(&new_mime) {
822 request
823 .headers
824 .insert(header::CONTENT_TYPE, content_type_header);
825 }
826 }
827 }
828 }
829 }
830 }
831
832 self.fetch_time.set(Instant::now());
833
834 let rv = self.fetch(cx, request, &self.global());
835 if self.sync.get() {
837 return rv;
838 }
839
840 let timeout = self.timeout.get();
841 if timeout > Duration::ZERO {
842 self.set_timeout(cx.no_gc(), timeout);
843 }
844 Ok(())
845 }
846
847 fn Abort(&self, cx: &mut JSContext) {
849 self.terminate_ongoing_fetch(cx.no_gc());
851 let state = self.ready_state.get();
853 if (state == XMLHttpRequestState::Opened && self.send_flag.get()) ||
854 state == XMLHttpRequestState::HeadersReceived ||
855 state == XMLHttpRequestState::Loading
856 {
857 let gen_id = self.generation_id.get();
858 self.process_partial_response(cx, XHRProgress::Errored(gen_id, ErrorType::Abort));
859 if self.generation_id.get() != gen_id {
862 return;
863 }
864 }
865 if self.ready_state.get() == XMLHttpRequestState::Done {
867 self.change_ready_state(cx, XMLHttpRequestState::Unsent);
868 self.response_status.set(Err(()));
869 *self.status.safe_borrow_mut(cx.no_gc()) = HttpStatus::new_error();
870 self.response.safe_borrow_mut(cx.no_gc()).clear();
871 self.response_headers.safe_borrow_mut(cx.no_gc()).clear();
872 }
873 }
874
875 fn ResponseURL(&self) -> USVString {
877 USVString(self.response_url.borrow().clone())
878 }
879
880 fn Status(&self) -> u16 {
882 self.status.borrow().raw_code()
883 }
884
885 fn StatusText(&self) -> ByteString {
887 ByteString::new(self.status.borrow().message().to_vec())
888 }
889
890 fn GetResponseHeader(&self, name: ByteString) -> Option<ByteString> {
892 let headers = self.filter_response_headers();
893 let headers = headers.get_all(HeaderName::from_str(name.as_str()?).ok()?);
896 let mut first = true;
897 let s = headers.iter().fold(Vec::new(), |mut vec, value| {
898 if !first {
899 vec.extend(", ".as_bytes());
900 }
901 if let Ok(v) = str::from_utf8(value.as_bytes()).map(|s| s.trim().as_bytes()) {
902 vec.extend(v);
903 first = false;
904 }
905 vec
906 });
907
908 if first {
910 None
911 } else {
912 Some(ByteString::new(s))
913 }
914 }
915
916 fn GetAllResponseHeaders(&self) -> ByteString {
918 let headers = self.filter_response_headers();
919 let keys = headers.keys();
920 let v = keys.fold(Vec::new(), |mut vec, k| {
921 let values = headers.get_all(k);
922 vec.extend(k.as_str().as_bytes());
923 vec.extend(": ".as_bytes());
924 let mut first = true;
925 for value in values {
926 if !first {
927 vec.extend(", ".as_bytes());
928 first = false;
929 }
930 vec.extend(value.as_bytes());
931 }
932 vec.extend("\r\n".as_bytes());
933 vec
934 });
935
936 ByteString::new(v)
937 }
938
939 fn OverrideMimeType(&self, no_gc: &NoGC, mime: DOMString) -> ErrorResult {
941 match self.ready_state.get() {
944 XMLHttpRequestState::Loading | XMLHttpRequestState::Done => {
945 return Err(Error::InvalidState(Some("Request already started".into())));
946 },
947 _ => {},
948 }
949
950 let override_mime = match mime.parse::<Mime>() {
954 Ok(mime) => mime,
955 Err(_) => "application/octet-stream"
956 .parse::<Mime>()
957 .expect("Fallback MIME type must always parse"),
958 };
959
960 *self.override_mime_type.safe_borrow_mut(no_gc) = Some(override_mime);
961 Ok(())
962 }
963
964 fn ResponseType(&self) -> XMLHttpRequestResponseType {
966 self.response_type.get()
967 }
968
969 fn SetResponseType(&self, response_type: XMLHttpRequestResponseType) -> ErrorResult {
971 if self.global().is::<WorkerGlobalScope>() &&
973 response_type == XMLHttpRequestResponseType::Document
974 {
975 return Ok(());
976 }
977 match self.ready_state.get() {
978 XMLHttpRequestState::Loading | XMLHttpRequestState::Done => {
980 Err(Error::InvalidState(Some("Request already started".into())))
981 },
982 _ => {
983 if self.sync_in_window() {
984 Err(Error::InvalidAccess(Some(
986 "Cannot set response type for synchronous requests".into(),
987 )))
988 } else {
989 self.response_type.set(response_type);
991 Ok(())
992 }
993 },
994 }
995 }
996
997 fn Response(&self, cx: &mut JSContext, mut rval: MutableHandleValue) {
999 match self.response_type.get() {
1000 XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => {
1001 let ready_state = self.ready_state.get();
1002 if ready_state == XMLHttpRequestState::Done ||
1004 ready_state == XMLHttpRequestState::Loading
1005 {
1006 self.text_response().to_jsval(cx, rval);
1007 } else {
1008 "".to_jsval(cx, rval);
1010 }
1011 },
1012 _ if self.ready_state.get() != XMLHttpRequestState::Done => {
1014 rval.set(NullValue());
1015 },
1016 XMLHttpRequestResponseType::Document => self.document_response(cx).to_jsval(cx, rval),
1018 XMLHttpRequestResponseType::Json => self.json_response(cx, rval),
1019 XMLHttpRequestResponseType::Blob => self.blob_response(cx).to_jsval(cx, rval),
1020 XMLHttpRequestResponseType::Arraybuffer => match self.arraybuffer_response(cx) {
1021 Some(array_buffer) => array_buffer.to_jsval(cx, rval),
1022 None => rval.set(NullValue()),
1023 },
1024 }
1025 }
1026
1027 fn GetResponseText(&self) -> Fallible<USVString> {
1029 match self.response_type.get() {
1030 XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Text => {
1031 Ok(USVString(match self.ready_state.get() {
1032 XMLHttpRequestState::Loading | XMLHttpRequestState::Done => {
1034 self.text_response()
1035 },
1036 _ => String::new(),
1038 }))
1039 },
1040 _ => Err(Error::InvalidState(Some(
1042 "Response type does not match".into(),
1043 ))),
1044 }
1045 }
1046
1047 fn GetResponseXML(&self, cx: &mut JSContext) -> Fallible<Option<DomRoot<Document>>> {
1049 match self.response_type.get() {
1050 XMLHttpRequestResponseType::_empty | XMLHttpRequestResponseType::Document => {
1051 if let XMLHttpRequestState::Done = self.ready_state.get() {
1053 Ok(self.document_response(cx))
1054 } else {
1055 Ok(None)
1057 }
1058 },
1059 _ => Err(Error::InvalidState(Some(
1061 "Response type does not match".into(),
1062 ))),
1063 }
1064 }
1065}
1066
1067pub(crate) type TrustedXHRAddress = Trusted<XMLHttpRequest>;
1068
1069impl XMLHttpRequest {
1070 fn change_ready_state(&self, cx: &mut JSContext, rs: XMLHttpRequestState) {
1071 assert_ne!(self.ready_state.get(), rs);
1072 self.ready_state.set(rs);
1073 if rs != XMLHttpRequestState::Unsent {
1074 let event = Event::new(
1075 cx,
1076 &self.global(),
1077 atom!("readystatechange"),
1078 EventBubbles::DoesNotBubble,
1079 EventCancelable::Cancelable,
1080 );
1081 event.fire(cx, self.upcast());
1082 }
1083 }
1084
1085 fn process_headers_available(
1086 &self,
1087 cx: &mut JSContext,
1088 gen_id: GenerationId,
1089 metadata: Result<FetchMetadata, NetworkError>,
1090 ) -> Result<(), Error> {
1091 let metadata = match metadata {
1092 Ok(meta) => match meta {
1093 FetchMetadata::Unfiltered(m) => m,
1094 FetchMetadata::Filtered { filtered, .. } => match filtered {
1095 FilteredMetadata::Basic(m) => m,
1096 FilteredMetadata::Cors(m) => m,
1097 FilteredMetadata::Opaque => return Err(Error::Network(None)),
1098 FilteredMetadata::OpaqueRedirect(_) => return Err(Error::Network(None)),
1099 },
1100 },
1101 Err(_) => {
1102 self.process_partial_response(cx, XHRProgress::Errored(gen_id, ErrorType::Network));
1103 return Err(Error::Network(None));
1104 },
1105 };
1106
1107 metadata.final_url[..Position::AfterQuery]
1108 .clone_into(&mut self.response_url.safe_borrow_mut(cx.no_gc()));
1109
1110 self.process_partial_response(
1112 cx,
1113 XHRProgress::HeadersReceived(
1114 gen_id,
1115 metadata.headers.map(Serde::into_inner),
1116 metadata.status,
1117 ),
1118 );
1119 Ok(())
1120 }
1121
1122 fn process_data_available(&self, cx: &mut JSContext, gen_id: GenerationId, payload: Bytes) {
1123 self.process_partial_response(cx, XHRProgress::Loading(gen_id, payload));
1124 }
1125
1126 fn process_response_complete(
1127 &self,
1128 cx: &mut JSContext,
1129 gen_id: GenerationId,
1130 status: Result<(), NetworkError>,
1131 ) -> ErrorResult {
1132 match status {
1133 Ok(()) => {
1134 self.process_partial_response(cx, XHRProgress::Done(gen_id));
1135 Ok(())
1136 },
1137 Err(_) => {
1138 self.process_partial_response(cx, XHRProgress::Errored(gen_id, ErrorType::Network));
1139 Err(Error::Network(None))
1140 },
1141 }
1142 }
1143
1144 fn process_partial_response(&self, cx: &mut JSContext, progress: XHRProgress) {
1145 let msg_id = progress.generation_id();
1146
1147 macro_rules! return_if_fetch_was_terminated(
1150 () => (
1151 if msg_id != self.generation_id.get() {
1152 return
1153 }
1154 );
1155 );
1156
1157 return_if_fetch_was_terminated!();
1159
1160 if self.response_status.get().is_err() {
1162 return;
1163 }
1164
1165 match progress {
1166 XHRProgress::HeadersReceived(_, headers, status) => {
1167 assert!(self.ready_state.get() == XMLHttpRequestState::Opened);
1168 self.upload_complete.set(true);
1174 if !self.sync.get() && self.upload_listener.get() {
1176 self.dispatch_upload_progress_event(cx, atom!("progress"), Ok(None));
1177 return_if_fetch_was_terminated!();
1178 self.dispatch_upload_progress_event(cx, atom!("load"), Ok(None));
1179 return_if_fetch_was_terminated!();
1180 self.dispatch_upload_progress_event(cx, atom!("loadend"), Ok(None));
1181 return_if_fetch_was_terminated!();
1182 }
1183 if !status.is_error() {
1187 *self.status.safe_borrow_mut(cx.no_gc()) = status;
1188 }
1189 if let Some(h) = headers.as_ref() {
1190 *self.response_headers.safe_borrow_mut(cx.no_gc()) = h.clone();
1191 }
1192 {
1193 let len = headers.and_then(|h| h.typed_get::<ContentLength>());
1194 let mut response = self.response.safe_borrow_mut(cx.no_gc());
1195 response.clear();
1196 if let Some(len) = len {
1197 let size = cmp::min(0b100_0000000000_0000000000, len.0 as usize);
1204
1205 response.reserve(size);
1207 }
1208 }
1209 if !self.sync.get() {
1211 self.change_ready_state(cx, XMLHttpRequestState::HeadersReceived);
1212 }
1213 },
1214 XHRProgress::Loading(_, partial_response) => {
1215 self.response
1220 .safe_borrow_mut(cx.no_gc())
1221 .extend_from_slice(&partial_response);
1222 if !self.sync.get() {
1223 if self.ready_state.get() == XMLHttpRequestState::HeadersReceived {
1224 self.ready_state.set(XMLHttpRequestState::Loading);
1225 }
1226 let event = Event::new(
1227 cx,
1228 &self.global(),
1229 atom!("readystatechange"),
1230 EventBubbles::DoesNotBubble,
1231 EventCancelable::Cancelable,
1232 );
1233 event.fire(cx, self.upcast());
1234 return_if_fetch_was_terminated!();
1235 self.dispatch_response_progress_event(cx, atom!("progress"));
1236 }
1237 },
1238 XHRProgress::Done(_) => {
1239 assert!(
1240 self.ready_state.get() == XMLHttpRequestState::HeadersReceived ||
1241 self.ready_state.get() == XMLHttpRequestState::Loading ||
1242 self.sync.get()
1243 );
1244
1245 self.cancel_timeout(cx.no_gc());
1246 self.controller.safe_borrow_mut(cx.no_gc()).ignore();
1247
1248 self.send_flag.set(false);
1253
1254 self.change_ready_state(cx, XMLHttpRequestState::Done);
1255 return_if_fetch_was_terminated!();
1256 self.dispatch_response_progress_event(cx, atom!("load"));
1258 return_if_fetch_was_terminated!();
1259 self.dispatch_response_progress_event(cx, atom!("loadend"));
1260 },
1261 XHRProgress::Errored(_, e) => {
1262 self.cancel_timeout(cx.no_gc());
1263 self.controller.safe_borrow_mut(cx.no_gc()).ignore();
1264
1265 self.discard_subsequent_responses();
1266 self.send_flag.set(false);
1267 *self.status.safe_borrow_mut(cx.no_gc()) = HttpStatus::new_error();
1268 self.response_headers.safe_borrow_mut(cx.no_gc()).clear();
1269 self.change_ready_state(cx, XMLHttpRequestState::Done);
1271 return_if_fetch_was_terminated!();
1272
1273 let errormsg = match e {
1274 ErrorType::Abort => "abort",
1275 ErrorType::Timeout => "timeout",
1276 ErrorType::Network => "error",
1277 };
1278
1279 let upload_complete = &self.upload_complete;
1280 if !upload_complete.get() {
1281 upload_complete.set(true);
1282 if self.upload_listener.get() {
1283 self.dispatch_upload_progress_event(cx, Atom::from(errormsg), Err(()));
1284 return_if_fetch_was_terminated!();
1285 self.dispatch_upload_progress_event(cx, atom!("loadend"), Err(()));
1286 return_if_fetch_was_terminated!();
1287 }
1288 }
1289 self.dispatch_response_progress_event(cx, Atom::from(errormsg));
1290 return_if_fetch_was_terminated!();
1291 self.dispatch_response_progress_event(cx, atom!("loadend"));
1292 },
1293 }
1294 }
1295
1296 fn terminate_ongoing_fetch(&self, no_gc: &NoGC) {
1297 self.controller.safe_borrow_mut(no_gc).abort();
1298 let GenerationId(prev_id) = self.generation_id.get();
1299 self.generation_id.set(GenerationId(prev_id + 1));
1300 self.response_status.set(Ok(()));
1301 }
1302
1303 fn dispatch_progress_event(
1304 &self,
1305 cx: &mut JSContext,
1306 upload: bool,
1307 type_: Atom,
1308 loaded: u64,
1309 total: Option<u64>,
1310 ) {
1311 let (total_length, length_computable) = if self
1312 .response_headers
1313 .borrow()
1314 .contains_key(header::CONTENT_ENCODING)
1315 {
1316 (0, false)
1317 } else {
1318 (total.unwrap_or(0), total.is_some())
1319 };
1320 let progressevent = ProgressEvent::new(
1321 cx,
1322 &self.global(),
1323 type_,
1324 EventBubbles::DoesNotBubble,
1325 EventCancelable::NotCancelable,
1326 length_computable,
1327 Finite::wrap(loaded as f64),
1328 Finite::wrap(total_length as f64),
1329 );
1330 let target = if upload {
1331 self.upload.upcast()
1332 } else {
1333 self.upcast()
1334 };
1335 progressevent.upcast::<Event>().fire(cx, target);
1336 }
1337
1338 fn dispatch_upload_progress_event(
1339 &self,
1340 cx: &mut JSContext,
1341 type_: Atom,
1342 partial_load: Result<Option<u64>, ()>,
1343 ) {
1344 let request_body_len = self.request_body_len.get() as u64;
1348 let (loaded, total) = match partial_load {
1349 Ok(l) => match l {
1350 Some(loaded) => (loaded, Some(request_body_len)),
1351 None => (request_body_len, Some(request_body_len)),
1352 },
1353 Err(()) => (0, None),
1354 };
1355 self.dispatch_progress_event(cx, true, type_, loaded, total);
1356 }
1357
1358 fn dispatch_response_progress_event(&self, cx: &mut JSContext, type_: Atom) {
1359 let len = self.response.borrow().len() as u64;
1360 let total = self
1361 .response_headers
1362 .borrow()
1363 .typed_get::<ContentLength>()
1364 .map(|v| v.0);
1365 self.dispatch_progress_event(cx, false, type_, len, total);
1366 }
1367
1368 fn set_timeout(&self, no_gc: &NoGC, duration: Duration) {
1369 let callback = OneshotTimerCallback::XhrTimeout(XHRTimeoutCallback {
1372 xhr: Trusted::new(self),
1373 generation_id: self.generation_id.get(),
1374 });
1375 *self.timeout_cancel.safe_borrow_mut(no_gc) =
1376 Some(self.global().schedule_callback(callback, duration));
1377 }
1378
1379 fn cancel_timeout(&self, no_gc: &NoGC) {
1380 if let Some(handle) = self.timeout_cancel.safe_borrow_mut(no_gc).take() {
1381 self.global().unschedule_callback(handle);
1382 }
1383 }
1384
1385 fn text_response(&self) -> String {
1387 let charset = self.final_charset().unwrap_or(UTF_8);
1389 let response = self.response.borrow();
1395 let (text, _, _) = charset.decode(&response);
1396 text.into_owned()
1397 }
1398
1399 fn blob_response(&self, cx: &mut JSContext) -> DomRoot<Blob> {
1401 if let Some(response) = self.response_blob.get() {
1403 return response;
1404 }
1405 let mime = normalize_type_string(&self.final_mime_type().to_string());
1407
1408 let bytes = self.response.borrow().to_vec();
1410 let blob = Blob::new(cx, &self.global(), BlobImpl::new_from_bytes(bytes, mime));
1411 self.response_blob.set(Some(&blob));
1412 blob
1413 }
1414
1415 fn arraybuffer_response(
1417 &self,
1418 cx: &mut JSContext,
1419 ) -> Option<RootedTraceableBox<HeapArrayBuffer>> {
1420 if !self.response_arraybuffer.is_initialized() {
1423 let bytes = self.response.borrow();
1424
1425 self.response_arraybuffer.set_data(cx, &bytes).ok()?;
1427 }
1428
1429 self.response_arraybuffer.get_typed_array().ok()
1431 }
1432
1433 fn document_response(&self, cx: &mut JSContext) -> Option<DomRoot<Document>> {
1435 let response = self.response_xml.get();
1437 if response.is_some() {
1438 return response;
1439 }
1440
1441 if self.response_status.get().is_err() {
1443 return None;
1444 }
1445
1446 let final_mime = self.final_mime_type();
1448
1449 let is_xml_mime_type = final_mime.matches(TEXT, XML) ||
1451 final_mime.matches(APPLICATION, XML) ||
1452 final_mime.has_suffix(XML);
1453 if !final_mime.matches(TEXT, HTML) && !is_xml_mime_type {
1454 return None;
1455 }
1456
1457 let charset;
1460 let temp_doc;
1461 if final_mime.matches(TEXT, HTML) {
1462 if self.response_type.get() == XMLHttpRequestResponseType::_empty {
1463 return None;
1464 }
1465
1466 charset = Some(self.final_charset().unwrap_or(UTF_8));
1473
1474 temp_doc = self.document_text_html(cx);
1478 } else {
1479 assert!(is_xml_mime_type);
1480
1481 temp_doc = self.handle_xml(cx);
1488 charset = self.final_charset();
1489
1490 let has_no_child_nodes = temp_doc.upcast::<Node>().children().next().is_none();
1494 if has_no_child_nodes {
1495 return None;
1496 }
1497 }
1498
1499 let charset = charset.unwrap_or(UTF_8);
1501
1502 temp_doc.set_encoding(charset);
1504
1505 self.response_xml.set(Some(&temp_doc));
1513 self.response_xml.get()
1514 }
1515
1516 #[expect(unsafe_code)]
1517 fn json_response(&self, cx: &mut JSContext, mut rval: MutableHandleValue) {
1519 let response_json = self.response_json.get();
1521 if !response_json.is_null_or_undefined() {
1522 return rval.set(response_json);
1523 }
1524 let bytes = self.response.borrow();
1526 if bytes.is_empty() {
1528 return rval.set(NullValue());
1529 }
1530 let json_text = decode_to_utf16_with_bom_removal(&bytes, UTF_8);
1537 unsafe {
1539 if !JS_ParseJSON(
1540 cx,
1541 json_text.as_ptr(),
1542 json_text.len() as u32,
1543 rval.reborrow(),
1544 ) {
1545 JS_ClearPendingException(cx);
1546 return rval.set(NullValue());
1547 }
1548 }
1549 self.response_json.set(rval.get());
1551 }
1552
1553 fn document_text_html(&self, cx: &mut JSContext) -> DomRoot<Document> {
1554 let charset = self.final_charset().unwrap_or(UTF_8);
1555 let wr = self.global();
1556 let response = self.response.borrow();
1557 let (decoded, _, _) = charset.decode(&response);
1558 let document = self.new_doc(cx, IsHTMLDocument::HTMLDocument);
1559 ServoParser::parse_html_document(
1561 cx,
1562 &document,
1563 Some(DOMString::from(decoded)),
1564 wr.get_url(),
1565 None,
1566 None,
1567 );
1568 document
1569 }
1570
1571 fn handle_xml(&self, cx: &mut JSContext) -> DomRoot<Document> {
1572 let charset = self.final_charset().unwrap_or(UTF_8);
1573 let wr = self.global();
1574 let response = self.response.borrow();
1575 let (decoded, _, _) = charset.decode(&response);
1576 let document = self.new_doc(cx, IsHTMLDocument::NonHTMLDocument);
1577 ServoParser::parse_xml_document(
1579 cx,
1580 &document,
1581 Some(DOMString::from(decoded)),
1582 wr.get_url(),
1583 None,
1584 );
1585 document
1586 }
1587
1588 fn new_doc(&self, cx: &mut JSContext, is_html_document: IsHTMLDocument) -> DomRoot<Document> {
1589 let wr = self.global();
1590 let win = wr.as_window();
1591 let doc = win.Document();
1592 let docloader = DocumentLoader::new(&doc.loader());
1593 let base = wr.get_url();
1594 let parsed_url = base.join(&self.ResponseURL().0).ok();
1595 let content_type = Some(self.final_mime_type());
1596 Document::new(
1597 cx,
1598 win,
1599 HasBrowsingContext::No,
1600 parsed_url,
1601 None,
1602 doc.origin().clone(),
1603 is_html_document,
1604 content_type,
1605 None,
1606 DocumentActivity::Inactive,
1607 docloader,
1608 None,
1609 None,
1610 false,
1611 false,
1612 Some(doc.insecure_requests_policy()),
1613 doc.has_trustworthy_ancestor_origin(),
1614 doc.custom_element_reaction_stack(),
1615 doc.creation_sandboxing_flag_set(),
1616 doc.pipeline_id(),
1617 doc.image_cache(),
1618 )
1619 }
1620
1621 fn filter_response_headers(&self) -> HeaderMap {
1622 let mut headers = self.response_headers.borrow().clone();
1624 headers.remove(header::SET_COOKIE);
1625 headers.remove(HeaderName::from_static("set-cookie2"));
1626 headers
1628 }
1629
1630 fn discard_subsequent_responses(&self) {
1631 self.response_status.set(Err(()));
1632 }
1633
1634 fn fetch(
1635 &self,
1636 cx: &mut JSContext,
1637 request_builder: RequestBuilder,
1638 global: &GlobalScope,
1639 ) -> ErrorResult {
1640 let xhr = Trusted::new(self);
1641
1642 let sync_status = Arc::new(AtomicRefCell::new(None));
1643 let context = XHRContext {
1644 xhr,
1645 gen_id: self.generation_id.get(),
1646 sync_status: sync_status.clone(),
1647 url: request_builder.url.url(),
1648 };
1649
1650 let (task_source, script_port) = if self.sync.get() {
1651 let (sender, receiver) = global.new_script_pair();
1652 (
1653 SendableTaskSource {
1654 sender,
1655 pipeline_id: global.pipeline_id(),
1656 name: TaskSourceName::Networking,
1657 canceller: Default::default(),
1658 },
1659 Some(receiver),
1660 )
1661 } else {
1662 (
1663 global.task_manager().networking_task_source().to_sendable(),
1664 None,
1665 )
1666 };
1667
1668 *self.controller.safe_borrow_mut(cx.no_gc()) =
1669 FetchController::new(request_builder.id, false, global.core_resource_thread());
1670
1671 global.fetch(request_builder, context, task_source);
1672
1673 if let Some(script_port) = script_port {
1674 loop {
1675 if !global.process_event(cx, script_port.recv().unwrap()) {
1676 return Err(Error::Abort(None));
1678 }
1679 if let Some(ref status) = *sync_status.borrow() {
1680 return status.clone();
1681 }
1682 }
1683 }
1684 Ok(())
1685 }
1686
1687 fn final_charset(&self) -> Option<&'static Encoding> {
1689 let response_charset = self
1693 .response_mime_type()
1694 .get_parameter(CHARSET)
1695 .map(ToString::to_string);
1696
1697 let override_charset = self
1699 .override_mime_type
1700 .borrow()
1701 .as_ref()
1702 .and_then(|mime| mime.get_parameter(CHARSET))
1703 .map(ToString::to_string);
1704
1705 override_charset
1710 .or(response_charset)
1711 .and_then(|charset| Encoding::for_label(charset.as_bytes()))
1712 }
1713
1714 fn response_mime_type(&self) -> Mime {
1716 extract_mime_type_as_dataurl_mime(&self.response_headers.borrow())
1721 .unwrap_or_else(|| Mime::new(TEXT, XML))
1722 }
1723
1724 fn final_mime_type(&self) -> Mime {
1726 self.override_mime_type
1727 .borrow()
1728 .as_ref()
1729 .map(MimeExt::clone)
1730 .unwrap_or_else(|| self.response_mime_type())
1731 }
1732}
1733
1734#[derive(JSTraceable, MallocSizeOf)]
1735pub(crate) struct XHRTimeoutCallback {
1736 #[ignore_malloc_size_of = "Because it is non-owning"]
1737 xhr: Trusted<XMLHttpRequest>,
1738 generation_id: GenerationId,
1739}
1740
1741impl XHRTimeoutCallback {
1742 pub(crate) fn invoke(self, cx: &mut JSContext) {
1743 let xhr = self.xhr.root();
1744 if xhr.ready_state.get() != XMLHttpRequestState::Done {
1745 xhr.process_partial_response(
1746 cx,
1747 XHRProgress::Errored(self.generation_id, ErrorType::Timeout),
1748 );
1749 }
1750 }
1751}
1752
1753fn serialize_document(doc: &Document) -> Fallible<DOMString> {
1754 let mut writer = vec![];
1755 if serialize(
1756 &mut writer,
1757 &HtmlSerialize::new(doc.upcast::<Node>()),
1758 SerializeOpts::default(),
1759 )
1760 .is_err()
1761 {
1762 return Err(Error::InvalidState(Some(
1763 "Could not serialize document".into(),
1764 )));
1765 };
1766 let Ok(string) = String::from_utf8(writer) else {
1767 return Err(Error::InvalidState(Some(
1768 "Could not serialize document".into(),
1769 )));
1770 };
1771 Ok(DOMString::from(string))
1772}
1773
1774pub(crate) fn is_field_value(slice: &[u8]) -> bool {
1777 #[derive(PartialEq)]
1779 #[expect(clippy::upper_case_acronyms)]
1780 enum PreviousCharacter {
1781 Other,
1782 CR,
1783 LF,
1784 SPHT, }
1786 let mut prev = PreviousCharacter::Other; slice.iter().all(|&x| {
1788 match x {
1790 13 if (prev == PreviousCharacter::Other || prev == PreviousCharacter::SPHT) => {
1791 prev = PreviousCharacter::CR;
1793 true
1794 },
1795 10 if prev == PreviousCharacter::CR => {
1796 prev = PreviousCharacter::LF;
1798 true
1799 },
1800 10 => false,
1801 32 => {
1802 if prev == PreviousCharacter::LF || prev == PreviousCharacter::SPHT {
1804 prev = PreviousCharacter::SPHT;
1805 true
1806 } else if prev == PreviousCharacter::Other {
1807 true
1812 } else {
1813 false
1814 }
1815 },
1816 9 if prev == PreviousCharacter::LF || prev == PreviousCharacter::SPHT => {
1817 prev = PreviousCharacter::SPHT;
1819 true
1820 },
1821 9 => false,
1822 0..=31 | 127 => false, x if x > 127 => false, _ if prev == PreviousCharacter::Other || prev == PreviousCharacter::SPHT => {
1825 prev = PreviousCharacter::Other;
1826 true
1827 },
1828 _ => false, }
1830 })
1831}