blob: de2f30841dab527b1bf21572151ebdd118f39d34 [file] [log] [blame]
// 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.
#import "ios/web/web_state/error_translation_util.h"
#include <CFNetwork/CFNetwork.h>
#include <Foundation/Foundation.h>
#import "base/ios/ns_error_util.h"
#import "ios/net/protocol_handler_util.h"
#import "ios/web/public/web_client.h"
#import "net/base/mac/url_conversions.h"
#include "net/base/net_errors.h"
#include "url/gurl.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace web {
bool GetNetErrorFromIOSErrorCode(NSInteger ios_error_code,
int* net_error_code,
NSURL* url) {
DCHECK(net_error_code);
bool translation_success = true;
switch (ios_error_code) {
case kCFURLErrorBackgroundSessionInUseByAnotherProcess:
*net_error_code = net::ERR_ACCESS_DENIED;
break;
case kCFURLErrorBackgroundSessionWasDisconnected:
*net_error_code = net::ERR_CONNECTION_ABORTED;
break;
case kCFURLErrorUnknown:
*net_error_code = net::ERR_FAILED;
break;
case kCFURLErrorCancelled:
*net_error_code = net::ERR_ABORTED;
break;
case kCFURLErrorBadURL:
*net_error_code = net::ERR_INVALID_URL;
break;
case kCFURLErrorTimedOut:
*net_error_code = net::ERR_CONNECTION_TIMED_OUT;
break;
case kCFURLErrorUnsupportedURL:
if (GetWebClient()->IsAppSpecificURL(net::GURLWithNSURL(url))) {
// Scheme is valid, but URL is not supported.
*net_error_code = net::ERR_INVALID_URL;
} else {
// Scheme is not app-specific and not supported by WebState.
*net_error_code = net::ERR_UNKNOWN_URL_SCHEME;
}
break;
case kCFURLErrorCannotFindHost:
*net_error_code = net::ERR_NAME_NOT_RESOLVED;
break;
case kCFURLErrorCannotConnectToHost:
*net_error_code = net::ERR_CONNECTION_FAILED;
break;
case kCFURLErrorNetworkConnectionLost:
// This looks like catch-all code for errors like ERR_CONNECTION_CLOSED,
// ERR_EMPTY_RESPONSE, ERR_NETWORK_CHANGED or ERR_CONNECTION_RESET.
// ERR_CONNECTION_CLOSED is too specific for this case, but there is no
// better cross platform analogue.
*net_error_code = net::ERR_CONNECTION_CLOSED;
break;
case kCFURLErrorDNSLookupFailed:
*net_error_code = net::ERR_NAME_RESOLUTION_FAILED;
break;
case kCFURLErrorHTTPTooManyRedirects:
*net_error_code = net::ERR_TOO_MANY_REDIRECTS;
break;
case kCFURLErrorResourceUnavailable:
*net_error_code = net::ERR_INSUFFICIENT_RESOURCES;
break;
case kCFURLErrorNotConnectedToInternet:
*net_error_code = net::ERR_INTERNET_DISCONNECTED;
break;
case kCFURLErrorRedirectToNonExistentLocation:
*net_error_code = net::ERR_NAME_NOT_RESOLVED;
break;
case kCFURLErrorBadServerResponse:
*net_error_code = net::ERR_INVALID_RESPONSE;
break;
case kCFURLErrorUserCancelledAuthentication:
*net_error_code = net::ERR_ABORTED;
break;
case kCFURLErrorUserAuthenticationRequired:
*net_error_code = net::ERR_FAILED;
break;
case kCFURLErrorZeroByteResource:
*net_error_code = net::ERR_EMPTY_RESPONSE;
break;
case kCFURLErrorCannotDecodeRawData:
*net_error_code = net::ERR_CONTENT_DECODING_FAILED;
break;
case kCFURLErrorCannotDecodeContentData:
*net_error_code = net::ERR_CONTENT_DECODING_FAILED;
break;
case kCFURLErrorCannotParseResponse:
*net_error_code = net::ERR_INVALID_RESPONSE;
break;
case kCFURLErrorInternationalRoamingOff:
*net_error_code = net::ERR_INTERNET_DISCONNECTED;
break;
case kCFURLErrorCallIsActive:
*net_error_code = net::ERR_CONNECTION_FAILED;
break;
case kCFURLErrorDataNotAllowed:
*net_error_code = net::ERR_INTERNET_DISCONNECTED;
break;
case kCFURLErrorRequestBodyStreamExhausted:
*net_error_code = net::ERR_CONTENT_LENGTH_MISMATCH;
break;
case kCFURLErrorFileDoesNotExist:
*net_error_code = net::ERR_FILE_NOT_FOUND;
break;
case kCFURLErrorFileIsDirectory:
*net_error_code = net::ERR_INVALID_HANDLE;
break;
case kCFURLErrorNoPermissionsToReadFile:
*net_error_code = net::ERR_ACCESS_DENIED;
break;
case kCFURLErrorDataLengthExceedsMaximum:
*net_error_code = net::ERR_FILE_TOO_BIG;
break;
case kCFURLErrorSecureConnectionFailed:
*net_error_code = net::ERR_SSL_PROTOCOL_ERROR;
break;
case kCFURLErrorServerCertificateHasBadDate:
*net_error_code = net::ERR_CERT_DATE_INVALID;
break;
case kCFURLErrorServerCertificateUntrusted:
*net_error_code = net::ERR_CERT_AUTHORITY_INVALID;
break;
case kCFURLErrorServerCertificateHasUnknownRoot:
*net_error_code = net::ERR_CERT_AUTHORITY_INVALID;
break;
case kCFURLErrorServerCertificateNotYetValid:
*net_error_code = net::ERR_CERT_DATE_INVALID;
break;
case kCFURLErrorClientCertificateRejected:
*net_error_code = net::ERR_BAD_SSL_CLIENT_AUTH_CERT;
break;
case kCFURLErrorClientCertificateRequired:
*net_error_code = net::ERR_SSL_CLIENT_AUTH_CERT_NEEDED;
break;
default:
translation_success = false;
break;
}
return translation_success;
}
NSError* NetErrorFromError(NSError* error) {
DCHECK(error);
NSError* underlying_error =
base::ios::GetFinalUnderlyingErrorFromError(error);
int net_error_code = net::ERR_FAILED;
if ([underlying_error.domain isEqualToString:NSURLErrorDomain] ||
[underlying_error.domain
isEqualToString:static_cast<NSString*>(kCFErrorDomainCFNetwork)]) {
// Attempt to translate NSURL and CFNetwork error codes into their
// corresponding net error codes.
NSString* url_spec = error.userInfo[NSURLErrorFailingURLStringErrorKey];
NSURL* url = url_spec ? [NSURL URLWithString:url_spec] : nil;
GetNetErrorFromIOSErrorCode(underlying_error.code, &net_error_code, url);
}
return NetErrorFromError(error, net_error_code);
}
NSError* NetErrorFromError(NSError* error, int net_error_code) {
DCHECK(error);
NSError* net_error =
[NSError errorWithDomain:net::kNSErrorDomain
code:static_cast<NSInteger>(net_error_code)
userInfo:nil];
return base::ios::ErrorWithAppendedUnderlyingError(error, net_error);
}
} // namespace web