Skip to content

NSLocalizedDescription for http errors taken from libcurl #1198

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 13, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CoreFoundation/URL.subproj/CFURLSessionInterface.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
//===----------------------------------------------------------------------===//

#include "CFURLSessionInterface.h"
#include <CoreFoundation/CFString.h>
#include <curl/curl.h>

FILE* aa = NULL;
Expand All @@ -31,6 +32,11 @@ static CFURLSessionMultiCode MakeMultiCode(CURLMcode value) {
return (CFURLSessionMultiCode) { value };
}

CFStringRef CFURLSessionCreateErrorDescription(int value) {
const char *description = curl_easy_strerror(value);
return CFStringCreateWithBytes(kCFAllocatorSystemDefault,
(const uint8_t *)description, strlen(description), kCFStringEncodingUTF8, NO);
}

CFURLSessionEasyHandle _Nonnull CFURLSessionEasyHandleInit() {
return curl_easy_init();
Expand Down Expand Up @@ -135,6 +141,7 @@ CFURLSessionEasyCode CFURLSessionInit(void) {
return MakeEasyCode(curl_global_init(CURL_GLOBAL_SSL));
}

int const CFURLSessionEasyErrorSize = { CURL_ERROR_SIZE + 1 };

CFURLSessionEasyCode const CFURLSessionEasyCodeOK = { CURLE_OK };
CFURLSessionEasyCode const CFURLSessionEasyCodeUNSUPPORTED_PROTOCOL = { CURLE_UNSUPPORTED_PROTOCOL };
Expand Down
4 changes: 4 additions & 0 deletions CoreFoundation/URL.subproj/CFURLSessionInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ typedef struct CFURLSessionEasyCode {
int value;
} CFURLSessionEasyCode;

CF_EXPORT CFStringRef _Nonnull CFURLSessionCreateErrorDescription(int value);

CF_EXPORT int const CFURLSessionEasyErrorSize;

/// CURLcode
CF_EXPORT CFURLSessionEasyCode const CFURLSessionEasyCodeOK; // CURLE_OK
CF_EXPORT CFURLSessionEasyCode const CFURLSessionEasyCodeUNSUPPORTED_PROTOCOL; // CURLE_UNSUPPORTED_PROTOCOL
Expand Down
2 changes: 1 addition & 1 deletion Foundation/NSString.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ extension unichar : ExpressibleByUnicodeScalarLiteral {
}
}

// Placeholder for a future implementation
/// Returns a localized string, using the main bundle if one is not specified.
public
func NSLocalizedString(_ key: String,
tableName: String? = nil,
Expand Down
10 changes: 6 additions & 4 deletions Foundation/URLSession/http/EasyHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ internal final class _EasyHandle {
fileprivate var headerList: _CurlStringList?
fileprivate var pauseState: _PauseState = []
internal var timeoutTimer: _TimeoutSource!
internal lazy var errorBuffer = [UInt8](repeating: 0, count: Int(CFURLSessionEasyErrorSize))
#if os(Android)
static fileprivate var _CAInfoFile: UnsafeMutablePointer<Int8>?
#endif
Expand Down Expand Up @@ -89,8 +90,8 @@ extension _EasyHandle {
}

internal extension _EasyHandle {
func completedTransfer(withErrorCode errorCode: Int?) {
delegate?.transferCompleted(withErrorCode: errorCode)
func completedTransfer(withError error: NSError?) {
delegate?.transferCompleted(withError: error)
}
}
internal protocol _EasyHandleDelegate: class {
Expand All @@ -107,7 +108,7 @@ internal protocol _EasyHandleDelegate: class {
func fill(writeBuffer buffer: UnsafeMutableBufferPointer<Int8>) -> _EasyHandle._WriteBufferResult
/// The transfer for this handle completed.
/// - parameter errorCode: An NSURLError code, or `nil` if no error occured.
func transferCompleted(withErrorCode errorCode: Int?)
func transferCompleted(withError error: NSError?)
/// Seek the input stream to the given position
func seekInputStream(to position: UInt64) throws
/// Gets called during the transfer to update progress.
Expand Down Expand Up @@ -146,7 +147,8 @@ extension _EasyHandle {
/// Set error buffer for error messages
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_ERRORBUFFER.html
func set(errorBuffer buffer: UnsafeMutableBufferPointer<UInt8>?) {
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionERRORBUFFER, buffer?.baseAddress ?? nil).asError()
let buffer = buffer ?? errorBuffer.withUnsafeMutableBufferPointer { $0 }
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionERRORBUFFER, buffer.baseAddress).asError()
}
/// Request failure on HTTP response >= 400
func set(failOnHTTPErrorCode flag: Bool) {
Expand Down
24 changes: 15 additions & 9 deletions Foundation/URLSession/http/HTTPURLProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,9 @@ fileprivate extension _HTTPURLProtocol {
// NSURLErrorNoPermissionsToReadFile
// NSURLErrorFileDoesNotExist
self.internalState = .transferFailed
failWith(errorCode: errorCode(fileSystemError: e), request: request)
let error = NSError(domain: NSURLErrorDomain, code: errorCode(fileSystemError: e),
userInfo: [NSLocalizedDescriptionKey: "File system error"])
failWith(error: error, request: request)
return
}

Expand Down Expand Up @@ -328,17 +330,19 @@ internal extension _HTTPURLProtocol {
case stream(InputStream)
}

func failWith(errorCode: Int, request: URLRequest) {
func failWith(error: NSError, request: URLRequest) {
//TODO: Error handling
let userInfo: [String : Any]? = request.url.map {
[
NSUnderlyingErrorKey: error,
NSURLErrorFailingURLErrorKey: $0,
NSURLErrorFailingURLStringErrorKey: $0.absoluteString,
NSLocalizedDescriptionKey: NSLocalizedString(error.localizedDescription, comment: "N/A")
]
}
let error = URLError(_nsError: NSError(domain: NSURLErrorDomain, code: errorCode, userInfo: userInfo))
completeTask(withError: error)
self.client?.urlProtocol(self, didFailWithError: error)
let urlError = URLError(_nsError: NSError(domain: NSURLErrorDomain, code: error.code, userInfo: userInfo))
completeTask(withError: urlError)
self.client?.urlProtocol(self, didFailWithError: urlError)
}
}

Expand Down Expand Up @@ -528,16 +532,16 @@ extension _HTTPURLProtocol: _EasyHandleDelegate {
}
}

func transferCompleted(withErrorCode errorCode: Int?) {
func transferCompleted(withError error: NSError?) {
// At this point the transfer is complete and we can decide what to do.
// If everything went well, we will simply forward the resulting data
// to the delegate. But in case of redirects etc. we might send another
// request.
guard case .transferInProgress(let ts) = internalState else { fatalError("Transfer completed, but it wasn't in progress.") }
guard let request = task?.currentRequest else { fatalError("Transfer completed, but there's no current request.") }
guard errorCode == nil else {
guard error == nil else {
internalState = .transferFailed
failWith(errorCode: errorCode!, request: request)
failWith(error: error!, request: request)
return
}

Expand All @@ -555,7 +559,9 @@ extension _HTTPURLProtocol: _EasyHandleDelegate {
completeTask()
case .failWithError(let errorCode):
internalState = .transferFailed
failWith(errorCode: errorCode, request: request)
let error = NSError(domain: NSURLErrorDomain, code: errorCode,
userInfo: [NSLocalizedDescriptionKey: "Completion failure"])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should be calling that new NSLocalizedString function here (once its signature is fixed).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signature fixed. NSLocalizedString() is called indirectly in the creation of the final URLError struct in failWith(error:….

failWith(error: error, request: request)
case .redirectWithRequest(let newRequest):
redirectFor(request: newRequest)
}
Expand Down
16 changes: 12 additions & 4 deletions Foundation/URLSession/http/MultiHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -202,12 +202,20 @@ fileprivate extension URLSession._MultiHandle {
}
let easyHandle = easyHandles[idx]
// Find the NSURLError code
let errorCode = easyHandle.urlErrorCode(for: easyCode)
completedTransfer(forEasyHandle: easyHandle, errorCode: errorCode)
var error: NSError?
if let errorCode = easyHandle.urlErrorCode(for: easyCode) {
let errorDescription = easyHandle.errorBuffer[0] != 0 ?
String(cString: easyHandle.errorBuffer) :
CFURLSessionCreateErrorDescription(easyCode.value)._swiftObject
error = NSError(domain: NSURLErrorDomain, code: errorCode, userInfo: [
NSLocalizedDescriptionKey: errorDescription
])
}
completedTransfer(forEasyHandle: easyHandle, error: error)
}
/// Transfer completed.
func completedTransfer(forEasyHandle handle: _EasyHandle, errorCode: Int?) {
handle.completedTransfer(withErrorCode: errorCode)
func completedTransfer(forEasyHandle handle: _EasyHandle, error: NSError?) {
handle.completedTransfer(withError: error)
}
}

Expand Down