From ae805f8d05585c7ba522d2fa8c67f6747b491a41 Mon Sep 17 00:00:00 2001 From: Alesandro Ortiz Date: Tue, 16 Jun 2020 17:57:10 -0400 Subject: [PATCH 1/2] Update SSL error handling for Android WebView Update SSL error handling to call onReceivedError() only on top-level navigations. This prevents iframes and other subresources from causing user-visible SSL error messages. The desired behavior is only to have top-level navigations show user-visible error messages. All other requests should be cancelled automatically with no user-visible error message. --- .../webview/RNCWebViewManager.java | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java index ab869cfe7..40520e2ab 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -801,10 +801,23 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request @Override public void onReceivedSslError(final WebView webView, final SslErrorHandler handler, final SslError error) { + // WebView.getUrl() will return the top-level window URL. + // If a top-level navigation triggers this error handler, the top-level URL will be the failing URL (not the current URL). + // This is desired behavior. We later use these values to determine whether the request is a top-level navigation or a subresource request. + String topWindowUrl = webView.getUrl(); + String failingUrl = error.getUrl(); + + // Cancel request after obtaining top-level URL. + // If request is cancelled before obtaining top-level URL, undesired behavior may occur. + // Undesired behavior: Return value of WebView.getUrl() may be the current URL instead of the failing URL. handler.cancel(); + if (!topWindowUrl.equalsIgnoreCase(failingUrl)) { + // If error is not due to top-level navigation, then do not call onReceivedError() + return; + } + int code = error.getPrimaryError(); - String failingUrl = error.getUrl(); String description = ""; String descriptionPrefix = "SSL error: "; From 2390ecd8a630beb1125dc70b707d1e9432755053 Mon Sep 17 00:00:00 2001 From: Alesandro Ortiz Date: Wed, 2 Sep 2020 13:29:30 -0400 Subject: [PATCH 2/2] Update RNCWebViewManager.java Clarify comments and add warning on blocked subresource --- .../com/reactnativecommunity/webview/RNCWebViewManager.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java index 40520e2ab..3d2fe147d 100644 --- a/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -17,6 +17,7 @@ import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; import android.text.TextUtils; +import android.util.Log; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; @@ -801,8 +802,9 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request @Override public void onReceivedSslError(final WebView webView, final SslErrorHandler handler, final SslError error) { + // onReceivedSslError is called for most requests, per Android docs: https://developer.android.com/reference/android/webkit/WebViewClient#onReceivedSslError(android.webkit.WebView,%2520android.webkit.SslErrorHandler,%2520android.net.http.SslError) // WebView.getUrl() will return the top-level window URL. - // If a top-level navigation triggers this error handler, the top-level URL will be the failing URL (not the current URL). + // If a top-level navigation triggers this error handler, the top-level URL will be the failing URL (not the URL of the currently-rendered page). // This is desired behavior. We later use these values to determine whether the request is a top-level navigation or a subresource request. String topWindowUrl = webView.getUrl(); String failingUrl = error.getUrl(); @@ -814,6 +816,7 @@ public void onReceivedSslError(final WebView webView, final SslErrorHandler hand if (!topWindowUrl.equalsIgnoreCase(failingUrl)) { // If error is not due to top-level navigation, then do not call onReceivedError() + Log.w("RNCWebViewManager", "Resource blocked from loading due to SSL error. Blocked URL: "+failingUrl); return; }