1 /*
2  *  Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
3  *  Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
4  *  Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
5  *  Copyright (C) 2008, 2011 Google Inc. All rights reserved.
6  *  Copyright (C) 2012 Intel Corporation
7  *
8  *  This library is free software; you can redistribute it and/or
9  *  modify it under the terms of the GNU Lesser General Public
10  *  License as published by the Free Software Foundation; either
11  *  version 2 of the License, or (at your option) any later version.
12  *
13  *  This library is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  *  Lesser General Public License for more details.
17  *
18  *  You should have received a copy of the GNU Lesser General Public
19  *  License along with this library; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  *  Boston, MA 02110-1301 USA
22  */
23 
24 #include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request.h"
25 
26 #include <memory>
27 #include <utility>
28 
29 #include "base/auto_reset.h"
30 #include "base/feature_list.h"
31 #include "base/metrics/histogram_macros.h"
32 #include "base/time/time.h"
33 #include "services/network/public/mojom/trust_tokens.mojom-shared.h"
34 #include "third_party/blink/public/common/blob/blob_utils.h"
35 #include "third_party/blink/public/common/features.h"
36 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink-forward.h"
37 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom-blink.h"
38 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
39 #include "third_party/blink/public/platform/web_url_request.h"
40 #include "third_party/blink/renderer/bindings/core/v8/array_buffer_or_array_buffer_view_or_blob_or_usv_string.h"
41 #include "third_party/blink/renderer/bindings/core/v8/document_or_xml_http_request_body_init.h"
42 #include "third_party/blink/renderer/core/dom/document_init.h"
43 #include "third_party/blink/renderer/core/dom/document_parser.h"
44 #include "third_party/blink/renderer/core/dom/dom_exception.h"
45 #include "third_party/blink/renderer/core/dom/events/event.h"
46 #include "third_party/blink/renderer/core/dom/xml_document.h"
47 #include "third_party/blink/renderer/core/editing/serializers/serialization.h"
48 #include "third_party/blink/renderer/core/events/progress_event.h"
49 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
50 #include "third_party/blink/renderer/core/fetch/trust_token_issuance_authorization.h"
51 #include "third_party/blink/renderer/core/fetch/trust_token_to_mojom.h"
52 #include "third_party/blink/renderer/core/fileapi/blob.h"
53 #include "third_party/blink/renderer/core/fileapi/file.h"
54 #include "third_party/blink/renderer/core/fileapi/file_reader_loader.h"
55 #include "third_party/blink/renderer/core/fileapi/file_reader_loader_client.h"
56 #include "third_party/blink/renderer/core/fileapi/public_url_manager.h"
57 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
58 #include "third_party/blink/renderer/core/frame/deprecation.h"
59 #include "third_party/blink/renderer/core/frame/frame.h"
60 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
61 #include "third_party/blink/renderer/core/frame/page_dismissal_scope.h"
62 #include "third_party/blink/renderer/core/frame/settings.h"
63 #include "third_party/blink/renderer/core/html/forms/form_data.h"
64 #include "third_party/blink/renderer/core/html/html_document.h"
65 #include "third_party/blink/renderer/core/html/parser/text_resource_decoder.h"
66 #include "third_party/blink/renderer/core/inspector/console_message.h"
67 #include "third_party/blink/renderer/core/inspector/inspector_trace_events.h"
68 #include "third_party/blink/renderer/core/loader/threadable_loader.h"
69 #include "third_party/blink/renderer/core/page/chrome_client.h"
70 #include "third_party/blink/renderer/core/page/page.h"
71 #include "third_party/blink/renderer/core/probe/core_probes.h"
72 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
73 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer_view.h"
74 #include "third_party/blink/renderer/core/typed_arrays/dom_typed_array.h"
75 #include "third_party/blink/renderer/core/url/url_search_params.h"
76 #include "third_party/blink/renderer/core/xmlhttprequest/xml_http_request_upload.h"
77 #include "third_party/blink/renderer/platform/bindings/dom_wrapper_world.h"
78 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
79 #include "third_party/blink/renderer/platform/bindings/script_state.h"
80 #include "third_party/blink/renderer/platform/blob/blob_data.h"
81 #include "third_party/blink/renderer/platform/file_metadata.h"
82 #include "third_party/blink/renderer/platform/heap/heap.h"
83 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
84 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
85 #include "third_party/blink/renderer/platform/loader/cors/cors.h"
86 #include "third_party/blink/renderer/platform/loader/fetch/fetch_initiator_type_names.h"
87 #include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h"
88 #include "third_party/blink/renderer/platform/loader/fetch/resource_error.h"
89 #include "third_party/blink/renderer/platform/loader/fetch/resource_loader_options.h"
90 #include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
91 #include "third_party/blink/renderer/platform/loader/fetch/text_resource_decoder_options.h"
92 #include "third_party/blink/renderer/platform/network/http_names.h"
93 #include "third_party/blink/renderer/platform/network/http_parsers.h"
94 #include "third_party/blink/renderer/platform/network/mime/mime_type_registry.h"
95 #include "third_party/blink/renderer/platform/network/network_log.h"
96 #include "third_party/blink/renderer/platform/network/parsed_content_type.h"
97 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
98 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
99 #include "third_party/blink/renderer/platform/weborigin/security_policy.h"
100 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
101 #include "third_party/blink/renderer/platform/wtf/assertions.h"
102 #include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
103 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
104 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
105 
106 namespace blink {
107 
108 namespace {
109 
110 // This class protects the wrapper of the associated XMLHttpRequest object
111 // via hasPendingActivity method which returns true if
112 // m_eventDispatchRecursionLevel is positive.
113 class ScopedEventDispatchProtect final {
114   STACK_ALLOCATED();
115 
116  public:
ScopedEventDispatchProtect(int * level)117   explicit ScopedEventDispatchProtect(int* level) : level_(level) { ++*level_; }
~ScopedEventDispatchProtect()118   ~ScopedEventDispatchProtect() {
119     DCHECK_GT(*level_, 0);
120     --*level_;
121   }
122 
123  private:
124   int* const level_;
125 };
126 
127 // These methods were placed in HTTPParsers.h. Since these methods don't
128 // perform ABNF validation but loosely look for the part that is likely to be
129 // indicating the charset parameter, new code should use
130 // HttpUtil::ParseContentType() than these. To discourage use of these methods,
131 // moved from HTTPParser.h to the only user XMLHttpRequest.cpp.
132 //
133 // TODO(tyoshino): Switch XHR to use HttpUtil. See crbug.com/743311.
FindCharsetInMediaType(const String & media_type,unsigned & charset_pos,unsigned & charset_len)134 void FindCharsetInMediaType(const String& media_type,
135                             unsigned& charset_pos,
136                             unsigned& charset_len) {
137   charset_len = 0;
138 
139   size_t pos = charset_pos;
140   unsigned length = media_type.length();
141 
142   while (pos < length) {
143     pos = media_type.FindIgnoringASCIICase("charset", pos);
144 
145     if (pos == kNotFound)
146       return;
147 
148     // Give up if we find "charset" at the head.
149     if (!pos)
150       return;
151 
152     // Now check that "charset" is not a substring of some longer word.
153     if (media_type[pos - 1] > ' ' && media_type[pos - 1] != ';') {
154       pos += 7;
155       continue;
156     }
157 
158     pos += 7;
159 
160     while (pos < length && media_type[pos] <= ' ')
161       ++pos;
162 
163     // Treat this as a charset parameter.
164     if (media_type[pos++] == '=')
165       break;
166   }
167 
168   while (pos < length && (media_type[pos] <= ' ' || media_type[pos] == '"' ||
169                           media_type[pos] == '\''))
170     ++pos;
171 
172   charset_pos = pos;
173 
174   // we don't handle spaces within quoted parameter values, because charset
175   // names cannot have any
176   while (pos < length && media_type[pos] > ' ' && media_type[pos] != '"' &&
177          media_type[pos] != '\'' && media_type[pos] != ';')
178     ++pos;
179 
180   charset_len = pos - charset_pos;
181 }
ExtractCharsetFromMediaType(const String & media_type)182 String ExtractCharsetFromMediaType(const String& media_type) {
183   unsigned pos = 0;
184   unsigned len = 0;
185   FindCharsetInMediaType(media_type, pos, len);
186   return media_type.Substring(pos, len);
187 }
188 
ReplaceCharsetInMediaType(String & media_type,const String & charset_value)189 void ReplaceCharsetInMediaType(String& media_type,
190                                const String& charset_value) {
191   unsigned pos = 0;
192 
193   while (true) {
194     unsigned len = 0;
195     FindCharsetInMediaType(media_type, pos, len);
196     if (!len)
197       return;
198     media_type.replace(pos, len, charset_value);
199     pos += charset_value.length();
200   }
201 }
202 
LogConsoleError(ExecutionContext * context,const String & message)203 void LogConsoleError(ExecutionContext* context, const String& message) {
204   if (!context)
205     return;
206   // FIXME: It's not good to report the bad usage without indicating what source
207   // line it came from.  We should pass additional parameters so we can tell the
208   // console where the mistake occurred.
209   auto* console_message = MakeGarbageCollected<ConsoleMessage>(
210       mojom::ConsoleMessageSource::kJavaScript,
211       mojom::ConsoleMessageLevel::kError, message);
212   context->AddConsoleMessage(console_message);
213 }
214 
ValidateOpenArguments(const AtomicString & method,const KURL & url,ExceptionState & exception_state)215 bool ValidateOpenArguments(const AtomicString& method,
216                            const KURL& url,
217                            ExceptionState& exception_state) {
218   if (!IsValidHTTPToken(method)) {
219     exception_state.ThrowDOMException(
220         DOMExceptionCode::kSyntaxError,
221         "'" + method + "' is not a valid HTTP method.");
222     return false;
223   }
224 
225   if (FetchUtils::IsForbiddenMethod(method)) {
226     exception_state.ThrowSecurityError("'" + method +
227                                        "' HTTP method is unsupported.");
228     return false;
229   }
230 
231   if (!url.IsValid()) {
232     exception_state.ThrowDOMException(DOMExceptionCode::kSyntaxError,
233                                       "Invalid URL");
234     return false;
235   }
236 
237   return true;
238 }
239 
240 }  // namespace
241 
242 class XMLHttpRequest::BlobLoader final
243     : public GarbageCollected<XMLHttpRequest::BlobLoader>,
244       public FileReaderLoaderClient {
245  public:
BlobLoader(XMLHttpRequest * xhr,scoped_refptr<BlobDataHandle> handle)246   BlobLoader(XMLHttpRequest* xhr, scoped_refptr<BlobDataHandle> handle)
247       : xhr_(xhr),
248         loader_(std::make_unique<FileReaderLoader>(
249             FileReaderLoader::kReadByClient,
250             this,
251             xhr->GetExecutionContext()->GetTaskRunner(
252                 TaskType::kFileReading))) {
253     loader_->Start(std::move(handle));
254   }
255 
256   // FileReaderLoaderClient functions.
DidStartLoading()257   void DidStartLoading() override {}
DidReceiveDataForClient(const char * data,unsigned length)258   void DidReceiveDataForClient(const char* data, unsigned length) override {
259     DCHECK_LE(length, static_cast<unsigned>(INT_MAX));
260     xhr_->DidReceiveData(data, length);
261   }
DidFinishLoading()262   void DidFinishLoading() override { xhr_->DidFinishLoadingFromBlob(); }
DidFail(FileErrorCode error)263   void DidFail(FileErrorCode error) override { xhr_->DidFailLoadingFromBlob(); }
264 
Cancel()265   void Cancel() { loader_->Cancel(); }
266 
Trace(Visitor * visitor) const267   void Trace(Visitor* visitor) const { visitor->Trace(xhr_); }
268 
269  private:
270   Member<XMLHttpRequest> xhr_;
271   std::unique_ptr<FileReaderLoader> loader_;
272 };
273 
Create(ScriptState * script_state)274 XMLHttpRequest* XMLHttpRequest::Create(ScriptState* script_state) {
275   return MakeGarbageCollected<XMLHttpRequest>(
276       ExecutionContext::From(script_state), script_state->GetIsolate(),
277       &script_state->World());
278 }
279 
Create(ExecutionContext * context)280 XMLHttpRequest* XMLHttpRequest::Create(ExecutionContext* context) {
281   v8::Isolate* isolate = context->GetIsolate();
282   CHECK(isolate);
283 
284   return MakeGarbageCollected<XMLHttpRequest>(context, isolate, nullptr);
285 }
286 
XMLHttpRequest(ExecutionContext * context,v8::Isolate * isolate,scoped_refptr<const DOMWrapperWorld> world)287 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context,
288                                v8::Isolate* isolate,
289                                scoped_refptr<const DOMWrapperWorld> world)
290     : ExecutionContextLifecycleObserver(context),
291       progress_event_throttle_(
292           MakeGarbageCollected<XMLHttpRequestProgressEventThrottle>(this)),
293       isolate_(isolate),
294       world_(std::move(world)),
295       isolated_world_security_origin_(world_ && world_->IsIsolatedWorld()
296                                           ? world_->IsolatedWorldSecurityOrigin(
297                                                 context->GetAgentClusterID())
298                                           : nullptr) {}
299 
~XMLHttpRequest()300 XMLHttpRequest::~XMLHttpRequest() {
301   binary_response_builder_ = nullptr;
302   length_downloaded_to_blob_ = 0;
303   ReportMemoryUsageToV8();
304 }
305 
readyState() const306 XMLHttpRequest::State XMLHttpRequest::readyState() const {
307   return state_;
308 }
309 
responseText(ExceptionState & exception_state)310 v8::Local<v8::String> XMLHttpRequest::responseText(
311     ExceptionState& exception_state) {
312   if (response_type_code_ != kResponseTypeDefault &&
313       response_type_code_ != kResponseTypeText) {
314     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
315                                       "The value is only accessible if the "
316                                       "object's 'responseType' is '' or 'text' "
317                                       "(was '" +
318                                           responseType() + "').");
319     return v8::Local<v8::String>();
320   }
321   if (error_ || (state_ != kLoading && state_ != kDone))
322     return v8::Local<v8::String>();
323   return response_text_.V8Value(isolate_);
324 }
325 
ResponseJSONSource()326 v8::Local<v8::String> XMLHttpRequest::ResponseJSONSource() {
327   DCHECK_EQ(response_type_code_, kResponseTypeJSON);
328 
329   if (error_ || state_ != kDone)
330     return v8::Local<v8::String>();
331   return response_text_.V8Value(isolate_);
332 }
333 
InitResponseDocument()334 void XMLHttpRequest::InitResponseDocument() {
335   // The W3C spec requires the final MIME type to be some valid XML type, or
336   // text/html.  If it is text/html, then the responseType of "document" must
337   // have been supplied explicitly.
338   bool is_html = ResponseIsHTML();
339   if ((response_.IsHTTP() && !ResponseIsXML() && !is_html) ||
340       (is_html && response_type_code_ == kResponseTypeDefault) ||
341       !GetExecutionContext() || GetExecutionContext()->IsWorkerGlobalScope()) {
342     response_document_ = nullptr;
343     return;
344   }
345 
346   auto* document = To<LocalDOMWindow>(GetExecutionContext())->document();
347   DocumentInit init = DocumentInit::Create()
348                           .WithExecutionContext(GetExecutionContext())
349                           .WithURL(response_.ResponseUrl());
350   if (is_html) {
351     response_document_ = MakeGarbageCollected<HTMLDocument>(init);
352     response_document_->setAllowDeclarativeShadowRoot(false);
353   } else
354     response_document_ = MakeGarbageCollected<XMLDocument>(init);
355 
356   // FIXME: Set Last-Modified.
357   response_document_->SetContextFeatures(document->GetContextFeatures());
358   response_document_->SetMimeType(FinalResponseMIMETypeWithFallback());
359 }
360 
responseXML(ExceptionState & exception_state)361 Document* XMLHttpRequest::responseXML(ExceptionState& exception_state) {
362   if (response_type_code_ != kResponseTypeDefault &&
363       response_type_code_ != kResponseTypeDocument) {
364     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
365                                       "The value is only accessible if the "
366                                       "object's 'responseType' is '' or "
367                                       "'document' (was '" +
368                                           responseType() + "').");
369     return nullptr;
370   }
371 
372   if (error_ || state_ != kDone)
373     return nullptr;
374 
375   if (!parsed_response_) {
376     InitResponseDocument();
377     if (!response_document_)
378       return nullptr;
379 
380     response_document_->SetContent(response_text_.Flatten(isolate_));
381     if (!response_document_->WellFormed()) {
382       response_document_ = nullptr;
383     } else {
384       response_document_->OverrideLastModified(
385           response_.HttpHeaderField(http_names::kLastModified));
386     }
387 
388     parsed_response_ = true;
389   }
390 
391   return response_document_;
392 }
393 
ResponseBlob()394 Blob* XMLHttpRequest::ResponseBlob() {
395   DCHECK_EQ(response_type_code_, kResponseTypeBlob);
396 
397   // We always return null before kDone.
398   if (error_ || state_ != kDone)
399     return nullptr;
400 
401   if (!response_blob_) {
402     auto blob_data = std::make_unique<BlobData>();
403     blob_data->SetContentType(FinalResponseMIMETypeWithFallback().LowerASCII());
404     size_t size = 0;
405     if (binary_response_builder_ && binary_response_builder_->size()) {
406       for (const auto& span : *binary_response_builder_)
407         blob_data->AppendBytes(span.data(), span.size());
408       size = binary_response_builder_->size();
409       binary_response_builder_ = nullptr;
410       ReportMemoryUsageToV8();
411     }
412     response_blob_ = MakeGarbageCollected<Blob>(
413         BlobDataHandle::Create(std::move(blob_data), size));
414   }
415 
416   return response_blob_;
417 }
418 
ResponseArrayBuffer()419 DOMArrayBuffer* XMLHttpRequest::ResponseArrayBuffer() {
420   DCHECK_EQ(response_type_code_, kResponseTypeArrayBuffer);
421 
422   if (error_ || state_ != kDone)
423     return nullptr;
424 
425   if (!response_array_buffer_ && !response_array_buffer_failure_) {
426     if (binary_response_builder_ && binary_response_builder_->size()) {
427       DOMArrayBuffer* buffer = DOMArrayBuffer::CreateUninitializedOrNull(
428           binary_response_builder_->size(), 1);
429       if (buffer) {
430         bool result = binary_response_builder_->GetBytes(buffer->Data(),
431                                                          buffer->ByteLength());
432         DCHECK(result);
433         response_array_buffer_ = buffer;
434       }
435       // https://xhr.spec.whatwg.org/#arraybuffer-response allows clearing
436       // of the 'received bytes' payload when the response buffer allocation
437       // fails.
438       binary_response_builder_ = nullptr;
439       ReportMemoryUsageToV8();
440       // Mark allocation as failed; subsequent calls to the accessor must
441       // continue to report |null|.
442       //
443       response_array_buffer_failure_ = !buffer;
444     } else {
445       response_array_buffer_ = DOMArrayBuffer::Create(nullptr, 0);
446     }
447   }
448 
449   return response_array_buffer_;
450 }
451 
setTimeout(unsigned timeout,ExceptionState & exception_state)452 void XMLHttpRequest::setTimeout(unsigned timeout,
453                                 ExceptionState& exception_state) {
454   // FIXME: Need to trigger or update the timeout Timer here, if needed.
455   // http://webkit.org/b/98156
456   // XHR2 spec, 4.7.3. "This implies that the timeout attribute can be set while
457   // fetching is in progress. If that occurs it will still be measured relative
458   // to the start of fetching."
459   if (GetExecutionContext() && GetExecutionContext()->IsWindow() && !async_) {
460     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
461                                       "Timeouts cannot be set for synchronous "
462                                       "requests made from a document.");
463     return;
464   }
465 
466   timeout_ = base::TimeDelta::FromMilliseconds(timeout);
467 
468   // From http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute:
469   // Note: This implies that the timeout attribute can be set while fetching is
470   // in progress. If that occurs it will still be measured relative to the start
471   // of fetching.
472   //
473   // The timeout may be overridden after send.
474   if (loader_)
475     loader_->SetTimeout(timeout_);
476 }
477 
setResponseType(const String & response_type,ExceptionState & exception_state)478 void XMLHttpRequest::setResponseType(const String& response_type,
479                                      ExceptionState& exception_state) {
480   if (state_ >= kLoading) {
481     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
482                                       "The response type cannot be set if the "
483                                       "object's state is LOADING or DONE.");
484     return;
485   }
486 
487   // Newer functionality is not available to synchronous requests in window
488   // contexts, as a spec-mandated attempt to discourage synchronous XHR use.
489   // responseType is one such piece of functionality.
490   if (GetExecutionContext() && GetExecutionContext()->IsWindow() && !async_) {
491     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
492                                       "The response type cannot be changed for "
493                                       "synchronous requests made from a "
494                                       "document.");
495     return;
496   }
497 
498   if (response_type == "") {
499     response_type_code_ = kResponseTypeDefault;
500   } else if (response_type == "text") {
501     response_type_code_ = kResponseTypeText;
502   } else if (response_type == "json") {
503     response_type_code_ = kResponseTypeJSON;
504   } else if (response_type == "document") {
505     response_type_code_ = kResponseTypeDocument;
506   } else if (response_type == "blob") {
507     response_type_code_ = kResponseTypeBlob;
508   } else if (response_type == "arraybuffer") {
509     response_type_code_ = kResponseTypeArrayBuffer;
510   } else {
511     NOTREACHED();
512   }
513 }
514 
responseType()515 String XMLHttpRequest::responseType() {
516   switch (response_type_code_) {
517     case kResponseTypeDefault:
518       return "";
519     case kResponseTypeText:
520       return "text";
521     case kResponseTypeJSON:
522       return "json";
523     case kResponseTypeDocument:
524       return "document";
525     case kResponseTypeBlob:
526       return "blob";
527     case kResponseTypeArrayBuffer:
528       return "arraybuffer";
529   }
530   return "";
531 }
532 
responseURL()533 String XMLHttpRequest::responseURL() {
534   KURL response_url(response_.ResponseUrl());
535   if (!response_url.IsNull())
536     response_url.RemoveFragmentIdentifier();
537   return response_url.GetString();
538 }
539 
upload()540 XMLHttpRequestUpload* XMLHttpRequest::upload() {
541   if (!upload_)
542     upload_ = MakeGarbageCollected<XMLHttpRequestUpload>(this);
543   return upload_;
544 }
545 
TrackProgress(uint64_t length)546 void XMLHttpRequest::TrackProgress(uint64_t length) {
547   received_length_ += length;
548 
549   ChangeState(kLoading);
550   if (async_) {
551     // readyStateChange event is fired as well.
552     DispatchProgressEventFromSnapshot(event_type_names::kProgress);
553   }
554 }
555 
ChangeState(State new_state)556 void XMLHttpRequest::ChangeState(State new_state) {
557   if (state_ != new_state) {
558     state_ = new_state;
559     DispatchReadyStateChangeEvent();
560   }
561 }
562 
DispatchReadyStateChangeEvent()563 void XMLHttpRequest::DispatchReadyStateChangeEvent() {
564   if (!GetExecutionContext())
565     return;
566 
567   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
568   if (async_ || (state_ <= kOpened || state_ == kDone)) {
569     TRACE_EVENT1("devtools.timeline", "XHRReadyStateChange", "data",
570                  inspector_xhr_ready_state_change_event::Data(
571                      GetExecutionContext(), this));
572     XMLHttpRequestProgressEventThrottle::DeferredEventAction action =
573         XMLHttpRequestProgressEventThrottle::kIgnore;
574     if (state_ == kDone) {
575       if (error_)
576         action = XMLHttpRequestProgressEventThrottle::kClear;
577       else
578         action = XMLHttpRequestProgressEventThrottle::kFlush;
579     }
580     progress_event_throttle_->DispatchReadyStateChangeEvent(
581         Event::Create(event_type_names::kReadystatechange), action);
582   }
583 
584   if (state_ == kDone && !error_) {
585     TRACE_EVENT1("devtools.timeline", "XHRLoad", "data",
586                  inspector_xhr_load_event::Data(GetExecutionContext(), this));
587     DispatchProgressEventFromSnapshot(event_type_names::kLoad);
588     DispatchProgressEventFromSnapshot(event_type_names::kLoadend);
589   }
590 }
591 
setWithCredentials(bool value,ExceptionState & exception_state)592 void XMLHttpRequest::setWithCredentials(bool value,
593                                         ExceptionState& exception_state) {
594   if (state_ > kOpened || send_flag_) {
595     exception_state.ThrowDOMException(
596         DOMExceptionCode::kInvalidStateError,
597         "The value may only be set if the object's state is UNSENT or OPENED.");
598     return;
599   }
600 
601   with_credentials_ = value;
602 }
603 
open(const AtomicString & method,const String & url_string,ExceptionState & exception_state)604 void XMLHttpRequest::open(const AtomicString& method,
605                           const String& url_string,
606                           ExceptionState& exception_state) {
607   if (!GetExecutionContext())
608     return;
609 
610   KURL url(GetExecutionContext()->CompleteURL(url_string));
611   if (!ValidateOpenArguments(method, url, exception_state))
612     return;
613 
614   open(method, url, true, exception_state);
615 }
616 
open(const AtomicString & method,const String & url_string,bool async,const String & username,const String & password,ExceptionState & exception_state)617 void XMLHttpRequest::open(const AtomicString& method,
618                           const String& url_string,
619                           bool async,
620                           const String& username,
621                           const String& password,
622                           ExceptionState& exception_state) {
623   if (!GetExecutionContext())
624     return;
625 
626   KURL url(GetExecutionContext()->CompleteURL(url_string));
627   if (!ValidateOpenArguments(method, url, exception_state))
628     return;
629 
630   if (!username.IsNull())
631     url.SetUser(username);
632   if (!password.IsNull())
633     url.SetPass(password);
634 
635   open(method, url, async, exception_state);
636 }
637 
open(const AtomicString & method,const KURL & url,bool async,ExceptionState & exception_state)638 void XMLHttpRequest::open(const AtomicString& method,
639                           const KURL& url,
640                           bool async,
641                           ExceptionState& exception_state) {
642   NETWORK_DVLOG(1) << this << " open(" << method << ", " << url.ElidedString()
643                    << ", " << async << ")";
644 
645   DCHECK(ValidateOpenArguments(method, url, exception_state));
646 
647   InternalAbort();
648 
649   State previous_state = state_;
650   state_ = kUnsent;
651   error_ = false;
652   upload_complete_ = false;
653 
654   auto* window = DynamicTo<LocalDOMWindow>(GetExecutionContext());
655   if (!async && window) {
656     if (window->GetFrame() &&
657         !window->GetFrame()->GetSettings()->GetSyncXHRInDocumentsEnabled()) {
658       exception_state.ThrowDOMException(
659           DOMExceptionCode::kInvalidAccessError,
660           "Synchronous requests are disabled for this page.");
661       return;
662     }
663 
664     // Newer functionality is not available to synchronous requests in window
665     // contexts, as a spec-mandated attempt to discourage synchronous XHR use.
666     // responseType is one such piece of functionality.
667     if (response_type_code_ != kResponseTypeDefault) {
668       exception_state.ThrowDOMException(
669           DOMExceptionCode::kInvalidAccessError,
670           "Synchronous requests from a document must not set a response type.");
671       return;
672     }
673 
674     // Similarly, timeouts are disabled for synchronous requests as well.
675     if (!timeout_.is_zero()) {
676       exception_state.ThrowDOMException(
677           DOMExceptionCode::kInvalidAccessError,
678           "Synchronous requests must not set a timeout.");
679       return;
680     }
681 
682     // Here we just warn that firing sync XHR's may affect responsiveness.
683     // Eventually sync xhr will be deprecated and an "InvalidAccessError"
684     // exception thrown.
685     // Refer : https://xhr.spec.whatwg.org/#sync-warning
686     // Use count for XHR synchronous requests on main thread only.
687     if (!window->document()->ProcessingBeforeUnload()) {
688       Deprecation::CountDeprecation(
689           GetExecutionContext(),
690           WebFeature::kXMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload);
691     }
692   }
693 
694   method_ = FetchUtils::NormalizeMethod(method);
695 
696   url_ = url;
697 
698   if (url_.ProtocolIs("blob")) {
699     GetExecutionContext()->GetPublicURLManager().Resolve(
700         url_, blob_url_loader_factory_.InitWithNewPipeAndPassReceiver());
701   }
702 
703   async_ = async;
704 
705   DCHECK(!loader_);
706   send_flag_ = false;
707 
708   // Check previous state to avoid dispatching readyState event
709   // when calling open several times in a row.
710   if (previous_state != kOpened)
711     ChangeState(kOpened);
712   else
713     state_ = kOpened;
714 }
715 
InitSend(ExceptionState & exception_state)716 bool XMLHttpRequest::InitSend(ExceptionState& exception_state) {
717   // We need to check ContextDestroyed because it is possible to create a
718   // XMLHttpRequest with already detached document.
719   // TODO(yhirano): Fix this.
720   if (!GetExecutionContext() || GetExecutionContext()->IsContextDestroyed()) {
721     HandleNetworkError();
722     ThrowForLoadFailureIfNeeded(exception_state,
723                                 "Document is already detached.");
724     return false;
725   }
726 
727   if (state_ != kOpened || send_flag_) {
728     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
729                                       "The object's state must be OPENED.");
730     return false;
731   }
732 
733   if (!async_) {
734     if (GetExecutionContext()->IsWindow() &&
735         !GetExecutionContext()->IsFeatureEnabled(
736             mojom::blink::FeaturePolicyFeature::kSyncXHR,
737             ReportOptions::kReportOnFailure,
738             "Synchronous requests are disabled by Feature Policy.")) {
739       HandleNetworkError();
740       ThrowForLoadFailureIfNeeded(exception_state, String());
741       return false;
742     }
743     v8::Isolate* isolate = v8::Isolate::GetCurrent();
744     if (isolate && v8::MicrotasksScope::IsRunningMicrotasks(isolate)) {
745       UseCounter::Count(GetExecutionContext(),
746                         WebFeature::kDuring_Microtask_SyncXHR);
747     }
748   }
749 
750   error_ = false;
751   return true;
752 }
753 
send(const DocumentOrBlobOrArrayBufferOrArrayBufferViewOrFormDataOrURLSearchParamsOrUSVString & body,ExceptionState & exception_state)754 void XMLHttpRequest::send(
755     const DocumentOrBlobOrArrayBufferOrArrayBufferViewOrFormDataOrURLSearchParamsOrUSVString&
756         body,
757     ExceptionState& exception_state) {
758   probe::WillSendXMLHttpOrFetchNetworkRequest(GetExecutionContext(), Url());
759 
760   if (body.IsNull()) {
761     send(String(), exception_state);
762     return;
763   }
764 
765   if (body.IsDocument()) {
766     send(body.GetAsDocument(), exception_state);
767     return;
768   }
769 
770   if (body.IsBlob()) {
771     send(body.GetAsBlob(), exception_state);
772     return;
773   }
774 
775   if (body.IsArrayBuffer()) {
776     send(body.GetAsArrayBuffer(), exception_state);
777     return;
778   }
779 
780   if (body.IsArrayBufferView()) {
781     send(body.GetAsArrayBufferView().View(), exception_state);
782     return;
783   }
784 
785   if (body.IsFormData()) {
786     send(body.GetAsFormData(), exception_state);
787     return;
788   }
789 
790   if (body.IsURLSearchParams()) {
791     send(body.GetAsURLSearchParams(), exception_state);
792     return;
793   }
794 
795   DCHECK(body.IsUSVString());
796   send(body.GetAsUSVString(), exception_state);
797 }
798 
AreMethodAndURLValidForSend()799 bool XMLHttpRequest::AreMethodAndURLValidForSend() {
800   return method_ != http_names::kGET && method_ != http_names::kHEAD &&
801          url_.ProtocolIsInHTTPFamily();
802 }
803 
send(Document * document,ExceptionState & exception_state)804 void XMLHttpRequest::send(Document* document, ExceptionState& exception_state) {
805   NETWORK_DVLOG(1) << this << " send() Document "
806                    << static_cast<void*>(document);
807 
808   DCHECK(document);
809 
810   if (!InitSend(exception_state))
811     return;
812 
813   scoped_refptr<EncodedFormData> http_body;
814 
815   if (AreMethodAndURLValidForSend()) {
816     if (IsA<HTMLDocument>(document))
817       UpdateContentTypeAndCharset("text/html;charset=UTF-8", "UTF-8");
818     else if (IsA<XMLDocument>(document))
819       UpdateContentTypeAndCharset("application/xml;charset=UTF-8", "UTF-8");
820 
821     String body = CreateMarkup(document);
822 
823     http_body = EncodedFormData::Create(
824         UTF8Encoding().Encode(body, WTF::kNoUnencodables));
825   }
826 
827   CreateRequest(std::move(http_body), exception_state);
828 }
829 
send(const String & body,ExceptionState & exception_state)830 void XMLHttpRequest::send(const String& body, ExceptionState& exception_state) {
831   NETWORK_DVLOG(1) << this << " send() String " << body;
832 
833   if (!InitSend(exception_state))
834     return;
835 
836   scoped_refptr<EncodedFormData> http_body;
837 
838   if (!body.IsNull() && AreMethodAndURLValidForSend()) {
839     http_body = EncodedFormData::Create(
840         UTF8Encoding().Encode(body, WTF::kNoUnencodables));
841     UpdateContentTypeAndCharset("text/plain;charset=UTF-8", "UTF-8");
842   }
843 
844   CreateRequest(std::move(http_body), exception_state);
845 }
846 
send(Blob * body,ExceptionState & exception_state)847 void XMLHttpRequest::send(Blob* body, ExceptionState& exception_state) {
848   NETWORK_DVLOG(1) << this << " send() Blob " << body->Uuid();
849 
850   if (!InitSend(exception_state))
851     return;
852 
853   scoped_refptr<EncodedFormData> http_body;
854 
855   if (AreMethodAndURLValidForSend()) {
856     if (!HasContentTypeRequestHeader()) {
857       const String& blob_type = FetchUtils::NormalizeHeaderValue(body->type());
858       if (!blob_type.IsEmpty() && ParsedContentType(blob_type).IsValid()) {
859         SetRequestHeaderInternal(http_names::kContentType,
860                                  AtomicString(blob_type));
861       }
862     }
863 
864     // FIXME: add support for uploading bundles.
865     http_body = EncodedFormData::Create();
866     if (body->HasBackingFile()) {
867       auto* file = To<File>(body);
868       if (!file->GetPath().IsEmpty())
869         http_body->AppendFile(file->GetPath(), file->LastModifiedTime());
870       else
871         NOTREACHED();
872     } else {
873       http_body->AppendBlob(body->Uuid(), body->GetBlobDataHandle());
874     }
875   }
876 
877   CreateRequest(std::move(http_body), exception_state);
878 }
879 
send(FormData * body,ExceptionState & exception_state)880 void XMLHttpRequest::send(FormData* body, ExceptionState& exception_state) {
881   NETWORK_DVLOG(1) << this << " send() FormData " << body;
882 
883   if (!InitSend(exception_state))
884     return;
885 
886   scoped_refptr<EncodedFormData> http_body;
887 
888   if (AreMethodAndURLValidForSend()) {
889     http_body = body->EncodeMultiPartFormData();
890 
891     // TODO (sof): override any author-provided charset= in the
892     // content type value to UTF-8 ?
893     if (!HasContentTypeRequestHeader()) {
894       AtomicString content_type =
895           AtomicString("multipart/form-data; boundary=") +
896           FetchUtils::NormalizeHeaderValue(http_body->Boundary().data());
897       SetRequestHeaderInternal(http_names::kContentType, content_type);
898     }
899   }
900 
901   CreateRequest(std::move(http_body), exception_state);
902 }
903 
send(URLSearchParams * body,ExceptionState & exception_state)904 void XMLHttpRequest::send(URLSearchParams* body,
905                           ExceptionState& exception_state) {
906   NETWORK_DVLOG(1) << this << " send() URLSearchParams " << body;
907 
908   if (!InitSend(exception_state))
909     return;
910 
911   scoped_refptr<EncodedFormData> http_body;
912 
913   if (AreMethodAndURLValidForSend()) {
914     http_body = body->ToEncodedFormData();
915     UpdateContentTypeAndCharset(
916         "application/x-www-form-urlencoded;charset=UTF-8", "UTF-8");
917   }
918 
919   CreateRequest(std::move(http_body), exception_state);
920 }
921 
send(DOMArrayBuffer * body,ExceptionState & exception_state)922 void XMLHttpRequest::send(DOMArrayBuffer* body,
923                           ExceptionState& exception_state) {
924   NETWORK_DVLOG(1) << this << " send() ArrayBuffer " << body;
925 
926   SendBytesData(body->Data(), body->ByteLength(), exception_state);
927 }
928 
send(DOMArrayBufferView * body,ExceptionState & exception_state)929 void XMLHttpRequest::send(DOMArrayBufferView* body,
930                           ExceptionState& exception_state) {
931   NETWORK_DVLOG(1) << this << " send() ArrayBufferView " << body;
932 
933   SendBytesData(body->BaseAddress(), body->byteLength(), exception_state);
934 }
935 
SendBytesData(const void * data,size_t length,ExceptionState & exception_state)936 void XMLHttpRequest::SendBytesData(const void* data,
937                                    size_t length,
938                                    ExceptionState& exception_state) {
939   if (!InitSend(exception_state))
940     return;
941 
942   scoped_refptr<EncodedFormData> http_body;
943 
944   if (AreMethodAndURLValidForSend()) {
945     http_body = EncodedFormData::Create(data, length);
946   }
947 
948   CreateRequest(std::move(http_body), exception_state);
949 }
950 
SendForInspectorXHRReplay(scoped_refptr<EncodedFormData> form_data,ExceptionState & exception_state)951 void XMLHttpRequest::SendForInspectorXHRReplay(
952     scoped_refptr<EncodedFormData> form_data,
953     ExceptionState& exception_state) {
954   CreateRequest(form_data ? form_data->DeepCopy() : nullptr, exception_state);
955   if (exception_state.HadException()) {
956     CHECK(IsDOMExceptionCode(exception_state.Code()));
957     exception_code_ = exception_state.CodeAs<DOMExceptionCode>();
958   }
959 }
960 
ThrowForLoadFailureIfNeeded(ExceptionState & exception_state,const String & reason)961 void XMLHttpRequest::ThrowForLoadFailureIfNeeded(
962     ExceptionState& exception_state,
963     const String& reason) {
964   if (error_ && exception_code_ == DOMExceptionCode::kNoError)
965     exception_code_ = DOMExceptionCode::kNetworkError;
966 
967   if (exception_code_ == DOMExceptionCode::kNoError)
968     return;
969 
970   StringBuilder message;
971   message.Append("Failed to load '");
972   message.Append(url_.ElidedString());
973   message.Append('\'');
974   if (reason.IsNull()) {
975     message.Append('.');
976   } else {
977     message.Append(": ");
978     message.Append(reason);
979   }
980 
981   exception_state.ThrowDOMException(exception_code_, message.ToString());
982 }
983 
CreateRequest(scoped_refptr<EncodedFormData> http_body,ExceptionState & exception_state)984 void XMLHttpRequest::CreateRequest(scoped_refptr<EncodedFormData> http_body,
985                                    ExceptionState& exception_state) {
986   // Only GET request is supported for blob URL.
987   if (url_.ProtocolIs("blob") && method_ != http_names::kGET) {
988     HandleNetworkError();
989 
990     if (!async_) {
991       ThrowForLoadFailureIfNeeded(
992           exception_state,
993           "'GET' is the only method allowed for 'blob:' URLs.");
994     }
995     return;
996   }
997 
998   if (url_.ProtocolIs("ftp")) {
999     LogConsoleError(GetExecutionContext(), "FTP is not supported.");
1000     HandleNetworkError();
1001     if (!async_) {
1002       ThrowForLoadFailureIfNeeded(
1003           exception_state, "Making a request to a FTP URL is not supported.");
1004     }
1005     return;
1006   }
1007 
1008   DCHECK(GetExecutionContext());
1009   ExecutionContext& execution_context = *GetExecutionContext();
1010 
1011   send_flag_ = true;
1012   // The presence of upload event listeners forces us to use preflighting
1013   // because POSTing to an URL that does not permit cross origin requests should
1014   // look exactly like POSTing to an URL that does not respond at all.
1015   // Also, only async requests support upload progress events.
1016   bool upload_events = false;
1017   if (async_) {
1018     probe::AsyncTaskScheduled(&execution_context, "XMLHttpRequest.send",
1019                               &async_task_id_);
1020     DispatchProgressEvent(event_type_names::kLoadstart, 0, 0);
1021     // Event handler could have invalidated this send operation,
1022     // (re)setting the send flag and/or initiating another send
1023     // operation; leave quietly if so.
1024     if (!send_flag_ || loader_)
1025       return;
1026     if (http_body && upload_) {
1027       upload_events = upload_->HasEventListeners();
1028       upload_->DispatchEvent(*ProgressEvent::Create(
1029           event_type_names::kLoadstart, true, 0, http_body->SizeInBytes()));
1030       // See above.
1031       if (!send_flag_ || loader_)
1032         return;
1033     }
1034   }
1035 
1036   // We also remember whether upload events should be allowed for this request
1037   // in case the upload listeners are added after the request is started.
1038   upload_events_allowed_ =
1039       GetExecutionContext()->GetSecurityOrigin()->CanRequest(url_) ||
1040       (isolated_world_security_origin_ &&
1041        isolated_world_security_origin_->CanRequest(url_)) ||
1042       upload_events || !cors::IsCorsSafelistedMethod(method_) ||
1043       !cors::ContainsOnlyCorsSafelistedHeaders(request_headers_);
1044 
1045   ResourceRequest request(url_);
1046   request.SetRequestorOrigin(GetExecutionContext()->GetSecurityOrigin());
1047   request.SetIsolatedWorldOrigin(isolated_world_security_origin_);
1048   request.SetHttpMethod(method_);
1049   request.SetRequestContext(mojom::blink::RequestContextType::XML_HTTP_REQUEST);
1050   request.SetFetchLikeAPI(true);
1051   request.SetMode(upload_events
1052                       ? network::mojom::RequestMode::kCorsWithForcedPreflight
1053                       : network::mojom::RequestMode::kCors);
1054   request.SetCredentialsMode(
1055       with_credentials_ ? network::mojom::CredentialsMode::kInclude
1056                         : network::mojom::CredentialsMode::kSameOrigin);
1057   request.SetSkipServiceWorker(world_ && world_->IsIsolatedWorld());
1058   request.SetExternalRequestStateFromRequestorAddressSpace(
1059       execution_context.AddressSpace());
1060   if (trust_token_params_)
1061     request.SetTrustTokenParams(*trust_token_params_);
1062 
1063   probe::WillLoadXHR(&execution_context, method_, url_, async_,
1064                      request_headers_, with_credentials_);
1065 
1066   if (http_body) {
1067     DCHECK_NE(method_, http_names::kGET);
1068     DCHECK_NE(method_, http_names::kHEAD);
1069     request.SetHttpBody(std::move(http_body));
1070   }
1071 
1072   if (request_headers_.size() > 0)
1073     request.AddHTTPHeaderFields(request_headers_);
1074 
1075   ResourceLoaderOptions resource_loader_options(world_);
1076   resource_loader_options.initiator_info.name =
1077       fetch_initiator_type_names::kXmlhttprequest;
1078   if (blob_url_loader_factory_) {
1079     resource_loader_options.url_loader_factory =
1080         base::MakeRefCounted<base::RefCountedData<
1081             mojo::PendingRemote<network::mojom::blink::URLLoaderFactory>>>(
1082             std::move(blob_url_loader_factory_));
1083   }
1084 
1085   // When responseType is set to "blob", we redirect the downloaded data to a
1086   // blob directly, except for data: URLs, since those are loaded by
1087   // renderer side code, and don't support being downloaded to a blob.
1088   downloading_to_blob_ =
1089       GetResponseTypeCode() == kResponseTypeBlob && !url_.ProtocolIsData();
1090   if (downloading_to_blob_) {
1091     request.SetDownloadToBlob(true);
1092     resource_loader_options.data_buffering_policy = kDoNotBufferData;
1093   }
1094 
1095   if (async_) {
1096     resource_loader_options.data_buffering_policy = kDoNotBufferData;
1097   }
1098 
1099   if (async_) {
1100     UseCounter::Count(&execution_context,
1101                       WebFeature::kXMLHttpRequestAsynchronous);
1102     if (upload_)
1103       request.SetReportUploadProgress(true);
1104 
1105     // TODO(yhirano): Turn this CHECK into DCHECK: see https://crbug.com/570946.
1106     CHECK(!loader_);
1107     DCHECK(send_flag_);
1108   } else {
1109     // Use count for XHR synchronous requests.
1110     UseCounter::Count(&execution_context, WebFeature::kXMLHttpRequestSynchronous);
1111     if (auto* window = DynamicTo<LocalDOMWindow>(GetExecutionContext())) {
1112       if (Frame* frame = window->GetFrame()) {
1113         if (frame->IsMainFrame()) {
1114           UseCounter::Count(&execution_context,
1115                             WebFeature::kXMLHttpRequestSynchronousInMainFrame);
1116         } else if (frame->IsCrossOriginToMainFrame()) {
1117           UseCounter::Count(
1118               &execution_context,
1119               WebFeature::kXMLHttpRequestSynchronousInCrossOriginSubframe);
1120         } else {
1121           UseCounter::Count(
1122               &execution_context,
1123               WebFeature::kXMLHttpRequestSynchronousInSameOriginSubframe);
1124         }
1125       }
1126       if (PageDismissalScope::IsActive() &&
1127           !RuntimeEnabledFeatures::AllowSyncXHRInPageDismissalEnabled(
1128               &execution_context)) {
1129         HandleNetworkError();
1130         ThrowForLoadFailureIfNeeded(exception_state,
1131                                     "Synchronous XHR in page dismissal. See "
1132                                     "https://www.chromestatus.com/feature/"
1133                                     "4664843055398912 for more details.");
1134         return;
1135       }
1136     } else {
1137       DCHECK(execution_context.IsWorkerGlobalScope());
1138       UseCounter::Count(&execution_context,
1139                         WebFeature::kXMLHttpRequestSynchronousInWorker);
1140     }
1141     resource_loader_options.synchronous_policy = kRequestSynchronously;
1142   }
1143 
1144   exception_code_ = DOMExceptionCode::kNoError;
1145   error_ = false;
1146 
1147   loader_ = MakeGarbageCollected<ThreadableLoader>(execution_context, this,
1148                                                    resource_loader_options);
1149   loader_->SetTimeout(timeout_);
1150   base::TimeTicks start_time = base::TimeTicks::Now();
1151   loader_->Start(std::move(request));
1152 
1153   if (!async_) {
1154     base::TimeDelta blocking_time = base::TimeTicks::Now() - start_time;
1155     if (execution_context.IsWindow()) {
1156       UMA_HISTOGRAM_MEDIUM_TIMES("XHR.Sync.BlockingTime.MainThread",
1157                                  blocking_time);
1158     } else {
1159       UMA_HISTOGRAM_MEDIUM_TIMES("XHR.Sync.BlockingTime.WorkerThread",
1160                                  blocking_time);
1161     }
1162 
1163     ThrowForLoadFailureIfNeeded(exception_state, String());
1164   }
1165 }
1166 
abort()1167 void XMLHttpRequest::abort() {
1168   NETWORK_DVLOG(1) << this << " abort()";
1169 
1170   // internalAbort() clears the response. Save the data needed for
1171   // dispatching ProgressEvents.
1172   int64_t expected_length = response_.ExpectedContentLength();
1173   int64_t received_length = received_length_;
1174 
1175   InternalAbort();
1176 
1177   // The script never gets any chance to call abort() on a sync XHR between
1178   // send() call and transition to the DONE state. It's because a sync XHR
1179   // doesn't dispatch any event between them. So, if |m_async| is false, we
1180   // can skip the "request error steps" (defined in the XHR spec) without any
1181   // state check.
1182   //
1183   // FIXME: It's possible open() is invoked in internalAbort() and |m_async|
1184   // becomes true by that. We should implement more reliable treatment for
1185   // nested method invocations at some point.
1186   if (async_) {
1187     if ((state_ == kOpened && send_flag_) || state_ == kHeadersReceived ||
1188         state_ == kLoading) {
1189       DCHECK(!loader_);
1190       HandleRequestError(DOMExceptionCode::kNoError, event_type_names::kAbort,
1191                          received_length, expected_length);
1192     }
1193   }
1194   if (state_ == kDone)
1195     state_ = kUnsent;
1196 }
1197 
Dispose()1198 void XMLHttpRequest::Dispose() {
1199   progress_event_throttle_->Stop();
1200   InternalAbort();
1201   // TODO(yhirano): Remove this CHECK: see https://crbug.com/570946.
1202   CHECK(!loader_);
1203 }
1204 
ClearVariablesForLoading()1205 void XMLHttpRequest::ClearVariablesForLoading() {
1206   if (blob_loader_) {
1207     blob_loader_->Cancel();
1208     blob_loader_ = nullptr;
1209   }
1210 
1211   decoder_.reset();
1212 
1213   if (response_document_parser_) {
1214     response_document_parser_->RemoveClient(this);
1215     response_document_parser_->Detach();
1216     response_document_parser_ = nullptr;
1217   }
1218 }
1219 
InternalAbort()1220 void XMLHttpRequest::InternalAbort() {
1221   // If there is an existing pending abort event, cancel it. The caller of this
1222   // function is responsible for firing any events on XMLHttpRequest, if
1223   // needed.
1224   pending_abort_event_.Cancel();
1225 
1226   // Fast path for repeated internalAbort()s; this
1227   // will happen if an XHR object is notified of context
1228   // destruction followed by finalization.
1229   if (error_ && !loader_)
1230     return;
1231 
1232   error_ = true;
1233 
1234   if (response_document_parser_ && !response_document_parser_->IsStopped())
1235     response_document_parser_->StopParsing();
1236 
1237   ClearVariablesForLoading();
1238 
1239   ClearResponse();
1240   ClearRequest();
1241 
1242   if (!loader_)
1243     return;
1244 
1245   ThreadableLoader* loader = loader_.Release();
1246   loader->Cancel();
1247 
1248   DCHECK(!loader_);
1249 }
1250 
ClearResponse()1251 void XMLHttpRequest::ClearResponse() {
1252   // FIXME: when we add the support for multi-part XHR, we will have to
1253   // be careful with this initialization.
1254   received_length_ = 0;
1255 
1256   response_ = ResourceResponse();
1257 
1258   response_text_.Clear();
1259 
1260   parsed_response_ = false;
1261   response_document_ = nullptr;
1262 
1263   response_blob_ = nullptr;
1264 
1265   length_downloaded_to_blob_ = 0;
1266   downloading_to_blob_ = false;
1267 
1268   // These variables may referred by the response accessors. So, we can clear
1269   // this only when we clear the response holder variables above.
1270   binary_response_builder_ = nullptr;
1271   response_array_buffer_.Clear();
1272   response_array_buffer_failure_ = false;
1273 
1274   ReportMemoryUsageToV8();
1275 }
1276 
ClearRequest()1277 void XMLHttpRequest::ClearRequest() {
1278   request_headers_.Clear();
1279 }
1280 
DispatchProgressEvent(const AtomicString & type,int64_t received_length,int64_t expected_length)1281 void XMLHttpRequest::DispatchProgressEvent(const AtomicString& type,
1282                                            int64_t received_length,
1283                                            int64_t expected_length) {
1284   bool length_computable =
1285       expected_length > 0 && received_length <= expected_length;
1286   uint64_t loaded =
1287       received_length >= 0 ? static_cast<uint64_t>(received_length) : 0;
1288   uint64_t total =
1289       length_computable ? static_cast<uint64_t>(expected_length) : 0;
1290 
1291   ExecutionContext* context = GetExecutionContext();
1292   probe::AsyncTask async_task(
1293       context, &async_task_id_,
1294       type == event_type_names::kLoadend ? nullptr : "progress", async_);
1295   progress_event_throttle_->DispatchProgressEvent(type, length_computable,
1296                                                   loaded, total);
1297 }
1298 
DispatchProgressEventFromSnapshot(const AtomicString & type)1299 void XMLHttpRequest::DispatchProgressEventFromSnapshot(
1300     const AtomicString& type) {
1301   DispatchProgressEvent(type, received_length_,
1302                         response_.ExpectedContentLength());
1303 }
1304 
HandleNetworkError()1305 void XMLHttpRequest::HandleNetworkError() {
1306   NETWORK_DVLOG(1) << this << " handleNetworkError()";
1307 
1308   // Response is cleared next, save needed progress event data.
1309   int64_t expected_length = response_.ExpectedContentLength();
1310   int64_t received_length = received_length_;
1311 
1312   InternalAbort();
1313 
1314   HandleRequestError(DOMExceptionCode::kNetworkError, event_type_names::kError,
1315                      received_length, expected_length);
1316 }
1317 
HandleDidCancel()1318 void XMLHttpRequest::HandleDidCancel() {
1319   NETWORK_DVLOG(1) << this << " handleDidCancel()";
1320 
1321   // Response is cleared next, save needed progress event data.
1322   int64_t expected_length = response_.ExpectedContentLength();
1323   int64_t received_length = received_length_;
1324 
1325   InternalAbort();
1326 
1327   pending_abort_event_ = PostCancellableTask(
1328       *GetExecutionContext()->GetTaskRunner(TaskType::kNetworking), FROM_HERE,
1329       WTF::Bind(&XMLHttpRequest::HandleRequestError, WrapPersistent(this),
1330                 DOMExceptionCode::kAbortError, event_type_names::kAbort,
1331                 received_length, expected_length));
1332 }
1333 
HandleRequestError(DOMExceptionCode exception_code,const AtomicString & type,int64_t received_length,int64_t expected_length)1334 void XMLHttpRequest::HandleRequestError(DOMExceptionCode exception_code,
1335                                         const AtomicString& type,
1336                                         int64_t received_length,
1337                                         int64_t expected_length) {
1338   NETWORK_DVLOG(1) << this << " handleRequestError()";
1339 
1340   probe::DidFinishXHR(GetExecutionContext(), this);
1341 
1342   send_flag_ = false;
1343   if (!async_) {
1344     DCHECK_NE(exception_code, DOMExceptionCode::kNoError);
1345     state_ = kDone;
1346     exception_code_ = exception_code;
1347     return;
1348   }
1349 
1350   // With m_error set, the state change steps are minimal: any pending
1351   // progress event is flushed + a readystatechange is dispatched.
1352   // No new progress events dispatched; as required, that happens at
1353   // the end here.
1354   DCHECK(error_);
1355   ChangeState(kDone);
1356 
1357   if (!upload_complete_) {
1358     upload_complete_ = true;
1359     if (upload_ && upload_events_allowed_)
1360       upload_->HandleRequestError(type);
1361   }
1362 
1363   // Note: The below event dispatch may be called while |hasPendingActivity() ==
1364   // false|, when |handleRequestError| is called after |internalAbort()|.  This
1365   // is safe, however, as |this| will be kept alive from a strong ref
1366   // |Event::m_target|.
1367   DispatchProgressEvent(type, received_length, expected_length);
1368   DispatchProgressEvent(event_type_names::kLoadend, received_length,
1369                         expected_length);
1370 }
1371 
1372 // https://xhr.spec.whatwg.org/#the-overridemimetype()-method
overrideMimeType(const AtomicString & mime_type,ExceptionState & exception_state)1373 void XMLHttpRequest::overrideMimeType(const AtomicString& mime_type,
1374                                       ExceptionState& exception_state) {
1375   if (state_ == kLoading || state_ == kDone) {
1376     exception_state.ThrowDOMException(
1377         DOMExceptionCode::kInvalidStateError,
1378         "MimeType cannot be overridden when the state is LOADING or DONE.");
1379     return;
1380   }
1381 
1382   mime_type_override_ = "application/octet-stream";
1383   if (ParsedContentType(mime_type).IsValid())
1384     mime_type_override_ = mime_type;
1385 }
1386 
1387 // https://xhr.spec.whatwg.org/#the-setrequestheader()-method
setRequestHeader(const AtomicString & name,const AtomicString & value,ExceptionState & exception_state)1388 void XMLHttpRequest::setRequestHeader(const AtomicString& name,
1389                                       const AtomicString& value,
1390                                       ExceptionState& exception_state) {
1391   // "1. If |state| is not "opened", throw an InvalidStateError exception.
1392   //  2. If the send() flag is set, throw an InvalidStateError exception."
1393   if (state_ != kOpened || send_flag_) {
1394     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
1395                                       "The object's state must be OPENED.");
1396     return;
1397   }
1398 
1399   // "3. Normalize |value|."
1400   const String normalized_value = FetchUtils::NormalizeHeaderValue(value);
1401 
1402   // "4. If |name| is not a name or |value| is not a value, throw a SyntaxError
1403   //     exception."
1404   if (!IsValidHTTPToken(name)) {
1405     exception_state.ThrowDOMException(
1406         DOMExceptionCode::kSyntaxError,
1407         "'" + name + "' is not a valid HTTP header field name.");
1408     return;
1409   }
1410   if (!IsValidHTTPHeaderValue(normalized_value)) {
1411     exception_state.ThrowDOMException(
1412         DOMExceptionCode::kSyntaxError,
1413         "'" + normalized_value + "' is not a valid HTTP header field value.");
1414     return;
1415   }
1416 
1417   // "5. Terminate these steps if |name| is a forbidden header name."
1418   // No script (privileged or not) can set unsafe headers.
1419   if (cors::IsForbiddenHeaderName(name)) {
1420     LogConsoleError(GetExecutionContext(),
1421                     "Refused to set unsafe header \"" + name + "\"");
1422     return;
1423   }
1424 
1425   // "6. Combine |name|/|value| in author request headers."
1426   SetRequestHeaderInternal(name, AtomicString(normalized_value));
1427 }
1428 
SetRequestHeaderInternal(const AtomicString & name,const AtomicString & value)1429 void XMLHttpRequest::SetRequestHeaderInternal(const AtomicString& name,
1430                                               const AtomicString& value) {
1431   DCHECK_EQ(value, FetchUtils::NormalizeHeaderValue(value))
1432       << "Header values must be normalized";
1433   HTTPHeaderMap::AddResult result = request_headers_.Add(name, value);
1434   if (!result.is_new_entry) {
1435     AtomicString new_value = result.stored_value->value + ", " + value;
1436     result.stored_value->value = new_value;
1437   }
1438 }
1439 
setTrustToken(const TrustToken * trust_token,ExceptionState & exception_state)1440 void XMLHttpRequest::setTrustToken(const TrustToken* trust_token,
1441                                    ExceptionState& exception_state) {
1442   // These precondition checks are copied from |setRequestHeader|.
1443   if (state_ != kOpened || send_flag_) {
1444     exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
1445                                       "The object's state must be OPENED.");
1446     return;
1447   }
1448 
1449   auto params = network::mojom::blink::TrustTokenParams::New();
1450   if (!ConvertTrustTokenToMojom(*trust_token, &exception_state, params.get())) {
1451     DCHECK(exception_state.HadException());
1452     return;
1453   }
1454 
1455   bool operation_requires_feature_policy =
1456       params->type ==
1457           network::mojom::blink::TrustTokenOperationType::kRedemption ||
1458       params->type == network::mojom::blink::TrustTokenOperationType::kSigning;
1459   if (operation_requires_feature_policy &&
1460       !GetExecutionContext()->IsFeatureEnabled(
1461           mojom::blink::FeaturePolicyFeature::kTrustTokenRedemption)) {
1462     exception_state.ThrowDOMException(
1463         DOMExceptionCode::kNotAllowedError,
1464         "Trust Tokens redemption and signing require the "
1465         "trust-token-redemption Feature Policy feature.");
1466     return;
1467   }
1468 
1469   if (params->type ==
1470           network::mojom::blink::TrustTokenOperationType::kIssuance &&
1471       !IsTrustTokenIssuanceAvailableInExecutionContext(
1472           *GetExecutionContext())) {
1473     exception_state.ThrowDOMException(
1474         DOMExceptionCode::kNotAllowedError,
1475         "Trust Tokens issuance is disabled except in "
1476         "contexts with the TrustTokens Origin Trial enabled.");
1477     return;
1478   }
1479 
1480   trust_token_params_ = std::move(params);
1481 }
1482 
HasContentTypeRequestHeader() const1483 bool XMLHttpRequest::HasContentTypeRequestHeader() const {
1484   return request_headers_.Find(http_names::kContentType) !=
1485          request_headers_.end();
1486 }
1487 
getAllResponseHeaders() const1488 String XMLHttpRequest::getAllResponseHeaders() const {
1489   if (state_ < kHeadersReceived || error_)
1490     return "";
1491 
1492   StringBuilder string_builder;
1493 
1494   HTTPHeaderSet access_control_expose_header_set =
1495       cors::ExtractCorsExposedHeaderNamesList(
1496           with_credentials_ ? network::mojom::CredentialsMode::kInclude
1497                             : network::mojom::CredentialsMode::kSameOrigin,
1498           response_);
1499 
1500   // "Let |headers| be the result of sorting |initialHeaders| in ascending
1501   // order, with |a| being less than |b| if |a|’s name is legacy-uppercased-byte
1502   // less than |b|’s name."
1503   Vector<std::pair<String, String>> headers;
1504   // Although we omit some headers in |response_.HttpHeaderFields()| below,
1505   // we pre-allocate the buffer for performance.
1506   headers.ReserveInitialCapacity(response_.HttpHeaderFields().size());
1507   for (auto it = response_.HttpHeaderFields().begin();
1508        it != response_.HttpHeaderFields().end(); ++it) {
1509     // Hide any headers whose name is a forbidden response-header name.
1510     // This is required for all kinds of filtered responses.
1511     //
1512     // TODO: Consider removing canLoadLocalResources() call.
1513     // crbug.com/567527
1514     if (FetchUtils::IsForbiddenResponseHeaderName(it->key) &&
1515         !GetExecutionContext()->GetSecurityOrigin()->CanLoadLocalResources()) {
1516       continue;
1517     }
1518 
1519     if (response_.GetType() == network::mojom::FetchResponseType::kCors &&
1520         !cors::IsCorsSafelistedResponseHeader(it->key) &&
1521         access_control_expose_header_set.find(it->key.Ascii()) ==
1522             access_control_expose_header_set.end()) {
1523       continue;
1524     }
1525 
1526     headers.push_back(std::make_pair(it->key.UpperASCII(), it->value));
1527   }
1528   std::sort(headers.begin(), headers.end(),
1529             [](const std::pair<String, String>& x,
1530                const std::pair<String, String>& y) {
1531               return CodeUnitCompareLessThan(x.first, y.first);
1532             });
1533   for (const auto& header : headers) {
1534     string_builder.Append(header.first.LowerASCII());
1535     string_builder.Append(':');
1536     string_builder.Append(' ');
1537     string_builder.Append(header.second);
1538     string_builder.Append('\r');
1539     string_builder.Append('\n');
1540   }
1541 
1542   return string_builder.ToString();
1543 }
1544 
getResponseHeader(const AtomicString & name) const1545 const AtomicString& XMLHttpRequest::getResponseHeader(
1546     const AtomicString& name) const {
1547   if (state_ < kHeadersReceived || error_)
1548     return g_null_atom;
1549 
1550   // See comment in getAllResponseHeaders above.
1551   if (FetchUtils::IsForbiddenResponseHeaderName(name) &&
1552       !GetExecutionContext()->GetSecurityOrigin()->CanLoadLocalResources()) {
1553     LogConsoleError(GetExecutionContext(),
1554                     "Refused to get unsafe header \"" + name + "\"");
1555     return g_null_atom;
1556   }
1557 
1558   HTTPHeaderSet access_control_expose_header_set =
1559       cors::ExtractCorsExposedHeaderNamesList(
1560           with_credentials_ ? network::mojom::CredentialsMode::kInclude
1561                             : network::mojom::CredentialsMode::kSameOrigin,
1562           response_);
1563 
1564   if (response_.GetType() == network::mojom::FetchResponseType::kCors &&
1565       !cors::IsCorsSafelistedResponseHeader(name) &&
1566       access_control_expose_header_set.find(name.Ascii()) ==
1567           access_control_expose_header_set.end()) {
1568     LogConsoleError(GetExecutionContext(),
1569                     "Refused to get unsafe header \"" + name + "\"");
1570     return g_null_atom;
1571   }
1572   return response_.HttpHeaderField(name);
1573 }
1574 
FinalResponseMIMEType() const1575 AtomicString XMLHttpRequest::FinalResponseMIMEType() const {
1576   AtomicString overridden_type =
1577       ExtractMIMETypeFromMediaType(mime_type_override_);
1578   if (!overridden_type.IsEmpty())
1579     return overridden_type;
1580 
1581   if (response_.IsHTTP()) {
1582     return ExtractMIMETypeFromMediaType(
1583         response_.HttpHeaderField(http_names::kContentType));
1584   }
1585 
1586   return response_.MimeType();
1587 }
1588 
FinalResponseMIMETypeWithFallback() const1589 AtomicString XMLHttpRequest::FinalResponseMIMETypeWithFallback() const {
1590   AtomicString final_type = FinalResponseMIMEType();
1591   if (!final_type.IsEmpty())
1592     return final_type;
1593 
1594   return AtomicString("text/xml");
1595 }
1596 
1597 // https://xhr.spec.whatwg.org/#final-charset
FinalResponseCharset() const1598 WTF::TextEncoding XMLHttpRequest::FinalResponseCharset() const {
1599   // 1. Let label be null. [spec text]
1600   //
1601   // 2. If response MIME type's parameters["charset"] exists, then set label to
1602   // it. [spec text]
1603   String label = response_.TextEncodingName();
1604 
1605   // 3. If override MIME type's parameters["charset"] exists, then set label to
1606   // it. [spec text]
1607   String override_response_charset =
1608       ExtractCharsetFromMediaType(mime_type_override_);
1609   if (!override_response_charset.IsEmpty())
1610     label = override_response_charset;
1611 
1612   // 4. If label is null, then return null. [spec text]
1613   //
1614   // 5. Let encoding be the result of getting an encoding from label. [spec
1615   // text]
1616   //
1617   // 6. If encoding is failure, then return null. [spec text]
1618   //
1619   // 7. Return encoding. [spec text]
1620   //
1621   // We rely on WTF::TextEncoding() to return invalid TextEncoding for
1622   // null, empty, or invalid/unsupported |label|.
1623   return WTF::TextEncoding(label);
1624 }
1625 
UpdateContentTypeAndCharset(const AtomicString & default_content_type,const String & charset)1626 void XMLHttpRequest::UpdateContentTypeAndCharset(
1627     const AtomicString& default_content_type,
1628     const String& charset) {
1629   // http://xhr.spec.whatwg.org/#the-send()-method step 4's concilliation of
1630   // "charset=" in any author-provided Content-Type: request header.
1631   String content_type = request_headers_.Get(http_names::kContentType);
1632   if (content_type.IsNull()) {
1633     SetRequestHeaderInternal(http_names::kContentType, default_content_type);
1634     return;
1635   }
1636   String original_content_type = content_type;
1637   ReplaceCharsetInMediaType(content_type, charset);
1638   request_headers_.Set(http_names::kContentType, AtomicString(content_type));
1639 
1640   if (original_content_type != content_type) {
1641     UseCounter::Count(GetExecutionContext(), WebFeature::kReplaceCharsetInXHR);
1642     if (!EqualIgnoringASCIICase(original_content_type, content_type)) {
1643       UseCounter::Count(GetExecutionContext(),
1644                         WebFeature::kReplaceCharsetInXHRIgnoringCase);
1645     }
1646   }
1647 }
1648 
ResponseIsXML() const1649 bool XMLHttpRequest::ResponseIsXML() const {
1650   return MIMETypeRegistry::IsXMLMIMEType(FinalResponseMIMETypeWithFallback());
1651 }
1652 
ResponseIsHTML() const1653 bool XMLHttpRequest::ResponseIsHTML() const {
1654   return EqualIgnoringASCIICase(FinalResponseMIMEType(), "text/html");
1655 }
1656 
status() const1657 int XMLHttpRequest::status() const {
1658   if (state_ == kUnsent || state_ == kOpened || error_)
1659     return 0;
1660 
1661   if (response_.HttpStatusCode())
1662     return response_.HttpStatusCode();
1663 
1664   return 0;
1665 }
1666 
statusText() const1667 String XMLHttpRequest::statusText() const {
1668   if (state_ == kUnsent || state_ == kOpened || error_)
1669     return String();
1670 
1671   if (!response_.HttpStatusText().IsNull())
1672     return response_.HttpStatusText();
1673 
1674   return String();
1675 }
1676 
DidFail(const ResourceError & error)1677 void XMLHttpRequest::DidFail(const ResourceError& error) {
1678   NETWORK_DVLOG(1) << this << " didFail()";
1679   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1680 
1681   // If we are already in an error state, for instance we called abort(), bail
1682   // out early.
1683   if (error_)
1684     return;
1685 
1686   // Internally, access check violations are considered `cancellations`, but
1687   // at least the mixed-content and CSP specs require them to be surfaced as
1688   // network errors to the page. See:
1689   //   [1] https://www.w3.org/TR/mixed-content/#algorithms,
1690   //   [2] https://www.w3.org/TR/CSP3/#fetch-integration.
1691   if (error.IsCancellation() && !error.IsAccessCheck()) {
1692     HandleDidCancel();
1693     return;
1694   }
1695 
1696   if (error.IsTimeout()) {
1697     HandleDidTimeout();
1698     return;
1699   }
1700 
1701   if (error.TrustTokenOperationError() !=
1702       network::mojom::TrustTokenOperationStatus::kOk) {
1703     trust_token_operation_error_ =
1704         TrustTokenErrorToDOMException(error.TrustTokenOperationError());
1705   }
1706 
1707   HandleNetworkError();
1708 }
1709 
DidFailRedirectCheck()1710 void XMLHttpRequest::DidFailRedirectCheck() {
1711   NETWORK_DVLOG(1) << this << " didFailRedirectCheck()";
1712   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1713 
1714   HandleNetworkError();
1715 }
1716 
DidFinishLoading(uint64_t identifier)1717 void XMLHttpRequest::DidFinishLoading(uint64_t identifier) {
1718   NETWORK_DVLOG(1) << this << " didFinishLoading(" << identifier << ")";
1719   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1720 
1721   if (error_)
1722     return;
1723 
1724   if (state_ < kHeadersReceived)
1725     ChangeState(kHeadersReceived);
1726 
1727   if (downloading_to_blob_ && response_type_code_ != kResponseTypeBlob &&
1728       response_blob_) {
1729     // In this case, we have sent the request with DownloadToBlob true,
1730     // but the user changed the response type after that. Hence we need to
1731     // read the response data and provide it to this object.
1732     blob_loader_ = MakeGarbageCollected<BlobLoader>(
1733         this, response_blob_->GetBlobDataHandle());
1734   } else {
1735     DidFinishLoadingInternal();
1736   }
1737 }
1738 
DidFinishLoadingInternal()1739 void XMLHttpRequest::DidFinishLoadingInternal() {
1740   if (response_document_parser_) {
1741     // |DocumentParser::finish()| tells the parser that we have reached end of
1742     // the data.  When using |HTMLDocumentParser|, which works asynchronously,
1743     // we do not have the complete document just after the
1744     // |DocumentParser::finish()| call.  Wait for the parser to call us back in
1745     // |notifyParserStopped| to progress state.
1746     response_document_parser_->Finish();
1747     DCHECK(response_document_);
1748     return;
1749   }
1750 
1751   if (decoder_) {
1752     auto text = decoder_->Flush();
1753     if (!text.IsEmpty() && !response_text_overflow_) {
1754       response_text_.Concat(isolate_, text);
1755       response_text_overflow_ = response_text_.IsEmpty();
1756     }
1757   }
1758 
1759   ClearVariablesForLoading();
1760   EndLoading();
1761 }
1762 
DidFinishLoadingFromBlob()1763 void XMLHttpRequest::DidFinishLoadingFromBlob() {
1764   NETWORK_DVLOG(1) << this << " didFinishLoadingFromBlob";
1765   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1766 
1767   DidFinishLoadingInternal();
1768 }
1769 
DidFailLoadingFromBlob()1770 void XMLHttpRequest::DidFailLoadingFromBlob() {
1771   NETWORK_DVLOG(1) << this << " didFailLoadingFromBlob()";
1772   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1773 
1774   if (error_)
1775     return;
1776   HandleNetworkError();
1777 }
1778 
NotifyParserStopped()1779 void XMLHttpRequest::NotifyParserStopped() {
1780   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1781 
1782   // This should only be called when response document is parsed asynchronously.
1783   DCHECK(response_document_parser_);
1784   DCHECK(!response_document_parser_->IsParsing());
1785 
1786   // Do nothing if we are called from |internalAbort()|.
1787   if (error_)
1788     return;
1789 
1790   ClearVariablesForLoading();
1791 
1792   if (!response_document_->WellFormed())
1793     response_document_ = nullptr;
1794 
1795   parsed_response_ = true;
1796 
1797   EndLoading();
1798 }
1799 
EndLoading()1800 void XMLHttpRequest::EndLoading() {
1801   probe::DidFinishXHR(GetExecutionContext(), this);
1802 
1803   if (loader_) {
1804     // Set |m_error| in order to suppress the cancel notification (see
1805     // XMLHttpRequest::didFail).
1806     base::AutoReset<bool> scope(&error_, true);
1807     loader_.Release()->Cancel();
1808   }
1809 
1810   send_flag_ = false;
1811   ChangeState(kDone);
1812 
1813   if (auto* window = DynamicTo<LocalDOMWindow>(GetExecutionContext())) {
1814     LocalFrame* frame = window->GetFrame();
1815     if (frame && cors::IsOkStatus(status()))
1816       frame->GetPage()->GetChromeClient().AjaxSucceeded(frame);
1817   }
1818 }
1819 
DidSendData(uint64_t bytes_sent,uint64_t total_bytes_to_be_sent)1820 void XMLHttpRequest::DidSendData(uint64_t bytes_sent,
1821                                  uint64_t total_bytes_to_be_sent) {
1822   NETWORK_DVLOG(1) << this << " didSendData(" << bytes_sent << ", "
1823                    << total_bytes_to_be_sent << ")";
1824   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1825 
1826   if (!upload_)
1827     return;
1828 
1829   if (upload_events_allowed_)
1830     upload_->DispatchProgressEvent(bytes_sent, total_bytes_to_be_sent);
1831 
1832   if (bytes_sent == total_bytes_to_be_sent && !upload_complete_) {
1833     upload_complete_ = true;
1834     if (upload_events_allowed_) {
1835       upload_->DispatchEventAndLoadEnd(event_type_names::kLoad, true,
1836                                        bytes_sent, total_bytes_to_be_sent);
1837     }
1838   }
1839 }
1840 
DidReceiveResponse(uint64_t identifier,const ResourceResponse & response)1841 void XMLHttpRequest::DidReceiveResponse(uint64_t identifier,
1842                                         const ResourceResponse& response) {
1843   // TODO(yhirano): Remove this CHECK: see https://crbug.com/570946.
1844   CHECK(&response);
1845 
1846   NETWORK_DVLOG(1) << this << " didReceiveResponse(" << identifier << ")";
1847   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1848 
1849   response_ = response;
1850 }
1851 
ParseDocumentChunk(const char * data,unsigned len)1852 void XMLHttpRequest::ParseDocumentChunk(const char* data, unsigned len) {
1853   if (!response_document_parser_) {
1854     DCHECK(!response_document_);
1855     InitResponseDocument();
1856     if (!response_document_)
1857       return;
1858 
1859     response_document_parser_ = response_document_->ImplicitOpen(
1860         RuntimeEnabledFeatures::ForceSynchronousHTMLParsingEnabled()
1861             ? kAllowDeferredParsing
1862             : kAllowAsynchronousParsing);
1863     response_document_parser_->AddClient(this);
1864   }
1865   DCHECK(response_document_parser_);
1866 
1867   if (response_document_parser_->NeedsDecoder())
1868     response_document_parser_->SetDecoder(CreateDecoder());
1869 
1870   response_document_parser_->AppendBytes(data, len);
1871 }
1872 
CreateDecoder() const1873 std::unique_ptr<TextResourceDecoder> XMLHttpRequest::CreateDecoder() const {
1874   const TextResourceDecoderOptions decoder_options_for_utf8_plain_text(
1875       TextResourceDecoderOptions::kPlainTextContent, UTF8Encoding());
1876   if (response_type_code_ == kResponseTypeJSON) {
1877     return std::make_unique<TextResourceDecoder>(
1878         decoder_options_for_utf8_plain_text);
1879   }
1880 
1881   WTF::TextEncoding final_response_charset = FinalResponseCharset();
1882   if (final_response_charset.IsValid()) {
1883     // If the final charset is given and valid, use the charset without
1884     // sniffing the content.
1885     return std::make_unique<TextResourceDecoder>(TextResourceDecoderOptions(
1886         TextResourceDecoderOptions::kPlainTextContent, final_response_charset));
1887   }
1888 
1889   TextResourceDecoderOptions decoder_options_for_xml(
1890       TextResourceDecoderOptions::kXMLContent);
1891   // Don't stop on encoding errors, unlike it is done for other kinds
1892   // of XML resources. This matches the behavior of previous WebKit
1893   // versions, Firefox and Opera.
1894   decoder_options_for_xml.SetUseLenientXMLDecoding();
1895 
1896   switch (response_type_code_) {
1897     case kResponseTypeDefault:
1898       if (ResponseIsXML())
1899         return std::make_unique<TextResourceDecoder>(decoder_options_for_xml);
1900       FALLTHROUGH;
1901     case kResponseTypeText:
1902       return std::make_unique<TextResourceDecoder>(
1903           decoder_options_for_utf8_plain_text);
1904     case kResponseTypeDocument:
1905       if (ResponseIsHTML()) {
1906         return std::make_unique<TextResourceDecoder>(TextResourceDecoderOptions(
1907             TextResourceDecoderOptions::kHTMLContent, UTF8Encoding()));
1908       }
1909       return std::make_unique<TextResourceDecoder>(decoder_options_for_xml);
1910     case kResponseTypeJSON:
1911     case kResponseTypeBlob:
1912     case kResponseTypeArrayBuffer:
1913       NOTREACHED();
1914       break;
1915   }
1916   NOTREACHED();
1917   return nullptr;
1918 }
1919 
DidReceiveData(const char * data,unsigned len)1920 void XMLHttpRequest::DidReceiveData(const char* data, unsigned len) {
1921   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1922   if (error_)
1923     return;
1924 
1925   DCHECK(!downloading_to_blob_ || blob_loader_);
1926 
1927   if (state_ < kHeadersReceived)
1928     ChangeState(kHeadersReceived);
1929 
1930   // We need to check for |m_error| again, because |changeState| may trigger
1931   // readystatechange, and user javascript can cause |abort()|.
1932   if (error_)
1933     return;
1934 
1935   if (!len)
1936     return;
1937 
1938   if (response_type_code_ == kResponseTypeDocument && ResponseIsHTML()) {
1939     ParseDocumentChunk(data, len);
1940   } else if (response_type_code_ == kResponseTypeDefault ||
1941              response_type_code_ == kResponseTypeText ||
1942              response_type_code_ == kResponseTypeJSON ||
1943              response_type_code_ == kResponseTypeDocument) {
1944     if (!decoder_)
1945       decoder_ = CreateDecoder();
1946 
1947     auto text = decoder_->Decode(data, len);
1948     if (!text.IsEmpty() && !response_text_overflow_) {
1949       response_text_.Concat(isolate_, text);
1950       response_text_overflow_ = response_text_.IsEmpty();
1951     }
1952   } else if (response_type_code_ == kResponseTypeArrayBuffer ||
1953              response_type_code_ == kResponseTypeBlob) {
1954     // Buffer binary data.
1955     if (!binary_response_builder_)
1956       binary_response_builder_ = SharedBuffer::Create();
1957     binary_response_builder_->Append(data, len);
1958     ReportMemoryUsageToV8();
1959   }
1960 
1961   if (blob_loader_) {
1962     // In this case, the data is provided by m_blobLoader. As progress
1963     // events are already fired, we should return here.
1964     return;
1965   }
1966   TrackProgress(len);
1967 }
1968 
DidDownloadData(uint64_t data_length)1969 void XMLHttpRequest::DidDownloadData(uint64_t data_length) {
1970   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1971   if (error_)
1972     return;
1973 
1974   DCHECK(downloading_to_blob_);
1975 
1976   if (state_ < kHeadersReceived)
1977     ChangeState(kHeadersReceived);
1978 
1979   if (!data_length)
1980     return;
1981 
1982   // readystatechange event handler may do something to put this XHR in error
1983   // state. We need to check m_error again here.
1984   if (error_)
1985     return;
1986 
1987   length_downloaded_to_blob_ += data_length;
1988   ReportMemoryUsageToV8();
1989 
1990   TrackProgress(data_length);
1991 }
1992 
DidDownloadToBlob(scoped_refptr<BlobDataHandle> blob)1993 void XMLHttpRequest::DidDownloadToBlob(scoped_refptr<BlobDataHandle> blob) {
1994   ScopedEventDispatchProtect protect(&event_dispatch_recursion_level_);
1995   if (error_)
1996     return;
1997 
1998   DCHECK(downloading_to_blob_);
1999 
2000   if (!blob) {
2001     // This generally indicates not enough quota for the blob, or somehow
2002     // failing to write the blob to disk. Treat this as a network error.
2003     // TODO(mek): Maybe print a more helpful/specific error message to the
2004     // console, to distinguish this from true network errors?
2005     // TODO(mek): This would best be treated as a network error, but for sync
2006     // requests this could also just mean succesfully reading a zero-byte blob
2007     // from a misbehaving URLLoader, so for now just ignore this and don't do
2008     // anything, which will result in an empty blob being returned by XHR.
2009     // HandleNetworkError();
2010   } else {
2011     // Fix content type if overrides or fallbacks are in effect.
2012     String mime_type = FinalResponseMIMETypeWithFallback().LowerASCII();
2013     if (blob->GetType() != mime_type) {
2014       auto blob_size = blob->size();
2015       auto blob_data = std::make_unique<BlobData>();
2016       blob_data->SetContentType(mime_type);
2017       blob_data->AppendBlob(std::move(blob), 0, blob_size);
2018       response_blob_ = MakeGarbageCollected<Blob>(
2019           BlobDataHandle::Create(std::move(blob_data), blob_size));
2020     } else {
2021       response_blob_ = MakeGarbageCollected<Blob>(std::move(blob));
2022     }
2023   }
2024 }
2025 
HandleDidTimeout()2026 void XMLHttpRequest::HandleDidTimeout() {
2027   NETWORK_DVLOG(1) << this << " handleDidTimeout()";
2028 
2029   // Response is cleared next, save needed progress event data.
2030   int64_t expected_length = response_.ExpectedContentLength();
2031   int64_t received_length = received_length_;
2032 
2033   InternalAbort();
2034 
2035   HandleRequestError(DOMExceptionCode::kTimeoutError,
2036                      event_type_names::kTimeout, received_length,
2037                      expected_length);
2038 }
2039 
ContextDestroyed()2040 void XMLHttpRequest::ContextDestroyed() {
2041   Dispose();
2042 
2043   // In case we are in the middle of send() function, unset the send flag to
2044   // stop the operation.
2045   send_flag_ = false;
2046 }
2047 
HasPendingActivity() const2048 bool XMLHttpRequest::HasPendingActivity() const {
2049   // Neither this object nor the JavaScript wrapper should be deleted while
2050   // a request is in progress because we need to keep the listeners alive,
2051   // and they are referenced by the JavaScript wrapper.
2052   // |m_loader| is non-null while request is active and ThreadableLoaderClient
2053   // callbacks may be called, and |m_responseDocumentParser| is non-null while
2054   // DocumentParserClient callbacks may be called.
2055   if (loader_ || response_document_parser_)
2056     return true;
2057   return event_dispatch_recursion_level_ > 0;
2058 }
2059 
InterfaceName() const2060 const AtomicString& XMLHttpRequest::InterfaceName() const {
2061   return event_target_names::kXMLHttpRequest;
2062 }
2063 
GetExecutionContext() const2064 ExecutionContext* XMLHttpRequest::GetExecutionContext() const {
2065   return ExecutionContextLifecycleObserver::GetExecutionContext();
2066 }
2067 
ReportMemoryUsageToV8()2068 void XMLHttpRequest::ReportMemoryUsageToV8() {
2069   // binary_response_builder_
2070   size_t size = binary_response_builder_ ? binary_response_builder_->size() : 0;
2071   int64_t diff =
2072       static_cast<int64_t>(size) -
2073       static_cast<int64_t>(binary_response_builder_last_reported_size_);
2074   binary_response_builder_last_reported_size_ = size;
2075 
2076   // Blob (downloading_to_blob_, length_downloaded_to_blob_)
2077   diff += static_cast<int64_t>(length_downloaded_to_blob_) -
2078           static_cast<int64_t>(length_downloaded_to_blob_last_reported_);
2079   length_downloaded_to_blob_last_reported_ = length_downloaded_to_blob_;
2080 
2081   if (diff)
2082     isolate_->AdjustAmountOfExternalAllocatedMemory(diff);
2083 }
2084 
Trace(Visitor * visitor) const2085 void XMLHttpRequest::Trace(Visitor* visitor) const {
2086   visitor->Trace(response_blob_);
2087   visitor->Trace(loader_);
2088   visitor->Trace(response_document_);
2089   visitor->Trace(response_document_parser_);
2090   visitor->Trace(response_array_buffer_);
2091   visitor->Trace(progress_event_throttle_);
2092   visitor->Trace(upload_);
2093   visitor->Trace(blob_loader_);
2094   visitor->Trace(response_text_);
2095   visitor->Trace(trust_token_operation_error_);
2096   XMLHttpRequestEventTarget::Trace(visitor);
2097   ThreadableLoaderClient::Trace(visitor);
2098   DocumentParserClient::Trace(visitor);
2099   ExecutionContextLifecycleObserver::Trace(visitor);
2100 }
2101 
operator <<(std::ostream & ostream,const XMLHttpRequest * xhr)2102 std::ostream& operator<<(std::ostream& ostream, const XMLHttpRequest* xhr) {
2103   return ostream << "XMLHttpRequest " << static_cast<const void*>(xhr);
2104 }
2105 
2106 }  // namespace blink
2107