From 9daac3de389f3f5aae2db8954cf1520ec1415da7 Mon Sep 17 00:00:00 2001 From: Lily Vulcano Date: Wed, 15 Apr 2020 15:26:12 -0700 Subject: [PATCH] Support Linux variants with older libcurl --- CMakeLists.txt | 1 + CoreFoundation/CMakeLists.txt | 10 ++++ .../URL.subproj/CFURLSessionInterface.c | 46 ++----------------- Foundation/CMakeLists.txt | 16 +++++++ Foundation/URLSession/NativeProtocol.swift | 9 ++-- .../URLSession/URLSessionConfiguration.swift | 8 +++- Foundation/URLSession/URLSessionTask.swift | 7 ++- .../URLSession/libcurl/EasyHandle.swift | 4 +- .../URLSession/libcurl/MultiHandle.swift | 3 ++ 9 files changed, 55 insertions(+), 49 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d5d68f9833..0592f16fb5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ if(CMAKE_VERSION VERSION_LESS 3.16.0) endif() option(BUILD_SHARED_LIBS "build shared libraries" ON) +option(NS_CURL_ASSUME_FEATURES_MISSING "Assume that optional libcurl features are missing rather than test the library's version, for build debugging" NO) find_package(CURL CONFIG) if(CURL_FOUND) diff --git a/CoreFoundation/CMakeLists.txt b/CoreFoundation/CMakeLists.txt index 90a777234e..94d87227ba 100644 --- a/CoreFoundation/CMakeLists.txt +++ b/CoreFoundation/CMakeLists.txt @@ -391,6 +391,16 @@ if(CMAKE_SYSTEM_NAME STREQUAL Android) log) endif() +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.32.0")) + add_compile_definitions($<$:NS_CURL_MISSING_XFERINFOFUNCTION>) + endif() + + if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.30.0")) + add_compile_definitions($<$:NS_CURL_MISSING_MAX_HOST_CONNECTIONS>) + endif() +endif() + add_framework(CFURLSessionInterface ${FRAMEWORK_LIBRARY_TYPE} FRAMEWORK_DIRECTORY diff --git a/CoreFoundation/URL.subproj/CFURLSessionInterface.c b/CoreFoundation/URL.subproj/CFURLSessionInterface.c index 581014856c..ba5dfd5766 100644 --- a/CoreFoundation/URL.subproj/CFURLSessionInterface.c +++ b/CoreFoundation/URL.subproj/CFURLSessionInterface.c @@ -157,7 +157,6 @@ CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_ACCEPT_TIMEOUT = { CURLE_FTP_ CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_WEIRD_PASV_REPLY = { CURLE_FTP_WEIRD_PASV_REPLY }; CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_WEIRD_227_FORMAT = { CURLE_FTP_WEIRD_227_FORMAT }; CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_CANT_GET_HOST = { CURLE_FTP_CANT_GET_HOST }; -//CFURLSessionEasyCode const CFURLSessionEasyCodeHTTP2 = { CURLE_HTTP2 }; CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_COULDNT_SET_TYPE = { CURLE_FTP_COULDNT_SET_TYPE }; CFURLSessionEasyCode const CFURLSessionEasyCodePARTIAL_FILE = { CURLE_PARTIAL_FILE }; CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_COULDNT_RETR_FILE = { CURLE_FTP_COULDNT_RETR_FILE }; @@ -185,7 +184,6 @@ CFURLSessionEasyCode const CFURLSessionEasyCodeBAD_DOWNLOAD_RESUME = { CURLE_BAD CFURLSessionEasyCode const CFURLSessionEasyCodeFILE_COULDNT_READ_FILE = { CURLE_FILE_COULDNT_READ_FILE }; CFURLSessionEasyCode const CFURLSessionEasyCodeLDAP_CANNOT_BIND = { CURLE_LDAP_CANNOT_BIND }; CFURLSessionEasyCode const CFURLSessionEasyCodeLDAP_SEARCH_FAILED = { CURLE_LDAP_SEARCH_FAILED }; -//CFURLSessionEasyCode const CFURLSessionEasyCodeOBSOLETE40 = { CURLE_OBSOLETE40 }; CFURLSessionEasyCode const CFURLSessionEasyCodeFUNCTION_NOT_FOUND = { CURLE_FUNCTION_NOT_FOUND }; CFURLSessionEasyCode const CFURLSessionEasyCodeABORTED_BY_CALLBACK = { CURLE_ABORTED_BY_CALLBACK }; CFURLSessionEasyCode const CFURLSessionEasyCodeBAD_FUNCTION_ARGUMENT = { CURLE_BAD_FUNCTION_ARGUMENT }; @@ -234,10 +232,6 @@ CFURLSessionEasyCode const CFURLSessionEasyCodeRTSP_CSEQ_ERROR = { CURLE_RTSP_CS CFURLSessionEasyCode const CFURLSessionEasyCodeRTSP_SESSION_ERROR = { CURLE_RTSP_SESSION_ERROR }; CFURLSessionEasyCode const CFURLSessionEasyCodeFTP_BAD_FILE_LIST = { CURLE_FTP_BAD_FILE_LIST }; CFURLSessionEasyCode const CFURLSessionEasyCodeCHUNK_FAILED = { CURLE_CHUNK_FAILED }; -CFURLSessionEasyCode const CFURLSessionEasyCodeNO_CONNECTION_AVAILABLE = { CURLE_NO_CONNECTION_AVAILABLE }; -//CFURLSessionEasyCode const CFURLSessionEasyCodeSSL_PINNEDPUBKEYNOTMATCH = { CURLE_SSL_PINNEDPUBKEYNOTMATCH }; -//CFURLSessionEasyCode const CFURLSessionEasyCodeSSL_INVALIDCERTSTATUS = { CURLE_SSL_INVALIDCERTSTATUS }; - CFURLSessionProtocol const CFURLSessionProtocolHTTP = CURLPROTO_HTTP; CFURLSessionProtocol const CFURLSessionProtocolHTTPS = CURLPROTO_HTTPS; @@ -265,8 +259,6 @@ CFURLSessionProtocol const CFURLSessionProtocolRTMPTE = CURLPROTO_RTMPTE; CFURLSessionProtocol const CFURLSessionProtocolRTMPS = CURLPROTO_RTMPS; CFURLSessionProtocol const CFURLSessionProtocolRTMPTS = CURLPROTO_RTMPTS; CFURLSessionProtocol const CFURLSessionProtocolGOPHER = CURLPROTO_GOPHER; -//CFURLSessionProtocol const CFURLSessionProtocolSMB = CURLPROTO_SMB; -//CFURLSessionProtocol const CFURLSessionProtocolSMBS = CURLPROTO_SMBS; CFURLSessionProtocol const CFURLSessionProtocolALL = CURLPROTO_ALL; @@ -308,7 +300,6 @@ CFURLSessionOption const CFURLSessionOptionTIMEVALUE = { CURLOPT_TIMEVALUE }; CFURLSessionOption const CFURLSessionOptionCUSTOMREQUEST = { CURLOPT_CUSTOMREQUEST }; CFURLSessionOption const CFURLSessionOptionSTDERR = { CURLOPT_STDERR }; CFURLSessionOption const CFURLSessionOptionPOSTQUOTE = { CURLOPT_POSTQUOTE }; -/*CFURLSessionOption const CFURLSessionOptionOBSOLETE40 = { CURLOPT_OBSOLETE40 };*/ CFURLSessionOption const CFURLSessionOptionVERBOSE = { CURLOPT_VERBOSE }; CFURLSessionOption const CFURLSessionOptionHEADER = { CURLOPT_HEADER }; CFURLSessionOption const CFURLSessionOptionNOPROGRESS = { CURLOPT_NOPROGRESS }; @@ -336,7 +327,6 @@ CFURLSessionOption const CFURLSessionOptionMAXREDIRS = { CURLOPT_MAXREDIRS }; CFURLSessionOption const CFURLSessionOptionFILETIME = { CURLOPT_FILETIME }; CFURLSessionOption const CFURLSessionOptionTELNETOPTIONS = { CURLOPT_TELNETOPTIONS }; CFURLSessionOption const CFURLSessionOptionMAXCONNECTS = { CURLOPT_MAXCONNECTS }; -//CFURLSessionOption const CFURLSessionOptionOBSOLETE72 = { CURLOPT_OBSOLETE72 }; CFURLSessionOption const CFURLSessionOptionFRESH_CONNECT = { CURLOPT_FRESH_CONNECT }; CFURLSessionOption const CFURLSessionOptionFORBID_REUSE = { CURLOPT_FORBID_REUSE }; CFURLSessionOption const CFURLSessionOptionRANDOM_FILE = { CURLOPT_RANDOM_FILE }; @@ -472,30 +462,9 @@ CFURLSessionOption const CFURLSessionOptionTCP_KEEPIDLE = { CURLOPT_TCP_KEEPIDLE CFURLSessionOption const CFURLSessionOptionTCP_KEEPINTVL = { CURLOPT_TCP_KEEPINTVL }; CFURLSessionOption const CFURLSessionOptionSSL_OPTIONS = { CURLOPT_SSL_OPTIONS }; CFURLSessionOption const CFURLSessionOptionMAIL_AUTH = { CURLOPT_MAIL_AUTH }; -CFURLSessionOption const CFURLSessionOptionSASL_IR = { CURLOPT_SASL_IR }; +#if !NS_CURL_MISSING_XFERINFOFUNCTION CFURLSessionOption const CFURLSessionOptionXFERINFOFUNCTION = { CURLOPT_XFERINFOFUNCTION }; -CFURLSessionOption const CFURLSessionOptionXFERINFODATA = { CURLOPT_XFERINFODATA }; -CFURLSessionOption const CFURLSessionOptionXOAUTH2_BEARER = { CURLOPT_XOAUTH2_BEARER }; -CFURLSessionOption const CFURLSessionOptionDNS_INTERFACE = { CURLOPT_DNS_INTERFACE }; -CFURLSessionOption const CFURLSessionOptionDNS_LOCAL_IP4 = { CURLOPT_DNS_LOCAL_IP4 }; -CFURLSessionOption const CFURLSessionOptionDNS_LOCAL_IP6 = { CURLOPT_DNS_LOCAL_IP6 }; -CFURLSessionOption const CFURLSessionOptionLOGIN_OPTIONS = { CURLOPT_LOGIN_OPTIONS }; - -//Options unavailable on Ubuntu 14.04 -/*CFURLSessionOption const CFURLSessionOptionSSL_ENABLE_NPN = { CURLOPT_SSL_ENABLE_NPN }; -CFURLSessionOption const CFURLSessionOptionSSL_ENABLE_ALPN = { CURLOPT_SSL_ENABLE_ALPN }; -CFURLSessionOption const CFURLSessionOptionEXPECT_100_TIMEOUT_MS = { CURLOPT_EXPECT_100_TIMEOUT_MS }; -CFURLSessionOption const CFURLSessionOptionPROXYHEADER = { CURLOPT_PROXYHEADER }; -CFURLSessionOption const CFURLSessionOptionHEADEROPT = { CURLOPT_HEADEROPT }; -CFURLSessionOption const CFURLSessionOptionPINNEDPUBLICKEY = { CURLOPT_PINNEDPUBLICKEY }; -CFURLSessionOption const CFURLSessionOptionUNIX_SOCKET_PATH = { CURLOPT_UNIX_SOCKET_PATH }; -CFURLSessionOption const CFURLSessionOptionSSL_VERIFYSTATUS = { CURLOPT_SSL_VERIFYSTATUS }; -CFURLSessionOption const CFURLSessionOptionSSL_FALSESTART = { CURLOPT_SSL_FALSESTART }; -CFURLSessionOption const CFURLSessionOptionPATH_AS_IS = { CURLOPT_PATH_AS_IS }; -CFURLSessionOption const CFURLSessionOptionPROXY_SERVICE_NAME = { CURLOPT_PROXY_SERVICE_NAME }; -CFURLSessionOption const CFURLSessionOptionSERVICE_NAME = { CURLOPT_SERVICE_NAME }; -CFURLSessionOption const CFURLSessionOptionPIPEWAIT = { CURLOPT_PIPEWAIT };*/ - +#endif CFURLSessionInfo const CFURLSessionInfoTEXT = { CURLINFO_TEXT }; CFURLSessionInfo const CFURLSessionInfoHEADER_IN = { CURLINFO_HEADER_IN }; @@ -548,7 +517,6 @@ CFURLSessionInfo const CFURLSessionInfoRTSP_CSEQ_RECV = { CURLINFO_RTSP_CSEQ_REC CFURLSessionInfo const CFURLSessionInfoPRIMARY_PORT = { CURLINFO_PRIMARY_PORT }; CFURLSessionInfo const CFURLSessionInfoLOCAL_IP = { CURLINFO_LOCAL_IP }; CFURLSessionInfo const CFURLSessionInfoLOCAL_PORT = { CURLINFO_LOCAL_PORT }; -CFURLSessionInfo const CFURLSessionInfoTLS_SESSION = { CURLINFO_TLS_SESSION }; CFURLSessionInfo const CFURLSessionInfoLASTONE = { CURLINFO_LASTONE }; @@ -558,14 +526,9 @@ CFURLSessionMultiOption const CFURLSessionMultiOptionPIPELINING = { CURLMOPT_PIP CFURLSessionMultiOption const CFURLSessionMultiOptionTIMERFUNCTION = { CURLMOPT_TIMERFUNCTION }; CFURLSessionMultiOption const CFURLSessionMultiOptionTIMERDATA = { CURLMOPT_TIMERDATA }; CFURLSessionMultiOption const CFURLSessionMultiOptionMAXCONNECTS = { CURLMOPT_MAXCONNECTS }; +#if !NS_CURL_MISSING_MAX_HOST_CONNECTIONS CFURLSessionMultiOption const CFURLSessionMultiOptionMAX_HOST_CONNECTIONS = { CURLMOPT_MAX_HOST_CONNECTIONS }; -CFURLSessionMultiOption const CFURLSessionMultiOptionMAX_PIPELINE_LENGTH = { CURLMOPT_MAX_PIPELINE_LENGTH }; -CFURLSessionMultiOption const CFURLSessionMultiOptionCONTENT_LENGTH_PENALTY_SIZE = { CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE }; -CFURLSessionMultiOption const CFURLSessionMultiOptionCHUNK_LENGTH_PENALTY_SIZE = { CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE }; -CFURLSessionMultiOption const CFURLSessionMultiOptionPIPELINING_SITE_BL = { CURLMOPT_PIPELINING_SITE_BL }; -CFURLSessionMultiOption const CFURLSessionMultiOptionPIPELINING_SERVER_BL = { CURLMOPT_PIPELINING_SERVER_BL }; -CFURLSessionMultiOption const CFURLSessionMultiOptionMAX_TOTAL_CONNECTIONS = { CURLMOPT_MAX_TOTAL_CONNECTIONS }; - +#endif CFURLSessionMultiCode const CFURLSessionMultiCodeCALL_MULTI_PERFORM = { CURLM_CALL_MULTI_PERFORM }; CFURLSessionMultiCode const CFURLSessionMultiCodeOK = { CURLM_OK }; @@ -575,7 +538,6 @@ CFURLSessionMultiCode const CFURLSessionMultiCodeOUT_OF_MEMORY = { CURLM_OUT_OF_ CFURLSessionMultiCode const CFURLSessionMultiCodeINTERNAL_ERROR = { CURLM_INTERNAL_ERROR }; CFURLSessionMultiCode const CFURLSessionMultiCodeBAD_SOCKET = { CURLM_BAD_SOCKET }; CFURLSessionMultiCode const CFURLSessionMultiCodeUNKNOWN_OPTION = { CURLM_UNKNOWN_OPTION }; -CFURLSessionMultiCode const CFURLSessionMultiCodeADDED_ALREADY = { CURLM_ADDED_ALREADY }; CFURLSessionMultiCode const CFURLSessionMultiCodeLAST = { CURLM_LAST }; diff --git a/Foundation/CMakeLists.txt b/Foundation/CMakeLists.txt index cf80e7dde9..c75970eee4 100644 --- a/Foundation/CMakeLists.txt +++ b/Foundation/CMakeLists.txt @@ -178,6 +178,22 @@ set_target_properties(Foundation PROPERTIES Swift_MODULE_DIRECTORY ${CMAKE_BINARY_DIR}/swift INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_BINARY_DIR}/swift) +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + find_package(CURL CONFIG) + if(NOT CURL_FOUND) + find_package(CURL REQUIRED) + endif() +endif() + +if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin) + if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.32.0")) + add_compile_definitions(NS_CURL_MISSING_XFERINFOFUNCTION) + endif() + + if((NS_CURL_ASSUME_FEATURES_MISSING) OR (CURL_VERSION_STRING VERSION_LESS "7.30.0")) + add_compile_definitions(NS_CURL_MISSING_MAX_HOST_CONNECTIONS) + endif() +endif() add_library(FoundationNetworking Boxing.swift diff --git a/Foundation/URLSession/NativeProtocol.swift b/Foundation/URLSession/NativeProtocol.swift index 43476011c3..078a6d3e0d 100644 --- a/Foundation/URLSession/NativeProtocol.swift +++ b/Foundation/URLSession/NativeProtocol.swift @@ -301,10 +301,11 @@ internal class _NativeProtocol: URLProtocol, _EasyHandleDelegate { } } - func updateProgressMeter(with propgress: _EasyHandle._Progress) { - //TODO: Update progress. Note that a single URLSessionTask might - // perform multiple transfers. The values in `progress` are only for - // the current transfer. + func updateProgressMeter(with progress: _EasyHandle._Progress) { + guard let progressReporter = self.task?.progress else { return } + + progressReporter.totalUnitCount = progress.totalBytesExpectedToReceive + progress.totalBytesExpectedToSend + progressReporter.completedUnitCount = progress.totalBytesReceived + progress.totalBytesSent } /// The data drain. diff --git a/Foundation/URLSession/URLSessionConfiguration.swift b/Foundation/URLSession/URLSessionConfiguration.swift index db8ffefbaa..3bf7ac4cb5 100644 --- a/Foundation/URLSession/URLSessionConfiguration.swift +++ b/Foundation/URLSession/URLSessionConfiguration.swift @@ -215,9 +215,15 @@ open class URLSessionConfiguration : NSObject, NSCopying { /* Specifies additional headers which will be set on outgoing requests. Note that these headers are added to the request only if not already present. */ open var httpAdditionalHeaders: [AnyHashable : Any]? = nil - + + #if NS_CURL_MISSING_MAX_HOST_CONNECTIONS + /* The maximum number of simultaneous persistent connections per host */ + @available(*, deprecated, message: "This platform does not support selecting the maximum number of simultaneous persistent connections per host. This property is ignored.") + open var httpMaximumConnectionsPerHost: Int + #else /* The maximum number of simultaneous persistent connections per host */ open var httpMaximumConnectionsPerHost: Int + #endif /* The cookie storage object to use, or nil to indicate that no cookies should be handled */ open var httpCookieStorage: HTTPCookieStorage? diff --git a/Foundation/URLSession/URLSessionTask.swift b/Foundation/URLSession/URLSessionTask.swift index c41378c8aa..4e716bcb6d 100644 --- a/Foundation/URLSession/URLSessionTask.swift +++ b/Foundation/URLSession/URLSessionTask.swift @@ -37,8 +37,13 @@ open class URLSessionTask : NSObject, NSCopying { open var countOfBytesClientExpectsToSend: Int64 = NSURLSessionTransferSizeUnknown { didSet { updateProgress() } } - + + #if NS_CURL_MISSING_XFERINFOFUNCTION + @available(*, deprecated, message: "This platform doesn't fully support reporting the progress of a URLSessionTask. The progress instance returned will be functional, but may not have continuous updates as bytes are sent or received.") + open private(set) var progress = Progress(totalUnitCount: -1) + #else open private(set) var progress = Progress(totalUnitCount: -1) + #endif func updateProgress() { self.workQueue.async { diff --git a/Foundation/URLSession/libcurl/EasyHandle.swift b/Foundation/URLSession/libcurl/EasyHandle.swift index 65e124c540..e5d7e02f6c 100644 --- a/Foundation/URLSession/libcurl/EasyHandle.swift +++ b/Foundation/URLSession/libcurl/EasyHandle.swift @@ -498,12 +498,14 @@ fileprivate extension _EasyHandle { try! CFURLSession_easy_setopt_long(rawHandle, CFURLSessionOptionNOPROGRESS, 0).asError() try! CFURLSession_easy_setopt_ptr(rawHandle, CFURLSessionOptionPROGRESSDATA, UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())).asError() - + + #if !NS_CURL_MISSING_XFERINFOFUNCTION try! CFURLSession_easy_setopt_tc(rawHandle, CFURLSessionOptionXFERINFOFUNCTION, { (userdata: UnsafeMutableRawPointer?, dltotal :Int64, dlnow: Int64, ultotal: Int64, ulnow: Int64) -> Int32 in guard let handle = _EasyHandle.from(callbackUserData: userdata) else { return -1 } handle.updateProgressMeter(with: _Progress(totalBytesSent: ulnow, totalBytesExpectedToSend: ultotal, totalBytesReceived: dlnow, totalBytesExpectedToReceive: dltotal)) return 0 }).asError() + #endif } /// This callback function gets called by libcurl when it receives body diff --git a/Foundation/URLSession/libcurl/MultiHandle.swift b/Foundation/URLSession/libcurl/MultiHandle.swift index 13d246e8f1..8c87a93117 100644 --- a/Foundation/URLSession/libcurl/MultiHandle.swift +++ b/Foundation/URLSession/libcurl/MultiHandle.swift @@ -65,7 +65,10 @@ extension URLSession { extension URLSession._MultiHandle { func configure(with configuration: URLSession._Configuration) { + #if !NS_CURL_MISSING_XFERINFOFUNCTION try! CFURLSession_multi_setopt_l(rawHandle, CFURLSessionMultiOptionMAX_HOST_CONNECTIONS, numericCast(configuration.httpMaximumConnectionsPerHost)).asError() + #endif + try! CFURLSession_multi_setopt_l(rawHandle, CFURLSessionMultiOptionPIPELINING, configuration.httpShouldUsePipelining ? 3 : 2).asError() //TODO: We may want to set // CFURLSessionMultiOptionMAXCONNECTS