Changeset 228852 in webkit
- Timestamp:
- Feb 20, 2018 5:08:28 PM (6 years ago)
- Location:
- trunk
- Files:
-
- 17 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WTF/ChangeLog
r228846 r228852 1 2018-02-20 Chris Dumez <cdumez@apple.com> 2 3 Provisional load may get committed before receiving the decidePolicyForNavigationResponse response 4 https://bugs.webkit.org/show_bug.cgi?id=182720 5 <rdar://problem/37515204> 6 7 Reviewed by Alex Christensen. 8 9 Add convenience CompletionHandlerCallingScope class which calls its CompletionHandler 10 when destroyed, and provides a release() methods to manually call the completionHandler. 11 12 * wtf/CompletionHandler.h: 13 (WTF::CompletionHandlerCallingScope::CompletionHandlerCallingScope): 14 (WTF::CompletionHandlerCallingScope::~CompletionHandlerCallingScope): 15 (WTF::CompletionHandlerCallingScope::CompletionHandler<void): 16 1 17 2018-02-20 Tim Horton <timothy_horton@apple.com> 2 18 -
trunk/Source/WTF/wtf/CompletionHandler.h
r225403 r228852 65 65 }; 66 66 67 class CompletionHandlerCallingScope { 68 public: 69 CompletionHandlerCallingScope(CompletionHandler<void()>&& completionHandler) 70 : m_completionHandler(WTFMove(completionHandler)) 71 { } 72 73 ~CompletionHandlerCallingScope() 74 { 75 if (m_completionHandler) 76 m_completionHandler(); 77 } 78 79 CompletionHandlerCallingScope(CompletionHandlerCallingScope&&) = default; 80 CompletionHandlerCallingScope& operator=(CompletionHandlerCallingScope&&) = default; 81 82 CompletionHandler<void()> release() { return WTFMove(m_completionHandler); } 83 84 private: 85 CompletionHandler<void()> m_completionHandler; 86 }; 87 67 88 } // namespace WTF 68 89 69 90 using WTF::CompletionHandler; 91 using WTF::CompletionHandlerCallingScope; -
trunk/Source/WebCore/ChangeLog
r228851 r228852 1 2018-02-20 Chris Dumez <cdumez@apple.com> 2 3 Provisional load may get committed before receiving the decidePolicyForNavigationResponse response 4 https://bugs.webkit.org/show_bug.cgi?id=182720 5 <rdar://problem/37515204> 6 7 Reviewed by Alex Christensen. 8 9 Wait for the policy response from the client after receiving a resource response, 10 before sending the NetworkResourceLoader::ContinueDidReceiveResponse IPC back to 11 the NetworkProcess. Otherwise, the network process may start sending us data and 12 we may end up committing the provisional load before receiving the policy decision 13 fron the client. 14 15 Change is covered by new API test. 16 17 * loader/DocumentLoader.cpp: 18 (WebCore::DocumentLoader::responseReceived): 19 * loader/NetscapePlugInStreamLoader.cpp: 20 (WebCore::NetscapePlugInStreamLoader::didReceiveResponse): 21 * loader/NetscapePlugInStreamLoader.h: 22 * loader/ResourceLoader.cpp: 23 (WebCore::ResourceLoader::deliverResponseAndData): 24 (WebCore::ResourceLoader::loadDataURL): 25 (WebCore::ResourceLoader::didReceiveResponse): 26 (WebCore::ResourceLoader::didReceiveResponseAsync): 27 * loader/ResourceLoader.h: 28 * loader/SubresourceLoader.cpp: 29 (WebCore::SubresourceLoader::didReceiveResponse): 30 (WebCore::SubresourceLoader::didReceiveResponsePolicy): 31 (WebCore::SubresourceLoader::willCancel): 32 * loader/SubresourceLoader.h: 33 * loader/ios/PreviewLoader.mm: 34 (-[WebPreviewLoader _sendDidReceiveResponseIfNecessary]): 35 1 36 2018-02-20 Chris Dumez <cdumez@apple.com> 2 37 -
trunk/Source/WebCore/loader/DocumentLoader.cpp
r228691 r228852 784 784 #endif 785 785 786 if (auto* mainResourceLoader = this->mainResourceLoader()) 787 mainResourceLoader->markInAsyncResponsePolicyCheck(); 786 788 frameLoader()->checkContentPolicy(m_response, [this, protectedThis = makeRef(*this)](PolicyAction policy) { 789 if (auto* mainResourceLoader = this->mainResourceLoader()) 790 mainResourceLoader->didReceiveResponsePolicy(); 791 787 792 continueAfterContentPolicy(policy); 788 793 }); -
trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.cpp
r224522 r228852 98 98 } 99 99 100 void NetscapePlugInStreamLoader::didReceiveResponse(const ResourceResponse& response )100 void NetscapePlugInStreamLoader::didReceiveResponse(const ResourceResponse& response, CompletionHandler<void()>&& policyCompletionHandler) 101 101 { 102 102 Ref<NetscapePlugInStreamLoader> protectedThis(*this); 103 CompletionHandlerCallingScope completionHandlerCaller(WTFMove(policyCompletionHandler)); 103 104 104 105 m_client->didReceiveResponse(this, response); … … 108 109 return; 109 110 110 ResourceLoader::didReceiveResponse(response); 111 ResourceLoader::didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis), response, completionHandlerCaller = WTFMove(completionHandlerCaller)]() mutable { 112 // Don't continue if the stream is cancelled 113 if (!m_client) 114 return; 111 115 112 // Don't continue if the stream is cancelled 113 if (!m_client) 114 return; 116 if (!response.isHTTP()) 117 return; 115 118 116 if (!response.isHTTP()) 117 return; 118 119 if (m_client->wantsAllStreams()) 120 return; 119 if (m_client->wantsAllStreams()) 120 return; 121 121 122 // Status code can be null when serving from a Web archive. 123 if (response.httpStatusCode() && (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400)) 124 cancel(frameLoader()->client().fileDoesNotExistError(response)); 122 // Status code can be null when serving from a Web archive. 123 if (response.httpStatusCode() && (response.httpStatusCode() < 100 || response.httpStatusCode() >= 400)) 124 cancel(frameLoader()->client().fileDoesNotExistError(response)); 125 }); 125 126 } 126 127 -
trunk/Source/WebCore/loader/NetscapePlugInStreamLoader.h
r224522 r228852 61 61 62 62 void willSendRequest(ResourceRequest&&, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&& callback) override; 63 void didReceiveResponse(const ResourceResponse& ) override;63 void didReceiveResponse(const ResourceResponse&, CompletionHandler<void()>&& policyCompletionHandler) override; 64 64 void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override; 65 65 void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType) override; -
trunk/Source/WebCore/loader/ResourceLoader.cpp
r228703 r228852 170 170 void ResourceLoader::deliverResponseAndData(const ResourceResponse& response, RefPtr<SharedBuffer>&& buffer) 171 171 { 172 Ref<ResourceLoader> protectedThis(*this); 173 174 didReceiveResponse(response); 175 if (reachedTerminalState()) 176 return; 177 178 if (buffer) { 179 unsigned size = buffer->size(); 180 didReceiveBuffer(buffer.releaseNonNull(), size, DataPayloadWholeResource); 172 didReceiveResponse(response, [this, protectedThis = makeRef(*this), buffer = WTFMove(buffer)]() mutable { 181 173 if (reachedTerminalState()) 182 174 return; 183 } 184 185 NetworkLoadMetrics emptyMetrics; 186 didFinishLoading(emptyMetrics); 175 176 if (buffer) { 177 unsigned size = buffer->size(); 178 didReceiveBuffer(buffer.releaseNonNull(), size, DataPayloadWholeResource); 179 if (reachedTerminalState()) 180 return; 181 } 182 183 NetworkLoadMetrics emptyMetrics; 184 didFinishLoading(emptyMetrics); 185 }); 187 186 } 188 187 … … 252 251 scheduleContext.scheduledPairs = *scheduledPairs; 253 252 #endif 254 DataURLDecoder::decode(url, scheduleContext, [ protectedThis = makeRef(*this), url](auto decodeResult){255 if ( protectedThis->reachedTerminalState())253 DataURLDecoder::decode(url, scheduleContext, [this, protectedThis = makeRef(*this), url](auto decodeResult) mutable { 254 if (this->reachedTerminalState()) 256 255 return; 257 256 if (!decodeResult) { … … 259 258 return; 260 259 } 261 if ( protectedThis->wasCancelled())260 if (this->wasCancelled()) 262 261 return; 263 262 auto& result = decodeResult.value(); … … 269 268 dataResponse.setHTTPHeaderField(HTTPHeaderName::ContentType, result.contentType); 270 269 dataResponse.setSource(ResourceResponse::Source::Network); 271 protectedThis->didReceiveResponse(dataResponse);272 273 if (!protectedThis->reachedTerminalState() && dataSize)274 protectedThis->didReceiveBuffer(result.data.releaseNonNull(), dataSize, DataPayloadWholeResource); 275 276 if (!protectedThis->reachedTerminalState()) {277 NetworkLoadMetrics emptyMetrics;278 protectedThis->didFinishLoading(emptyMetrics);279 } 270 this->didReceiveResponse(dataResponse, [this, protectedThis = WTFMove(protectedThis), dataSize, data = result.data.releaseNonNull()]() mutable { 271 if (!this->reachedTerminalState() && dataSize) 272 this->didReceiveBuffer(WTFMove(data), dataSize, DataPayloadWholeResource); 273 274 if (!this->reachedTerminalState()) { 275 NetworkLoadMetrics emptyMetrics; 276 this->didFinishLoading(emptyMetrics); 277 } 278 }); 280 279 }); 281 280 } … … 460 459 } 461 460 462 void ResourceLoader::didReceiveResponse(const ResourceResponse& r )461 void ResourceLoader::didReceiveResponse(const ResourceResponse& r, CompletionHandler<void()>&& policyCompletionHandler) 463 462 { 464 463 ASSERT(!m_reachedTerminalState); 464 CompletionHandlerCallingScope completionHandlerCaller(WTFMove(policyCompletionHandler)); 465 465 466 466 // Protect this in this delegate method since the additional processing can do … … 661 661 return; 662 662 } 663 didReceiveResponse(response); 664 completionHandler(); 663 didReceiveResponse(response, WTFMove(completionHandler)); 665 664 } 666 665 -
trunk/Source/WebCore/loader/ResourceLoader.h
r228703 r228852 102 102 virtual void willSendRequest(ResourceRequest&&, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&& callback); 103 103 virtual void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent); 104 virtual void didReceiveResponse(const ResourceResponse& );104 virtual void didReceiveResponse(const ResourceResponse&, CompletionHandler<void()>&& policyCompletionHandler); 105 105 virtual void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType); 106 106 virtual void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType); -
trunk/Source/WebCore/loader/SubresourceLoader.cpp
r228486 r228852 289 289 #endif 290 290 291 void SubresourceLoader::didReceiveResponse(const ResourceResponse& response )291 void SubresourceLoader::didReceiveResponse(const ResourceResponse& response, CompletionHandler<void()>&& policyCompletionHandler) 292 292 { 293 293 ASSERT(!response.isNull()); 294 294 ASSERT(m_state == Initialized); 295 296 CompletionHandlerCallingScope completionHandlerCaller(WTFMove(policyCompletionHandler)); 295 297 296 298 #if USE(QUICK_LOOK) … … 336 338 m_frame->page()->diagnosticLoggingClient().logDiagnosticMessageWithResult(DiagnosticLoggingKeys::cachedResourceRevalidationKey(), emptyString(), DiagnosticLoggingResultPass, ShouldSample::Yes); 337 339 if (!reachedTerminalState()) 338 ResourceLoader::didReceiveResponse(revalidationResponse );340 ResourceLoader::didReceiveResponse(revalidationResponse, [completionHandlerCaller = WTFMove(completionHandlerCaller)] { }); 339 341 return; 340 342 } … … 357 359 return; 358 360 359 ResourceLoader::didReceiveResponse(response); 360 if (reachedTerminalState()) 361 return; 362 363 // FIXME: Main resources have a different set of rules for multipart than images do. 364 // Hopefully we can merge those 2 paths. 365 if (response.isMultipart() && m_resource->type() != CachedResource::MainResource) { 366 m_loadingMultipartContent = true; 367 368 // We don't count multiParts in a CachedResourceLoader's request count 369 m_requestCountTracker = std::nullopt; 370 if (!m_resource->isImage()) { 371 cancel(); 361 bool isResponseMultipart = response.isMultipart(); 362 ResourceLoader::didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis), isResponseMultipart, completionHandlerCaller = WTFMove(completionHandlerCaller)]() mutable { 363 if (reachedTerminalState()) 372 364 return; 373 } 374 } 375 376 auto* buffer = resourceData(); 377 if (m_loadingMultipartContent && buffer && buffer->size()) { 378 // The resource data will change as the next part is loaded, so we need to make a copy. 379 m_resource->finishLoading(buffer->copy().ptr()); 380 clearResourceData(); 381 // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once. 382 // After the first multipart section is complete, signal to delegates that this load is "finished" 383 NetworkLoadMetrics emptyMetrics; 384 m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this); 385 didFinishLoadingOnePart(emptyMetrics); 386 } 387 388 checkForHTTPStatusCodeError(); 365 366 // FIXME: Main resources have a different set of rules for multipart than images do. 367 // Hopefully we can merge those 2 paths. 368 if (isResponseMultipart && m_resource->type() != CachedResource::MainResource) { 369 m_loadingMultipartContent = true; 370 371 // We don't count multiParts in a CachedResourceLoader's request count 372 m_requestCountTracker = std::nullopt; 373 if (!m_resource->isImage()) { 374 cancel(); 375 return; 376 } 377 } 378 379 auto* buffer = resourceData(); 380 if (m_loadingMultipartContent && buffer && buffer->size()) { 381 // The resource data will change as the next part is loaded, so we need to make a copy. 382 m_resource->finishLoading(buffer->copy().ptr()); 383 clearResourceData(); 384 // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once. 385 // After the first multipart section is complete, signal to delegates that this load is "finished" 386 NetworkLoadMetrics emptyMetrics; 387 m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this); 388 didFinishLoadingOnePart(emptyMetrics); 389 } 390 391 checkForHTTPStatusCodeError(); 392 393 if (m_inAsyncResponsePolicyCheck) 394 m_policyForResponseCompletionHandler = completionHandlerCaller.release(); 395 }); 396 } 397 398 void SubresourceLoader::didReceiveResponsePolicy() 399 { 400 ASSERT(m_inAsyncResponsePolicyCheck); 401 m_inAsyncResponsePolicyCheck = false; 402 if (auto completionHandler = WTFMove(m_policyForResponseCompletionHandler)) 403 completionHandler(); 389 404 } 390 405 … … 660 675 LOG(ResourceLoading, "Cancelled load of '%s'.\n", m_resource->url().string().latin1().data()); 661 676 677 if (auto policyForResponseCompletionHandler = WTFMove(m_policyForResponseCompletionHandler)) 678 policyForResponseCompletionHandler(); 679 662 680 Ref<SubresourceLoader> protectedThis(*this); 663 681 #if PLATFORM(IOS) -
trunk/Source/WebCore/loader/SubresourceLoader.h
r228486 r228852 31 31 #include "FrameLoaderTypes.h" 32 32 #include "ResourceLoader.h" 33 #include <wtf/CompletionHandler.h> 33 34 #include <wtf/text/WTFString.h> 34 35 … … 61 62 unsigned redirectCount() const { return m_redirectCount; } 62 63 64 void markInAsyncResponsePolicyCheck() { m_inAsyncResponsePolicyCheck = true; } 65 void didReceiveResponsePolicy(); 66 63 67 private: 64 68 SubresourceLoader(Frame&, CachedResource&, const ResourceLoaderOptions&); … … 68 72 void willSendRequestInternal(ResourceRequest&&, const ResourceResponse& redirectResponse, CompletionHandler<void(ResourceRequest&&)>&&) override; 69 73 void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override; 70 void didReceiveResponse(const ResourceResponse& ) override;74 void didReceiveResponse(const ResourceResponse&, CompletionHandler<void()>&& policyCompletionHandler) override; 71 75 void didReceiveData(const char*, unsigned, long long encodedDataLength, DataPayloadType) override; 72 76 void didReceiveBuffer(Ref<SharedBuffer>&&, long long encodedDataLength, DataPayloadType) override; … … 125 129 std::optional<RequestCountTracker> m_requestCountTracker; 126 130 RefPtr<SecurityOrigin> m_origin; 131 CompletionHandler<void()> m_policyForResponseCompletionHandler; 127 132 unsigned m_redirectCount { 0 }; 128 133 bool m_loadingMultipartContent { false }; 134 bool m_inAsyncResponsePolicyCheck { false }; 129 135 }; 130 136 -
trunk/Source/WebCore/loader/ios/PreviewLoader.mm
r220809 r228852 131 131 132 132 _hasSentDidReceiveResponse = YES; 133 _resourceLoader->didReceiveResponse(response );133 _resourceLoader->didReceiveResponse(response, nullptr); 134 134 } 135 135 -
trunk/Source/WebKit/ChangeLog
r228845 r228852 1 2018-02-20 Chris Dumez <cdumez@apple.com> 2 3 Provisional load may get committed before receiving the decidePolicyForNavigationResponse response 4 https://bugs.webkit.org/show_bug.cgi?id=182720 5 <rdar://problem/37515204> 6 7 Reviewed by Alex Christensen. 8 9 * WebProcess/Network/WebResourceLoader.cpp: 10 (WebKit::WebResourceLoader::didReceiveResponse): 11 * WebProcess/Storage/ServiceWorkerClientFetch.cpp: 12 (WebKit::ServiceWorkerClientFetch::didReceiveResponse): 13 * WebProcess/WebPage/WebURLSchemeTaskProxy.cpp: 14 (WebKit::WebURLSchemeTaskProxy::didReceiveResponse): 15 1 16 2018-02-20 Matt Lewis <jlewis3@apple.com> 2 17 -
trunk/Source/WebKit/WebProcess/Network/WebResourceLoader.cpp
r228231 r228852 108 108 RELEASE_LOG_IF_ALLOWED("didReceiveResponse: (pageID = %" PRIu64 ", frameID = %" PRIu64 ", resourceID = %" PRIu64 ", status = %d)", m_trackingParameters.pageID, m_trackingParameters.frameID, m_trackingParameters.resourceID, response.httpStatusCode()); 109 109 110 Ref<WebResourceLoader> protect (*this);110 Ref<WebResourceLoader> protectedThis(*this); 111 111 112 112 if (m_coreLoader->documentLoader()->applicationCacheHost().maybeLoadFallbackForResponse(m_coreLoader.get(), response)) 113 113 return; 114 114 115 m_coreLoader->didReceiveResponse(response); 116 117 // If m_coreLoader becomes null as a result of the didReceiveResponse callback, we can't use the send function(). 118 if (!m_coreLoader) 119 return; 120 121 if (needsContinueDidReceiveResponseMessage) 122 send(Messages::NetworkResourceLoader::ContinueDidReceiveResponse()); 115 CompletionHandler<void()> policyDecisionCompletionHandler; 116 if (needsContinueDidReceiveResponseMessage) { 117 policyDecisionCompletionHandler = [this, protectedThis = WTFMove(protectedThis)] { 118 // If m_coreLoader becomes null as a result of the didReceiveResponse callback, we can't use the send function(). 119 if (m_coreLoader) 120 send(Messages::NetworkResourceLoader::ContinueDidReceiveResponse()); 121 }; 122 } 123 124 m_coreLoader->didReceiveResponse(response, WTFMove(policyDecisionCompletionHandler)); 123 125 } 124 126 -
trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.cpp
r228198 r228852 142 142 response.setURL(m_loader->request().url()); 143 143 144 m_loader->didReceiveResponse(response); 145 if (auto callback = WTFMove(m_callback)) 146 callback(Result::Succeeded); 144 m_loader->didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis)] { 145 if (auto callback = WTFMove(m_callback)) 146 callback(Result::Succeeded); 147 }); 147 148 }); 148 149 } -
trunk/Source/WebKit/WebProcess/WebPage/WebURLSchemeTaskProxy.cpp
r225358 r228852 94 94 return; 95 95 96 m_coreLoader->didReceiveResponse(response );96 m_coreLoader->didReceiveResponse(response, nullptr); 97 97 } 98 98 -
trunk/Tools/ChangeLog
r228827 r228852 1 2018-02-20 Chris Dumez <cdumez@apple.com> 2 3 Provisional load may get committed before receiving the decidePolicyForNavigationResponse response 4 https://bugs.webkit.org/show_bug.cgi?id=182720 5 <rdar://problem/37515204> 6 7 Reviewed by Alex Christensen. 8 9 Add API test coverage. 10 11 * TestWebKitAPI/Tests/WebKitCocoa/AsyncPolicyForNavigationResponse.mm: 12 (-[TestAsyncNavigationDelegate webView:decidePolicyForNavigationResponse:decisionHandler:]): 13 (TestWebKitAPI::TEST): 14 1 15 2018-02-20 Nan Wang <n_wang@apple.com> 2 16 -
trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/AsyncPolicyForNavigationResponse.mm
r228430 r228852 32 32 33 33 #if WK_API_ENABLED 34 static bool shouldAccept = true; 34 35 static bool navigationComplete = false; 35 36 static bool navigationFailed = false; … … 67 68 dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, deferredWaitTime); 68 69 dispatch_after(when, dispatch_get_main_queue(), ^{ 69 decisionHandler( WKNavigationResponsePolicyAllow);70 decisionHandler(shouldAccept ? WKNavigationResponsePolicyAllow : WKNavigationResponsePolicyCancel); 70 71 }); 71 72 } … … 83 84 [webView setUIDelegate:delegate.get()]; 84 85 86 shouldAccept = true; 87 navigationFailed = false; 88 navigationComplete = false; 85 89 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 86 90 TestWebKitAPI::Util::run(&navigationComplete); … … 89 93 } 90 94 95 TEST(WebKit, PolicyForNavigationResponseCancelAsynchronously) 96 { 97 RetainPtr<NSURL> testURL = [[NSBundle mainBundle] URLForResource:@"simple" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"]; 98 99 auto webView = adoptNS([[WKWebView alloc] init]); 100 auto delegate = adoptNS([[TestAsyncNavigationDelegate alloc] init]); 101 [webView setNavigationDelegate:delegate.get()]; 102 [webView setUIDelegate:delegate.get()]; 103 104 shouldAccept = false; 105 navigationFailed = false; 106 navigationComplete = false; 107 [webView loadRequest:[NSURLRequest requestWithURL:testURL.get()]]; 108 TestWebKitAPI::Util::run(&navigationComplete); 109 110 EXPECT_TRUE(navigationFailed); 111 } 112 91 113 } // namespace TestWebKitAPI 92 114
Note: See TracChangeset
for help on using the changeset viewer.