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

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

Issue 2427553002: Fix XHR's logic to determine whether or not to dispatch upload progress events
Patch Set: a Created 4 years, 2 months 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 219 matching lines...) Expand 10 before | Expand all | Expand 10 after
230 m_exceptionCode(0), 230 m_exceptionCode(0),
231 m_progressEventThrottle( 231 m_progressEventThrottle(
232 XMLHttpRequestProgressEventThrottle::create(this)), 232 XMLHttpRequestProgressEventThrottle::create(this)),
233 m_responseTypeCode(ResponseTypeDefault), 233 m_responseTypeCode(ResponseTypeDefault),
234 m_isolatedWorldSecurityOrigin(isolatedWorldSecurityOrigin), 234 m_isolatedWorldSecurityOrigin(isolatedWorldSecurityOrigin),
235 m_eventDispatchRecursionLevel(0), 235 m_eventDispatchRecursionLevel(0),
236 m_async(true), 236 m_async(true),
237 m_includeCredentials(false), 237 m_includeCredentials(false),
238 m_parsedResponse(false), 238 m_parsedResponse(false),
239 m_error(false), 239 m_error(false),
240 m_uploadEventsAllowed(true), 240 m_uploadListenerFlag(false),
241 m_uploadComplete(false), 241 m_uploadCompleteFlag(false),
242 m_sameOriginRequest(true), 242 m_sameOriginRequest(true),
243 m_downloadingToFile(false), 243 m_downloadingToFile(false),
244 m_responseTextOverflow(false) {} 244 m_responseTextOverflow(false) {}
245 245
246 XMLHttpRequest::~XMLHttpRequest() {} 246 XMLHttpRequest::~XMLHttpRequest() {}
247 247
248 Document* XMLHttpRequest::document() const { 248 Document* XMLHttpRequest::document() const {
249 DCHECK(getExecutionContext()->isDocument()); 249 DCHECK(getExecutionContext()->isDocument());
250 return toDocument(getExecutionContext()); 250 return toDocument(getExecutionContext());
251 } 251 }
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
615 << ", " << async << ")"; 615 << ", " << async << ")";
616 616
617 DCHECK(validateOpenArguments(method, url, exceptionState)); 617 DCHECK(validateOpenArguments(method, url, exceptionState));
618 618
619 if (!internalAbort()) 619 if (!internalAbort())
620 return; 620 return;
621 621
622 State previousState = m_state; 622 State previousState = m_state;
623 m_state = kUnsent; 623 m_state = kUnsent;
624 m_error = false; 624 m_error = false;
625 m_uploadComplete = false; 625 m_uploadCompleteFlag = false;
626 626
627 if (!ContentSecurityPolicy::shouldBypassMainWorld(getExecutionContext()) && 627 if (!ContentSecurityPolicy::shouldBypassMainWorld(getExecutionContext()) &&
628 !getExecutionContext()->contentSecurityPolicy()->allowConnectToSource( 628 !getExecutionContext()->contentSecurityPolicy()->allowConnectToSource(
629 url)) { 629 url)) {
630 // We can safely expose the URL to JavaScript, as these checks happen 630 // We can safely expose the URL to JavaScript, as these checks happen
631 // synchronously before redirection. JavaScript receives no new information. 631 // synchronously before redirection. JavaScript receives no new information.
632 exceptionState.throwSecurityError( 632 exceptionState.throwSecurityError(
633 "Refused to connect to '" + url.elidedString() + 633 "Refused to connect to '" + url.elidedString() +
634 "' because it violates the document's Content Security Policy."); 634 "' because it violates the document's Content Security Policy.");
635 return; 635 return;
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after
933 if (!m_async) { 933 if (!m_async) {
934 throwForLoadFailureIfNeeded( 934 throwForLoadFailureIfNeeded(
935 exceptionState, "'GET' is the only method allowed for 'blob:' URLs."); 935 exceptionState, "'GET' is the only method allowed for 'blob:' URLs.");
936 } 936 }
937 return; 937 return;
938 } 938 }
939 939
940 DCHECK(getExecutionContext()); 940 DCHECK(getExecutionContext());
941 ExecutionContext& executionContext = *getExecutionContext(); 941 ExecutionContext& executionContext = *getExecutionContext();
942 942
943 // The presence of upload event listeners forces us to use preflighting 943 m_uploadListenerFlag = false;
yhirano 2016/10/20 11:27:54 In the spec this flag is initialized in open funct
944 // because POSTing to an URL that does not permit cross origin requests should
945 // look exactly like POSTing to an URL that does not respond at all.
946 // Also, only async requests support upload progress events.
947 bool uploadEvents = false;
948 if (m_async) { 944 if (m_async) {
949 InspectorInstrumentation::asyncTaskScheduled( 945 InspectorInstrumentation::asyncTaskScheduled(
950 &executionContext, "XMLHttpRequest.send", this, true); 946 &executionContext, "XMLHttpRequest.send", this, true);
947
951 dispatchProgressEvent(EventTypeNames::loadstart, 0, 0); 948 dispatchProgressEvent(EventTypeNames::loadstart, 0, 0);
952 if (httpBody && m_upload) { 949
953 uploadEvents = m_upload->hasEventListeners(); 950 // For optimization, we set the upload listener flag only when m_async is
951 // true unlike the spec.
952 if (m_upload && m_upload->hasEventListeners()) {
953 m_uploadListenerFlag = true;
954
954 m_upload->dispatchEvent( 955 m_upload->dispatchEvent(
955 ProgressEvent::create(EventTypeNames::loadstart, false, 0, 0)); 956 ProgressEvent::create(EventTypeNames::loadstart, false, 0, 0));
956 } 957 }
957 } 958 }
958 959
959 m_sameOriginRequest = getSecurityOrigin()->canRequestNoSuborigin(m_url); 960 m_sameOriginRequest = getSecurityOrigin()->canRequestNoSuborigin(m_url);
960 961
961 if (!m_sameOriginRequest && m_includeCredentials) 962 if (!m_sameOriginRequest && m_includeCredentials)
962 UseCounter::count(&executionContext, 963 UseCounter::count(&executionContext,
963 UseCounter::XMLHttpRequestCrossOriginWithCredentials); 964 UseCounter::XMLHttpRequestCrossOriginWithCredentials);
964 965
965 // We also remember whether upload events should be allowed for this request
966 // in case the upload listeners are added after the request is started.
967 m_uploadEventsAllowed =
968 m_sameOriginRequest || uploadEvents ||
969 !FetchUtils::isSimpleRequest(m_method, m_requestHeaders);
970
971 ResourceRequest request(m_url); 966 ResourceRequest request(m_url);
972 request.setHTTPMethod(m_method); 967 request.setHTTPMethod(m_method);
973 request.setRequestContext(WebURLRequest::RequestContextXMLHttpRequest); 968 request.setRequestContext(WebURLRequest::RequestContextXMLHttpRequest);
974 request.setFetchCredentialsMode( 969 request.setFetchCredentialsMode(
975 m_includeCredentials ? WebURLRequest::FetchCredentialsModeInclude 970 m_includeCredentials ? WebURLRequest::FetchCredentialsModeInclude
976 : WebURLRequest::FetchCredentialsModeSameOrigin); 971 : WebURLRequest::FetchCredentialsModeSameOrigin);
977 request.setSkipServiceWorker(m_isolatedWorldSecurityOrigin.get() 972 request.setSkipServiceWorker(m_isolatedWorldSecurityOrigin.get()
978 ? WebURLRequest::SkipServiceWorker::All 973 ? WebURLRequest::SkipServiceWorker::All
979 : WebURLRequest::SkipServiceWorker::None); 974 : WebURLRequest::SkipServiceWorker::None);
980 request.setExternalRequestStateFromRequestorAddressSpace( 975 request.setExternalRequestStateFromRequestorAddressSpace(
981 executionContext.securityContext().addressSpace()); 976 executionContext.securityContext().addressSpace());
982 977
983 InspectorInstrumentation::willLoadXHR( 978 InspectorInstrumentation::willLoadXHR(
984 &executionContext, this, this, m_method, m_url, m_async, 979 &executionContext, this, this, m_method, m_url, m_async,
985 httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders, 980 httpBody ? httpBody->deepCopy() : nullptr, m_requestHeaders,
986 m_includeCredentials); 981 m_includeCredentials);
987 982
988 if (httpBody) { 983 if (httpBody) {
989 DCHECK_NE(m_method, HTTPNames::GET); 984 DCHECK_NE(m_method, HTTPNames::GET);
990 DCHECK_NE(m_method, HTTPNames::HEAD); 985 DCHECK_NE(m_method, HTTPNames::HEAD);
991 request.setHTTPBody(std::move(httpBody)); 986 request.setHTTPBody(std::move(httpBody));
992 } 987 }
993 988
994 if (m_requestHeaders.size() > 0) 989 if (m_requestHeaders.size() > 0)
995 request.addHTTPHeaderFields(m_requestHeaders); 990 request.addHTTPHeaderFields(m_requestHeaders);
996 991
997 ThreadableLoaderOptions options; 992 ThreadableLoaderOptions options;
998 options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; 993 options.preflightPolicy =
994 m_uploadListenerFlag ? ForcePreflight : ConsiderPreflight;
999 options.crossOriginRequestPolicy = UseAccessControl; 995 options.crossOriginRequestPolicy = UseAccessControl;
1000 options.initiator = FetchInitiatorTypeNames::xmlhttprequest; 996 options.initiator = FetchInitiatorTypeNames::xmlhttprequest;
1001 options.contentSecurityPolicyEnforcement = 997 options.contentSecurityPolicyEnforcement =
1002 ContentSecurityPolicy::shouldBypassMainWorld(&executionContext) 998 ContentSecurityPolicy::shouldBypassMainWorld(&executionContext)
1003 ? DoNotEnforceContentSecurityPolicy 999 ? DoNotEnforceContentSecurityPolicy
1004 : EnforceContentSecurityPolicy; 1000 : EnforceContentSecurityPolicy;
1005 options.timeoutMilliseconds = m_timeoutMilliseconds; 1001 options.timeoutMilliseconds = m_timeoutMilliseconds;
1006 1002
1007 ResourceLoaderOptions resourceLoaderOptions; 1003 ResourceLoaderOptions resourceLoaderOptions;
1008 resourceLoaderOptions.allowCredentials = 1004 resourceLoaderOptions.allowCredentials =
(...skipping 12 matching lines...) Expand all
1021 request.setDownloadToFile(true); 1017 request.setDownloadToFile(true);
1022 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; 1018 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
1023 } 1019 }
1024 1020
1025 m_exceptionCode = 0; 1021 m_exceptionCode = 0;
1026 m_error = false; 1022 m_error = false;
1027 1023
1028 if (m_async) { 1024 if (m_async) {
1029 UseCounter::count(&executionContext, 1025 UseCounter::count(&executionContext,
1030 UseCounter::XMLHttpRequestAsynchronous); 1026 UseCounter::XMLHttpRequestAsynchronous);
1031 if (m_upload) 1027
1028 // The presence of upload event listeners forces us to use preflighting
1029 // because POSTing to an URL that does not permit cross origin requests
1030 // should look exactly like POSTing to an URL that does not respond at all.
1031 // Also, only async requests support upload progress events.
1032 if (m_uploadListenerFlag)
1032 request.setReportUploadProgress(true); 1033 request.setReportUploadProgress(true);
1033 1034
1034 DCHECK(!m_loader); 1035 DCHECK(!m_loader);
1035 m_loader = ThreadableLoader::create(executionContext, this, options, 1036 m_loader = ThreadableLoader::create(executionContext, this, options,
1036 resourceLoaderOptions); 1037 resourceLoaderOptions);
1037 m_loader->start(request); 1038 m_loader->start(request);
1038 1039
1039 return; 1040 return;
1040 } 1041 }
1041 1042
(...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after
1237 return; 1238 return;
1238 } 1239 }
1239 1240
1240 // With m_error set, the state change steps are minimal: any pending 1241 // With m_error set, the state change steps are minimal: any pending
1241 // progress event is flushed + a readystatechange is dispatched. 1242 // progress event is flushed + a readystatechange is dispatched.
1242 // No new progress events dispatched; as required, that happens at 1243 // No new progress events dispatched; as required, that happens at
1243 // the end here. 1244 // the end here.
1244 DCHECK(m_error); 1245 DCHECK(m_error);
1245 changeState(kDone); 1246 changeState(kDone);
1246 1247
1247 if (!m_uploadComplete) { 1248 if (!m_uploadCompleteFlag) {
1248 m_uploadComplete = true; 1249 m_uploadCompleteFlag = true;
yhirano 2016/10/20 11:27:54 Is substituting unconditionally enough?
1249 if (m_upload && m_uploadEventsAllowed) 1250
1251 if (m_uploadListenerFlag) {
1252 DCHECK(m_upload);
1250 m_upload->handleRequestError(type); 1253 m_upload->handleRequestError(type);
1254 }
1251 } 1255 }
1252 1256
1253 // Note: The below event dispatch may be called while |hasPendingActivity() == 1257 // Note: The below event dispatch may be called while |hasPendingActivity() ==
1254 // false|, when |handleRequestError| is called after |internalAbort()|. This 1258 // false|, when |handleRequestError| is called after |internalAbort()|. This
1255 // is safe, however, as |this| will be kept alive from a strong ref 1259 // is safe, however, as |this| will be kept alive from a strong ref
1256 // |Event::m_target|. 1260 // |Event::m_target|.
1257 dispatchProgressEvent(EventTypeNames::progress, receivedLength, 1261 dispatchProgressEvent(EventTypeNames::progress, receivedLength,
1258 expectedLength); 1262 expectedLength);
1259 dispatchProgressEvent(type, receivedLength, expectedLength); 1263 dispatchProgressEvent(type, receivedLength, expectedLength);
1260 dispatchProgressEvent(EventTypeNames::loadend, receivedLength, 1264 dispatchProgressEvent(EventTypeNames::loadend, receivedLength,
(...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after
1625 return; 1629 return;
1626 1630
1627 if (status() >= 200 && status() < 300) { 1631 if (status() >= 200 && status() < 300) {
1628 document()->frame()->page()->chromeClient().ajaxSucceeded( 1632 document()->frame()->page()->chromeClient().ajaxSucceeded(
1629 document()->frame()); 1633 document()->frame());
1630 } 1634 }
1631 } 1635 }
1632 1636
1633 void XMLHttpRequest::didSendData(unsigned long long bytesSent, 1637 void XMLHttpRequest::didSendData(unsigned long long bytesSent,
1634 unsigned long long totalBytesToBeSent) { 1638 unsigned long long totalBytesToBeSent) {
1639 DCHECK(m_async);
yhirano 2016/10/20 12:17:02 You call setReportUploadProgress only when m_uploa
1635 NETWORK_DVLOG(1) << this << " didSendData(" << bytesSent << ", " 1640 NETWORK_DVLOG(1) << this << " didSendData(" << bytesSent << ", "
1636 << totalBytesToBeSent << ")"; 1641 << totalBytesToBeSent << ")";
1637 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel); 1642 ScopedEventDispatchProtect protect(&m_eventDispatchRecursionLevel);
1638 1643
1639 if (!m_upload) 1644 if (m_uploadListenerFlag) {
1640 return; 1645 DCHECK(m_upload);
1646 m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
1647 }
1641 1648
yhirano 2016/10/20 12:17:02 Not related to this CL but we may need an early-re
1642 if (m_uploadEventsAllowed) 1649 // TODO(tyoshino): Since AsyncResourceHandler doesn't send us any
yhirano 2016/10/20 11:27:54 "Since" is not needed?
1643 m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent); 1650 // notification when the total size is 0. Therefore, we cannot depend on
1651 // didSendData() invocation to dispatch the progress events for "process
1652 // request end-of-body" hook as specified in the XHR spec. Fix this.
1653 if (bytesSent == totalBytesToBeSent && !m_uploadCompleteFlag) {
1654 m_uploadCompleteFlag = true;
1644 1655
1645 if (bytesSent == totalBytesToBeSent && !m_uploadComplete) { 1656 if (m_uploadListenerFlag) {
1646 m_uploadComplete = true; 1657 DCHECK(m_upload);
1647 if (m_uploadEventsAllowed)
1648 m_upload->dispatchEventAndLoadEnd(EventTypeNames::load, true, bytesSent, 1658 m_upload->dispatchEventAndLoadEnd(EventTypeNames::load, true, bytesSent,
1649 totalBytesToBeSent); 1659 totalBytesToBeSent);
1660 }
1661
1662 return;
yhirano 2016/10/20 11:27:54 This statement is redundant.
1650 } 1663 }
1651 } 1664 }
1652 1665
1653 void XMLHttpRequest::didReceiveResponse( 1666 void XMLHttpRequest::didReceiveResponse(
1654 unsigned long identifier, 1667 unsigned long identifier,
1655 const ResourceResponse& response, 1668 const ResourceResponse& response,
1656 std::unique_ptr<WebDataConsumerHandle> handle) { 1669 std::unique_ptr<WebDataConsumerHandle> handle) {
1657 ALLOW_UNUSED_LOCAL(handle); 1670 ALLOW_UNUSED_LOCAL(handle);
1658 DCHECK(!handle); 1671 DCHECK(!handle);
1659 NETWORK_DVLOG(1) << this << " didReceiveResponse(" << identifier << ")"; 1672 NETWORK_DVLOG(1) << this << " didReceiveResponse(" << identifier << ")";
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
1856 visitor->traceWrappers(m_responseLegacyStream); 1869 visitor->traceWrappers(m_responseLegacyStream);
1857 visitor->traceWrappers(m_responseDocument); 1870 visitor->traceWrappers(m_responseDocument);
1858 visitor->traceWrappers(m_responseArrayBuffer); 1871 visitor->traceWrappers(m_responseArrayBuffer);
1859 } 1872 }
1860 1873
1861 std::ostream& operator<<(std::ostream& ostream, const XMLHttpRequest* xhr) { 1874 std::ostream& operator<<(std::ostream& ostream, const XMLHttpRequest* xhr) {
1862 return ostream << "XMLHttpRequest " << static_cast<const void*>(xhr); 1875 return ostream << "XMLHttpRequest " << static_cast<const void*>(xhr);
1863 } 1876 }
1864 1877
1865 } // namespace blink 1878 } // 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