Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(181)

Side by Side Diff: Source/core/xml/XMLHttpRequest.cpp

Issue 666153003: Move XMLHttpRequest related files to core/xmlhttprequest. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebase Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « Source/core/xml/XMLHttpRequest.h ('k') | Source/core/xml/XMLHttpRequest.idl » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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, Boston, MA 02110-1301 U SA
21 */
22
23 #include "config.h"
24 #include "core/xml/XMLHttpRequest.h"
25
26 #include "bindings/core/v8/ExceptionState.h"
27 #include "core/FetchInitiatorTypeNames.h"
28 #include "core/dom/ContextFeatures.h"
29 #include "core/dom/DOMArrayBuffer.h"
30 #include "core/dom/DOMException.h"
31 #include "core/dom/DOMImplementation.h"
32 #include "core/dom/DocumentParser.h"
33 #include "core/dom/ExceptionCode.h"
34 #include "core/dom/XMLDocument.h"
35 #include "core/editing/markup.h"
36 #include "core/events/Event.h"
37 #include "core/fetch/FetchUtils.h"
38 #include "core/fileapi/Blob.h"
39 #include "core/fileapi/File.h"
40 #include "core/fileapi/FileReaderLoader.h"
41 #include "core/fileapi/FileReaderLoaderClient.h"
42 #include "core/frame/Settings.h"
43 #include "core/frame/UseCounter.h"
44 #include "core/frame/csp/ContentSecurityPolicy.h"
45 #include "core/html/DOMFormData.h"
46 #include "core/html/HTMLDocument.h"
47 #include "core/html/parser/TextResourceDecoder.h"
48 #include "core/inspector/ConsoleMessage.h"
49 #include "core/inspector/InspectorInstrumentation.h"
50 #include "core/inspector/InspectorTraceEvents.h"
51 #include "core/loader/ThreadableLoader.h"
52 #include "core/streams/ReadableStream.h"
53 #include "core/streams/ReadableStreamImpl.h"
54 #include "core/streams/Stream.h"
55 #include "core/streams/UnderlyingSource.h"
56 #include "core/xml/XMLHttpRequestProgressEvent.h"
57 #include "core/xml/XMLHttpRequestUpload.h"
58 #include "platform/Logging.h"
59 #include "platform/RuntimeEnabledFeatures.h"
60 #include "platform/SharedBuffer.h"
61 #include "platform/blob/BlobData.h"
62 #include "platform/network/HTTPParsers.h"
63 #include "platform/network/ParsedContentType.h"
64 #include "platform/network/ResourceError.h"
65 #include "platform/network/ResourceRequest.h"
66 #include "public/platform/WebURLRequest.h"
67 #include "wtf/ArrayBuffer.h"
68 #include "wtf/ArrayBufferView.h"
69 #include "wtf/Assertions.h"
70 #include "wtf/RefCountedLeakCounter.h"
71 #include "wtf/StdLibExtras.h"
72 #include "wtf/text/CString.h"
73
74 namespace blink {
75
76 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, xmlHttpRequestCounter, ("XM LHttpRequest"));
77
78 static bool isSetCookieHeader(const AtomicString& name)
79 {
80 return equalIgnoringCase(name, "set-cookie") || equalIgnoringCase(name, "set -cookie2");
81 }
82
83 static void replaceCharsetInMediaType(String& mediaType, const String& charsetVa lue)
84 {
85 unsigned pos = 0, len = 0;
86
87 findCharsetInMediaType(mediaType, pos, len);
88
89 if (!len) {
90 // When no charset found, do nothing.
91 return;
92 }
93
94 // Found at least one existing charset, replace all occurrences with new cha rset.
95 while (len) {
96 mediaType.replace(pos, len, charsetValue);
97 unsigned start = pos + charsetValue.length();
98 findCharsetInMediaType(mediaType, pos, len, start);
99 }
100 }
101
102 static void logConsoleError(ExecutionContext* context, const String& message)
103 {
104 if (!context)
105 return;
106 // FIXME: It's not good to report the bad usage without indicating what sour ce line it came from.
107 // We should pass additional parameters so we can tell the console where the mistake occurred.
108 context->addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMess ageLevel, message));
109 }
110
111 namespace {
112
113 class ReadableStreamSource : public GarbageCollectedFinalized<ReadableStreamSour ce>, public UnderlyingSource {
114 USING_GARBAGE_COLLECTED_MIXIN(ReadableStreamSource);
115 public:
116 ReadableStreamSource(XMLHttpRequest* owner) : m_owner(owner) { }
117 virtual ~ReadableStreamSource() { }
118 virtual void pullSource() override { }
119 virtual ScriptPromise cancelSource(ScriptState* scriptState, ScriptValue rea son) override
120 {
121 m_owner->abort();
122 return ScriptPromise::cast(scriptState, v8::Undefined(scriptState->isola te()));
123 }
124 virtual void trace(Visitor* visitor) override
125 {
126 visitor->trace(m_owner);
127 UnderlyingSource::trace(visitor);
128 }
129
130 private:
131 // This is RawPtr in non-oilpan build to avoid the reference cycle. To
132 // avoid use-after free, the associated ReadableStream must be closed
133 // or errored when m_owner is gone.
134 RawPtrWillBeMember<XMLHttpRequest> m_owner;
135 };
136
137 } // namespace
138
139 class XMLHttpRequest::BlobLoader final : public NoBaseWillBeGarbageCollectedFina lized<XMLHttpRequest::BlobLoader>, public FileReaderLoaderClient {
140 public:
141 static PassOwnPtrWillBeRawPtr<BlobLoader> create(XMLHttpRequest* xhr, PassRe fPtr<BlobDataHandle> handle)
142 {
143 return adoptPtrWillBeNoop(new BlobLoader(xhr, handle));
144 }
145
146 // FileReaderLoaderClient functions.
147 virtual void didStartLoading() override { }
148 virtual void didReceiveDataForClient(const char* data, unsigned length) over ride
149 {
150 ASSERT(length <= INT_MAX);
151 m_xhr->didReceiveData(data, length);
152 }
153 virtual void didFinishLoading() override
154 {
155 m_xhr->didFinishLoadingFromBlob();
156 }
157 virtual void didFail(FileError::ErrorCode error) override
158 {
159 m_xhr->didFailLoadingFromBlob();
160 }
161
162 void cancel()
163 {
164 m_loader.cancel();
165 }
166
167 void trace(Visitor* visitor)
168 {
169 visitor->trace(m_xhr);
170 }
171
172 private:
173 BlobLoader(XMLHttpRequest* xhr, PassRefPtr<BlobDataHandle> handle)
174 : m_xhr(xhr)
175 , m_loader(FileReaderLoader::ReadByClient, this)
176 {
177 m_loader.start(m_xhr->executionContext(), handle);
178 }
179
180 RawPtrWillBeMember<XMLHttpRequest> m_xhr;
181 FileReaderLoader m_loader;
182 };
183
184 PassRefPtrWillBeRawPtr<XMLHttpRequest> XMLHttpRequest::create(ExecutionContext* context, PassRefPtr<SecurityOrigin> securityOrigin)
185 {
186 RefPtrWillBeRawPtr<XMLHttpRequest> xmlHttpRequest = adoptRefWillBeNoop(new X MLHttpRequest(context, securityOrigin));
187 xmlHttpRequest->suspendIfNeeded();
188
189 return xmlHttpRequest.release();
190 }
191
192 XMLHttpRequest::XMLHttpRequest(ExecutionContext* context, PassRefPtr<SecurityOri gin> securityOrigin)
193 : ActiveDOMObject(context)
194 , m_timeoutMilliseconds(0)
195 , m_loaderIdentifier(0)
196 , m_state(UNSENT)
197 , m_lengthDownloadedToFile(0)
198 , m_receivedLength(0)
199 , m_exceptionCode(0)
200 , m_progressEventThrottle(this)
201 , m_responseTypeCode(ResponseTypeDefault)
202 , m_securityOrigin(securityOrigin)
203 , m_async(true)
204 , m_includeCredentials(false)
205 , m_parsedResponse(false)
206 , m_error(false)
207 , m_uploadEventsAllowed(true)
208 , m_uploadComplete(false)
209 , m_sameOriginRequest(true)
210 , m_downloadingToFile(false)
211 {
212 #ifndef NDEBUG
213 xmlHttpRequestCounter.increment();
214 #endif
215 }
216
217 XMLHttpRequest::~XMLHttpRequest()
218 {
219 #ifndef NDEBUG
220 xmlHttpRequestCounter.decrement();
221 #endif
222 }
223
224 Document* XMLHttpRequest::document() const
225 {
226 ASSERT(executionContext()->isDocument());
227 return toDocument(executionContext());
228 }
229
230 SecurityOrigin* XMLHttpRequest::securityOrigin() const
231 {
232 return m_securityOrigin ? m_securityOrigin.get() : executionContext()->secur ityOrigin();
233 }
234
235 XMLHttpRequest::State XMLHttpRequest::readyState() const
236 {
237 return m_state;
238 }
239
240 ScriptString XMLHttpRequest::responseText(ExceptionState& exceptionState)
241 {
242 if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != Respo nseTypeText) {
243 exceptionState.throwDOMException(InvalidStateError, "The value is only a ccessible if the object's 'responseType' is '' or 'text' (was '" + responseType( ) + "').");
244 return ScriptString();
245 }
246 if (m_error || (m_state != LOADING && m_state != DONE))
247 return ScriptString();
248 return m_responseText;
249 }
250
251 ScriptString XMLHttpRequest::responseJSONSource()
252 {
253 ASSERT(m_responseTypeCode == ResponseTypeJSON);
254
255 if (m_error || m_state != DONE)
256 return ScriptString();
257 return m_responseText;
258 }
259
260 void XMLHttpRequest::initResponseDocument()
261 {
262 // The W3C spec requires the final MIME type to be some valid XML type, or t ext/html.
263 // If it is text/html, then the responseType of "document" must have been su pplied explicitly.
264 bool isHTML = responseIsHTML();
265 if ((m_response.isHTTP() && !responseIsXML() && !isHTML)
266 || (isHTML && m_responseTypeCode == ResponseTypeDefault)
267 || executionContext()->isWorkerGlobalScope()) {
268 m_responseDocument = nullptr;
269 return;
270 }
271
272 DocumentInit init = DocumentInit::fromContext(document()->contextDocument(), m_url);
273 if (isHTML)
274 m_responseDocument = HTMLDocument::create(init);
275 else
276 m_responseDocument = XMLDocument::create(init);
277
278 // FIXME: Set Last-Modified.
279 m_responseDocument->setSecurityOrigin(securityOrigin());
280 m_responseDocument->setContextFeatures(document()->contextFeatures());
281 m_responseDocument->setMimeType(finalResponseMIMETypeWithFallback());
282 }
283
284 Document* XMLHttpRequest::responseXML(ExceptionState& exceptionState)
285 {
286 if (m_responseTypeCode != ResponseTypeDefault && m_responseTypeCode != Respo nseTypeDocument) {
287 exceptionState.throwDOMException(InvalidStateError, "The value is only a ccessible if the object's 'responseType' is '' or 'document' (was '" + responseT ype() + "').");
288 return 0;
289 }
290
291 if (m_error || m_state != DONE)
292 return 0;
293
294 if (!m_parsedResponse) {
295 initResponseDocument();
296 if (!m_responseDocument)
297 return nullptr;
298
299 m_responseDocument->setContent(m_responseText.flattenToString());
300 if (!m_responseDocument->wellFormed())
301 m_responseDocument = nullptr;
302
303 m_parsedResponse = true;
304 }
305
306 return m_responseDocument.get();
307 }
308
309 Blob* XMLHttpRequest::responseBlob()
310 {
311 ASSERT(m_responseTypeCode == ResponseTypeBlob);
312
313 // We always return null before DONE.
314 if (m_error || m_state != DONE)
315 return 0;
316
317 if (!m_responseBlob) {
318 if (m_downloadingToFile) {
319 ASSERT(!m_binaryResponseBuilder);
320
321 // When responseType is set to "blob", we redirect the downloaded
322 // data to a file-handle directly in the browser process. We get
323 // the file-path from the ResourceResponse directly instead of
324 // copying the bytes between the browser and the renderer.
325 m_responseBlob = Blob::create(createBlobDataHandleFromResponse());
326 } else {
327 OwnPtr<BlobData> blobData = BlobData::create();
328 size_t size = 0;
329 if (m_binaryResponseBuilder && m_binaryResponseBuilder->size()) {
330 size = m_binaryResponseBuilder->size();
331 blobData->appendBytes(m_binaryResponseBuilder->data(), size);
332 blobData->setContentType(finalResponseMIMETypeWithFallback());
333 m_binaryResponseBuilder.clear();
334 }
335 m_responseBlob = Blob::create(BlobDataHandle::create(blobData.releas e(), size));
336 }
337 }
338
339 return m_responseBlob.get();
340 }
341
342 DOMArrayBuffer* XMLHttpRequest::responseArrayBuffer()
343 {
344 ASSERT(m_responseTypeCode == ResponseTypeArrayBuffer);
345
346 if (m_error || m_state != DONE)
347 return 0;
348
349 if (!m_responseArrayBuffer) {
350 if (m_binaryResponseBuilder && m_binaryResponseBuilder->size()) {
351 m_responseArrayBuffer = DOMArrayBuffer::create(m_binaryResponseBuild er->getAsArrayBuffer());
352 if (!m_responseArrayBuffer) {
353 // m_binaryResponseBuilder failed to allocate an ArrayBuffer.
354 // We need to crash the renderer since there's no way defined in
355 // the spec to tell this to the user.
356 CRASH();
357 }
358 m_binaryResponseBuilder.clear();
359 } else {
360 m_responseArrayBuffer = DOMArrayBuffer::create(static_cast<void*>(0) , 0);
361 }
362 }
363
364 return m_responseArrayBuffer.get();
365 }
366
367 Stream* XMLHttpRequest::responseLegacyStream()
368 {
369 ASSERT(m_responseTypeCode == ResponseTypeLegacyStream);
370
371 if (m_error || (m_state != LOADING && m_state != DONE))
372 return 0;
373
374 return m_responseLegacyStream.get();
375 }
376
377 ReadableStream* XMLHttpRequest::responseStream()
378 {
379 ASSERT(m_responseTypeCode == ResponseTypeStream);
380 if (m_error || (m_state != LOADING && m_state != DONE))
381 return 0;
382
383 return m_responseStream;
384 }
385
386 void XMLHttpRequest::setTimeout(unsigned long timeout, ExceptionState& exception State)
387 {
388 // FIXME: Need to trigger or update the timeout Timer here, if needed. http: //webkit.org/b/98156
389 // XHR2 spec, 4.7.3. "This implies that the timeout attribute can be set whi le fetching is in progress. If that occurs it will still be measured relative to the start of fetching."
390 if (executionContext()->isDocument() && !m_async) {
391 exceptionState.throwDOMException(InvalidAccessError, "Timeouts cannot be set for synchronous requests made from a document.");
392 return;
393 }
394
395 m_timeoutMilliseconds = timeout;
396
397 // From http://www.w3.org/TR/XMLHttpRequest/#the-timeout-attribute:
398 // Note: This implies that the timeout attribute can be set while fetching i s in progress. If
399 // that occurs it will still be measured relative to the start of fetching.
400 //
401 // The timeout may be overridden after send.
402 if (m_loader)
403 m_loader->overrideTimeout(timeout);
404 }
405
406 void XMLHttpRequest::setResponseType(const String& responseType, ExceptionState& exceptionState)
407 {
408 if (m_state >= LOADING) {
409 exceptionState.throwDOMException(InvalidStateError, "The response type c annot be set if the object's state is LOADING or DONE.");
410 return;
411 }
412
413 // Newer functionality is not available to synchronous requests in window co ntexts, as a spec-mandated
414 // attempt to discourage synchronous XHR use. responseType is one such piece of functionality.
415 if (!m_async && executionContext()->isDocument()) {
416 exceptionState.throwDOMException(InvalidAccessError, "The response type cannot be changed for synchronous requests made from a document.");
417 return;
418 }
419
420 if (responseType == "") {
421 m_responseTypeCode = ResponseTypeDefault;
422 } else if (responseType == "text") {
423 m_responseTypeCode = ResponseTypeText;
424 } else if (responseType == "json") {
425 m_responseTypeCode = ResponseTypeJSON;
426 } else if (responseType == "document") {
427 m_responseTypeCode = ResponseTypeDocument;
428 } else if (responseType == "blob") {
429 m_responseTypeCode = ResponseTypeBlob;
430 } else if (responseType == "arraybuffer") {
431 m_responseTypeCode = ResponseTypeArrayBuffer;
432 } else if (responseType == "legacystream") {
433 if (RuntimeEnabledFeatures::streamEnabled())
434 m_responseTypeCode = ResponseTypeLegacyStream;
435 else
436 return;
437 } else if (responseType == "stream") {
438 if (RuntimeEnabledFeatures::streamEnabled())
439 m_responseTypeCode = ResponseTypeStream;
440 else
441 return;
442 } else {
443 ASSERT_NOT_REACHED();
444 }
445 }
446
447 String XMLHttpRequest::responseType()
448 {
449 switch (m_responseTypeCode) {
450 case ResponseTypeDefault:
451 return "";
452 case ResponseTypeText:
453 return "text";
454 case ResponseTypeJSON:
455 return "json";
456 case ResponseTypeDocument:
457 return "document";
458 case ResponseTypeBlob:
459 return "blob";
460 case ResponseTypeArrayBuffer:
461 return "arraybuffer";
462 case ResponseTypeLegacyStream:
463 return "legacystream";
464 case ResponseTypeStream:
465 return "stream";
466 }
467 return "";
468 }
469
470 String XMLHttpRequest::responseURL()
471 {
472 return m_response.url().string();
473 }
474
475 XMLHttpRequestUpload* XMLHttpRequest::upload()
476 {
477 if (!m_upload)
478 m_upload = XMLHttpRequestUpload::create(this);
479 return m_upload.get();
480 }
481
482 void XMLHttpRequest::trackProgress(long long length)
483 {
484 m_receivedLength += length;
485
486 if (m_state != LOADING) {
487 changeState(LOADING);
488 } else {
489 // Dispatch a readystatechange event because many applications use
490 // it to track progress although this is not specified.
491 //
492 // FIXME: Stop dispatching this event for progress tracking.
493 dispatchReadyStateChangeEvent();
494 }
495 if (m_async)
496 dispatchProgressEventFromSnapshot(EventTypeNames::progress);
497 }
498
499 void XMLHttpRequest::changeState(State newState)
500 {
501 if (m_state != newState) {
502 m_state = newState;
503 dispatchReadyStateChangeEvent();
504 }
505 }
506
507 void XMLHttpRequest::dispatchReadyStateChangeEvent()
508 {
509 if (!executionContext())
510 return;
511
512 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDispat chXHRReadyStateChangeEvent(executionContext(), this);
513
514 if (m_async || (m_state <= OPENED || m_state == DONE)) {
515 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "XHRReadySt ateChange", "data", InspectorXhrReadyStateChangeEvent::data(executionContext(), this));
516 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.stack" ), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
517 XMLHttpRequestProgressEventThrottle::DeferredEventAction action = XMLHtt pRequestProgressEventThrottle::Ignore;
518 if (m_state == DONE) {
519 if (m_error)
520 action = XMLHttpRequestProgressEventThrottle::Clear;
521 else
522 action = XMLHttpRequestProgressEventThrottle::Flush;
523 }
524 m_progressEventThrottle.dispatchReadyStateChangeEvent(Event::create(Even tTypeNames::readystatechange), action);
525 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Up dateCounters", "data", InspectorUpdateCountersEvent::data());
526 }
527
528 InspectorInstrumentation::didDispatchXHRReadyStateChangeEvent(cookie);
529 if (m_state == DONE && !m_error) {
530 {
531 TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "XHRLoa d", "data", InspectorXhrLoadEvent::data(executionContext(), this));
532 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline.st ack"), "CallStack", "stack", InspectorCallStackEvent::currentCallStack());
533 InspectorInstrumentationCookie cookie = InspectorInstrumentation::wi llDispatchXHRLoadEvent(executionContext(), this);
534 dispatchProgressEventFromSnapshot(EventTypeNames::load);
535 InspectorInstrumentation::didDispatchXHRLoadEvent(cookie);
536 }
537 dispatchProgressEventFromSnapshot(EventTypeNames::loadend);
538 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Up dateCounters", "data", InspectorUpdateCountersEvent::data());
539 }
540 }
541
542 void XMLHttpRequest::setWithCredentials(bool value, ExceptionState& exceptionSta te)
543 {
544 if (m_state > OPENED || m_loader) {
545 exceptionState.throwDOMException(InvalidStateError, "The value may only be set if the object's state is UNSENT or OPENED.");
546 return;
547 }
548
549 // FIXME: According to XMLHttpRequest Level 2 we should throw InvalidAccessE rror exception here.
550 // However for time being only print warning message to warn web developers.
551 if (!m_async)
552 UseCounter::countDeprecation(executionContext(), UseCounter::SyncXHRWith Credentials);
553
554 m_includeCredentials = value;
555 }
556
557 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, Exception State& exceptionState)
558 {
559 open(method, url, true, exceptionState);
560 }
561
562 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool asyn c, ExceptionState& exceptionState)
563 {
564 WTF_LOG(Network, "XMLHttpRequest %p open('%s', '%s', %d)", this, method.utf8 ().data(), url.elidedString().utf8().data(), async);
565
566 if (!internalAbort())
567 return;
568
569 State previousState = m_state;
570 m_state = UNSENT;
571 m_error = false;
572 m_uploadComplete = false;
573
574 if (!isValidHTTPToken(method)) {
575 exceptionState.throwDOMException(SyntaxError, "'" + method + "' is not a valid HTTP method.");
576 return;
577 }
578
579 if (FetchUtils::isForbiddenMethod(method)) {
580 exceptionState.throwSecurityError("'" + method + "' HTTP method is unsup ported.");
581 return;
582 }
583
584 if (!ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) && !ex ecutionContext()->contentSecurityPolicy()->allowConnectToSource(url)) {
585 // We can safely expose the URL to JavaScript, as these checks happen sy nchronously before redirection. JavaScript receives no new information.
586 exceptionState.throwSecurityError("Refused to connect to '" + url.elided String() + "' because it violates the document's Content Security Policy.");
587 return;
588 }
589
590 if (!async && executionContext()->isDocument()) {
591 if (document()->settings() && !document()->settings()->syncXHRInDocument sEnabled()) {
592 exceptionState.throwDOMException(InvalidAccessError, "Synchronous re quests are disabled for this page.");
593 return;
594 }
595
596 // Newer functionality is not available to synchronous requests in windo w contexts, as a spec-mandated
597 // attempt to discourage synchronous XHR use. responseType is one such p iece of functionality.
598 if (m_responseTypeCode != ResponseTypeDefault) {
599 exceptionState.throwDOMException(InvalidAccessError, "Synchronous re quests from a document must not set a response type.");
600 return;
601 }
602
603 // Similarly, timeouts are disabled for synchronous requests as well.
604 if (m_timeoutMilliseconds > 0) {
605 exceptionState.throwDOMException(InvalidAccessError, "Synchronous re quests must not set a timeout.");
606 return;
607 }
608 }
609
610 m_method = FetchUtils::normalizeMethod(method);
611
612 m_url = url;
613
614 m_async = async;
615
616 ASSERT(!m_loader);
617
618 // Check previous state to avoid dispatching readyState event
619 // when calling open several times in a row.
620 if (previousState != OPENED)
621 changeState(OPENED);
622 else
623 m_state = OPENED;
624 }
625
626 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool asyn c, const String& user, ExceptionState& exceptionState)
627 {
628 KURL urlWithCredentials(url);
629 urlWithCredentials.setUser(user);
630
631 open(method, urlWithCredentials, async, exceptionState);
632 }
633
634 void XMLHttpRequest::open(const AtomicString& method, const KURL& url, bool asyn c, const String& user, const String& password, ExceptionState& exceptionState)
635 {
636 KURL urlWithCredentials(url);
637 urlWithCredentials.setUser(user);
638 urlWithCredentials.setPass(password);
639
640 open(method, urlWithCredentials, async, exceptionState);
641 }
642
643 bool XMLHttpRequest::initSend(ExceptionState& exceptionState)
644 {
645 if (!executionContext())
646 return false;
647
648 if (m_state != OPENED || m_loader) {
649 exceptionState.throwDOMException(InvalidStateError, "The object's state must be OPENED.");
650 return false;
651 }
652
653 m_error = false;
654 return true;
655 }
656
657 void XMLHttpRequest::send(ExceptionState& exceptionState)
658 {
659 send(String(), exceptionState);
660 }
661
662 bool XMLHttpRequest::areMethodAndURLValidForSend()
663 {
664 return m_method != "GET" && m_method != "HEAD" && m_url.protocolIsInHTTPFami ly();
665 }
666
667 void XMLHttpRequest::send(Document* document, ExceptionState& exceptionState)
668 {
669 WTF_LOG(Network, "XMLHttpRequest %p send() Document %p", this, document);
670
671 ASSERT(document);
672
673 if (!initSend(exceptionState))
674 return;
675
676 RefPtr<FormData> httpBody;
677
678 if (areMethodAndURLValidForSend()) {
679 if (getRequestHeader("Content-Type").isEmpty()) {
680 // FIXME: this should include the charset used for encoding.
681 setRequestHeaderInternal("Content-Type", "application/xml");
682 }
683
684 // FIXME: According to XMLHttpRequest Level 2, this should use the Docum ent.innerHTML algorithm
685 // from the HTML5 specification to serialize the document.
686 String body = createMarkup(document);
687
688 // FIXME: This should use value of document.inputEncoding to determine t he encoding to use.
689 httpBody = FormData::create(UTF8Encoding().encode(body, WTF::EntitiesFor Unencodables));
690 if (m_upload)
691 httpBody->setAlwaysStream(true);
692 }
693
694 createRequest(httpBody.release(), exceptionState);
695 }
696
697 void XMLHttpRequest::send(const String& body, ExceptionState& exceptionState)
698 {
699 WTF_LOG(Network, "XMLHttpRequest %p send() String '%s'", this, body.utf8().d ata());
700
701 if (!initSend(exceptionState))
702 return;
703
704 RefPtr<FormData> httpBody;
705
706 if (!body.isNull() && areMethodAndURLValidForSend()) {
707 String contentType = getRequestHeader("Content-Type");
708 if (contentType.isEmpty()) {
709 setRequestHeaderInternal("Content-Type", "text/plain;charset=UTF-8") ;
710 } else {
711 replaceCharsetInMediaType(contentType, "UTF-8");
712 m_requestHeaders.set("Content-Type", AtomicString(contentType));
713 }
714
715 httpBody = FormData::create(UTF8Encoding().encode(body, WTF::EntitiesFor Unencodables));
716 if (m_upload)
717 httpBody->setAlwaysStream(true);
718 }
719
720 createRequest(httpBody.release(), exceptionState);
721 }
722
723 void XMLHttpRequest::send(Blob* body, ExceptionState& exceptionState)
724 {
725 WTF_LOG(Network, "XMLHttpRequest %p send() Blob '%s'", this, body->uuid().ut f8().data());
726
727 if (!initSend(exceptionState))
728 return;
729
730 RefPtr<FormData> httpBody;
731
732 if (areMethodAndURLValidForSend()) {
733 if (getRequestHeader("Content-Type").isEmpty()) {
734 const String& blobType = body->type();
735 if (!blobType.isEmpty() && isValidContentType(blobType)) {
736 setRequestHeaderInternal("Content-Type", AtomicString(blobType)) ;
737 } else {
738 // From FileAPI spec, whenever media type cannot be determined,
739 // empty string must be returned.
740 setRequestHeaderInternal("Content-Type", "");
741 }
742 }
743
744 // FIXME: add support for uploading bundles.
745 httpBody = FormData::create();
746 if (body->hasBackingFile()) {
747 File* file = toFile(body);
748 if (!file->path().isEmpty())
749 httpBody->appendFile(file->path());
750 else if (!file->fileSystemURL().isEmpty())
751 httpBody->appendFileSystemURL(file->fileSystemURL());
752 else
753 ASSERT_NOT_REACHED();
754 } else {
755 httpBody->appendBlob(body->uuid(), body->blobDataHandle());
756 }
757 }
758
759 createRequest(httpBody.release(), exceptionState);
760 }
761
762 void XMLHttpRequest::send(DOMFormData* body, ExceptionState& exceptionState)
763 {
764 WTF_LOG(Network, "XMLHttpRequest %p send() DOMFormData %p", this, body);
765
766 if (!initSend(exceptionState))
767 return;
768
769 RefPtr<FormData> httpBody;
770
771 if (areMethodAndURLValidForSend()) {
772 httpBody = body->createMultiPartFormData();
773
774 if (getRequestHeader("Content-Type").isEmpty()) {
775 AtomicString contentType = AtomicString("multipart/form-data; bounda ry=", AtomicString::ConstructFromLiteral) + httpBody->boundary().data();
776 setRequestHeaderInternal("Content-Type", contentType);
777 }
778 }
779
780 createRequest(httpBody.release(), exceptionState);
781 }
782
783 void XMLHttpRequest::send(ArrayBuffer* body, ExceptionState& exceptionState)
784 {
785 WTF_LOG(Network, "XMLHttpRequest %p send() ArrayBuffer %p", this, body);
786
787 sendBytesData(body->data(), body->byteLength(), exceptionState);
788 }
789
790 void XMLHttpRequest::send(ArrayBufferView* body, ExceptionState& exceptionState)
791 {
792 WTF_LOG(Network, "XMLHttpRequest %p send() ArrayBufferView %p", this, body);
793
794 sendBytesData(body->baseAddress(), body->byteLength(), exceptionState);
795 }
796
797 void XMLHttpRequest::sendBytesData(const void* data, size_t length, ExceptionSta te& exceptionState)
798 {
799 if (!initSend(exceptionState))
800 return;
801
802 RefPtr<FormData> httpBody;
803
804 if (areMethodAndURLValidForSend()) {
805 httpBody = FormData::create(data, length);
806 if (m_upload)
807 httpBody->setAlwaysStream(true);
808 }
809
810 createRequest(httpBody.release(), exceptionState);
811 }
812
813 void XMLHttpRequest::sendForInspectorXHRReplay(PassRefPtr<FormData> formData, Ex ceptionState& exceptionState)
814 {
815 createRequest(formData ? formData->deepCopy() : nullptr, exceptionState);
816 m_exceptionCode = exceptionState.code();
817 }
818
819 void XMLHttpRequest::createRequest(PassRefPtr<FormData> httpBody, ExceptionState & exceptionState)
820 {
821 // Only GET request is supported for blob URL.
822 if (m_url.protocolIs("blob") && m_method != "GET") {
823 exceptionState.throwDOMException(NetworkError, "'GET' is the only method allowed for 'blob:' URLs.");
824 return;
825 }
826
827 // The presence of upload event listeners forces us to use preflighting beca use POSTing to an URL that does not
828 // permit cross origin requests should look exactly like POSTing to an URL t hat does not respond at all.
829 // Also, only async requests support upload progress events.
830 bool uploadEvents = false;
831 if (m_async) {
832 dispatchProgressEvent(EventTypeNames::loadstart, 0, 0);
833 if (httpBody && m_upload) {
834 uploadEvents = m_upload->hasEventListeners();
835 m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTyp eNames::loadstart));
836 }
837 }
838
839 m_sameOriginRequest = securityOrigin()->canRequest(m_url);
840
841 // We also remember whether upload events should be allowed for this request in case the upload listeners are
842 // added after the request is started.
843 m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !FetchUtils:: isSimpleRequest(m_method, m_requestHeaders);
844
845 ASSERT(executionContext());
846 ExecutionContext& executionContext = *this->executionContext();
847
848 ResourceRequest request(m_url);
849 request.setHTTPMethod(m_method);
850 request.setRequestContext(blink::WebURLRequest::RequestContextXMLHttpRequest );
851
852 InspectorInstrumentation::willLoadXHR(&executionContext, this, this, m_metho d, m_url, m_async, httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders, m_includeCredentials);
853
854 if (httpBody) {
855 ASSERT(m_method != "GET");
856 ASSERT(m_method != "HEAD");
857 request.setHTTPBody(httpBody);
858 }
859
860 if (m_requestHeaders.size() > 0)
861 request.addHTTPHeaderFields(m_requestHeaders);
862
863 ThreadableLoaderOptions options;
864 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight;
865 options.crossOriginRequestPolicy = UseAccessControl;
866 options.initiator = FetchInitiatorTypeNames::xmlhttprequest;
867 options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypa ssMainWorld(&executionContext) ? DoNotEnforceContentSecurityPolicy : EnforceConn ectSrcDirective;
868 options.timeoutMilliseconds = m_timeoutMilliseconds;
869
870 ResourceLoaderOptions resourceLoaderOptions;
871 resourceLoaderOptions.allowCredentials = (m_sameOriginRequest || m_includeCr edentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials;
872 resourceLoaderOptions.credentialsRequested = m_includeCredentials ? ClientRe questedCredentials : ClientDidNotRequestCredentials;
873 resourceLoaderOptions.securityOrigin = securityOrigin();
874 resourceLoaderOptions.mixedContentBlockingTreatment = RuntimeEnabledFeatures ::laxMixedContentCheckingEnabled() ? TreatAsPassiveContent : TreatAsActiveConten t;
875
876 // When responseType is set to "blob", we redirect the downloaded data to a
877 // file-handle directly.
878 m_downloadingToFile = responseTypeCode() == ResponseTypeBlob;
879 if (m_downloadingToFile) {
880 request.setDownloadToFile(true);
881 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
882 }
883
884 m_exceptionCode = 0;
885 m_error = false;
886
887 if (m_async) {
888 if (m_upload)
889 request.setReportUploadProgress(true);
890
891 // ThreadableLoader::create can return null here, for example if we're n o longer attached to a page.
892 // This is true while running onunload handlers.
893 // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload , <http://bugs.webkit.org/show_bug.cgi?id=10904>.
894 // FIXME: Maybe create() can return null for other reasons too?
895 ASSERT(!m_loader);
896 m_loader = ThreadableLoader::create(executionContext, this, request, opt ions, resourceLoaderOptions);
897 } else {
898 // Use count for XHR synchronous requests.
899 UseCounter::count(&executionContext, UseCounter::XMLHttpRequestSynchrono us);
900 ThreadableLoader::loadResourceSynchronously(executionContext, request, * this, options, resourceLoaderOptions);
901 }
902
903 if (!m_exceptionCode && m_error)
904 m_exceptionCode = NetworkError;
905 if (m_exceptionCode)
906 exceptionState.throwDOMException(m_exceptionCode, "Failed to load '" + m _url.elidedString() + "'.");
907 }
908
909 void XMLHttpRequest::abort()
910 {
911 WTF_LOG(Network, "XMLHttpRequest %p abort()", this);
912
913 // internalAbort() clears |m_loader|. Compute |sendFlag| now.
914 //
915 // |sendFlag| corresponds to "the send() flag" defined in the XHR spec.
916 //
917 // |sendFlag| is only set when we have an active, asynchronous loader.
918 // Don't use it as "the send() flag" when the XHR is in sync mode.
919 bool sendFlag = m_loader;
920
921 // internalAbort() clears the response. Save the data needed for
922 // dispatching ProgressEvents.
923 long long expectedLength = m_response.expectedContentLength();
924 long long receivedLength = m_receivedLength;
925
926 if (!internalAbort())
927 return;
928
929 // The script never gets any chance to call abort() on a sync XHR between
930 // send() call and transition to the DONE state. It's because a sync XHR
931 // doesn't dispatch any event between them. So, if |m_async| is false, we
932 // can skip the "request error steps" (defined in the XHR spec) without any
933 // state check.
934 //
935 // FIXME: It's possible open() is invoked in internalAbort() and |m_async|
936 // becomes true by that. We should implement more reliable treatment for
937 // nested method invocations at some point.
938 if (m_async) {
939 if ((m_state == OPENED && sendFlag) || m_state == HEADERS_RECEIVED || m_ state == LOADING) {
940 ASSERT(!m_loader);
941 handleRequestError(0, EventTypeNames::abort, receivedLength, expecte dLength);
942 }
943 }
944 m_state = UNSENT;
945 }
946
947 void XMLHttpRequest::clearVariablesForLoading()
948 {
949 if (m_blobLoader) {
950 m_blobLoader->cancel();
951 m_blobLoader = nullptr;
952 }
953
954 m_decoder.clear();
955
956 if (m_responseDocumentParser) {
957 m_responseDocumentParser->removeClient(this);
958 #if !ENABLE(OILPAN)
959 m_responseDocumentParser->detach();
960 #endif
961 m_responseDocumentParser = nullptr;
962 }
963
964 m_finalResponseCharset = String();
965 }
966
967 bool XMLHttpRequest::internalAbort()
968 {
969 m_error = true;
970
971 if (m_responseDocumentParser && !m_responseDocumentParser->isStopped())
972 m_responseDocumentParser->stopParsing();
973
974 clearVariablesForLoading();
975
976 InspectorInstrumentation::didFailXHRLoading(executionContext(), this, this);
977
978 if (m_responseLegacyStream && m_state != DONE)
979 m_responseLegacyStream->abort();
980
981 if (m_responseStream) {
982 // When the stream is already closed (including canceled from the
983 // user), |error| does nothing.
984 // FIXME: Create a more specific error.
985 m_responseStream->error(DOMException::create(!m_async && m_exceptionCode ? m_exceptionCode : AbortError, "XMLHttpRequest::abort"));
986 }
987
988 clearResponse();
989 clearRequest();
990
991 if (!m_loader)
992 return true;
993
994 // Cancelling the ThreadableLoader m_loader may result in calling
995 // window.onload synchronously. If such an onload handler contains open()
996 // call on the same XMLHttpRequest object, reentry happens.
997 //
998 // If, window.onload contains open() and send(), m_loader will be set to
999 // non 0 value. So, we cannot continue the outer open(). In such case,
1000 // just abort the outer open() by returning false.
1001 RefPtr<ThreadableLoader> loader = m_loader.release();
1002 loader->cancel();
1003
1004 // If abort() called internalAbort() and a nested open() ended up
1005 // clearing the error flag, but didn't send(), make sure the error
1006 // flag is still set.
1007 bool newLoadStarted = hasPendingActivity();
1008 if (!newLoadStarted)
1009 m_error = true;
1010
1011 return !newLoadStarted;
1012 }
1013
1014 void XMLHttpRequest::clearResponse()
1015 {
1016 // FIXME: when we add the support for multi-part XHR, we will have to
1017 // be careful with this initialization.
1018 m_receivedLength = 0;
1019
1020 m_response = ResourceResponse();
1021
1022 m_responseText.clear();
1023
1024 m_parsedResponse = false;
1025 m_responseDocument = nullptr;
1026
1027 m_responseBlob = nullptr;
1028
1029 m_downloadingToFile = false;
1030 m_lengthDownloadedToFile = 0;
1031
1032 m_responseLegacyStream = nullptr;
1033 m_responseStream = nullptr;
1034
1035 // These variables may referred by the response accessors. So, we can clear
1036 // this only when we clear the response holder variables above.
1037 m_binaryResponseBuilder.clear();
1038 m_responseArrayBuffer.clear();
1039 }
1040
1041 void XMLHttpRequest::clearRequest()
1042 {
1043 m_requestHeaders.clear();
1044 }
1045
1046 void XMLHttpRequest::dispatchProgressEvent(const AtomicString& type, long long r eceivedLength, long long expectedLength)
1047 {
1048 bool lengthComputable = expectedLength > 0 && receivedLength <= expectedLeng th;
1049 unsigned long long loaded = receivedLength >= 0 ? static_cast<unsigned long long>(receivedLength) : 0;
1050 unsigned long long total = lengthComputable ? static_cast<unsigned long long >(expectedLength) : 0;
1051
1052 m_progressEventThrottle.dispatchProgressEvent(type, lengthComputable, loaded , total);
1053
1054 if (type == EventTypeNames::loadend)
1055 InspectorInstrumentation::didDispatchXHRLoadendEvent(executionContext(), this);
1056 }
1057
1058 void XMLHttpRequest::dispatchProgressEventFromSnapshot(const AtomicString& type)
1059 {
1060 dispatchProgressEvent(type, m_receivedLength, m_response.expectedContentLeng th());
1061 }
1062
1063 void XMLHttpRequest::handleNetworkError()
1064 {
1065 WTF_LOG(Network, "XMLHttpRequest %p handleNetworkError()", this);
1066
1067 // Response is cleared next, save needed progress event data.
1068 long long expectedLength = m_response.expectedContentLength();
1069 long long receivedLength = m_receivedLength;
1070
1071 // Prevent the XMLHttpRequest instance from being destoryed during
1072 // |internalAbort()|.
1073 RefPtrWillBeRawPtr<XMLHttpRequest> protect(this);
1074
1075 if (!internalAbort())
1076 return;
1077
1078 handleRequestError(NetworkError, EventTypeNames::error, receivedLength, expe ctedLength);
1079 }
1080
1081 void XMLHttpRequest::handleDidCancel()
1082 {
1083 WTF_LOG(Network, "XMLHttpRequest %p handleDidCancel()", this);
1084
1085 // Response is cleared next, save needed progress event data.
1086 long long expectedLength = m_response.expectedContentLength();
1087 long long receivedLength = m_receivedLength;
1088
1089 // Prevent the XMLHttpRequest instance from being destoryed during
1090 // |internalAbort()|.
1091 RefPtrWillBeRawPtr<XMLHttpRequest> protect(this);
1092
1093 if (!internalAbort())
1094 return;
1095
1096 handleRequestError(AbortError, EventTypeNames::abort, receivedLength, expect edLength);
1097 }
1098
1099 void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode, const Atomi cString& type, long long receivedLength, long long expectedLength)
1100 {
1101 WTF_LOG(Network, "XMLHttpRequest %p handleRequestError()", this);
1102
1103 // The request error steps for event 'type' and exception 'exceptionCode'.
1104
1105 if (!m_async && exceptionCode) {
1106 m_state = DONE;
1107 m_exceptionCode = exceptionCode;
1108 return;
1109 }
1110 // With m_error set, the state change steps are minimal: any pending
1111 // progress event is flushed + a readystatechange is dispatched.
1112 // No new progress events dispatched; as required, that happens at
1113 // the end here.
1114 ASSERT(m_error);
1115 changeState(DONE);
1116
1117 if (!m_uploadComplete) {
1118 m_uploadComplete = true;
1119 if (m_upload && m_uploadEventsAllowed)
1120 m_upload->handleRequestError(type);
1121 }
1122
1123 // Note: The below event dispatch may be called while |hasPendingActivity() == false|,
1124 // when |handleRequestError| is called after |internalAbort()|.
1125 // This is safe, however, as |this| will be kept alive from a strong ref |Ev ent::m_target|.
1126 dispatchProgressEvent(EventTypeNames::progress, receivedLength, expectedLeng th);
1127 dispatchProgressEvent(type, receivedLength, expectedLength);
1128 dispatchProgressEvent(EventTypeNames::loadend, receivedLength, expectedLengt h);
1129 }
1130
1131 void XMLHttpRequest::overrideMimeType(const AtomicString& mimeType, ExceptionSta te& exceptionState)
1132 {
1133 if (m_state == LOADING || m_state == DONE) {
1134 exceptionState.throwDOMException(InvalidStateError, "MimeType cannot be overridden when the state is LOADING or DONE.");
1135 return;
1136 }
1137
1138 m_mimeTypeOverride = mimeType;
1139 }
1140
1141 void XMLHttpRequest::setRequestHeader(const AtomicString& name, const AtomicStri ng& value, ExceptionState& exceptionState)
1142 {
1143 if (m_state != OPENED || m_loader) {
1144 exceptionState.throwDOMException(InvalidStateError, "The object's state must be OPENED.");
1145 return;
1146 }
1147
1148 if (!isValidHTTPToken(name)) {
1149 exceptionState.throwDOMException(SyntaxError, "'" + name + "' is not a v alid HTTP header field name.");
1150 return;
1151 }
1152
1153 if (!isValidHTTPHeaderValue(value)) {
1154 exceptionState.throwDOMException(SyntaxError, "'" + value + "' is not a valid HTTP header field value.");
1155 return;
1156 }
1157
1158 // No script (privileged or not) can set unsafe headers.
1159 if (FetchUtils::isForbiddenHeaderName(name)) {
1160 logConsoleError(executionContext(), "Refused to set unsafe header \"" + name + "\"");
1161 return;
1162 }
1163
1164 setRequestHeaderInternal(name, value);
1165 }
1166
1167 void XMLHttpRequest::setRequestHeaderInternal(const AtomicString& name, const At omicString& value)
1168 {
1169 HTTPHeaderMap::AddResult result = m_requestHeaders.add(name, value);
1170 if (!result.isNewEntry)
1171 result.storedValue->value = result.storedValue->value + ", " + value;
1172 }
1173
1174 const AtomicString& XMLHttpRequest::getRequestHeader(const AtomicString& name) c onst
1175 {
1176 return m_requestHeaders.get(name);
1177 }
1178
1179 String XMLHttpRequest::getAllResponseHeaders() const
1180 {
1181 if (m_state < HEADERS_RECEIVED || m_error)
1182 return "";
1183
1184 StringBuilder stringBuilder;
1185
1186 HTTPHeaderSet accessControlExposeHeaderSet;
1187 parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access- Control-Expose-Headers"), accessControlExposeHeaderSet);
1188 HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
1189 for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin( ); it!= end; ++it) {
1190 // Hide Set-Cookie header fields from the XMLHttpRequest client for thes e reasons:
1191 // 1) If the client did have access to the fields, then it could rea d HTTP-only
1192 // cookies; those cookies are supposed to be hidden from scripts.
1193 // 2) There's no known harm in hiding Set-Cookie header fields entir ely; we don't
1194 // know any widely used technique that requires access to them.
1195 // 3) Firefox has implemented this policy.
1196 if (isSetCookieHeader(it->key) && !securityOrigin()->canLoadLocalResourc es())
1197 continue;
1198
1199 if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(it ->key) && !accessControlExposeHeaderSet.contains(it->key))
1200 continue;
1201
1202 stringBuilder.append(it->key);
1203 stringBuilder.append(':');
1204 stringBuilder.append(' ');
1205 stringBuilder.append(it->value);
1206 stringBuilder.append('\r');
1207 stringBuilder.append('\n');
1208 }
1209
1210 return stringBuilder.toString();
1211 }
1212
1213 const AtomicString& XMLHttpRequest::getResponseHeader(const AtomicString& name) const
1214 {
1215 if (m_state < HEADERS_RECEIVED || m_error)
1216 return nullAtom;
1217
1218 // See comment in getAllResponseHeaders above.
1219 if (isSetCookieHeader(name) && !securityOrigin()->canLoadLocalResources()) {
1220 logConsoleError(executionContext(), "Refused to get unsafe header \"" + name + "\"");
1221 return nullAtom;
1222 }
1223
1224 HTTPHeaderSet accessControlExposeHeaderSet;
1225 parseAccessControlExposeHeadersAllowList(m_response.httpHeaderField("Access- Control-Expose-Headers"), accessControlExposeHeaderSet);
1226
1227 if (!m_sameOriginRequest && !isOnAccessControlResponseHeaderWhitelist(name) && !accessControlExposeHeaderSet.contains(name)) {
1228 logConsoleError(executionContext(), "Refused to get unsafe header \"" + name + "\"");
1229 return nullAtom;
1230 }
1231 return m_response.httpHeaderField(name);
1232 }
1233
1234 AtomicString XMLHttpRequest::finalResponseMIMEType() const
1235 {
1236 AtomicString overriddenType = extractMIMETypeFromMediaType(m_mimeTypeOverrid e);
1237 if (!overriddenType.isEmpty())
1238 return overriddenType;
1239
1240 if (m_response.isHTTP())
1241 return extractMIMETypeFromMediaType(m_response.httpHeaderField("Content- Type"));
1242
1243 return m_response.mimeType();
1244 }
1245
1246 AtomicString XMLHttpRequest::finalResponseMIMETypeWithFallback() const
1247 {
1248 AtomicString finalType = finalResponseMIMEType();
1249 if (!finalType.isEmpty())
1250 return finalType;
1251
1252 // FIXME: This fallback is not specified in the final MIME type algorithm
1253 // of the XHR spec. Move this to more appropriate place.
1254 return AtomicString("text/xml", AtomicString::ConstructFromLiteral);
1255 }
1256
1257 bool XMLHttpRequest::responseIsXML() const
1258 {
1259 return DOMImplementation::isXMLMIMEType(finalResponseMIMETypeWithFallback()) ;
1260 }
1261
1262 bool XMLHttpRequest::responseIsHTML() const
1263 {
1264 return equalIgnoringCase(finalResponseMIMEType(), "text/html");
1265 }
1266
1267 int XMLHttpRequest::status() const
1268 {
1269 if (m_state == UNSENT || m_state == OPENED || m_error)
1270 return 0;
1271
1272 if (m_response.httpStatusCode())
1273 return m_response.httpStatusCode();
1274
1275 return 0;
1276 }
1277
1278 String XMLHttpRequest::statusText() const
1279 {
1280 if (m_state == UNSENT || m_state == OPENED || m_error)
1281 return String();
1282
1283 if (!m_response.httpStatusText().isNull())
1284 return m_response.httpStatusText();
1285
1286 return String();
1287 }
1288
1289 void XMLHttpRequest::didFail(const ResourceError& error)
1290 {
1291 WTF_LOG(Network, "XMLHttpRequest %p didFail()", this);
1292
1293 // If we are already in an error state, for instance we called abort(), bail out early.
1294 if (m_error)
1295 return;
1296
1297 if (error.isCancellation()) {
1298 handleDidCancel();
1299 // Now the XMLHttpRequest instance may be dead.
1300 return;
1301 }
1302
1303 if (error.isTimeout()) {
1304 handleDidTimeout();
1305 // Now the XMLHttpRequest instance may be dead.
1306 return;
1307 }
1308
1309 // Network failures are already reported to Web Inspector by ResourceLoader.
1310 if (error.domain() == errorDomainBlinkInternal)
1311 logConsoleError(executionContext(), "XMLHttpRequest cannot load " + erro r.failingURL() + ". " + error.localizedDescription());
1312
1313 handleNetworkError();
1314 // Now the XMLHttpRequest instance may be dead.
1315 }
1316
1317 void XMLHttpRequest::didFailRedirectCheck()
1318 {
1319 WTF_LOG(Network, "XMLHttpRequest %p didFailRedirectCheck()", this);
1320
1321 handleNetworkError();
1322 // Now the XMLHttpRequest instance may be dead.
1323 }
1324
1325 void XMLHttpRequest::didFinishLoading(unsigned long identifier, double)
1326 {
1327 WTF_LOG(Network, "XMLHttpRequest %p didFinishLoading(%lu)", this, identifier );
1328
1329 if (m_error)
1330 return;
1331
1332 if (m_state < HEADERS_RECEIVED)
1333 changeState(HEADERS_RECEIVED);
1334
1335 m_loaderIdentifier = identifier;
1336
1337 if (m_downloadingToFile && m_responseTypeCode != ResponseTypeBlob && m_lengt hDownloadedToFile) {
1338 ASSERT(m_state == LOADING);
1339 // In this case, we have sent the request with DownloadToFile true,
1340 // but the user changed the response type after that. Hence we need to
1341 // read the response data and provide it to this object.
1342 m_blobLoader = BlobLoader::create(this, createBlobDataHandleFromResponse ());
1343 } else {
1344 didFinishLoadingInternal();
1345 }
1346 }
1347
1348 void XMLHttpRequest::didFinishLoadingInternal()
1349 {
1350 if (m_responseDocumentParser) {
1351 // |DocumentParser::finish()| tells the parser that we have reached end of the data.
1352 // When using |HTMLDocumentParser|, which works asynchronously, we do no t have the
1353 // complete document just after the |DocumentParser::finish()| call.
1354 // Wait for the parser to call us back in |notifyParserStopped| to progr ess state.
1355 m_responseDocumentParser->finish();
1356 ASSERT(m_responseDocument);
1357 return;
1358 }
1359
1360 if (m_decoder)
1361 m_responseText = m_responseText.concatenateWith(m_decoder->flush());
1362
1363 if (m_responseLegacyStream)
1364 m_responseLegacyStream->finalize();
1365
1366 if (m_responseStream)
1367 m_responseStream->close();
1368
1369 clearVariablesForLoading();
1370 endLoading();
1371 }
1372
1373 void XMLHttpRequest::didFinishLoadingFromBlob()
1374 {
1375 WTF_LOG(Network, "XMLHttpRequest %p didFinishLoadingFromBlob", this);
1376
1377 didFinishLoadingInternal();
1378 }
1379
1380 void XMLHttpRequest::didFailLoadingFromBlob()
1381 {
1382 WTF_LOG(Network, "XMLHttpRequest %p didFailLoadingFromBlob()", this);
1383
1384 if (m_error)
1385 return;
1386 handleNetworkError();
1387 }
1388
1389 PassRefPtr<BlobDataHandle> XMLHttpRequest::createBlobDataHandleFromResponse()
1390 {
1391 ASSERT(m_downloadingToFile);
1392 OwnPtr<BlobData> blobData = BlobData::create();
1393 String filePath = m_response.downloadedFilePath();
1394 // If we errored out or got no data, we return an empty handle.
1395 if (!filePath.isEmpty() && m_lengthDownloadedToFile) {
1396 blobData->appendFile(filePath);
1397 // FIXME: finalResponseMIMETypeWithFallback() defaults to
1398 // text/xml which may be incorrect. Replace it with
1399 // finalResponseMIMEType() after compatibility investigation.
1400 blobData->setContentType(finalResponseMIMETypeWithFallback());
1401 }
1402 return BlobDataHandle::create(blobData.release(), m_lengthDownloadedToFile);
1403 }
1404
1405 void XMLHttpRequest::notifyParserStopped()
1406 {
1407 // This should only be called when response document is parsed asynchronousl y.
1408 ASSERT(m_responseDocumentParser);
1409 ASSERT(!m_responseDocumentParser->isParsing());
1410 ASSERT(!m_responseLegacyStream);
1411 ASSERT(!m_responseStream);
1412
1413 // Do nothing if we are called from |internalAbort()|.
1414 if (m_error)
1415 return;
1416
1417 clearVariablesForLoading();
1418
1419 m_responseDocument->implicitClose();
1420
1421 if (!m_responseDocument->wellFormed())
1422 m_responseDocument = nullptr;
1423
1424 m_parsedResponse = true;
1425
1426 endLoading();
1427 }
1428
1429 void XMLHttpRequest::endLoading()
1430 {
1431 InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, this , m_loaderIdentifier, m_responseText, m_method, m_url);
1432
1433 if (m_loader)
1434 m_loader = nullptr;
1435 m_loaderIdentifier = 0;
1436
1437 changeState(DONE);
1438 }
1439
1440 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long lon g totalBytesToBeSent)
1441 {
1442 WTF_LOG(Network, "XMLHttpRequest %p didSendData(%llu, %llu)", this, bytesSen t, totalBytesToBeSent);
1443
1444 if (!m_upload)
1445 return;
1446
1447 if (m_uploadEventsAllowed)
1448 m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
1449
1450 if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
1451 m_uploadComplete = true;
1452 if (m_uploadEventsAllowed)
1453 m_upload->dispatchEventAndLoadEnd(EventTypeNames::load, true, bytesS ent, totalBytesToBeSent);
1454 }
1455 }
1456
1457 void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const Resource Response& response)
1458 {
1459 WTF_LOG(Network, "XMLHttpRequest %p didReceiveResponse(%lu)", this, identifi er);
1460
1461 m_response = response;
1462 if (!m_mimeTypeOverride.isEmpty()) {
1463 m_response.setHTTPHeaderField("Content-Type", m_mimeTypeOverride);
1464 m_finalResponseCharset = extractCharsetFromMediaType(m_mimeTypeOverride) ;
1465 }
1466
1467 if (m_finalResponseCharset.isEmpty())
1468 m_finalResponseCharset = response.textEncodingName();
1469 }
1470
1471 void XMLHttpRequest::parseDocumentChunk(const char* data, unsigned len)
1472 {
1473 if (!m_responseDocumentParser) {
1474 ASSERT(!m_responseDocument);
1475 initResponseDocument();
1476 if (!m_responseDocument)
1477 return;
1478
1479 m_responseDocumentParser = m_responseDocument->implicitOpen();
1480 m_responseDocumentParser->addClient(this);
1481 }
1482 ASSERT(m_responseDocumentParser);
1483
1484 if (m_responseDocumentParser->needsDecoder())
1485 m_responseDocumentParser->setDecoder(createDecoder());
1486
1487 m_responseDocumentParser->appendBytes(data, len);
1488 }
1489
1490 PassOwnPtr<TextResourceDecoder> XMLHttpRequest::createDecoder() const
1491 {
1492 if (m_responseTypeCode == ResponseTypeJSON)
1493 return TextResourceDecoder::create("application/json", "UTF-8");
1494
1495 if (!m_finalResponseCharset.isEmpty())
1496 return TextResourceDecoder::create("text/plain", m_finalResponseCharset) ;
1497
1498 // allow TextResourceDecoder to look inside the m_response if it's XML or HT ML
1499 if (responseIsXML()) {
1500 OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("appli cation/xml");
1501 // Don't stop on encoding errors, unlike it is done for other kinds
1502 // of XML resources. This matches the behavior of previous WebKit
1503 // versions, Firefox and Opera.
1504 decoder->useLenientXMLDecoding();
1505
1506 return decoder.release();
1507 }
1508
1509 if (responseIsHTML())
1510 return TextResourceDecoder::create("text/html", "UTF-8");
1511
1512 return TextResourceDecoder::create("text/plain", "UTF-8");
1513 }
1514
1515 void XMLHttpRequest::didReceiveData(const char* data, unsigned len)
1516 {
1517 if (m_error)
1518 return;
1519
1520 if (m_state < HEADERS_RECEIVED)
1521 changeState(HEADERS_RECEIVED);
1522
1523 // We need to check for |m_error| again, because |changeState| may trigger
1524 // readystatechange, and user javascript can cause |abort()|.
1525 if (m_error)
1526 return;
1527
1528 if (!len)
1529 return;
1530
1531 if (m_responseTypeCode == ResponseTypeDocument && responseIsHTML()) {
1532 parseDocumentChunk(data, len);
1533 } else if (m_responseTypeCode == ResponseTypeDefault || m_responseTypeCode = = ResponseTypeText || m_responseTypeCode == ResponseTypeJSON || m_responseTypeCo de == ResponseTypeDocument) {
1534 if (!m_decoder)
1535 m_decoder = createDecoder();
1536
1537 m_responseText = m_responseText.concatenateWith(m_decoder->decode(data, len));
1538 } else if (m_responseTypeCode == ResponseTypeArrayBuffer || m_responseTypeCo de == ResponseTypeBlob) {
1539 // Buffer binary data.
1540 if (!m_binaryResponseBuilder)
1541 m_binaryResponseBuilder = SharedBuffer::create();
1542 m_binaryResponseBuilder->append(data, len);
1543 } else if (m_responseTypeCode == ResponseTypeLegacyStream) {
1544 if (!m_responseLegacyStream)
1545 m_responseLegacyStream = Stream::create(executionContext(), response Type());
1546 m_responseLegacyStream->addData(data, len);
1547 } else if (m_responseTypeCode == ResponseTypeStream) {
1548 if (!m_responseStream) {
1549 m_responseStream = new ReadableStreamImpl<ReadableStreamChunkTypeTra its<DOMArrayBuffer> >(executionContext(), new ReadableStreamSource(this));
1550 m_responseStream->didSourceStart();
1551 }
1552 m_responseStream->enqueue(DOMArrayBuffer::create(data, len));
1553 }
1554
1555 if (m_blobLoader) {
1556 // In this case, the data is provided by m_blobLoader. As progress
1557 // events are already fired, we should return here.
1558 return;
1559 }
1560 trackProgress(len);
1561 }
1562
1563 void XMLHttpRequest::didDownloadData(int dataLength)
1564 {
1565 if (m_error)
1566 return;
1567
1568 ASSERT(m_downloadingToFile);
1569
1570 if (m_state < HEADERS_RECEIVED)
1571 changeState(HEADERS_RECEIVED);
1572
1573 if (!dataLength)
1574 return;
1575
1576 // readystatechange event handler may do something to put this XHR in error
1577 // state. We need to check m_error again here.
1578 if (m_error)
1579 return;
1580
1581 m_lengthDownloadedToFile += dataLength;
1582
1583 trackProgress(dataLength);
1584 }
1585
1586 void XMLHttpRequest::handleDidTimeout()
1587 {
1588 WTF_LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this);
1589
1590 // Response is cleared next, save needed progress event data.
1591 long long expectedLength = m_response.expectedContentLength();
1592 long long receivedLength = m_receivedLength;
1593
1594 // Prevent the XMLHttpRequest instance from being destoryed during
1595 // |internalAbort()|.
1596 RefPtrWillBeRawPtr<XMLHttpRequest> protect(this);
1597
1598 if (!internalAbort())
1599 return;
1600
1601 handleRequestError(TimeoutError, EventTypeNames::timeout, receivedLength, ex pectedLength);
1602 }
1603
1604 void XMLHttpRequest::suspend()
1605 {
1606 m_progressEventThrottle.suspend();
1607 }
1608
1609 void XMLHttpRequest::resume()
1610 {
1611 m_progressEventThrottle.resume();
1612 }
1613
1614 void XMLHttpRequest::stop()
1615 {
1616 internalAbort();
1617 }
1618
1619 bool XMLHttpRequest::hasPendingActivity() const
1620 {
1621 // Neither this object nor the JavaScript wrapper should be deleted while
1622 // a request is in progress because we need to keep the listeners alive,
1623 // and they are referenced by the JavaScript wrapper.
1624 // |m_loader| is non-null while request is active and ThreadableLoaderClient
1625 // callbacks may be called, and |m_responseDocumentParser| is non-null while
1626 // DocumentParserClient callbacks may be called.
1627 return m_loader || m_responseDocumentParser;
1628 }
1629
1630 void XMLHttpRequest::contextDestroyed()
1631 {
1632 ASSERT(!m_loader);
1633 ActiveDOMObject::contextDestroyed();
1634 }
1635
1636 const AtomicString& XMLHttpRequest::interfaceName() const
1637 {
1638 return EventTargetNames::XMLHttpRequest;
1639 }
1640
1641 ExecutionContext* XMLHttpRequest::executionContext() const
1642 {
1643 return ActiveDOMObject::executionContext();
1644 }
1645
1646 void XMLHttpRequest::trace(Visitor* visitor)
1647 {
1648 visitor->trace(m_responseBlob);
1649 visitor->trace(m_responseLegacyStream);
1650 visitor->trace(m_responseStream);
1651 visitor->trace(m_streamSource);
1652 visitor->trace(m_responseDocument);
1653 visitor->trace(m_responseDocumentParser);
1654 visitor->trace(m_progressEventThrottle);
1655 visitor->trace(m_upload);
1656 visitor->trace(m_blobLoader);
1657 XMLHttpRequestEventTarget::trace(visitor);
1658 DocumentParserClient::trace(visitor);
1659 }
1660
1661 } // namespace blink
OLDNEW
« no previous file with comments | « Source/core/xml/XMLHttpRequest.h ('k') | Source/core/xml/XMLHttpRequest.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698