summaryrefslogtreecommitdiffstats
path: root/android_webview
diff options
context:
space:
mode:
authormnaganov <mnaganov@chromium.org>2015-03-17 08:56:44 -0700
committerCommit bot <commit-bot@chromium.org>2015-03-17 15:57:21 +0000
commita83c3cafa72c29051cbcf2b5a26a33d488559547 (patch)
tree58b436443cf4aa5288e81ed5813401a2cc74e349 /android_webview
parent12cf7b569a3dc4cbf0f5ee88377bae8e47fc6653 (diff)
downloadchromium_src-a83c3cafa72c29051cbcf2b5a26a33d488559547.zip
chromium_src-a83c3cafa72c29051cbcf2b5a26a33d488559547.tar.gz
chromium_src-a83c3cafa72c29051cbcf2b5a26a33d488559547.tar.bz2
[Android WebView] Implement a better OnReceivedError callback
The new callback (aptly named OnReceivedError2) is also called for subresource load failures and provides more information about the failed request. Note that calling OnReceivedError2 is not yet implemented for requests blocked due to security considerations by Blink. This will be implemented separately. BUG=456782 Review URL: https://codereview.chromium.org/1001003004 Cr-Commit-Position: refs/heads/master@{#320923}
Diffstat (limited to 'android_webview')
-rw-r--r--android_webview/browser/aw_contents_io_thread_client.h5
-rw-r--r--android_webview/browser/aw_request_interceptor.cc5
-rw-r--r--android_webview/browser/aw_request_interceptor.h1
-rw-r--r--android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc18
-rw-r--r--android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h2
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java26
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java10
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java26
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java4
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java26
-rw-r--r--android_webview/java/src/org/chromium/android_webview/ErrorCodeConversionHelper.java2
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java47
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java17
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java414
-rw-r--r--android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java32
-rw-r--r--android_webview/native/aw_contents_io_thread_client_impl.cc142
-rw-r--r--android_webview/native/aw_contents_io_thread_client_impl.h2
17 files changed, 636 insertions, 143 deletions
diff --git a/android_webview/browser/aw_contents_io_thread_client.h b/android_webview/browser/aw_contents_io_thread_client.h
index 15fddc8..e240976 100644
--- a/android_webview/browser/aw_contents_io_thread_client.h
+++ b/android_webview/browser/aw_contents_io_thread_client.h
@@ -70,7 +70,6 @@ class AwContentsIoThreadClient {
// This method is called on the IO thread only.
virtual scoped_ptr<AwWebResourceResponse> ShouldInterceptRequest(
- const GURL& location,
const net::URLRequest* request) = 0;
// Retrieve the AllowContentAccess setting value of this AwContents.
@@ -104,6 +103,10 @@ class AwContentsIoThreadClient {
const std::string& account,
const std::string& args) = 0;
+ // Called when a resource loading error has occured (e.g. an I/O error,
+ // host name lookup failure etc.)
+ virtual void OnReceivedError(const net::URLRequest* request) = 0;
+
// Called when a response from the server is received with status code >= 400.
virtual void OnReceivedHttpError(
const net::URLRequest* request,
diff --git a/android_webview/browser/aw_request_interceptor.cc b/android_webview/browser/aw_request_interceptor.cc
index 381a8ab..45adfb6 100644
--- a/android_webview/browser/aw_request_interceptor.cc
+++ b/android_webview/browser/aw_request_interceptor.cc
@@ -36,7 +36,6 @@ AwRequestInterceptor::~AwRequestInterceptor() {
scoped_ptr<AwWebResourceResponse>
AwRequestInterceptor::QueryForAwWebResourceResponse(
- const GURL& location,
net::URLRequest* request) const {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
int render_process_id, render_frame_id;
@@ -50,7 +49,7 @@ AwRequestInterceptor::QueryForAwWebResourceResponse(
if (!io_thread_client.get())
return scoped_ptr<AwWebResourceResponse>();
- return io_thread_client->ShouldInterceptRequest(location, request).Pass();
+ return io_thread_client->ShouldInterceptRequest(request).Pass();
}
net::URLRequestJob* AwRequestInterceptor::MaybeInterceptRequest(
@@ -71,7 +70,7 @@ net::URLRequestJob* AwRequestInterceptor::MaybeInterceptRequest(
new base::SupportsUserData::Data());
scoped_ptr<AwWebResourceResponse> aw_web_resource_response =
- QueryForAwWebResourceResponse(request->url(), request);
+ QueryForAwWebResourceResponse(request);
if (!aw_web_resource_response)
return NULL;
diff --git a/android_webview/browser/aw_request_interceptor.h b/android_webview/browser/aw_request_interceptor.h
index adbb18b..a3c54b3 100644
--- a/android_webview/browser/aw_request_interceptor.h
+++ b/android_webview/browser/aw_request_interceptor.h
@@ -36,7 +36,6 @@ class AwRequestInterceptor : public net::URLRequestInterceptor {
private:
scoped_ptr<AwWebResourceResponse> QueryForAwWebResourceResponse(
- const GURL& location,
net::URLRequest* request) const;
DISALLOW_COPY_AND_ASSIGN(AwRequestInterceptor);
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index 36f37d4..dfa4aa2 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -24,6 +24,7 @@
#include "net/base/net_errors.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_status.h"
#include "url/url_constants.h"
using android_webview::AwContentsIoThreadClient;
@@ -241,6 +242,23 @@ void AwResourceDispatcherHostDelegate::OnRequestRedirected(
AddExtraHeadersIfNeeded(request, resource_context);
}
+void AwResourceDispatcherHostDelegate::RequestComplete(
+ net::URLRequest* request) {
+ if (request && !request->status().is_success()) {
+ const content::ResourceRequestInfo* request_info =
+ content::ResourceRequestInfo::ForRequest(request);
+ scoped_ptr<AwContentsIoThreadClient> io_client =
+ AwContentsIoThreadClient::FromID(request_info->GetChildID(),
+ request_info->GetRenderFrameID());
+ if (io_client) {
+ io_client->OnReceivedError(request);
+ } else {
+ DLOG(WARNING) << "io_client is null, onReceivedError dropped for " <<
+ request->url();
+ }
+ }
+}
+
void AwResourceDispatcherHostDelegate::DownloadStarting(
net::URLRequest* request,
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
index dd08235..3add203 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
@@ -60,6 +60,8 @@ class AwResourceDispatcherHostDelegate
content::ResourceContext* resource_context,
content::ResourceResponse* response) override;
+ void RequestComplete(net::URLRequest* request) override;
+
void RemovePendingThrottleOnIoThread(IoThreadClientThrottle* throttle);
static void OnIoThreadClientReady(int new_render_process_id,
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index 8fa1b33..96d3481 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -62,6 +62,7 @@ import org.chromium.content_public.browser.WebContents;
import org.chromium.content_public.browser.navigation_controller.LoadURLType;
import org.chromium.content_public.browser.navigation_controller.UserAgentOverrideOption;
import org.chromium.content_public.common.Referrer;
+import org.chromium.net.NetError;
import org.chromium.ui.base.ActivityWindowAndroid;
import org.chromium.ui.base.PageTransition;
import org.chromium.ui.base.WindowAndroid;
@@ -419,6 +420,31 @@ public class AwContents implements SmartClipProvider,
}
@Override
+ public void onReceivedError(AwContentsClient.AwWebResourceRequest request,
+ AwContentsClient.AwWebResourceError error) {
+ String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
+ boolean isErrorUrl =
+ unreachableWebDataUrl != null && unreachableWebDataUrl.equals(request.url);
+ if (!isErrorUrl && error.errorCode != NetError.ERR_ABORTED) {
+ // NetError.ERR_ABORTED error code is generated for the following reasons:
+ // - WebView.stopLoading is called;
+ // - the navigation is intercepted by the embedder via shouldOverrideUrlLoading;
+ // - server returned 204 status (no content).
+ //
+ // Android WebView does not notify the embedder of these situations using
+ // this error code with the WebViewClient.onReceivedError callback.
+ error.errorCode = ErrorCodeConversionHelper.convertErrorCode(error.errorCode);
+ mContentsClient.getCallbackHelper().postOnReceivedError(request, error);
+ if (request.isMainFrame) {
+ // Need to call onPageFinished after onReceivedError for backwards compatibility
+ // with the classic webview. See also AwWebContentsObserver.didFailLoad which is
+ // used when we want to send onPageFinished alone.
+ mContentsClient.getCallbackHelper().postOnPageFinished(request.url);
+ }
+ }
+ }
+
+ @Override
public void onReceivedHttpError(AwContentsClient.AwWebResourceRequest request,
AwWebResourceResponse response) {
mContentsClient.getCallbackHelper().postOnReceivedHttpError(request, response);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java b/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
index 73dd0c8..500d22c 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsClientCallbackHelper.java
@@ -88,6 +88,7 @@ public class AwContentsClientCallbackHelper {
private static final int MSG_ON_NEW_PICTURE = 6;
private static final int MSG_ON_SCALE_CHANGED_SCALED = 7;
private static final int MSG_ON_RECEIVED_HTTP_ERROR = 8;
+ private static final int MSG_ON_PAGE_FINISHED = 9;
// Minimum period allowed between consecutive onNewPicture calls, to rate-limit the callbacks.
private static final long ON_NEW_PICTURE_MIN_PERIOD_MILLIS = 500;
@@ -157,6 +158,11 @@ public class AwContentsClientCallbackHelper {
mContentsClient.onReceivedHttpError(info.mRequest, info.mResponse);
break;
}
+ case MSG_ON_PAGE_FINISHED: {
+ final String url = (String) msg.obj;
+ mContentsClient.onPageFinished(url);
+ break;
+ }
default:
throw new IllegalStateException(
"AwContentsClientCallbackHelper: unhandled message " + msg.what);
@@ -219,4 +225,8 @@ public class AwContentsClientCallbackHelper {
new OnReceivedHttpErrorInfo(request, response);
mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_RECEIVED_HTTP_ERROR, info));
}
+
+ public void postOnPageFinished(String url) {
+ mHandler.sendMessage(mHandler.obtainMessage(MSG_ON_PAGE_FINISHED, url));
+ }
}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java b/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java
index d298c25..07c0299 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsIoThreadClient.java
@@ -43,6 +43,9 @@ public abstract class AwContentsIoThreadClient {
public abstract AwWebResourceResponse shouldInterceptRequest(
AwContentsClient.AwWebResourceRequest request);
+ public abstract void onReceivedError(AwContentsClient.AwWebResourceRequest request,
+ AwContentsClient.AwWebResourceError error);
+
public abstract void onReceivedHttpError(AwContentsClient.AwWebResourceRequest request,
AwWebResourceResponse response);
@@ -66,6 +69,29 @@ public abstract class AwContentsIoThreadClient {
}
@CalledByNative
+ protected void onReceivedError(
+ // WebResourceRequest
+ String url, boolean isMainFrame, boolean hasUserGesture, String method,
+ String[] requestHeaderNames, String[] requestHeaderValues,
+ // WebResourceError
+ int errorCode, String description) {
+ AwContentsClient.AwWebResourceRequest request =
+ new AwContentsClient.AwWebResourceRequest();
+ request.url = url;
+ request.isMainFrame = isMainFrame;
+ request.hasUserGesture = hasUserGesture;
+ request.method = method;
+ request.requestHeaders = new HashMap<String, String>(requestHeaderNames.length);
+ for (int i = 0; i < requestHeaderNames.length; ++i) {
+ request.requestHeaders.put(requestHeaderNames[i], requestHeaderValues[i]);
+ }
+ AwContentsClient.AwWebResourceError error = new AwContentsClient.AwWebResourceError();
+ error.errorCode = errorCode;
+ error.description = description;
+ onReceivedError(request, error);
+ }
+
+ @CalledByNative
protected void onReceivedHttpError(
// WebResourceRequest
String url, boolean isMainFrame, boolean hasUserGesture, String method,
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
index dab4274..f38c7342 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContentsStatics.java
@@ -64,6 +64,10 @@ public class AwContentsStatics {
}
public static String getUnreachableWebDataUrl() {
+ // Note that this method may be called from both IO and UI threads,
+ // but as it only retrieves a value of a constant from native, even if
+ // two calls will be running at the same time, this should not cause
+ // any harm.
if (sUnreachableWebDataUrl == null) {
sUnreachableWebDataUrl = nativeGetUnreachableWebDataUrl();
}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
index a248d39..f985369 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwWebContentsObserver.java
@@ -51,29 +51,9 @@ public class AwWebContentsObserver extends WebContentsObserver {
String unreachableWebDataUrl = AwContentsStatics.getUnreachableWebDataUrl();
boolean isErrorUrl =
unreachableWebDataUrl != null && unreachableWebDataUrl.equals(failingUrl);
- if (isErrorUrl) return;
- if (errorCode != NetError.ERR_ABORTED) {
- // This error code is generated for the following reasons:
- // - WebView.stopLoading is called,
- // - the navigation is intercepted by the embedder via shouldOverrideNavigation.
- //
- // The Android WebView does not notify the embedder of these situations using
- // this error code with the WebViewClient.onReceivedError callback.
- AwContentsClient.AwWebResourceRequest request =
- new AwContentsClient.AwWebResourceRequest();
- request.url = failingUrl;
- request.isMainFrame = isMainFrame;
- // TODO(mnaganov): Fill in the rest of AwWebResourceRequest fields. Probably,
- // we will have to actually invoke the error callback from the network delegate
- // in order to catch load errors for all resources.
- AwContentsClient.AwWebResourceError error = new AwContentsClient.AwWebResourceError();
- error.errorCode = ErrorCodeConversionHelper.convertErrorCode(errorCode);
- error.description = description;
- mAwContentsClient.onReceivedError(request, error);
- }
- if (isMainFrame) {
- // Need to call onPageFinished after onReceivedError (if there is an error) for
- // backwards compatibility with the classic webview.
+ if (isMainFrame && !isErrorUrl && errorCode == NetError.ERR_ABORTED) {
+ // Need to call onPageFinished for backwards compatibility with the classic webview.
+ // See also AwContents.IoThreadClientImpl.onReceivedError.
mAwContentsClient.onPageFinished(failingUrl);
}
}
diff --git a/android_webview/java/src/org/chromium/android_webview/ErrorCodeConversionHelper.java b/android_webview/java/src/org/chromium/android_webview/ErrorCodeConversionHelper.java
index a4d3888..7656d8e 100644
--- a/android_webview/java/src/org/chromium/android_webview/ErrorCodeConversionHelper.java
+++ b/android_webview/java/src/org/chromium/android_webview/ErrorCodeConversionHelper.java
@@ -42,6 +42,8 @@ public abstract class ErrorCodeConversionHelper {
public static final int ERROR_FILE_NOT_FOUND = -14;
// Too many requests during this load
public static final int ERROR_TOO_MANY_REQUESTS = -15;
+ // Request blocked by the browser
+ public static final int ERROR_BLOCKED = -16;
static int convertErrorCode(int netError) {
// Note: many NetError.Error constants don't have an obvious mapping.
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java
index eb3d7f7..db0e1e3 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/AwWebContentsObserverTest.java
@@ -11,7 +11,6 @@ import org.chromium.android_webview.AwContentsStatics;
import org.chromium.android_webview.AwWebContentsObserver;
import org.chromium.base.test.util.Feature;
import org.chromium.base.test.util.MinAndroidSdkLevel;
-import org.chromium.net.NetError;
/**
* Tests for the AwWebContentsObserver class.
@@ -65,26 +64,6 @@ public class AwWebContentsObserverTest extends AwTestBase {
assertEquals("onPageFinished should be called for main frame navigations.", callCount + 1,
mContentsClient.getOnPageFinishedHelper().getCallCount());
- boolean provisionalLoad = true;
-
- callCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
- mWebContentsObserver.didFailLoad(!provisionalLoad, mainFrame,
- NetError.ERR_ABORTED, ERROR_DESCRIPTION, EXAMPLE_URL);
- assertEquals("onPageFinished should be called for main frame errors.", callCount + 1,
- mContentsClient.getOnPageFinishedHelper().getCallCount());
-
- callCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
- mWebContentsObserver.didFailLoad(!provisionalLoad, subFrame,
- NetError.ERR_ABORTED, ERROR_DESCRIPTION, EXAMPLE_URL);
- assertEquals("onPageFinished should only be called for main frame errors.", callCount,
- mContentsClient.getOnPageFinishedHelper().getCallCount());
-
- callCount = mContentsClient.getOnPageFinishedHelper().getCallCount();
- mWebContentsObserver.didFailLoad(!provisionalLoad, mainFrame,
- NetError.ERR_ABORTED, ERROR_DESCRIPTION, mUnreachableWebDataUrl);
- assertEquals("onPageFinished should not be called on unrechable url errors.", callCount,
- mContentsClient.getOnPageFinishedHelper().getCallCount());
-
String baseUrl = null;
boolean navigationToDifferentPage = true;
boolean fragmentNavigation = true;
@@ -104,32 +83,6 @@ public class AwWebContentsObserverTest extends AwTestBase {
@SmallTest
@Feature({"AndroidWebView"})
- public void testOnReceivedError() {
- boolean provisionalLoad = true;
- boolean mainFrame = true;
- boolean subFrame = false;
-
- int callCount = mContentsClient.getOnReceivedErrorHelper().getCallCount();
- mWebContentsObserver.didFailLoad(!provisionalLoad, subFrame,
- NetError.ERR_TIMED_OUT, ERROR_DESCRIPTION, EXAMPLE_URL);
- assertEquals("onReceivedError should only be called for the main frame", callCount,
- mContentsClient.getOnReceivedErrorHelper().getCallCount());
-
- callCount = mContentsClient.getOnReceivedErrorHelper().getCallCount();
- mWebContentsObserver.didFailLoad(!provisionalLoad, mainFrame,
- NetError.ERR_TIMED_OUT, ERROR_DESCRIPTION, EXAMPLE_URL);
- assertEquals("onReceivedError should be called for the main frame", callCount + 1,
- mContentsClient.getOnReceivedErrorHelper().getCallCount());
-
- callCount = mContentsClient.getOnReceivedErrorHelper().getCallCount();
- mWebContentsObserver.didFailLoad(!provisionalLoad, mainFrame,
- NetError.ERR_ABORTED, ERROR_DESCRIPTION, EXAMPLE_URL);
- assertEquals("onReceivedError should not be called for aborted navigations", callCount,
- mContentsClient.getOnReceivedErrorHelper().getCallCount());
- }
-
- @SmallTest
- @Feature({"AndroidWebView"})
public void testDidNavigateMainFrame() {
String nullUrl = null;
String baseUrl = null;
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
index d363c5c..1084c0f 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnPageFinishedTest.java
@@ -359,4 +359,21 @@ public class ClientOnPageFinishedTest extends AwTestBase {
assertEquals(syncUrl, onPageFinishedHelper.getUrl());
assertEquals(onPageFinishedCallCount + 1, onPageFinishedHelper.getCallCount());
}
+
+ @MediumTest
+ @Feature({"AndroidWebView"})
+ public void testOnPageFinishedCalledAfter204Reply() throws Throwable {
+ TestWebServer webServer = TestWebServer.start();
+ try {
+ final String url = webServer.setResponseWithNoContentStatus("/page.html");
+ TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
+ mContentsClient.getOnPageFinishedHelper();
+ int currentCallCount = onPageFinishedHelper.getCallCount();
+ loadUrlAsync(mAwContents, url);
+ onPageFinishedHelper.waitForCallback(currentCallCount);
+ assertEquals(url, onPageFinishedHelper.getUrl());
+ } finally {
+ webServer.shutdown();
+ }
+ }
}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java
new file mode 100644
index 0000000..d9bdc8e6
--- /dev/null
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/ClientOnReceivedError2Test.java
@@ -0,0 +1,414 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.android_webview.test;
+
+import android.os.Build;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.webkit.WebSettings;
+
+import org.chromium.android_webview.AwContents;
+import org.chromium.android_webview.AwContentsClient.AwWebResourceError;
+import org.chromium.android_webview.AwContentsClient.AwWebResourceRequest;
+import org.chromium.android_webview.ErrorCodeConversionHelper;
+import org.chromium.android_webview.test.util.AwTestTouchUtils;
+import org.chromium.android_webview.test.util.CommonResources;
+import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.MinAndroidSdkLevel;
+import org.chromium.content.browser.test.util.TestCallbackHelperContainer;
+import org.chromium.net.test.util.TestWebServer;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests for the ContentViewClient.onReceivedError2() method.
+ */
+@MinAndroidSdkLevel(Build.VERSION_CODES.KITKAT)
+public class ClientOnReceivedError2Test extends AwTestBase {
+
+ private VerifyOnReceivedError2CallClient mContentsClient;
+ private AwTestContainerView mTestContainerView;
+ private AwContents mAwContents;
+ private TestWebServer mWebServer;
+
+ private static final String BAD_HTML_URL =
+ "http://man.id.be.really.surprised.if.this.address.existed/a.html";
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mContentsClient = new VerifyOnReceivedError2CallClient();
+ mTestContainerView = createAwTestContainerViewOnMainSync(mContentsClient);
+ mAwContents = mTestContainerView.getAwContents();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mWebServer != null) mWebServer.shutdown();
+ super.tearDown();
+ }
+
+ private void startWebServer() throws Exception {
+ mWebServer = TestWebServer.start();
+ }
+
+ private void useDefaultTestAwContentsClient() throws Exception {
+ mContentsClient.enableBypass();
+ }
+
+ private static class VerifyOnReceivedError2CallClient extends TestAwContentsClient {
+ private boolean mBypass = false;
+ private boolean mIsOnPageFinishedCalled = false;
+ private boolean mIsOnReceivedError2Called = false;
+
+ void enableBypass() {
+ mBypass = true;
+ }
+
+ @Override
+ public void onPageFinished(String url) {
+ if (!mBypass) {
+ assertEquals(
+ "onPageFinished called twice for " + url, false, mIsOnPageFinishedCalled);
+ mIsOnPageFinishedCalled = true;
+ assertEquals("onReceivedError2 not called before onPageFinished for " + url, true,
+ mIsOnReceivedError2Called);
+ }
+ super.onPageFinished(url);
+ }
+
+ @Override
+ public void onReceivedError2(AwWebResourceRequest request,
+ AwWebResourceError error) {
+ if (!mBypass) {
+ assertEquals("onReceivedError2 called twice for " + request.url, false,
+ mIsOnReceivedError2Called);
+ mIsOnReceivedError2Called = true;
+ }
+ super.onReceivedError2(request, error);
+ }
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testMainFrame() throws Throwable {
+ loadUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), BAD_HTML_URL);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(BAD_HTML_URL, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ // No actual request has been made, as the host name can't be resolved.
+ assertTrue(request.requestHeaders.isEmpty());
+ assertTrue(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ // The particular error code that is returned depends on the configuration of the device
+ // (such as existence of a proxy) so we don't test for it.
+ assertFalse(ErrorCodeConversionHelper.ERROR_UNKNOWN == error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testUserGesture() throws Throwable {
+ useDefaultTestAwContentsClient();
+ final String pageHtml = CommonResources.makeHtmlPageWithSimpleLinkTo(BAD_HTML_URL);
+ loadDataAsync(mAwContents, pageHtml, "text/html", false);
+ waitForVisualStateCallback(mAwContents);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ int onReceivedError2CallCount = onReceivedError2Helper.getCallCount();
+ AwTestTouchUtils.simulateTouchCenterOfView(mTestContainerView);
+ onReceivedError2Helper.waitForCallback(onReceivedError2CallCount,
+ 1 /* numberOfCallsToWaitFor */,
+ WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(BAD_HTML_URL, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ // No actual request has been made, as the host name can't be resolved.
+ assertTrue(request.requestHeaders.isEmpty());
+ assertTrue(request.isMainFrame);
+ assertTrue(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ // The particular error code that is returned depends on the configuration of the device
+ // (such as existence of a proxy) so we don't test for it.
+ assertFalse(ErrorCodeConversionHelper.ERROR_UNKNOWN == error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testIframeSubresource() throws Throwable {
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<iframe src='" + BAD_HTML_URL + "' />");
+ loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
+ pageHtml, "text/html", false);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(BAD_HTML_URL, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ // No actual request has been made, as the host name can't be resolved.
+ assertTrue(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ // The particular error code that is returned depends on the configuration of the device
+ // (such as existence of a proxy) so we don't test for it.
+ assertFalse(ErrorCodeConversionHelper.ERROR_UNKNOWN == error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testUserGestureForIframeSubresource() throws Throwable {
+ useDefaultTestAwContentsClient();
+ startWebServer();
+ final String iframeHtml = CommonResources.makeHtmlPageWithSimpleLinkTo(BAD_HTML_URL);
+ final String iframeUrl = mWebServer.setResponse("/iframe.html", iframeHtml, null);
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<iframe style='width:100%;height:100%;' src='" + iframeUrl + "' />");
+ loadDataAsync(mAwContents, pageHtml, "text/html", false);
+ waitForVisualStateCallback(mAwContents);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ int onReceivedError2CallCount = onReceivedError2Helper.getCallCount();
+ AwTestTouchUtils.simulateTouchCenterOfView(mTestContainerView);
+ onReceivedError2Helper.waitForCallback(onReceivedError2CallCount,
+ 1 /* numberOfCallsToWaitFor */,
+ WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(BAD_HTML_URL, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ // No actual request has been made, as the host name can't be resolved.
+ assertTrue(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertTrue(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ // The particular error code that is returned depends on the configuration of the device
+ // (such as existence of a proxy) so we don't test for it.
+ assertFalse(ErrorCodeConversionHelper.ERROR_UNKNOWN == error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testImageSubresource() throws Throwable {
+ final String imageUrl = "http://man.id.be.really.surprised.if.this.address.existed/a.png";
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<img src='" + imageUrl + "' />");
+ loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
+ pageHtml, "text/html", false);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(imageUrl, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ // No actual request has been made, as the host name can't be resolved.
+ assertTrue(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ // The particular error code that is returned depends on the configuration of the device
+ // (such as existence of a proxy) so we don't test for it.
+ assertFalse(ErrorCodeConversionHelper.ERROR_UNKNOWN == error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testOnInvalidScheme() throws Throwable {
+ final String iframeUrl = "foo://some/resource";
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<iframe src='" + iframeUrl + "' />");
+ loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
+ pageHtml, "text/html", false);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(iframeUrl, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ assertFalse(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ assertEquals(ErrorCodeConversionHelper.ERROR_UNSUPPORTED_SCHEME, error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testOnNonExistentAssetUrl() throws Throwable {
+ final String baseUrl = "file:///android_asset/";
+ final String iframeUrl = baseUrl + "does_not_exist.html";
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<iframe src='" + iframeUrl + "' />");
+ loadDataWithBaseUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
+ pageHtml, "text/html", false, baseUrl, "about:blank");
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(iframeUrl, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ assertFalse(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ assertEquals(ErrorCodeConversionHelper.ERROR_UNKNOWN, error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testOnNonExistentResourceUrl() throws Throwable {
+ final String baseUrl = "file:///android_res/raw/";
+ final String iframeUrl = baseUrl + "does_not_exist.html";
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<iframe src='" + iframeUrl + "' />");
+ loadDataWithBaseUrlSync(mAwContents, mContentsClient.getOnPageFinishedHelper(), pageHtml,
+ "text/html", false, baseUrl, "about:blank");
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(iframeUrl, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ assertFalse(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ assertEquals(ErrorCodeConversionHelper.ERROR_UNKNOWN, error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testOnCacheMiss() throws Throwable {
+ final String iframeUrl = "http://example.com/index.html";
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<iframe src='" + iframeUrl + "' />");
+ getAwSettingsOnUiThread(mAwContents).setCacheMode(WebSettings.LOAD_CACHE_ONLY);
+ loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
+ pageHtml, "text/html", false);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(iframeUrl, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ assertFalse(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ assertEquals(ErrorCodeConversionHelper.ERROR_UNKNOWN, error.errorCode);
+ assertNotNull(error.description);
+ }
+
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testNotCalledOnStopLoading() throws Throwable {
+ useDefaultTestAwContentsClient();
+ final CountDownLatch latch = new CountDownLatch(1);
+ startWebServer();
+ final String url = mWebServer.setResponseWithRunnableAction(
+ "/about.html", CommonResources.ABOUT_HTML, null,
+ new Runnable() {
+ @Override
+ public void run() {
+ try {
+ latch.await(
+ WAIT_TIMEOUT_MS, java.util.concurrent.TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("Caught InterruptedException " + e);
+ }
+ }
+ });
+ TestCallbackHelperContainer.OnPageFinishedHelper onPageFinishedHelper =
+ mContentsClient.getOnPageFinishedHelper();
+ final int onPageFinishedCallCount = onPageFinishedHelper.getCallCount();
+ loadUrlAsync(mAwContents, url);
+ mAwContents.stopLoading();
+ onPageFinishedHelper.waitForCallback(onPageFinishedCallCount,
+ 1 /* numberOfCallsToWaitFor */,
+ WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ latch.countDown(); // Release the server.
+
+ // Instead of waiting for OnReceivedError2 not to be called, we schedule
+ // a load that will result in a error, and check that we have only got one callback,
+ // originating from the last attempt.
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ final int onReceivedError2CallCount = onReceivedError2Helper.getCallCount();
+ loadUrlAsync(mAwContents, BAD_HTML_URL);
+ onReceivedError2Helper.waitForCallback(onReceivedError2CallCount,
+ 1 /* numberOfCallsToWaitFor */,
+ WAIT_TIMEOUT_MS,
+ TimeUnit.MILLISECONDS);
+ assertEquals(onReceivedError2CallCount + 1, onReceivedError2Helper.getCallCount());
+ assertEquals(BAD_HTML_URL, onReceivedError2Helper.getRequest().url);
+ }
+
+ /*
+ * TODO(mnaganov): Implement, add tests for other security blocks in Blink.
+ @SmallTest
+ @Feature({"AndroidWebView"})
+ public void testOnXFrameOptionsDenial() throws Throwable {
+ startWebServer();
+ final String iframeHtml = CommonResources.makeHtmlPageFrom(
+ "", "You shouldn't see me :)");
+ List<Pair<String, String>> iframeHeaders = new ArrayList<Pair<String, String>>();
+ iframeHeaders.add(Pair.create("x-frame-options", "DENY"));
+ final String iframeUrl = mWebServer.setResponse("/iframe.html", iframeHeaders);
+ final String pageHtml = CommonResources.makeHtmlPageFrom(
+ "", "<iframe src='" + iframeUrl + "' />");
+ getAwSettingsOnUiThread(mAwContents).setCacheMode(WebSettings.LOAD_CACHE_ONLY);
+ loadDataSync(mAwContents, mContentsClient.getOnPageFinishedHelper(),
+ pageHtml, "text/html", false);
+
+ TestAwContentsClient.OnReceivedError2Helper onReceivedError2Helper =
+ mContentsClient.getOnReceivedError2Helper();
+ AwWebResourceRequest request = onReceivedError2Helper.getRequest();
+ assertNotNull(request);
+ assertEquals(iframeUrl, request.url);
+ assertEquals("GET", request.method);
+ assertNotNull(request.requestHeaders);
+ assertFalse(request.requestHeaders.isEmpty());
+ assertFalse(request.isMainFrame);
+ assertFalse(request.hasUserGesture);
+ AwWebResourceError error = onReceivedError2Helper.getError();
+ assertEquals(ErrorCodeConversionHelper.ERROR_BLOCKED, error.errorCode);
+ assertNotNull(error.description);
+ }
+ */
+}
diff --git a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
index 7c8884d..a890f5d 100644
--- a/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
+++ b/android_webview/javatests/src/org/chromium/android_webview/test/TestAwContentsClient.java
@@ -29,6 +29,7 @@ public class TestAwContentsClient extends NullContentsClient {
private final OnPageFinishedHelper mOnPageFinishedHelper;
private final OnPageCommitVisibleHelper mOnPageCommitVisibleHelper;
private final OnReceivedErrorHelper mOnReceivedErrorHelper;
+ private final OnReceivedError2Helper mOnReceivedError2Helper;
private final OnReceivedHttpErrorHelper mOnReceivedHttpErrorHelper;
private final CallbackHelper mOnReceivedSslErrorHelper;
private final OnDownloadStartHelper mOnDownloadStartHelper;
@@ -47,6 +48,7 @@ public class TestAwContentsClient extends NullContentsClient {
mOnPageFinishedHelper = new OnPageFinishedHelper();
mOnPageCommitVisibleHelper = new OnPageCommitVisibleHelper();
mOnReceivedErrorHelper = new OnReceivedErrorHelper();
+ mOnReceivedError2Helper = new OnReceivedError2Helper();
mOnReceivedHttpErrorHelper = new OnReceivedHttpErrorHelper();
mOnReceivedSslErrorHelper = new CallbackHelper();
mOnDownloadStartHelper = new OnDownloadStartHelper();
@@ -77,6 +79,10 @@ public class TestAwContentsClient extends NullContentsClient {
return mOnReceivedErrorHelper;
}
+ public OnReceivedError2Helper getOnReceivedError2Helper() {
+ return mOnReceivedError2Helper;
+ }
+
public OnReceivedHttpErrorHelper getOnReceivedHttpErrorHelper() {
return mOnReceivedHttpErrorHelper;
}
@@ -177,6 +183,11 @@ public class TestAwContentsClient extends NullContentsClient {
}
@Override
+ public void onReceivedError2(AwWebResourceRequest request, AwWebResourceError error) {
+ mOnReceivedError2Helper.notifyCalled(request, error);
+ }
+
+ @Override
public void onReceivedSslError(ValueCallback<Boolean> callback, SslError error) {
callback.onReceiveValue(mAllowSslError);
mOnReceivedSslErrorHelper.notifyCalled();
@@ -461,6 +472,27 @@ public class TestAwContentsClient extends NullContentsClient {
}
/**
+ * CallbackHelper for OnReceivedError2.
+ */
+ public static class OnReceivedError2Helper extends CallbackHelper {
+ private AwWebResourceRequest mRequest;
+ private AwWebResourceError mError;
+ public void notifyCalled(AwWebResourceRequest request, AwWebResourceError error) {
+ mRequest = request;
+ mError = error;
+ notifyCalled();
+ }
+ public AwWebResourceRequest getRequest() {
+ assert getCallCount() > 0;
+ return mRequest;
+ }
+ public AwWebResourceError getError() {
+ assert getCallCount() > 0;
+ return mError;
+ }
+ }
+
+ /**
* CallbackHelper for OnReceivedHttpError.
*/
public static class OnReceivedHttpErrorHelper extends CallbackHelper {
diff --git a/android_webview/native/aw_contents_io_thread_client_impl.cc b/android_webview/native/aw_contents_io_thread_client_impl.cc
index 0cadc94..419631e 100644
--- a/android_webview/native/aw_contents_io_thread_client_impl.cc
+++ b/android_webview/native/aw_contents_io_thread_client_impl.cc
@@ -24,6 +24,7 @@
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "jni/AwContentsIoThreadClient_jni.h"
+#include "net/base/net_errors.h"
#include "net/http/http_request_headers.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request.h"
@@ -153,6 +154,38 @@ void ClientMapEntryUpdater::WebContentsDestroyed() {
delete this;
}
+struct WebResourceRequest {
+ ScopedJavaLocalRef<jstring> jstring_url;
+ bool is_main_frame;
+ bool has_user_gesture;
+ ScopedJavaLocalRef<jstring> jstring_method;
+ ScopedJavaLocalRef<jobjectArray> jstringArray_header_names;
+ ScopedJavaLocalRef<jobjectArray> jstringArray_header_values;
+
+ WebResourceRequest(JNIEnv* env, const net::URLRequest* request)
+ : jstring_url(ConvertUTF8ToJavaString(env, request->url().spec())),
+ jstring_method(ConvertUTF8ToJavaString(env, request->method())) {
+ const content::ResourceRequestInfo* info =
+ content::ResourceRequestInfo::ForRequest(request);
+ is_main_frame =
+ info && info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME;
+ has_user_gesture = info && info->HasUserGesture();
+
+ vector<string> header_names;
+ vector<string> header_values;
+ net::HttpRequestHeaders headers;
+ if (!request->GetFullRequestHeaders(&headers))
+ headers = request->extra_request_headers();
+ net::HttpRequestHeaders::Iterator headers_iterator(headers);
+ while (headers_iterator.GetNext()) {
+ header_names.push_back(headers_iterator.name());
+ header_values.push_back(headers_iterator.value());
+ }
+ jstringArray_header_names = ToJavaArrayOfStrings(env, header_names);
+ jstringArray_header_values = ToJavaArrayOfStrings(env, header_values);
+ }
+};
+
} // namespace
// AwContentsIoThreadClientImpl -----------------------------------------------
@@ -236,51 +269,26 @@ AwContentsIoThreadClientImpl::GetCacheMode() const {
scoped_ptr<AwWebResourceResponse>
AwContentsIoThreadClientImpl::ShouldInterceptRequest(
- const GURL& location,
const net::URLRequest* request) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
if (java_object_.is_null())
return scoped_ptr<AwWebResourceResponse>();
- const content::ResourceRequestInfo* info =
- content::ResourceRequestInfo::ForRequest(request);
- bool is_main_frame = info &&
- info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME;
- bool has_user_gesture = info && info->HasUserGesture();
-
- vector<string> headers_names;
- vector<string> headers_values;
- {
- net::HttpRequestHeaders headers;
- if (!request->GetFullRequestHeaders(&headers))
- headers = request->extra_request_headers();
- net::HttpRequestHeaders::Iterator headers_iterator(headers);
- while (headers_iterator.GetNext()) {
- headers_names.push_back(headers_iterator.name());
- headers_values.push_back(headers_iterator.value());
- }
- }
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> jstring_url =
- ConvertUTF8ToJavaString(env, location.spec());
- ScopedJavaLocalRef<jstring> jstring_method =
- ConvertUTF8ToJavaString(env, request->method());
- ScopedJavaLocalRef<jobjectArray> jstringArray_headers_names =
- ToJavaArrayOfStrings(env, headers_names);
- ScopedJavaLocalRef<jobjectArray> jstringArray_headers_values =
- ToJavaArrayOfStrings(env, headers_values);
+ WebResourceRequest web_request(env, request);
+
devtools_instrumentation::ScopedEmbedderCallbackTask embedder_callback(
"shouldInterceptRequest");
ScopedJavaLocalRef<jobject> ret =
Java_AwContentsIoThreadClient_shouldInterceptRequest(
env,
java_object_.obj(),
- jstring_url.obj(),
- is_main_frame,
- has_user_gesture,
- jstring_method.obj(),
- jstringArray_headers_names.obj(),
- jstringArray_headers_values.obj());
+ web_request.jstring_url.obj(),
+ web_request.is_main_frame,
+ web_request.has_user_gesture,
+ web_request.jstring_method.obj(),
+ web_request.jstringArray_header_names.obj(),
+ web_request.jstringArray_header_values.obj());
if (ret.is_null())
return scoped_ptr<AwWebResourceResponse>();
return scoped_ptr<AwWebResourceResponse>(
@@ -376,6 +384,32 @@ void AwContentsIoThreadClientImpl::NewLoginRequest(const string& realm,
env, java_object_.obj(), jrealm.obj(), jaccount.obj(), jargs.obj());
}
+void AwContentsIoThreadClientImpl::OnReceivedError(
+ const net::URLRequest* request) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (java_object_.is_null())
+ return;
+
+ JNIEnv* env = AttachCurrentThread();
+ WebResourceRequest web_request(env, request);
+
+ int error_code = request->status().error();
+ ScopedJavaLocalRef<jstring> jstring_description = ConvertUTF8ToJavaString(
+ env, net::ErrorToString(request->status().error()));
+
+ Java_AwContentsIoThreadClient_onReceivedError(
+ env,
+ java_object_.obj(),
+ web_request.jstring_url.obj(),
+ web_request.is_main_frame,
+ web_request.has_user_gesture,
+ web_request.jstring_method.obj(),
+ web_request.jstringArray_header_names.obj(),
+ web_request.jstringArray_header_values.obj(),
+ error_code,
+ jstring_description.obj());
+}
+
void AwContentsIoThreadClientImpl::OnReceivedHttpError(
const net::URLRequest* request,
const net::HttpResponseHeaders* response_headers) {
@@ -383,18 +417,8 @@ void AwContentsIoThreadClientImpl::OnReceivedHttpError(
if (java_object_.is_null())
return;
- vector<string> request_header_names;
- vector<string> request_header_values;
- {
- net::HttpRequestHeaders headers;
- if (!request->GetFullRequestHeaders(&headers))
- headers = request->extra_request_headers();
- net::HttpRequestHeaders::Iterator headers_iterator(headers);
- while (headers_iterator.GetNext()) {
- request_header_names.push_back(headers_iterator.name());
- request_header_values.push_back(headers_iterator.value());
- }
- }
+ JNIEnv* env = AttachCurrentThread();
+ WebResourceRequest web_request(env, request);
vector<string> response_header_names;
vector<string> response_header_values;
@@ -408,22 +432,6 @@ void AwContentsIoThreadClientImpl::OnReceivedHttpError(
}
}
- JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> jstring_url =
- ConvertUTF8ToJavaString(env, request->url().spec());
- ScopedJavaLocalRef<jstring> jstring_method =
- ConvertUTF8ToJavaString(env, request->method());
- ScopedJavaLocalRef<jobjectArray> jstringArray_request_header_names =
- ToJavaArrayOfStrings(env, request_header_names);
- ScopedJavaLocalRef<jobjectArray> jstringArray_request_header_values =
- ToJavaArrayOfStrings(env, request_header_values);
-
- const content::ResourceRequestInfo* info =
- content::ResourceRequestInfo::ForRequest(request);
- bool is_main_frame = info &&
- info->GetResourceType() == content::RESOURCE_TYPE_MAIN_FRAME;
- bool has_user_gesture = info && info->HasUserGesture();
-
string mime_type, encoding;
response_headers->GetMimeTypeAndCharset(&mime_type, &encoding);
ScopedJavaLocalRef<jstring> jstring_mime_type =
@@ -441,12 +449,12 @@ void AwContentsIoThreadClientImpl::OnReceivedHttpError(
Java_AwContentsIoThreadClient_onReceivedHttpError(
env,
java_object_.obj(),
- jstring_url.obj(),
- is_main_frame,
- has_user_gesture,
- jstring_method.obj(),
- jstringArray_request_header_names.obj(),
- jstringArray_request_header_values.obj(),
+ web_request.jstring_url.obj(),
+ web_request.is_main_frame,
+ web_request.has_user_gesture,
+ web_request.jstring_method.obj(),
+ web_request.jstringArray_header_names.obj(),
+ web_request.jstringArray_header_values.obj(),
jstring_mime_type.obj(),
jstring_encoding.obj(),
status_code,
diff --git a/android_webview/native/aw_contents_io_thread_client_impl.h b/android_webview/native/aw_contents_io_thread_client_impl.h
index 41c7b8a..97ba314 100644
--- a/android_webview/native/aw_contents_io_thread_client_impl.h
+++ b/android_webview/native/aw_contents_io_thread_client_impl.h
@@ -48,7 +48,6 @@ class AwContentsIoThreadClientImpl : public AwContentsIoThreadClient {
bool PendingAssociation() const override;
CacheMode GetCacheMode() const override;
scoped_ptr<AwWebResourceResponse> ShouldInterceptRequest(
- const GURL& location,
const net::URLRequest* request) override;
bool ShouldBlockContentUrls() const override;
bool ShouldBlockFileUrls() const override;
@@ -62,6 +61,7 @@ class AwContentsIoThreadClientImpl : public AwContentsIoThreadClient {
void NewLoginRequest(const std::string& realm,
const std::string& account,
const std::string& args) override;
+ void OnReceivedError(const net::URLRequest* request) override;
void OnReceivedHttpError(
const net::URLRequest* request,
const net::HttpResponseHeaders* response_headers) override;