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

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

Issue 79953004: Improve fidelity of XHR progress events. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Also deliver faithful 'progress' events on request error Created 7 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
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
tyoshino (SeeGerritForStatus) 2013/11/25 05:06:31 abarth: sigbjornf has made substantial amount of c
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
11 * version 2 of the License, or (at your option) any later version. 11 * version 2 of the License, or (at your option) any later version.
12 * 12 *
13 * This library is distributed in the hope that it will be useful, 13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details. 16 * Lesser General Public License for more details.
(...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after
434 flushAction = FlushDeferredProgressEvent; 434 flushAction = FlushDeferredProgressEvent;
435 else 435 else
436 flushAction = FlushProgressEvent; 436 flushAction = FlushProgressEvent;
437 } 437 }
438 m_progressEventThrottle.dispatchReadyStateChangeEvent(XMLHttpRequestProg ressEvent::create(EventTypeNames::readystatechange), flushAction); 438 m_progressEventThrottle.dispatchReadyStateChangeEvent(XMLHttpRequestProg ressEvent::create(EventTypeNames::readystatechange), flushAction);
439 } 439 }
440 440
441 InspectorInstrumentation::didDispatchXHRReadyStateChangeEvent(cookie); 441 InspectorInstrumentation::didDispatchXHRReadyStateChangeEvent(cookie);
442 if (m_state == DONE && !m_error) { 442 if (m_state == DONE && !m_error) {
443 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDi spatchXHRLoadEvent(executionContext(), this); 443 InspectorInstrumentationCookie cookie = InspectorInstrumentation::willDi spatchXHRLoadEvent(executionContext(), this);
444 m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::creat e(EventTypeNames::load)); 444 dispatchThrottledProgressEvent(EventTypeNames::load);
445 InspectorInstrumentation::didDispatchXHRLoadEvent(cookie); 445 InspectorInstrumentation::didDispatchXHRLoadEvent(cookie);
446 m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::creat e(EventTypeNames::loadend)); 446 dispatchThrottledProgressEvent(EventTypeNames::loadend);
447 } 447 }
448 } 448 }
449 449
450 void XMLHttpRequest::setWithCredentials(bool value, ExceptionState& exceptionSta te) 450 void XMLHttpRequest::setWithCredentials(bool value, ExceptionState& exceptionSta te)
451 { 451 {
452 if (m_state > OPENED || m_loader) { 452 if (m_state > OPENED || m_loader) {
453 exceptionState.throwDOMException(InvalidStateError, ExceptionMessages::f ailedToSet("withCredentials", "XMLHttpRequest", "the value may only be set if th e object's state is UNSENT or OPENED.")); 453 exceptionState.throwDOMException(InvalidStateError, ExceptionMessages::f ailedToSet("withCredentials", "XMLHttpRequest", "the value may only be set if th e object's state is UNSENT or OPENED."));
454 return; 454 return;
455 } 455 }
456 456
(...skipping 392 matching lines...) Expand 10 before | Expand all | Expand 10 after
849 849
850 void XMLHttpRequest::abort() 850 void XMLHttpRequest::abort()
851 { 851 {
852 LOG(Network, "XMLHttpRequest %p abort()", this); 852 LOG(Network, "XMLHttpRequest %p abort()", this);
853 853
854 // internalAbort() calls dropProtection(), which may release the last refere nce. 854 // internalAbort() calls dropProtection(), which may release the last refere nce.
855 RefPtr<XMLHttpRequest> protect(this); 855 RefPtr<XMLHttpRequest> protect(this);
856 856
857 bool sendFlag = m_loader; 857 bool sendFlag = m_loader;
858 858
859 // Response is cleared next, save needed progress event data.
860 long long expectedLength = m_response.expectedContentLength();
861 long long receivedLength = m_receivedLength;
862
859 if (!internalAbort()) 863 if (!internalAbort())
860 return; 864 return;
861 865
862 clearResponse(); 866 clearResponse();
863 867
864 // Clear headers as required by the spec 868 // Clear headers as required by the spec
865 m_requestHeaders.clear(); 869 m_requestHeaders.clear();
866 870
867 if (!((m_state <= OPENED && !sendFlag) || m_state == DONE)) { 871 if (!((m_state <= OPENED && !sendFlag) || m_state == DONE)) {
868 ASSERT(!m_loader); 872 ASSERT(!m_loader);
869 handleRequestError(0, EventTypeNames::abort); 873 handleRequestError(0, EventTypeNames::abort, receivedLength, expectedLen gth);
870 } 874 }
871 m_state = UNSENT; 875 m_state = UNSENT;
872 } 876 }
873 877
874 void XMLHttpRequest::clearVariablesForLoading() 878 void XMLHttpRequest::clearVariablesForLoading()
875 { 879 {
876 // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization. 880 // FIXME: when we add the support for multi-part XHR, we will have to think be careful with this initialization.
877 m_receivedLength = 0; 881 m_receivedLength = 0;
878 m_decoder.clear(); 882 m_decoder.clear();
879 883
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 } 955 }
952 956
953 void XMLHttpRequest::handleDidFailGeneric() 957 void XMLHttpRequest::handleDidFailGeneric()
954 { 958 {
955 clearResponse(); 959 clearResponse();
956 clearRequest(); 960 clearRequest();
957 961
958 m_error = true; 962 m_error = true;
959 } 963 }
960 964
961 void XMLHttpRequest::dispatchEventAndLoadEnd(const AtomicString& type) 965 void XMLHttpRequest::dispatchEventAndLoadEnd(const AtomicString& type, long long receivedLength, long long expectedLength)
962 { 966 {
963 if (!m_uploadComplete) { 967 bool lengthComputable = expectedLength > 0 && receivedLength <= expectedLeng th;
964 m_uploadComplete = true; 968 unsigned long long loaded = receivedLength >= 0 ? static_cast<unsigned long long>(receivedLength) : 0;
965 if (m_upload && m_uploadEventsAllowed) 969 unsigned long long total = lengthComputable ? static_cast<unsigned long long >(expectedLength) : 0;
966 m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::creat e(type)); 970
967 } 971 m_progressEventThrottle.dispatchEventAndLoadEnd(type, lengthComputable, load ed, total);
968 m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent: :create(type));
969 } 972 }
970 973
971 void XMLHttpRequest::dispatchThrottledProgressEvent() 974 void XMLHttpRequest::dispatchThrottledProgressEvent(const AtomicString& type, lo ng long receivedLength, long long expectedLength)
tyoshino (SeeGerritForStatus) 2013/11/25 05:06:31 how about having two methods one takes two argumen
sof 2013/11/25 06:48:12 Yes, how about dispatchThrottledProgressEventSnaps
972 { 975 {
973 long long expectedLength = m_response.expectedContentLength(); 976 if (!receivedLength)
977 receivedLength = m_receivedLength;
978 if (!expectedLength)
979 expectedLength = m_response.expectedContentLength();
980
974 bool lengthComputable = expectedLength > 0 && m_receivedLength <= expectedLe ngth; 981 bool lengthComputable = expectedLength > 0 && m_receivedLength <= expectedLe ngth;
975 unsigned long long total = lengthComputable ? expectedLength : 0; 982 unsigned long long loaded = m_receivedLength >= 0 ? static_cast<unsigned lon g long>(m_receivedLength) : 0;
983 unsigned long long total = lengthComputable ? static_cast<unsigned long long >(expectedLength) : 0;
976 984
977 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, m_receivedLe ngth, total); 985 if (type == EventTypeNames::progress)
986 m_progressEventThrottle.dispatchProgressEvent(lengthComputable, loaded, total);
987 else
988 m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::creat e(type, lengthComputable, loaded, total));
978 } 989 }
979 990
980 void XMLHttpRequest::handleNetworkError() 991 void XMLHttpRequest::handleNetworkError()
981 { 992 {
982 LOG(Network, "XMLHttpRequest %p handleNetworkError()", this); 993 LOG(Network, "XMLHttpRequest %p handleNetworkError()", this);
983 994
995 // Response is cleared next, save needed progress event data.
996 long long expectedLength = m_response.expectedContentLength();
997 long long receivedLength = m_receivedLength;
998
984 handleDidFailGeneric(); 999 handleDidFailGeneric();
985 handleRequestError(NetworkError, EventTypeNames::error); 1000 handleRequestError(NetworkError, EventTypeNames::error, receivedLength, expe ctedLength);
986 internalAbort(); 1001 internalAbort();
987 } 1002 }
988 1003
989 void XMLHttpRequest::handleDidCancel() 1004 void XMLHttpRequest::handleDidCancel()
990 { 1005 {
991 LOG(Network, "XMLHttpRequest %p handleDidCancel()", this); 1006 LOG(Network, "XMLHttpRequest %p handleDidCancel()", this);
992 1007
1008 // Response is cleared next, save needed progress event data.
1009 long long expectedLength = m_response.expectedContentLength();
1010 long long receivedLength = m_receivedLength;
1011
993 handleDidFailGeneric(); 1012 handleDidFailGeneric();
994 handleRequestError(AbortError, EventTypeNames::abort); 1013 handleRequestError(AbortError, EventTypeNames::abort, receivedLength, expect edLength);
995 } 1014 }
996 1015
997 void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode, const Atomi cString& type) 1016 void XMLHttpRequest::handleRequestError(ExceptionCode exceptionCode, const Atomi cString& type, long long receivedLength, long long expectedLength)
998 { 1017 {
999 LOG(Network, "XMLHttpRequest %p handleRequestError()", this); 1018 LOG(Network, "XMLHttpRequest %p handleRequestError()", this);
1000 1019
1001 // The request error steps for event 'type' and exception 'exceptionCode'. 1020 // The request error steps for event 'type' and exception 'exceptionCode'.
1002 1021
1003 if (!m_async && exceptionCode) { 1022 if (!m_async && exceptionCode) {
1004 m_state = DONE; 1023 m_state = DONE;
1005 m_exceptionCode = exceptionCode; 1024 m_exceptionCode = exceptionCode;
1006 return; 1025 return;
1007 } 1026 }
1008 // With m_error set, the state change steps are minimal: any pending 1027 // With m_error set, the state change steps are minimal: any pending
1009 // progress event is flushed + a readystatechange is dispatched. 1028 // progress event is flushed + a readystatechange is dispatched.
1010 // No new progress events dispatched; as required, that happens at 1029 // No new progress events dispatched; as required, that happens at
1011 // the end here. 1030 // the end here.
1012 ASSERT(m_error); 1031 ASSERT(m_error);
1013 changeState(DONE); 1032 changeState(DONE);
1014 1033
1015 if (!m_uploadComplete) { 1034 if (!m_uploadComplete) {
1016 m_uploadComplete = true; 1035 m_uploadComplete = true;
1017 if (m_upload && m_uploadEventsAllowed) 1036 if (m_upload && m_uploadEventsAllowed)
1018 m_upload->handleRequestError(type); 1037 m_upload->handleRequestError(type);
1019 } 1038 }
1020 1039
1021 dispatchThrottledProgressEvent(); 1040 dispatchThrottledProgressEvent(EventTypeNames::progress, receivedLength, exp ectedLength);
1022 m_progressEventThrottle.dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent: :create(type)); 1041 dispatchEventAndLoadEnd(type, receivedLength, expectedLength);
1023 } 1042 }
1024 1043
1025 void XMLHttpRequest::dropProtectionSoon() 1044 void XMLHttpRequest::dropProtectionSoon()
1026 { 1045 {
1027 m_dropProtectionRunner.runAsync(); 1046 m_dropProtectionRunner.runAsync();
1028 } 1047 }
1029 1048
1030 void XMLHttpRequest::dropProtection() 1049 void XMLHttpRequest::dropProtection()
1031 { 1050 {
1032 unsetPendingActivity(this); 1051 unsetPendingActivity(this);
(...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after
1212 1231
1213 if (m_error) 1232 if (m_error)
1214 return; 1233 return;
1215 1234
1216 if (m_state < HEADERS_RECEIVED) 1235 if (m_state < HEADERS_RECEIVED)
1217 changeState(HEADERS_RECEIVED); 1236 changeState(HEADERS_RECEIVED);
1218 1237
1219 if (m_decoder) 1238 if (m_decoder)
1220 m_responseText = m_responseText.concatenateWith(m_decoder->flush()); 1239 m_responseText = m_responseText.concatenateWith(m_decoder->flush());
1221 1240
1222 clearVariablesForLoading();
1223
1224 if (m_responseStream) 1241 if (m_responseStream)
1225 m_responseStream->finalize(); 1242 m_responseStream->finalize();
1226 1243
1227 InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, iden tifier, m_responseText, m_url, m_lastSendURL, m_lastSendLineNumber); 1244 InspectorInstrumentation::didFinishXHRLoading(executionContext(), this, iden tifier, m_responseText, m_url, m_lastSendURL, m_lastSendLineNumber);
1228 1245
1229 // Prevent dropProtection releasing the last reference, and retain |this| un til the end of this method. 1246 // Prevent dropProtection releasing the last reference, and retain |this| un til the end of this method.
1230 RefPtr<XMLHttpRequest> protect(this); 1247 RefPtr<XMLHttpRequest> protect(this);
1231 1248
1232 if (m_loader) { 1249 if (m_loader) {
1233 m_loader = 0; 1250 m_loader = 0;
1234 dropProtection(); 1251 dropProtection();
1235 } 1252 }
1236 1253
1237 changeState(DONE); 1254 changeState(DONE);
1255
1256 clearVariablesForLoading();
1238 } 1257 }
1239 1258
1240 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long lon g totalBytesToBeSent) 1259 void XMLHttpRequest::didSendData(unsigned long long bytesSent, unsigned long lon g totalBytesToBeSent)
1241 { 1260 {
1242 LOG(Network, "XMLHttpRequest %p didSendData(%llu, %llu)", this, bytesSent, t otalBytesToBeSent); 1261 LOG(Network, "XMLHttpRequest %p didSendData(%llu, %llu)", this, bytesSent, t otalBytesToBeSent);
1243 1262
1244 if (!m_upload) 1263 if (!m_upload)
1245 return; 1264 return;
1246 1265
1247 if (m_uploadEventsAllowed) 1266 if (m_uploadEventsAllowed)
1248 m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent); 1267 m_upload->dispatchProgressEvent(bytesSent, totalBytesToBeSent);
1249 1268
1250 if (bytesSent == totalBytesToBeSent && !m_uploadComplete) { 1269 if (bytesSent == totalBytesToBeSent && !m_uploadComplete) {
1251 m_uploadComplete = true; 1270 m_uploadComplete = true;
1252 if (m_uploadEventsAllowed) 1271 if (m_uploadEventsAllowed)
1253 m_upload->dispatchEventAndLoadEnd(XMLHttpRequestProgressEvent::creat e(EventTypeNames::load)); 1272 m_upload->dispatchEventAndLoadEnd(EventTypeNames::load, true, bytesS ent, totalBytesToBeSent);
1254 } 1273 }
1255 } 1274 }
1256 1275
1257 void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const Resource Response& response) 1276 void XMLHttpRequest::didReceiveResponse(unsigned long identifier, const Resource Response& response)
1258 { 1277 {
1259 LOG(Network, "XMLHttpRequest %p didReceiveResponse(%lu)", this, identifier); 1278 LOG(Network, "XMLHttpRequest %p didReceiveResponse(%lu)", this, identifier);
1260 1279
1261 InspectorInstrumentation::didReceiveXHRResponse(executionContext(), identifi er); 1280 InspectorInstrumentation::didReceiveXHRResponse(executionContext(), identifi er);
1262 1281
1263 m_response = response; 1282 m_response = response;
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
1314 m_responseStream = Stream::create(executionContext(), responseMIMETy pe()); 1333 m_responseStream = Stream::create(executionContext(), responseMIMETy pe());
1315 m_responseStream->addData(data, len); 1334 m_responseStream->addData(data, len);
1316 } 1335 }
1317 1336
1318 if (m_error) 1337 if (m_error)
1319 return; 1338 return;
1320 1339
1321 m_receivedLength += len; 1340 m_receivedLength += len;
1322 1341
1323 if (m_async) 1342 if (m_async)
1324 dispatchThrottledProgressEvent(); 1343 dispatchThrottledProgressEvent(EventTypeNames::progress);
1325 1344
1326 if (m_state != LOADING) { 1345 if (m_state != LOADING) {
1327 changeState(LOADING); 1346 changeState(LOADING);
1328 } else { 1347 } else {
1329 // Firefox calls readyStateChanged every time it receives data. Do 1348 // Firefox calls readyStateChanged every time it receives data. Do
1330 // the same to align with Firefox. 1349 // the same to align with Firefox.
1331 // 1350 //
1332 // FIXME: Make our implementation and the spec consistent. This 1351 // FIXME: Make our implementation and the spec consistent. This
1333 // behavior was needed when the progress event was not available. 1352 // behavior was needed when the progress event was not available.
1334 dispatchReadyStateChangeEvent(); 1353 dispatchReadyStateChangeEvent();
1335 } 1354 }
1336 } 1355 }
1337 1356
1338 void XMLHttpRequest::handleDidTimeout() 1357 void XMLHttpRequest::handleDidTimeout()
1339 { 1358 {
1340 LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this); 1359 LOG(Network, "XMLHttpRequest %p handleDidTimeout()", this);
1341 1360
1342 // internalAbort() calls dropProtection(), which may release the last refere nce. 1361 // internalAbort() calls dropProtection(), which may release the last refere nce.
1343 RefPtr<XMLHttpRequest> protect(this); 1362 RefPtr<XMLHttpRequest> protect(this);
1344 1363
1364 // Response is cleared next, save needed progress event data.
1365 long long expectedLength = m_response.expectedContentLength();
1366 long long receivedLength = m_receivedLength;
1367
1345 if (!internalAbort()) 1368 if (!internalAbort())
1346 return; 1369 return;
1347 1370
1348 handleDidFailGeneric(); 1371 handleDidFailGeneric();
1349 handleRequestError(TimeoutError, EventTypeNames::timeout); 1372 handleRequestError(TimeoutError, EventTypeNames::timeout, receivedLength, ex pectedLength);
1350 } 1373 }
1351 1374
1352 void XMLHttpRequest::suspend() 1375 void XMLHttpRequest::suspend()
1353 { 1376 {
1354 m_progressEventThrottle.suspend(); 1377 m_progressEventThrottle.suspend();
1355 } 1378 }
1356 1379
1357 void XMLHttpRequest::resume() 1380 void XMLHttpRequest::resume()
1358 { 1381 {
1359 m_progressEventThrottle.resume(); 1382 m_progressEventThrottle.resume();
(...skipping 14 matching lines...) Expand all
1374 { 1397 {
1375 return EventTargetNames::XMLHttpRequest; 1398 return EventTargetNames::XMLHttpRequest;
1376 } 1399 }
1377 1400
1378 ExecutionContext* XMLHttpRequest::executionContext() const 1401 ExecutionContext* XMLHttpRequest::executionContext() const
1379 { 1402 {
1380 return ActiveDOMObject::executionContext(); 1403 return ActiveDOMObject::executionContext();
1381 } 1404 }
1382 1405
1383 } // namespace WebCore 1406 } // namespace WebCore
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698