Skip to content

Download toolchains using proxy if one is set in the environment #189

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 3 commits into from
Dec 2, 2024
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
11 changes: 11 additions & 0 deletions Documentation/SwiftlyDocs.docc/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
43 changes: 41 additions & 2 deletions Sources/SwiftlyCore/HTTPClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}

Expand Down
44 changes: 0 additions & 44 deletions Tests/SwiftlyTests/SwiftlyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down