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