Changeset 245901 in webkit
- Timestamp:
- May 30, 2019 12:52:57 PM (5 years ago)
- Location:
- trunk
- Files:
-
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebKit/ChangeLog
r245899 r245901 1 2019-05-30 David Quesada <david_quesada@apple.com> 2 3 REGRESSION (r245756) [Mac] 2 TestWebKitAPI.DownloadProgress* and TestWebKitAPI._WKDownload.DownloadMonitorCancel are flaky timeouts 4 https://bugs.webkit.org/show_bug.cgi?id=198298 5 rdar://problem/51182393 6 7 Reviewed by Alexey Proskuryakov. 8 9 When canceling a download, there has always been a race condition between: 10 11 (A) the execution of Download::didCancel() within the block passed to 12 -[NSURLSessionDownloadTask cancelByProducingResumeData:] within 13 Download::platformCancelNetworkLoad(), and 14 15 (B) the invocation of -[WKNetworkSessionDelegate URLSession:task:didCompleteWithError:] 16 17 If A happens before B, the block calls didCancel() on the download, which reports the 18 cancellation to the UI process and tears down the download. When B happens, WKNetworkSessionDelegate 19 gracefully handles the fact that the Download has been removed from the map, and nothing 20 else happens. Life is good. 21 22 If B happens before A, -URLSession:task:didCompleteWithError: invokes Download::didFail(), 23 which reports a download failure (*not* a cancellation) to the UI process and tears down 24 the Download and DownloadProxy. On release builds, this can leave the tests waiting for a 25 cancellation until they time out. When A happens, the block calls Download::didCancel(). 26 This messages the UI process, which results in a debug assertion failure from an unhandled 27 message since the DownloadProxy was torn down when the failure was reported. Meanwhile, 28 the network process hits a debug assertion in DownloadManager::downloadFinished() when 29 trying to remove the Download *again*. 30 31 r245756 made the bad case (B before A) more likely by adding a delay before didCancel() 32 is called. 33 34 Make this race condition impossible by eliminating the didCancel() from the cancellation 35 block, and instead relying on -URLSession:task:didCompleteWithError: to report the 36 download as canceled. This also effectively coalesces calls to platformCancelNetworkLoad(), 37 which, if called multiple times before CFNetwork reports that the download was canceled, 38 could cause multiple calls to didCancel(), resulting in the same assertion failures seen 39 in the B-before-A case. 40 41 No new tests, as recreating this race condition in the test scenario would require 42 additional machinery, and is no longer even possible since we don't depend on the calling 43 of the cancellation handler in order to report the Download as canceled. 44 45 * NetworkProcess/Downloads/Download.cpp: 46 (WebKit::Download::cancel): 47 * NetworkProcess/Downloads/Download.h: 48 (WebKit::Download::wasCanceled const): 49 * NetworkProcess/Downloads/cocoa/DownloadCocoa.mm: 50 (WebKit::Download::platformCancelNetworkLoad): 51 * NetworkProcess/cocoa/NetworkSessionCocoa.mm: 52 (-[WKNetworkSessionDelegate URLSession:task:didCompleteWithError:]): 53 1 54 2019-05-30 Chris Dumez <cdumez@apple.com> 2 55 -
trunk/Source/WebKit/NetworkProcess/Downloads/Download.cpp
r243110 r245901 87 87 void Download::cancel() 88 88 { 89 m_wasCanceled = true; 89 90 if (m_download) { 90 91 m_download->cancel(); -
trunk/Source/WebKit/NetworkProcess/Downloads/Download.h
r243110 r245901 93 93 94 94 bool isAlwaysOnLoggingAllowed() const; 95 bool wasCanceled() const { return m_wasCanceled; } 95 96 96 97 void applicationDidEnterBackground() { m_monitor.applicationDidEnterBackground(); } … … 120 121 PAL::SessionID m_sessionID; 121 122 String m_suggestedName; 123 bool m_wasCanceled { false }; 122 124 bool m_hasReceivedData { false }; 123 125 DownloadMonitor m_monitor { *this }; -
trunk/Source/WebKit/NetworkProcess/Downloads/cocoa/DownloadCocoa.mm
r245756 r245901 81 81 { 82 82 ASSERT(m_downloadTask); 83 84 // The download's resume data is accessed in the network session delegate 85 // method -URLSession:task:didCompleteWithError: instead of inside this block, 86 // to avoid race conditions between the two. Calling -cancel is not sufficient 87 // here because CFNetwork won't provide the resume data unless we ask for it. 83 88 [m_downloadTask cancelByProducingResumeData:^(NSData *resumeData) { 84 callOnMainThread([this, resumeData = retainPtr(resumeData)] { 85 if (resumeData && resumeData.get().bytes && resumeData.get().length) 86 didCancel(IPC::DataReference(reinterpret_cast<const uint8_t*>(resumeData.get().bytes), resumeData.get().length)); 87 else 88 didCancel({ }); 89 }); 89 UNUSED_PARAM(resumeData); 90 90 }]; 91 91 } -
trunk/Source/WebKit/NetworkProcess/cocoa/NetworkSessionCocoa.mm
r245540 r245901 624 624 NSData *resumeData = nil; 625 625 if (id userInfo = error.userInfo) { 626 if ([userInfo isKindOfClass:[NSDictionary class]]) 626 if ([userInfo isKindOfClass:[NSDictionary class]]) { 627 627 resumeData = userInfo[@"NSURLSessionDownloadTaskResumeData"]; 628 if (resumeData && ![resumeData isKindOfClass:[NSData class]]) { 629 RELEASE_LOG(NetworkSession, "Download task %llu finished with resume data of wrong class: %s", (unsigned long long)task.taskIdentifier, NSStringFromClass([resumeData class]).UTF8String); 630 ASSERT_NOT_REACHED(); 631 resumeData = nil; 632 } 633 } 628 634 } 629 630 if (resumeData && [resumeData isKindOfClass:[NSData class]]) 631 download->didFail(error, { static_cast<const uint8_t*>(resumeData.bytes), resumeData.length }); 635 636 auto resumeDataReference = resumeData ? IPC::DataReference { static_cast<const uint8_t*>(resumeData.bytes), resumeData.length } : IPC::DataReference { }; 637 638 if (download->wasCanceled()) 639 download->didCancel(resumeDataReference); 632 640 else 633 download->didFail(error, { });641 download->didFail(error, resumeDataReference); 634 642 } 635 643 } -
trunk/Tools/ChangeLog
r245891 r245901 1 2019-05-30 David Quesada <david_quesada@apple.com> 2 3 REGRESSION (r245756) [Mac] 2 TestWebKitAPI.DownloadProgress* and TestWebKitAPI._WKDownload.DownloadMonitorCancel are flaky timeouts 4 https://bugs.webkit.org/show_bug.cgi?id=198298 5 rdar://problem/51182393 6 7 Reviewed by Alexey Proskuryakov. 8 9 Re-enable _WKDownload.DownloadMonitorCancel, which should no longer time out with this fix. 10 11 * TestWebKitAPI/Tests/WebKitCocoa/Download.mm: 12 (TestWebKitAPI::TEST): 13 1 14 2019-05-30 Truitt Savell <tsavell@apple.com> 2 15 -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/Download.mm
r245851 r245901 880 880 } 881 881 882 TEST(_WKDownload, D ISABLED_DownloadMonitorCancel)882 TEST(_WKDownload, DownloadMonitorCancel) 883 883 { 884 884 downloadAtRate(0.5, 120); // Should cancel in ~0.5 seconds
Note: See TracChangeset
for help on using the changeset viewer.