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

Side by Side Diff: third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.cpp

Issue 2496933002: XMLHttpRequest: implement "send() flag" tracking and updating per spec. (Closed)
Patch Set: add recursive send() test Created 4 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 | « third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org> 3 * Copyright (C) 2005-2007 Alexey Proskuryakov <ap@webkit.org>
4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org> 4 * Copyright (C) 2007, 2008 Julien Chaffraix <jchaffraix@webkit.org>
5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved. 5 * Copyright (C) 2008, 2011 Google Inc. All rights reserved.
6 * Copyright (C) 2012 Intel Corporation 6 * Copyright (C) 2012 Intel Corporation
7 * 7 *
8 * This library is free software; you can redistribute it and/or 8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public 9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either 10 * License as published by the Free Software Foundation; either
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 m_isolatedWorldSecurityOrigin(isolatedWorldSecurityOrigin), 239 m_isolatedWorldSecurityOrigin(isolatedWorldSecurityOrigin),
240 m_eventDispatchRecursionLevel(0), 240 m_eventDispatchRecursionLevel(0),
241 m_async(true), 241 m_async(true),
242 m_includeCredentials(false), 242 m_includeCredentials(false),
243 m_parsedResponse(false), 243 m_parsedResponse(false),
244 m_error(false), 244 m_error(false),
245 m_uploadEventsAllowed(true), 245 m_uploadEventsAllowed(true),
246 m_uploadComplete(false), 246 m_uploadComplete(false),
247 m_sameOriginRequest(true), 247 m_sameOriginRequest(true),
248 m_downloadingToFile(false), 248 m_downloadingToFile(false),
249 m_responseTextOverflow(false) {} 249 m_responseTextOverflow(false) {}
yhirano 2016/11/15 02:26:08 Please initialize the flag.
sof 2016/11/15 06:48:46 oops, thanks - done.
250 250
251 XMLHttpRequest::~XMLHttpRequest() {} 251 XMLHttpRequest::~XMLHttpRequest() {}
252 252
253 Document* XMLHttpRequest::document() const { 253 Document* XMLHttpRequest::document() const {
254 DCHECK(getExecutionContext()->isDocument()); 254 DCHECK(getExecutionContext()->isDocument());
255 return toDocument(getExecutionContext()); 255 return toDocument(getExecutionContext());
256 } 256 }
257 257
258 SecurityOrigin* XMLHttpRequest::getSecurityOrigin() const { 258 SecurityOrigin* XMLHttpRequest::getSecurityOrigin() const {
259 return m_isolatedWorldSecurityOrigin 259 return m_isolatedWorldSecurityOrigin
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
545 dispatchProgressEventFromSnapshot(EventTypeNames::load); 545 dispatchProgressEventFromSnapshot(EventTypeNames::load);
546 dispatchProgressEventFromSnapshot(EventTypeNames::loadend); 546 dispatchProgressEventFromSnapshot(EventTypeNames::loadend);
547 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), 547 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"),
548 "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data", 548 "UpdateCounters", TRACE_EVENT_SCOPE_THREAD, "data",
549 InspectorUpdateCountersEvent::data()); 549 InspectorUpdateCountersEvent::data());
550 } 550 }
551 } 551 }
552 552
553 void XMLHttpRequest::setWithCredentials(bool value, 553 void XMLHttpRequest::setWithCredentials(bool value,
554 ExceptionState& exceptionState) { 554 ExceptionState& exceptionState) {
555 if (m_state > kOpened || m_loader) { 555 if (m_state > kOpened || m_sendFlag) {
556 exceptionState.throwDOMException( 556 exceptionState.throwDOMException(
557 InvalidStateError, 557 InvalidStateError,
558 "The value may only be set if the object's state is UNSENT or OPENED."); 558 "The value may only be set if the object's state is UNSENT or OPENED.");
559 return; 559 return;
560 } 560 }
561 561
562 m_includeCredentials = value; 562 m_includeCredentials = value;
563 } 563 }
564 564
565 void XMLHttpRequest::open(const AtomicString& method, 565 void XMLHttpRequest::open(const AtomicString& method,
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
661 UseCounter::XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload); 661 UseCounter::XMLHttpRequestSynchronousInNonWorkerOutsideBeforeUnload);
662 } 662 }
663 663
664 m_method = FetchUtils::normalizeMethod(method); 664 m_method = FetchUtils::normalizeMethod(method);
665 665
666 m_url = url; 666 m_url = url;
667 667
668 m_async = async; 668 m_async = async;
669 669
670 DCHECK(!m_loader); 670 DCHECK(!m_loader);
671 m_sendFlag = false;
671 672
672 // Check previous state to avoid dispatching readyState event 673 // Check previous state to avoid dispatching readyState event
673 // when calling open several times in a row. 674 // when calling open several times in a row.
674 if (previousState != kOpened) 675 if (previousState != kOpened)
675 changeState(kOpened); 676 changeState(kOpened);
676 else 677 else
677 m_state = kOpened; 678 m_state = kOpened;
678 } 679 }
679 680
680 bool XMLHttpRequest::initSend(ExceptionState& exceptionState) { 681 bool XMLHttpRequest::initSend(ExceptionState& exceptionState) {
681 if (!getExecutionContext()) { 682 if (!getExecutionContext()) {
682 handleNetworkError(); 683 handleNetworkError();
683 throwForLoadFailureIfNeeded(exceptionState, 684 throwForLoadFailureIfNeeded(exceptionState,
684 "Document is already detached."); 685 "Document is already detached.");
685 return false; 686 return false;
686 } 687 }
687 688
688 if (m_state != kOpened || m_loader) { 689 if (m_state != kOpened || m_sendFlag) {
689 exceptionState.throwDOMException(InvalidStateError, 690 exceptionState.throwDOMException(InvalidStateError,
690 "The object's state must be OPENED."); 691 "The object's state must be OPENED.");
691 return false; 692 return false;
692 } 693 }
693 694
694 if (!m_async) { 695 if (!m_async) {
695 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 696 v8::Isolate* isolate = v8::Isolate::GetCurrent();
696 if (isolate && v8::MicrotasksScope::IsRunningMicrotasks(isolate)) { 697 if (isolate && v8::MicrotasksScope::IsRunningMicrotasks(isolate)) {
697 UseCounter::count(getExecutionContext(), 698 UseCounter::count(getExecutionContext(),
698 UseCounter::During_Microtask_SyncXHR); 699 UseCounter::During_Microtask_SyncXHR);
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after
922 if (!m_async) { 923 if (!m_async) {
923 throwForLoadFailureIfNeeded( 924 throwForLoadFailureIfNeeded(
924 exceptionState, "'GET' is the only method allowed for 'blob:' URLs."); 925 exceptionState, "'GET' is the only method allowed for 'blob:' URLs.");
925 } 926 }
926 return; 927 return;
927 } 928 }
928 929
929 DCHECK(getExecutionContext()); 930 DCHECK(getExecutionContext());
930 ExecutionContext& executionContext = *getExecutionContext(); 931 ExecutionContext& executionContext = *getExecutionContext();
931 932
933 m_sendFlag = true;
932 // The presence of upload event listeners forces us to use preflighting 934 // The presence of upload event listeners forces us to use preflighting
933 // because POSTing to an URL that does not permit cross origin requests should 935 // because POSTing to an URL that does not permit cross origin requests should
934 // look exactly like POSTing to an URL that does not respond at all. 936 // look exactly like POSTing to an URL that does not respond at all.
935 // Also, only async requests support upload progress events. 937 // Also, only async requests support upload progress events.
936 bool uploadEvents = false; 938 bool uploadEvents = false;
937 if (m_async) { 939 if (m_async) {
938 InspectorInstrumentation::asyncTaskScheduled( 940 InspectorInstrumentation::asyncTaskScheduled(
939 &executionContext, "XMLHttpRequest.send", this, true); 941 &executionContext, "XMLHttpRequest.send", this, true);
940 dispatchProgressEvent(EventTypeNames::loadstart, 0, 0); 942 dispatchProgressEvent(EventTypeNames::loadstart, 0, 0);
941 if (httpBody && m_upload) { 943 if (httpBody && m_upload) {
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
1025 m_exceptionCode = 0; 1027 m_exceptionCode = 0;
1026 m_error = false; 1028 m_error = false;
1027 1029
1028 if (m_async) { 1030 if (m_async) {
1029 UseCounter::count(&executionContext, 1031 UseCounter::count(&executionContext,
1030 UseCounter::XMLHttpRequestAsynchronous); 1032 UseCounter::XMLHttpRequestAsynchronous);
1031 if (m_upload) 1033 if (m_upload)
1032 request.setReportUploadProgress(true); 1034 request.setReportUploadProgress(true);
1033 1035
1034 DCHECK(!m_loader); 1036 DCHECK(!m_loader);
1037 DCHECK(m_sendFlag);
1035 m_loader = ThreadableLoader::create(executionContext, this, options, 1038 m_loader = ThreadableLoader::create(executionContext, this, options,
1036 resourceLoaderOptions); 1039 resourceLoaderOptions);
1037 m_loader->start(request); 1040 m_loader->start(request);
1038 1041
1039 return; 1042 return;
1040 } 1043 }
1041 1044
1042 // Use count for XHR synchronous requests. 1045 // Use count for XHR synchronous requests.
1043 UseCounter::count(&executionContext, UseCounter::XMLHttpRequestSynchronous); 1046 UseCounter::count(&executionContext, UseCounter::XMLHttpRequestSynchronous);
1044 ThreadableLoader::loadResourceSynchronously(executionContext, request, *this, 1047 ThreadableLoader::loadResourceSynchronously(executionContext, request, *this,
1045 options, resourceLoaderOptions); 1048 options, resourceLoaderOptions);
1046 1049
1047 throwForLoadFailureIfNeeded(exceptionState, String()); 1050 throwForLoadFailureIfNeeded(exceptionState, String());
1048 } 1051 }
1049 1052
1050 void XMLHttpRequest::abort() { 1053 void XMLHttpRequest::abort() {
1051 NETWORK_DVLOG(1) << this << " abort()"; 1054 NETWORK_DVLOG(1) << this << " abort()";
1052 1055
1053 // internalAbort() clears |m_loader|. Compute |sendFlag| now.
1054 //
1055 // |sendFlag| corresponds to "the send() flag" defined in the XHR spec.
1056 //
1057 // |sendFlag| is only set when we have an active, asynchronous loader.
1058 // Don't use it as "the send() flag" when the XHR is in sync mode.
1059 bool sendFlag = m_loader.get();
1060
1061 // internalAbort() clears the response. Save the data needed for 1056 // internalAbort() clears the response. Save the data needed for
1062 // dispatching ProgressEvents. 1057 // dispatching ProgressEvents.
1063 long long expectedLength = m_response.expectedContentLength(); 1058 long long expectedLength = m_response.expectedContentLength();
1064 long long receivedLength = m_receivedLength; 1059 long long receivedLength = m_receivedLength;
1065 1060
1066 if (!internalAbort()) 1061 if (!internalAbort())
1067 return; 1062 return;
1068 1063
1069 // The script never gets any chance to call abort() on a sync XHR between 1064 // The script never gets any chance to call abort() on a sync XHR between
1070 // send() call and transition to the DONE state. It's because a sync XHR 1065 // send() call and transition to the DONE state. It's because a sync XHR
1071 // doesn't dispatch any event between them. So, if |m_async| is false, we 1066 // doesn't dispatch any event between them. So, if |m_async| is false, we
1072 // can skip the "request error steps" (defined in the XHR spec) without any 1067 // can skip the "request error steps" (defined in the XHR spec) without any
1073 // state check. 1068 // state check.
1074 // 1069 //
1075 // FIXME: It's possible open() is invoked in internalAbort() and |m_async| 1070 // FIXME: It's possible open() is invoked in internalAbort() and |m_async|
1076 // becomes true by that. We should implement more reliable treatment for 1071 // becomes true by that. We should implement more reliable treatment for
1077 // nested method invocations at some point. 1072 // nested method invocations at some point.
1078 if (m_async) { 1073 if (m_async) {
1079 if ((m_state == kOpened && sendFlag) || m_state == kHeadersReceived || 1074 if ((m_state == kOpened && m_sendFlag) || m_state == kHeadersReceived ||
1080 m_state == kLoading) { 1075 m_state == kLoading) {
1081 DCHECK(!m_loader); 1076 DCHECK(!m_loader);
1082 handleRequestError(0, EventTypeNames::abort, receivedLength, 1077 handleRequestError(0, EventTypeNames::abort, receivedLength,
1083 expectedLength); 1078 expectedLength);
1084 } 1079 }
1085 } 1080 }
1086 m_state = kUnsent; 1081 m_state = kUnsent;
1087 } 1082 }
1088 1083
1089 void XMLHttpRequest::clearVariablesForLoading() { 1084 void XMLHttpRequest::clearVariablesForLoading() {
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after
1218 1213
1219 void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode, 1214 void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode,
1220 const AtomicString& type, 1215 const AtomicString& type,
1221 long long receivedLength, 1216 long long receivedLength,
1222 long long expectedLength) { 1217 long long expectedLength) {
1223 NETWORK_DVLOG(1) << this << " handleRequestError()"; 1218 NETWORK_DVLOG(1) << this << " handleRequestError()";
1224 1219
1225 InspectorInstrumentation::didFailXHRLoading(getExecutionContext(), this, this, 1220 InspectorInstrumentation::didFailXHRLoading(getExecutionContext(), this, this,
1226 m_method, m_url); 1221 m_method, m_url);
1227 1222
1223 m_sendFlag = false;
1228 if (!m_async) { 1224 if (!m_async) {
1229 DCHECK(exceptionCode); 1225 DCHECK(exceptionCode);
1230 m_state = kDone; 1226 m_state = kDone;
1231 m_exceptionCode = exceptionCode; 1227 m_exceptionCode = exceptionCode;
1232 return; 1228 return;
1233 } 1229 }
1234 1230
1235 // With m_error set, the state change steps are minimal: any pending 1231 // With m_error set, the state change steps are minimal: any pending
1236 // progress event is flushed + a readystatechange is dispatched. 1232 // progress event is flushed + a readystatechange is dispatched.
1237 // No new progress events dispatched; as required, that happens at 1233 // No new progress events dispatched; as required, that happens at
(...skipping 26 matching lines...) Expand all
1264 "MimeType cannot be overridden when the state is LOADING or DONE."); 1260 "MimeType cannot be overridden when the state is LOADING or DONE.");
1265 return; 1261 return;
1266 } 1262 }
1267 1263
1268 m_mimeTypeOverride = mimeType; 1264 m_mimeTypeOverride = mimeType;
1269 } 1265 }
1270 1266
1271 void XMLHttpRequest::setRequestHeader(const AtomicString& name, 1267 void XMLHttpRequest::setRequestHeader(const AtomicString& name,
1272 const AtomicString& value, 1268 const AtomicString& value,
1273 ExceptionState& exceptionState) { 1269 ExceptionState& exceptionState) {
1274 if (m_state != kOpened || m_loader) { 1270 if (m_state != kOpened || m_sendFlag) {
1275 exceptionState.throwDOMException(InvalidStateError, 1271 exceptionState.throwDOMException(InvalidStateError,
1276 "The object's state must be OPENED."); 1272 "The object's state must be OPENED.");
1277 return; 1273 return;
1278 } 1274 }
1279 1275
1280 if (!isValidHTTPToken(name)) { 1276 if (!isValidHTTPToken(name)) {
1281 exceptionState.throwDOMException( 1277 exceptionState.throwDOMException(
1282 SyntaxError, "'" + name + "' is not a valid HTTP header field name."); 1278 SyntaxError, "'" + name + "' is not a valid HTTP header field name.");
1283 return; 1279 return;
1284 } 1280 }
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
1602 if (m_loader) { 1598 if (m_loader) {
1603 const bool hasError = m_error; 1599 const bool hasError = m_error;
1604 // Set |m_error| in order to suppress the cancel notification (see 1600 // Set |m_error| in order to suppress the cancel notification (see
1605 // XMLHttpRequest::didFail). 1601 // XMLHttpRequest::didFail).
1606 m_error = true; 1602 m_error = true;
1607 m_loader->cancel(); 1603 m_loader->cancel();
1608 m_error = hasError; 1604 m_error = hasError;
1609 m_loader = nullptr; 1605 m_loader = nullptr;
1610 } 1606 }
1611 1607
1608 m_sendFlag = false;
1612 changeState(kDone); 1609 changeState(kDone);
1613 1610
1614 if (!getExecutionContext() || !getExecutionContext()->isDocument() || 1611 if (!getExecutionContext() || !getExecutionContext()->isDocument() ||
1615 !document() || !document()->frame() || !document()->frame()->page()) 1612 !document() || !document()->frame() || !document()->frame()->page())
1616 return; 1613 return;
1617 1614
1618 if (status() >= 200 && status() < 300) { 1615 if (status() >= 200 && status() < 300) {
1619 document()->frame()->page()->chromeClient().ajaxSucceeded( 1616 document()->frame()->page()->chromeClient().ajaxSucceeded(
1620 document()->frame()); 1617 document()->frame());
1621 } 1618 }
(...skipping 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
1841 visitor->traceWrappers(m_responseDocument); 1838 visitor->traceWrappers(m_responseDocument);
1842 visitor->traceWrappers(m_responseArrayBuffer); 1839 visitor->traceWrappers(m_responseArrayBuffer);
1843 XMLHttpRequestEventTarget::traceWrappers(visitor); 1840 XMLHttpRequestEventTarget::traceWrappers(visitor);
1844 } 1841 }
1845 1842
1846 std::ostream& operator<<(std::ostream& ostream, const XMLHttpRequest* xhr) { 1843 std::ostream& operator<<(std::ostream& ostream, const XMLHttpRequest* xhr) {
1847 return ostream << "XMLHttpRequest " << static_cast<const void*>(xhr); 1844 return ostream << "XMLHttpRequest " << static_cast<const void*>(xhr);
1848 } 1845 }
1849 1846
1850 } // namespace blink 1847 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/xmlhttprequest/XMLHttpRequest.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698