diff --git a/Documentation/SwiftlyDocs.docc/getting-started.md b/Documentation/SwiftlyDocs.docc/getting-started.md index b66d50e3..422f7852 100644 --- a/Documentation/SwiftlyDocs.docc/getting-started.md +++ b/Documentation/SwiftlyDocs.docc/getting-started.md @@ -58,6 +58,17 @@ Uninstall this toolchain after you're finished with it: $ swiftly uninstall main-snapshot ``` +# Proxy + +Swiftly downloads a list of toolchains from https://www.swift.org/ and retrieves them from Apple/Akamai CDN via https://download.swift.org. +If your environment requires a proxy, Swiftly will attempt to use the standard environment variables `http_proxy`, `HTTP_PROXY`, `https_proxy` or `HTTPS_PROXY` to determine which proxy server to use instead of making a direct connection. + +To download latest nightly snapshot using a proxy: +``` +$ export https_proxy=http://proxy:3128 +$ swiftly install main-snapshot +``` + # See Also: - [Install Toolchains](install-toolchains) diff --git a/Sources/SwiftlyCore/HTTPClient.swift b/Sources/SwiftlyCore/HTTPClient.swift index b34d0211..c3d00a50 100644 --- a/Sources/SwiftlyCore/HTTPClient.swift +++ b/Sources/SwiftlyCore/HTTPClient.swift @@ -10,9 +10,48 @@ public protocol HTTPRequestExecutor { } /// An `HTTPRequestExecutor` backed by the shared `HTTPClient`. -internal struct HTTPRequestExecutorImpl: HTTPRequestExecutor { +internal class HTTPRequestExecutorImpl: HTTPRequestExecutor { + let httpClient: HTTPClient + + public init() { + var proxy: HTTPClient.Configuration.Proxy? + + func getProxyFromEnv(keys: [String]) -> HTTPClient.Configuration.Proxy? { + let environment = ProcessInfo.processInfo.environment + for key in keys { + if let proxyString = environment[key], + let url = URL(string: proxyString), + let host = url.host, + let port = url.port + { + return .server(host: host, port: port) + } + } + return nil + } + + if let httpProxy = getProxyFromEnv(keys: ["http_proxy", "HTTP_PROXY"]) { + proxy = httpProxy + } + if let httpsProxy = getProxyFromEnv(keys: ["https_proxy", "HTTPS_PROXY"]) { + proxy = httpsProxy + } + + if proxy != nil { + self.httpClient = HTTPClient(eventLoopGroupProvider: .singleton, configuration: HTTPClient.Configuration(proxy: proxy)) + } else { + self.httpClient = HTTPClient.shared + } + } + + deinit { + if httpClient !== HTTPClient.shared { + try? httpClient.syncShutdown() + } + } + public func execute(_ request: HTTPClientRequest, timeout: TimeAmount) async throws -> HTTPClientResponse { - try await HTTPClient.shared.execute(request, timeout: timeout) + try await self.httpClient.execute(request, timeout: timeout) } } diff --git a/Tests/SwiftlyTests/SwiftlyTests.swift b/Tests/SwiftlyTests/SwiftlyTests.swift index cc59daee..1616cf51 100644 --- a/Tests/SwiftlyTests/SwiftlyTests.swift +++ b/Tests/SwiftlyTests/SwiftlyTests.swift @@ -17,51 +17,7 @@ struct SwiftlyTestError: LocalizedError { let message: String } -var proxyExecutorInstalled = false - -/// An `HTTPRequestExecutor` backed by an `HTTPClient` that can take http proxy -/// information from the environment in either HTTP_PROXY or HTTPS_PROXY -class ProxyHTTPRequestExecutorImpl: HTTPRequestExecutor { - let httpClient: HTTPClient - public init() { - var proxy: HTTPClient.Configuration.Proxy? - - let environment = ProcessInfo.processInfo.environment - let httpProxy = environment["HTTP_PROXY"] - if let httpProxy, let url = URL(string: httpProxy), let host = url.host, let port = url.port { - proxy = .server(host: host, port: port) - } - - let httpsProxy = environment["HTTPS_PROXY"] - if let httpsProxy, let url = URL(string: httpsProxy), let host = url.host, let port = url.port { - proxy = .server(host: host, port: port) - } - - if proxy != nil { - self.httpClient = HTTPClient(eventLoopGroupProvider: .singleton, configuration: HTTPClient.Configuration(proxy: proxy)) - } else { - self.httpClient = HTTPClient.shared - } - } - - public func execute(_ request: HTTPClientRequest, timeout: TimeAmount) async throws -> HTTPClientResponse { - try await self.httpClient.execute(request, timeout: timeout) - } - - deinit { - if httpClient !== HTTPClient.shared { - try? httpClient.syncShutdown() - } - } -} - class SwiftlyTests: XCTestCase { - override class func setUp() { - if !proxyExecutorInstalled { - SwiftlyCore.httpRequestExecutor = ProxyHTTPRequestExecutorImpl() - } - } - override class func tearDown() { #if os(Linux) let deleteTestGPGKeys = Process()