Skip to content

Commit

Permalink
Ensure URLSession and curl agree on the host (#4836) (#4853)
Browse files Browse the repository at this point in the history
Cherry-pick of #4836 to release/5.10
  • Loading branch information
jrflat authored Dec 16, 2023
1 parent 50a77b5 commit 19e5eb0
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 5 deletions.
19 changes: 19 additions & 0 deletions CoreFoundation/URL.subproj/CFURLSessionInterface.c
Original file line number Diff line number Diff line change
Expand Up @@ -657,3 +657,22 @@ CFURLSessionSList *_Nullable CFURLSessionSListAppend(CFURLSessionSList *_Nullabl
void CFURLSessionSListFreeAll(CFURLSessionSList *_Nullable list) {
curl_slist_free_all((struct curl_slist *) list);
}

bool CFURLSessionCurlHostIsEqual(const char *_Nonnull url, const char *_Nonnull expectedHost) {
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 62)
bool isEqual = false;
CURLU *h = curl_url();
if (0 == curl_url_set(h, CURLUPART_URL, url, 0)) {
char *curlHost = NULL;
if (0 == curl_url_get(h, CURLUPART_HOST, &curlHost, 0)) {
isEqual = (strlen(curlHost) == strlen(expectedHost) &&
strncmp(curlHost, expectedHost, strlen(curlHost)) == 0);
curl_free(curlHost);
}
curl_free(h);
}
return isEqual;
#else
return true;
#endif
}
1 change: 1 addition & 0 deletions CoreFoundation/URL.subproj/CFURLSessionInterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,7 @@ typedef struct CFURLSessionSList CFURLSessionSList;
CF_EXPORT CFURLSessionSList *_Nullable CFURLSessionSListAppend(CFURLSessionSList *_Nullable list, const char * _Nullable string);
CF_EXPORT void CFURLSessionSListFreeAll(CFURLSessionSList *_Nullable list);

CF_EXPORT bool CFURLSessionCurlHostIsEqual(const char *_Nonnull url, const char *_Nonnull expectedHost);


CF_EXTERN_C_END
Expand Down
16 changes: 15 additions & 1 deletion Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,21 @@ internal class _FTPURLProtocol: _NativeProtocol {
easyHandle.set(debugOutputOn: enableLibcurlDebugOutput, task: task!)
easyHandle.set(skipAllSignalHandling: true)
guard let url = request.url else { fatalError("No URL in request.") }
easyHandle.set(url: url)
guard url.host != nil else {
self.internalState = .transferFailed
let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL,
userInfo: [NSLocalizedDescriptionKey: "FTP URL must have a host"])
failWith(error: error, request: request)
return
}
do {
try easyHandle.set(url: url)
} catch {
self.internalState = .transferFailed
let nsError = error as? NSError ?? NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL)
failWith(error: nsError, request: request)
return
}
easyHandle.set(preferredReceiveBufferSize: Int.max)
do {
switch (body, try body.getBodyLength()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,21 @@ internal class _HTTPURLProtocol: _NativeProtocol {
guard let url = request.url else {
fatalError("No URL in request.")
}
easyHandle.set(url: url)
guard url.host != nil else {
self.internalState = .transferFailed
let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL,
userInfo: [NSLocalizedDescriptionKey: "HTTP URL must have a host"])
failWith(error: error, request: request)
return
}
do {
try easyHandle.set(url: url)
} catch {
self.internalState = .transferFailed
let nsError = error as? NSError ?? NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL)
failWith(error: nsError, request: request)
return
}
let session = task?.session as! URLSession
let _config = session._configuration
easyHandle.set(sessionConfig: _config)
Expand Down
12 changes: 9 additions & 3 deletions Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,16 @@ extension _EasyHandle {
}
/// URL to use in the request
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_URL.html
func set(url: URL) {
func set(url: URL) throws {
_url = url
url.absoluteString.withCString {
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionURL, UnsafeMutablePointer(mutating: $0)).asError()
try url.absoluteString.withCString { urlPtr in
try url.host?.withCString { hostPtr in
guard CFURLSessionCurlHostIsEqual(urlPtr, hostPtr) else {
throw NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL,
userInfo: [NSLocalizedDescriptionKey: "URLSession and curl did not agree on URL host"])
}
}
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionURL, UnsafeMutablePointer(mutating: urlPtr)).asError()
}
}

Expand Down

0 comments on commit 19e5eb0

Please sign in to comment.