- Revision
- 229477
- Author
- [email protected]
- Date
- 2018-03-09 12:47:11 -0800 (Fri, 09 Mar 2018)
Log Message
ServiceWorkerClientFetch should send data to its resource loader once the didReceiveResponse completion handler is called
https://bugs.webkit.org/show_bug.cgi?id=183110
Reviewed by Chris Dumez.
Buffering data/finish event/fail event until the response completion handler is called.
* WebProcess/Storage/ServiceWorkerClientFetch.cpp:
(WebKit::ServiceWorkerClientFetch::didReceiveResponse):
(WebKit::ServiceWorkerClientFetch::didReceiveData):
(WebKit::ServiceWorkerClientFetch::didFinish):
(WebKit::ServiceWorkerClientFetch::didFail):
(WebKit::ServiceWorkerClientFetch::didNotHandle):
(WebKit::ServiceWorkerClientFetch::cancel):
(WebKit::ServiceWorkerClientFetch::continueLoadingAfterCheckingResponse):
* WebProcess/Storage/ServiceWorkerClientFetch.h:
Modified Paths
Diff
Modified: trunk/Source/WebKit/ChangeLog (229476 => 229477)
--- trunk/Source/WebKit/ChangeLog 2018-03-09 20:27:40 UTC (rev 229476)
+++ trunk/Source/WebKit/ChangeLog 2018-03-09 20:47:11 UTC (rev 229477)
@@ -1,3 +1,22 @@
+2018-03-09 Youenn Fablet <[email protected]>
+
+ ServiceWorkerClientFetch should send data to its resource loader once the didReceiveResponse completion handler is called
+ https://bugs.webkit.org/show_bug.cgi?id=183110
+
+ Reviewed by Chris Dumez.
+
+ Buffering data/finish event/fail event until the response completion handler is called.
+
+ * WebProcess/Storage/ServiceWorkerClientFetch.cpp:
+ (WebKit::ServiceWorkerClientFetch::didReceiveResponse):
+ (WebKit::ServiceWorkerClientFetch::didReceiveData):
+ (WebKit::ServiceWorkerClientFetch::didFinish):
+ (WebKit::ServiceWorkerClientFetch::didFail):
+ (WebKit::ServiceWorkerClientFetch::didNotHandle):
+ (WebKit::ServiceWorkerClientFetch::cancel):
+ (WebKit::ServiceWorkerClientFetch::continueLoadingAfterCheckingResponse):
+ * WebProcess/Storage/ServiceWorkerClientFetch.h:
+
2018-03-09 Jer Noble <[email protected]>
Add new CSS env constants for use with fullscreen
Modified: trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.cpp (229476 => 229477)
--- trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.cpp 2018-03-09 20:27:40 UTC (rev 229476)
+++ trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.cpp 2018-03-09 20:47:11 UTC (rev 229477)
@@ -106,6 +106,7 @@
if (auto error = validateResponse(response)) {
m_loader->didFail(error.value());
+ ASSERT(!m_loader);
if (auto callback = WTFMove(m_callback))
callback(Result::Succeeded);
return;
@@ -141,7 +142,10 @@
if (response.url().isNull())
response.setURL(m_loader->request().url());
+ m_isCheckingResponse = true;
m_loader->didReceiveResponse(response, [this, protectedThis = WTFMove(protectedThis)] {
+ m_isCheckingResponse = false;
+ continueLoadingAfterCheckingResponse();
if (auto callback = WTFMove(m_callback))
callback(Result::Succeeded);
});
@@ -148,13 +152,26 @@
});
}
-void ServiceWorkerClientFetch::didReceiveData(const IPC::DataReference& data, int64_t encodedDataLength)
+void ServiceWorkerClientFetch::didReceiveData(const IPC::DataReference& dataReference, int64_t encodedDataLength)
{
- callOnMainThread([this, protectedThis = makeRef(*this), data = "" encodedDataLength] {
+ auto* data = "" char*>(dataReference.data());
+ if (!m_buffer) {
+ m_buffer = SharedBuffer::create(data, dataReference.size());
+ m_encodedDataLength = encodedDataLength;
+ } else {
+ m_buffer->append(data, dataReference.size());
+ m_encodedDataLength += encodedDataLength;
+ }
+
+ if (m_isCheckingResponse)
+ return;
+
+ callOnMainThread([this, protectedThis = makeRef(*this)] {
if (!m_loader)
return;
- m_loader->didReceiveData(reinterpret_cast<const char*>(data.data()), data.size(), encodedDataLength, DataPayloadBytes);
+ m_loader->didReceiveBuffer(m_buffer.releaseNonNull(), m_encodedDataLength, DataPayloadBytes);
+ m_encodedDataLength = 0;
});
}
@@ -165,6 +182,11 @@
void ServiceWorkerClientFetch::didFinish()
{
+ m_didFinish = true;
+
+ if (m_isCheckingResponse)
+ return;
+
callOnMainThread([this, protectedThis = makeRef(*this)] {
if (!m_loader)
return;
@@ -192,6 +214,11 @@
void ServiceWorkerClientFetch::didFail()
{
+ m_didFail = true;
+
+ if (m_isCheckingResponse)
+ return;
+
callOnMainThread([this, protectedThis = makeRef(*this)] {
if (!m_loader)
return;
@@ -207,6 +234,8 @@
void ServiceWorkerClientFetch::didNotHandle()
{
+ ASSERT(!m_isCheckingResponse);
+
callOnMainThread([this, protectedThis = makeRef(*this)] {
if (!m_loader)
return;
@@ -223,8 +252,33 @@
if (auto callback = WTFMove(m_callback))
callback(Result::Cancelled);
m_loader = nullptr;
+ m_buffer = nullptr;
}
+void ServiceWorkerClientFetch::continueLoadingAfterCheckingResponse()
+{
+ ASSERT(!m_isCheckingResponse);
+ if (!m_loader)
+ return;
+
+ if (m_encodedDataLength) {
+ callOnMainThread([this, protectedThis = makeRef(*this)] {
+ if (!m_loader || !m_encodedDataLength)
+ return;
+ m_loader->didReceiveBuffer(m_buffer.releaseNonNull(), m_encodedDataLength, DataPayloadBytes);
+ m_encodedDataLength = 0;
+ });
+ }
+
+ if (m_didFail) {
+ didFail();
+ return;
+ }
+
+ if (m_didFinish)
+ didFinish();
+}
+
} // namespace WebKit
#endif // ENABLE(SERVICE_WORKER)
Modified: trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.h (229476 => 229477)
--- trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.h 2018-03-09 20:27:40 UTC (rev 229476)
+++ trunk/Source/WebKit/WebProcess/Storage/ServiceWorkerClientFetch.h 2018-03-09 20:47:11 UTC (rev 229477)
@@ -66,6 +66,8 @@
void didFail();
void didNotHandle();
+ void continueLoadingAfterCheckingResponse();
+
WebServiceWorkerProvider& m_serviceWorkerProvider;
RefPtr<WebCore::ResourceLoader> m_loader;
uint64_t m_identifier { 0 };
@@ -74,6 +76,11 @@
enum class RedirectionStatus { None, Receiving, Following, Received };
RedirectionStatus m_redirectionStatus { RedirectionStatus::None };
bool m_shouldClearReferrerOnHTTPSToHTTPRedirect { true };
+ RefPtr<WebCore::SharedBuffer> m_buffer;
+ int64_t m_encodedDataLength { 0 };
+ bool m_isCheckingResponse { false };
+ bool m_didFinish { false };
+ bool m_didFail { false };
};
} // namespace WebKit
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm (229476 => 229477)
--- trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm 2018-03-09 20:27:40 UTC (rev 229476)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ServiceWorkerBasic.mm 2018-03-09 20:47:11 UTC (rev 229477)
@@ -153,6 +153,48 @@
@end
+static bool shouldAccept = true;
+static bool navigationComplete = false;
+static bool navigationFailed = false;
+
+@interface TestSWAsyncNavigationDelegate : NSObject <WKNavigationDelegate, WKUIDelegate>
+@end
+
+@implementation TestSWAsyncNavigationDelegate
+
+- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation
+{
+ navigationComplete = true;
+}
+
+- (void)webView:(WKWebView *)webView didFailNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
+{
+ navigationFailed = true;
+ navigationComplete = true;
+}
+
+- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(null_unspecified WKNavigation *)navigation withError:(NSError *)error
+{
+ navigationFailed = true;
+ navigationComplete = true;
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
+{
+ decisionHandler(WKNavigationActionPolicyAllow);
+}
+
+- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler
+{
+ int64_t deferredWaitTime = 100 * NSEC_PER_MSEC;
+ dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, deferredWaitTime);
+ dispatch_after(when, dispatch_get_main_queue(), ^{
+ decisionHandler(shouldAccept ? WKNavigationResponsePolicyAllow : WKNavigationResponsePolicyCancel);
+ });
+}
+@end
+
+
static const char* mainBytes = R"SWRESOURCE(
<script>
@@ -618,6 +660,97 @@
done = false;
}
+TEST(ServiceWorkers, WaitForPolicyDelegate)
+{
+ [WKWebsiteDataStore _allowWebsiteDataRecordsForAllOrigins];
+
+ // Start with a clean slate data store
+ [[WKWebsiteDataStore defaultDataStore] removeDataOfTypes:[WKWebsiteDataStore allWebsiteDataTypes] modifiedSince:[NSDate distantPast] completionHandler:^() {
+ done = true;
+ }];
+ TestWebKitAPI::Util::run(&done);
+ done = false;
+
+ RetainPtr<WKWebViewConfiguration> configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+
+ RetainPtr<SWMessageHandlerWithExpectedMessage> messageHandler = adoptNS([[SWMessageHandlerWithExpectedMessage alloc] init]);
+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+ RetainPtr<SWSchemes> handler = adoptNS([[SWSchemes alloc] init]);
+ handler->resources.set("sw://host/main.html", ResourceInfo { @"text/html", mainForFirstLoadInterceptTestBytes });
+ handler->resources.set("sw://host/sw.js", ResourceInfo { @"application/_javascript_", scriptInterceptingFirstLoadBytes });
+ [configuration setURLSchemeHandler:handler.get() forURLScheme:@"SW"];
+
+ RetainPtr<WKWebView> webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+ [webView.get().configuration.processPool _registerURLSchemeServiceWorkersCanHandle:@"sw"];
+
+ // Register a service worker and activate it.
+ expectedMessage = "Service Worker activated";
+ NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"sw://host/main.html"]];
+ [webView loadRequest:request];
+
+ TestWebKitAPI::Util::run(&done);
+
+ webView = nullptr;
+ configuration = nullptr;
+ messageHandler = nullptr;
+ handler = nullptr;
+
+ done = false;
+
+ configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
+ messageHandler = adoptNS([[SWMessageHandlerWithExpectedMessage alloc] init]);
+ [[configuration userContentController] addScriptMessageHandler:messageHandler.get() name:@"sw"];
+
+ handler = adoptNS([[SWSchemes alloc] init]);
+ handler->resources.set("sw://host/main.html", ResourceInfo { @"text/html", mainForFirstLoadInterceptTestBytes });
+ handler->resources.set("sw://host/sw.js", ResourceInfo { @"application/_javascript_", scriptInterceptingFirstLoadBytes });
+ [configuration setURLSchemeHandler:handler.get() forURLScheme:@"SW"];
+
+ webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+ [webView.get().configuration.processPool _registerURLSchemeServiceWorkersCanHandle:@"sw"];
+
+ // Verify service worker is intercepting load.
+ expectedMessage = "Intercepted by worker";
+ request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"sw://host/main.html"]];
+ [webView loadRequest:request];
+
+ TestWebKitAPI::Util::run(&done);
+ done = false;
+
+ webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+ [webView.get().configuration.processPool _registerURLSchemeServiceWorkersCanHandle:@"sw"];
+ auto delegate = adoptNS([[TestSWAsyncNavigationDelegate alloc] init]);
+ [webView setNavigationDelegate:delegate.get()];
+ [webView setUIDelegate:delegate.get()];
+
+ shouldAccept = true;
+ navigationFailed = false;
+ navigationComplete = false;
+
+ // Verify service worker load goes well when policy delegate is ok.
+ request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"sw://host/main.html"]];
+ [webView loadRequest:request];
+ TestWebKitAPI::Util::run(&navigationComplete);
+
+ EXPECT_FALSE(navigationFailed);
+
+ webView = adoptNS([[WKWebView alloc] initWithFrame:NSMakeRect(0, 0, 800, 600) configuration:configuration.get()]);
+ [webView.get().configuration.processPool _registerURLSchemeServiceWorkersCanHandle:@"sw"];
+ [webView setNavigationDelegate:delegate.get()];
+ [webView setUIDelegate:delegate.get()];
+
+ shouldAccept = false;
+ navigationFailed = false;
+ navigationComplete = false;
+
+ // Verify service worker load fails well when policy delegate is not ok.
+ request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"sw://host/main.html"]];
+ [webView loadRequest:request];
+ TestWebKitAPI::Util::run(&navigationComplete);
+
+ EXPECT_TRUE(navigationFailed);
+}
#if WK_HAVE_C_SPI
void setConfigurationInjectedBundlePath(WKWebViewConfiguration* configuration)