Index: ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
index 3d0562d7c2dcdf6ed58a2d8a8961e8e371941a82..2e7823f9556c9d415b35379ada7acbfbbc919e0a 100644 |
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm |
@@ -51,6 +51,30 @@ NSString* GetRefererFromNavigationAction(WKNavigationAction* action) { |
NSString* const kScriptMessageName = @"crwebinvoke"; |
NSString* const kScriptImmediateName = @"crwebinvokeimmediate"; |
+// Utility functions for storing the source of NSErrors received by WKWebViews: |
+// - Errors received by |-webView:didFailProvisionalNavigation:withError:| are |
+// recorded using WKWebViewErrorSource::PROVISIONAL_LOAD. These should be |
+// aborted. |
+// - Errors received by |-webView:didFailNavigation:withError:| are recorded |
+// using WKWebViewsource::NAVIGATION. These errors should not be aborted, as |
+// the WKWebView will automatically retry the load. |
+NSString* const kWKWebViewErrorSourceKey = @"ErrorSource"; |
+typedef enum { NONE = 0, PROVISIONAL_LOAD, NAVIGATION } WKWebViewErrorSource; |
+NSError* WKWebViewErrorWithSource(NSError* error, WKWebViewErrorSource source) { |
+ DCHECK(error); |
+ base::scoped_nsobject<NSMutableDictionary> userInfo( |
+ [error.userInfo mutableCopy]); |
+ [userInfo setObject:@(source) forKey:kWKWebViewErrorSourceKey]; |
+ return [NSError errorWithDomain:error.domain |
+ code:error.code |
+ userInfo:userInfo]; |
+} |
+WKWebViewErrorSource WKWebViewErrorSourceFromError(NSError* error) { |
+ DCHECK(error); |
+ return static_cast<WKWebViewErrorSource>( |
+ [error.userInfo[kWKWebViewErrorSourceKey] integerValue]); |
+} |
+ |
} // namespace |
@interface CRWWKWebViewWebController () <WKNavigationDelegate, |
@@ -412,10 +436,18 @@ NSString* const kScriptImmediateName = @"crwebinvokeimmediate"; |
self.webScrollView.zoomScale = zoomScale; |
} |
-- (BOOL)shouldAbortLoadForCancelledURL:(const GURL&)cancelledURL { |
+- (BOOL)shouldAbortLoadForCancelledError:(NSError*)cancelledError { |
+ DCHECK_EQ(cancelledError.code, NSURLErrorCancelled); |
// Do not abort the load if it is for an app specific URL, as such errors |
// are produced during the app specific URL load process. |
- return !web::GetWebClient()->IsAppSpecificURL(cancelledURL); |
+ const GURL errorURL = |
+ net::GURLWithNSURL(cancelledError.userInfo[NSURLErrorFailingURLErrorKey]); |
+ if (web::GetWebClient()->IsAppSpecificURL(errorURL)) |
+ return NO; |
+ // Don't abort NSURLErrorCancelled errors originating from navigation, as the |
+ // WKWebView will automatically retry these loads. |
+ WKWebViewErrorSource source = WKWebViewErrorSourceFromError(cancelledError); |
+ return source != NAVIGATION; |
} |
#pragma mark Private methods |
@@ -1013,6 +1045,7 @@ NSString* const kScriptImmediateName = @"crwebinvokeimmediate"; |
withError:(NSError *)error { |
[self discardPendingReferrerString]; |
+ error = WKWebViewErrorWithSource(error, PROVISIONAL_LOAD); |
#if !defined(ENABLE_CHROME_NET_STACK_FOR_WKWEBVIEW) |
if (web::IsWKWebViewSSLError(error)) |
[self handleSSLError:error]; |
@@ -1056,7 +1089,8 @@ NSString* const kScriptImmediateName = @"crwebinvokeimmediate"; |
- (void)webView:(WKWebView *)webView |
didFailNavigation:(WKNavigation *)navigation |
withError:(NSError *)error { |
- [self handleLoadError:error inMainFrame:YES]; |
+ [self handleLoadError:WKWebViewErrorWithSource(error, NAVIGATION) |
+ inMainFrame:YES]; |
} |
- (void)webView:(WKWebView *)webView |