Diff
Modified: trunk/Source/WebKit/chromium/ChangeLog (88465 => 88466)
--- trunk/Source/WebKit/chromium/ChangeLog 2011-06-09 18:21:23 UTC (rev 88465)
+++ trunk/Source/WebKit/chromium/ChangeLog 2011-06-09 18:21:48 UTC (rev 88466)
@@ -1,3 +1,37 @@
+2011-06-09 Bill Budge <[email protected]>
+
+ Reviewed by Adam Barth.
+
+ The AssociatedURLLoader returns URL access errors synchronously. Use a timer to return such errors asynchronously. Also add unit tests for successful loads, same-origin restriction by default, and successful cross-origin loads.
+ https://bugs.webkit.org/show_bug.cgi?id=60059
+
+ * WebKit.gyp:
+ * WebKit.gypi:
+ * src/AssociatedURLLoader.cpp:
+ (WebKit::AssociatedURLLoader::ClientAdapter::clearClient):
+ (WebKit::AssociatedURLLoader::ClientAdapter::ClientAdapter):
+ (WebKit::AssociatedURLLoader::ClientAdapter::didFinishLoading):
+ (WebKit::AssociatedURLLoader::ClientAdapter::didFail):
+ (WebKit::AssociatedURLLoader::ClientAdapter::enableErrorNotifications):
+ (WebKit::AssociatedURLLoader::ClientAdapter::notifyError):
+ (WebKit::AssociatedURLLoader::loadAsynchronously):
+ * tests/AssociatedURLLoaderTest.cpp: Added.
+ (WebKit::TestWebFrameClient::cancelledError):
+ (WebKit::AssociatedURLLoaderTest::AssociatedURLLoaderTest):
+ (WebKit::AssociatedURLLoaderTest::SetUp):
+ (WebKit::AssociatedURLLoaderTest::TearDown):
+ (WebKit::AssociatedURLLoaderTest::serveRequests):
+ (WebKit::AssociatedURLLoaderTest::createAssociatedURLLoader):
+ (WebKit::AssociatedURLLoaderTest::willSendRequest):
+ (WebKit::AssociatedURLLoaderTest::didSendData):
+ (WebKit::AssociatedURLLoaderTest::didReceiveResponse):
+ (WebKit::AssociatedURLLoaderTest::didDownloadData):
+ (WebKit::AssociatedURLLoaderTest::didReceiveData):
+ (WebKit::AssociatedURLLoaderTest::didReceiveCachedMetadata):
+ (WebKit::AssociatedURLLoaderTest::didFinishLoading):
+ (WebKit::AssociatedURLLoaderTest::didFail):
+ (WebKit::TEST_F):
+
2011-06-09 Nico Weber <[email protected]>
Reviewed by Darin Fisher.
Modified: trunk/Source/WebKit/chromium/WebKit.gyp (88465 => 88466)
--- trunk/Source/WebKit/chromium/WebKit.gyp 2011-06-09 18:21:23 UTC (rev 88465)
+++ trunk/Source/WebKit/chromium/WebKit.gyp 2011-06-09 18:21:48 UTC (rev 88466)
@@ -644,6 +644,7 @@
'tests/CCThreadTest.cpp',
# These tests depend on webkit_support and
# functions defined only in !WEBKIT_IMPLEMENTATION.
+ 'tests/AssociatedURLLoaderTest.cpp',
'tests/WebFrameTest.cpp',
'tests/WebPageNewSerializerTest.cpp',
'tests/WebPageSerializerTest.cpp',
Modified: trunk/Source/WebKit/chromium/WebKit.gypi (88465 => 88466)
--- trunk/Source/WebKit/chromium/WebKit.gypi 2011-06-09 18:21:23 UTC (rev 88465)
+++ trunk/Source/WebKit/chromium/WebKit.gypi 2011-06-09 18:21:48 UTC (rev 88466)
@@ -53,6 +53,7 @@
],
'webkit_unittest_files': [
'tests/ArenaTestHelpers.h',
+ 'tests/AssociatedURLLoaderTest.cpp',
'tests/InnerGestureRecognizerTest.cpp',
'tests/CCThreadTaskTest.cpp',
'tests/CCThreadTest.cpp',
Modified: trunk/Source/WebKit/chromium/src/AssociatedURLLoader.cpp (88465 => 88466)
--- trunk/Source/WebKit/chromium/src/AssociatedURLLoader.cpp 2011-06-09 18:21:23 UTC (rev 88465)
+++ trunk/Source/WebKit/chromium/src/AssociatedURLLoader.cpp 2011-06-09 18:21:48 UTC (rev 88466)
@@ -34,6 +34,7 @@
#include "DocumentThreadableLoader.h"
#include "DocumentThreadableLoaderClient.h"
#include "SubresourceLoader.h"
+#include "Timer.h"
#include "WebApplicationCacheHost.h"
#include "WebDataSource.h"
#include "WebFrameImpl.h"
@@ -54,6 +55,7 @@
// This class bridges the interface differences between WebCore and WebKit loader clients.
// It forwards its ThreadableLoaderClient notifications to a WebURLLoaderClient.
class AssociatedURLLoader::ClientAdapter : public DocumentThreadableLoaderClient {
+ WTF_MAKE_NONCOPYABLE(ClientAdapter);
public:
static PassOwnPtr<ClientAdapter> create(AssociatedURLLoader*, WebURLLoaderClient*, bool /*downloadToFile*/);
@@ -68,16 +70,27 @@
virtual bool isDocumentThreadableLoaderClient() { return true; }
- // This method stops loading and releases the DocumentThreadableLoader as early as possible.
- void clearClient() { m_client = 0; }
+ // Enables forwarding of error notifications to the WebURLLoaderClient. These must be
+ // deferred until after the call to AssociatedURLLoader::loadAsynchronously() completes.
+ void enableErrorNotifications();
+ // Stops loading and releases the DocumentThreadableLoader as early as possible.
+ void clearClient() { m_client = 0; }
+
private:
ClientAdapter(AssociatedURLLoader*, WebURLLoaderClient*, bool /*downloadToFile*/);
+ void notifyError(Timer<ClientAdapter>*);
+
AssociatedURLLoader* m_loader;
WebURLLoaderClient* m_client;
+ WebURLError m_error;
+
+ Timer<ClientAdapter> m_errorTimer;
unsigned long m_downloadLength;
bool m_downloadToFile;
+ bool m_enableErrorNotifications;
+ bool m_didFail;
};
PassOwnPtr<AssociatedURLLoader::ClientAdapter> AssociatedURLLoader::ClientAdapter::create(AssociatedURLLoader* loader, WebURLLoaderClient* client, bool downloadToFile)
@@ -88,8 +101,11 @@
AssociatedURLLoader::ClientAdapter::ClientAdapter(AssociatedURLLoader* loader, WebURLLoaderClient* client, bool downloadToFile)
: m_loader(loader)
, m_client(client)
+ , m_errorTimer(this, &ClientAdapter::notifyError)
, m_downloadLength(0)
, m_downloadToFile(downloadToFile)
+ , m_enableErrorNotifications(false)
+ , m_didFail(false)
{
ASSERT(m_loader);
ASSERT(m_client);
@@ -144,7 +160,7 @@
if (m_downloadToFile) {
int downloadLength = m_downloadLength <= INT_MAX ? m_downloadLength : INT_MAX;
m_client->didDownloadData(m_loader, downloadLength);
- // While the client could have cancelled, continue, since the load finished.
+ // While the client could have canceled, continue, since the load finished.
}
m_client->didFinishLoading(m_loader, finishTime);
@@ -155,10 +171,28 @@
if (!m_client)
return;
- WebURLError webError(error);
- m_client->didFail(m_loader, webError);
+ m_didFail = true;
+ m_error = WebURLError(error);
+ if (m_enableErrorNotifications)
+ notifyError(&m_errorTimer);
}
+void AssociatedURLLoader::ClientAdapter::enableErrorNotifications()
+{
+ m_enableErrorNotifications = true;
+ // If an error has already been received, start a timer to report it to the client
+ // after AssociatedURLLoader::loadAsynchronously has returned to the caller.
+ if (m_didFail)
+ m_errorTimer.startOneShot(0);
+}
+
+void AssociatedURLLoader::ClientAdapter::notifyError(Timer<ClientAdapter>* timer)
+{
+ ASSERT_UNUSED(timer, timer == &m_errorTimer);
+
+ m_client->didFail(m_loader, m_error);
+}
+
AssociatedURLLoader::AssociatedURLLoader(PassRefPtr<WebFrameImpl> frameImpl)
: m_frameImpl(frameImpl)
, m_client(0)
@@ -215,8 +249,8 @@
const ResourceRequest& webcoreRequest = request.toResourceRequest();
Document* webcoreDocument = m_frameImpl->frame()->document();
m_clientAdapter = ClientAdapter::create(this, m_client, request.downloadToFile());
-
m_loader = DocumentThreadableLoader::create(webcoreDocument, m_clientAdapter.get(), webcoreRequest, options);
+ m_clientAdapter->enableErrorNotifications();
}
void AssociatedURLLoader::cancel()
Added: trunk/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp (0 => 88466)
--- trunk/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp (rev 0)
+++ trunk/Source/WebKit/chromium/tests/AssociatedURLLoaderTest.cpp 2011-06-09 18:21:48 UTC (rev 88466)
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2011 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "WebFrame.h"
+#include "WebFrameClient.h"
+#include "WebString.h"
+#include "WebURL.h"
+#include "WebURLLoader.h"
+#include "WebURLLoaderClient.h"
+#include "WebURLLoaderOptions.h"
+#include "WebURLRequest.h"
+#include "WebURLResponse.h"
+#include "WebView.h"
+
+#include <googleurl/src/gurl.h>
+#include <gtest/gtest.h>
+#include <webkit/support/webkit_support.h>
+
+using namespace WebKit;
+
+namespace {
+
+class TestWebFrameClient : public WebFrameClient {
+ // Return a non-null cancellation error so the WebFrame loaders can shut down without asserting.
+ // Make 'reason' non-zero so WebURLError isn't considered null.
+ WebURLError cancelledError(WebFrame*, const WebURLRequest& request)
+ {
+ WebURLError error;
+ error.reason = 1;
+ error.unreachableURL = request.url();
+ return error;
+ }
+};
+
+class AssociatedURLLoaderTest : public testing::Test,
+ public WebURLLoaderClient {
+public:
+ AssociatedURLLoaderTest()
+ : m_willSendRequest(false)
+ , m_didSendData(false)
+ , m_didReceiveResponse(false)
+ , m_didReceiveData(false)
+ , m_didReceiveCachedMetadata(false)
+ , m_didFinishLoading(false)
+ , m_didFail(false)
+ {
+ // Reuse one of the test files from WebFrameTest.
+ std::string filePath = webkit_support::GetWebKitRootDir().utf8();
+ filePath += "/Source/WebKit/chromium/tests/data/iframes_test.html";
+ m_frameFilePath = WebString::fromUTF8(filePath);
+ }
+
+ void SetUp()
+ {
+ m_webView = WebView::create(0);
+ m_webView->initializeMainFrame(&m_webFrameClient);
+
+ // Load the frame before trying to load resources.
+ GURL url = ""
+ WebURLResponse response;
+ response.initialize();
+ response.setMIMEType("text/html");
+ webkit_support::RegisterMockedURL(url, response, m_frameFilePath);
+
+ WebURLRequest request;
+ request.initialize();
+ request.setURL(url);
+ m_webView->mainFrame()->loadRequest(request);
+ serveRequests();
+
+ webkit_support::UnregisterMockedURL(url);
+ }
+
+ void TearDown()
+ {
+ webkit_support::UnregisterAllMockedURLs();
+ m_webView->close();
+ }
+
+ void serveRequests()
+ {
+ webkit_support::ServeAsynchronousMockedRequests();
+ }
+
+ WebURLLoader* createAssociatedURLLoader(const WebURLLoaderOptions options = WebURLLoaderOptions())
+ {
+ return m_webView->mainFrame()->createAssociatedURLLoader(options);
+ }
+
+ // WebURLLoaderClient implementation.
+ void willSendRequest(WebURLLoader* loader, WebURLRequest& newRequest, const WebURLResponse& redirectResponse)
+ {
+ m_willSendRequest = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ EXPECT_EQ(m_expectedNewRequest.url(), newRequest.url());
+ EXPECT_EQ(m_expectedRedirectResponse.url(), redirectResponse.url());
+ EXPECT_EQ(m_expectedRedirectResponse.mimeType(), redirectResponse.mimeType());
+ EXPECT_EQ(m_expectedRedirectResponse.httpStatusCode(), redirectResponse.httpStatusCode());
+ }
+
+ void didSendData(WebURLLoader* loader, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
+ {
+ m_didSendData = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ }
+
+ void didReceiveResponse(WebURLLoader* loader, const WebURLResponse& response)
+ {
+ m_didReceiveResponse = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ EXPECT_EQ(m_expectedResponse.url(), response.url());
+ EXPECT_EQ(m_expectedResponse.httpStatusCode(), response.httpStatusCode());
+ }
+
+ void didDownloadData(WebURLLoader* loader, int dataLength)
+ {
+ m_didDownloadData = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ }
+
+ void didReceiveData(WebURLLoader* loader, const char* data, int dataLength, int encodedDataLength)
+ {
+ m_didReceiveData = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ EXPECT_TRUE(data);
+ EXPECT_GT(dataLength, 0);
+ }
+
+ void didReceiveCachedMetadata(WebURLLoader* loader, const char* data, int dataLength)
+ {
+ m_didReceiveCachedMetadata = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ }
+
+ void didFinishLoading(WebURLLoader* loader, double finishTime)
+ {
+ m_didFinishLoading = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ }
+
+ void didFail(WebURLLoader* loader, const WebURLError& error)
+ {
+ m_didFail = true;
+ EXPECT_EQ(m_expectedLoader, loader);
+ webkit_support::QuitMessageLoop();
+ }
+
+protected:
+ WebString m_frameFilePath;
+ TestWebFrameClient m_webFrameClient;
+ WebView* m_webView;
+
+ WebURLLoader* m_expectedLoader;
+ WebURLResponse m_expectedResponse;
+ WebURLRequest m_expectedNewRequest;
+ WebURLResponse m_expectedRedirectResponse;
+ bool m_willSendRequest;
+ bool m_didSendData;
+ bool m_didReceiveResponse;
+ bool m_didDownloadData;
+ bool m_didReceiveData;
+ bool m_didReceiveCachedMetadata;
+ bool m_didFinishLoading;
+ bool m_didFail;
+};
+
+// Test a successful URL load.
+TEST_F(AssociatedURLLoaderTest, Success)
+{
+ GURL url = ""
+ WebURLRequest request;
+ request.initialize();
+ request.setURL(url);
+
+ m_expectedResponse = WebURLResponse();
+ m_expectedResponse.initialize();
+ m_expectedResponse.setMIMEType("text/html");
+ webkit_support::RegisterMockedURL(url, m_expectedResponse, m_frameFilePath);
+
+ m_expectedLoader = createAssociatedURLLoader();
+ EXPECT_TRUE(m_expectedLoader);
+ m_expectedLoader->loadAsynchronously(request, this);
+ serveRequests();
+ EXPECT_TRUE(m_didReceiveResponse);
+ EXPECT_TRUE(m_didReceiveData);
+ EXPECT_TRUE(m_didFinishLoading);
+}
+
+// Test that the same-origin restriction is the default.
+TEST_F(AssociatedURLLoaderTest, SameOriginRestriction)
+{
+ // This is cross-origin since the frame was loaded from www.test.com.
+ GURL url = ""
+ WebURLRequest request;
+ request.initialize();
+ request.setURL(url);
+
+ m_expectedLoader = createAssociatedURLLoader();
+ EXPECT_TRUE(m_expectedLoader);
+ m_expectedLoader->loadAsynchronously(request, this);
+ // Failure should not be reported synchronously.
+ EXPECT_FALSE(m_didFail);
+ // Allow the loader to return the error.
+ webkit_support::RunMessageLoop();
+ EXPECT_TRUE(m_didFail);
+}
+
+// Test a successful cross-origin load.
+TEST_F(AssociatedURLLoaderTest, CrossOriginSuccess)
+{
+ // This is cross-origin since the frame was loaded from www.test.com.
+ GURL url = ""
+ WebURLRequest request;
+ request.initialize();
+ request.setURL(url);
+
+ m_expectedResponse = WebURLResponse();
+ m_expectedResponse.initialize();
+ m_expectedResponse.setMIMEType("text/html");
+ webkit_support::RegisterMockedURL(url, m_expectedResponse, m_frameFilePath);
+
+ WebURLLoaderOptions options;
+ options.crossOriginRequestPolicy = WebURLLoaderOptions::CrossOriginRequestPolicyAllow;
+ m_expectedLoader = createAssociatedURLLoader(options);
+ EXPECT_TRUE(m_expectedLoader);
+ m_expectedLoader->loadAsynchronously(request, this);
+ serveRequests();
+ EXPECT_TRUE(m_didReceiveResponse);
+ EXPECT_TRUE(m_didReceiveData);
+ EXPECT_TRUE(m_didFinishLoading);
+}
+
+}