Skip to content

Ensure URLSession and curl agree on the host #4836

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
Nov 16, 2023
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
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