Skip to content

Commit 36a411b

Browse files
authored
Ensure URLSession and curl agree on the host (swiftlang#4836)
1 parent 1c929e5 commit 36a411b

File tree

5 files changed

+59
-5
lines changed

5 files changed

+59
-5
lines changed

CoreFoundation/URL.subproj/CFURLSessionInterface.c

+19
Original file line numberDiff line numberDiff line change
@@ -657,3 +657,22 @@ CFURLSessionSList *_Nullable CFURLSessionSListAppend(CFURLSessionSList *_Nullabl
657657
void CFURLSessionSListFreeAll(CFURLSessionSList *_Nullable list) {
658658
curl_slist_free_all((struct curl_slist *) list);
659659
}
660+
661+
bool CFURLSessionCurlHostIsEqual(const char *_Nonnull url, const char *_Nonnull expectedHost) {
662+
#if LIBCURL_VERSION_MAJOR > 7 || (LIBCURL_VERSION_MAJOR == 7 && LIBCURL_VERSION_MINOR >= 62)
663+
bool isEqual = false;
664+
CURLU *h = curl_url();
665+
if (0 == curl_url_set(h, CURLUPART_URL, url, 0)) {
666+
char *curlHost = NULL;
667+
if (0 == curl_url_get(h, CURLUPART_HOST, &curlHost, 0)) {
668+
isEqual = (strlen(curlHost) == strlen(expectedHost) &&
669+
strncmp(curlHost, expectedHost, strlen(curlHost)) == 0);
670+
curl_free(curlHost);
671+
}
672+
curl_free(h);
673+
}
674+
return isEqual;
675+
#else
676+
return true;
677+
#endif
678+
}

CoreFoundation/URL.subproj/CFURLSessionInterface.h

+1
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ typedef struct CFURLSessionSList CFURLSessionSList;
642642
CF_EXPORT CFURLSessionSList *_Nullable CFURLSessionSListAppend(CFURLSessionSList *_Nullable list, const char * _Nullable string);
643643
CF_EXPORT void CFURLSessionSListFreeAll(CFURLSessionSList *_Nullable list);
644644

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

646647

647648
CF_EXTERN_C_END

Sources/FoundationNetworking/URLSession/FTP/FTPURLProtocol.swift

+15-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,21 @@ internal class _FTPURLProtocol: _NativeProtocol {
5656
easyHandle.set(debugOutputOn: enableLibcurlDebugOutput, task: task!)
5757
easyHandle.set(skipAllSignalHandling: true)
5858
guard let url = request.url else { fatalError("No URL in request.") }
59-
easyHandle.set(url: url)
59+
guard url.host != nil else {
60+
self.internalState = .transferFailed
61+
let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL,
62+
userInfo: [NSLocalizedDescriptionKey: "FTP URL must have a host"])
63+
failWith(error: error, request: request)
64+
return
65+
}
66+
do {
67+
try easyHandle.set(url: url)
68+
} catch {
69+
self.internalState = .transferFailed
70+
let nsError = error as? NSError ?? NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL)
71+
failWith(error: nsError, request: request)
72+
return
73+
}
6074
easyHandle.set(preferredReceiveBufferSize: Int.max)
6175
do {
6276
switch (body, try body.getBodyLength()) {

Sources/FoundationNetworking/URLSession/HTTP/HTTPURLProtocol.swift

+15-1
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,21 @@ internal class _HTTPURLProtocol: _NativeProtocol {
311311
guard let url = request.url else {
312312
fatalError("No URL in request.")
313313
}
314-
easyHandle.set(url: url)
314+
guard url.host != nil else {
315+
self.internalState = .transferFailed
316+
let error = NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL,
317+
userInfo: [NSLocalizedDescriptionKey: "HTTP URL must have a host"])
318+
failWith(error: error, request: request)
319+
return
320+
}
321+
do {
322+
try easyHandle.set(url: url)
323+
} catch {
324+
self.internalState = .transferFailed
325+
let nsError = error as? NSError ?? NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL)
326+
failWith(error: nsError, request: request)
327+
return
328+
}
315329
let session = task?.session as! URLSession
316330
let _config = session._configuration
317331
easyHandle.set(sessionConfig: _config)

Sources/FoundationNetworking/URLSession/libcurl/EasyHandle.swift

+9-3
Original file line numberDiff line numberDiff line change
@@ -165,10 +165,16 @@ extension _EasyHandle {
165165
}
166166
/// URL to use in the request
167167
/// - SeeAlso: https://curl.haxx.se/libcurl/c/CURLOPT_URL.html
168-
func set(url: URL) {
168+
func set(url: URL) throws {
169169
_url = url
170-
url.absoluteString.withCString {
171-
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionURL, UnsafeMutablePointer(mutating: $0)).asError()
170+
try url.absoluteString.withCString { urlPtr in
171+
try url.host?.withCString { hostPtr in
172+
guard CFURLSessionCurlHostIsEqual(urlPtr, hostPtr) else {
173+
throw NSError(domain: NSURLErrorDomain, code: NSURLErrorBadURL,
174+
userInfo: [NSLocalizedDescriptionKey: "URLSession and curl did not agree on URL host"])
175+
}
176+
}
177+
try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionURL, UnsafeMutablePointer(mutating: urlPtr)).asError()
172178
}
173179
}
174180

0 commit comments

Comments
 (0)