Skip to content

Commit c5518b6

Browse files
authored
Download toolchains using proxy if one is set in the environment (#189)
Swiftly doesn't currently handle the standard HTTP proxy server environment variables when making its network connections. It only handles it as a necessity in the current macOS CI environment and only in the tests. Make the built-in http executor read these environment variables if they are present and use those for all http requests. Add documentation in the GSG showing how to use this feature.
1 parent ec7887e commit c5518b6

File tree

3 files changed

+52
-46
lines changed

3 files changed

+52
-46
lines changed

Documentation/SwiftlyDocs.docc/getting-started.md

+11
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,17 @@ Uninstall this toolchain after you're finished with it:
5858
$ swiftly uninstall main-snapshot
5959
```
6060

61+
# Proxy
62+
63+
Swiftly downloads a list of toolchains from https://www.swift.org/ and retrieves them from Apple/Akamai CDN via https://download.swift.org.
64+
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.
65+
66+
To download latest nightly snapshot using a proxy:
67+
```
68+
$ export https_proxy=http://proxy:3128
69+
$ swiftly install main-snapshot
70+
```
71+
6172
# See Also:
6273

6374
- [Install Toolchains](install-toolchains)

Sources/SwiftlyCore/HTTPClient.swift

+41-2
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,48 @@ public protocol HTTPRequestExecutor {
1010
}
1111

1212
/// An `HTTPRequestExecutor` backed by the shared `HTTPClient`.
13-
internal struct HTTPRequestExecutorImpl: HTTPRequestExecutor {
13+
internal class HTTPRequestExecutorImpl: HTTPRequestExecutor {
14+
let httpClient: HTTPClient
15+
16+
public init() {
17+
var proxy: HTTPClient.Configuration.Proxy?
18+
19+
func getProxyFromEnv(keys: [String]) -> HTTPClient.Configuration.Proxy? {
20+
let environment = ProcessInfo.processInfo.environment
21+
for key in keys {
22+
if let proxyString = environment[key],
23+
let url = URL(string: proxyString),
24+
let host = url.host,
25+
let port = url.port
26+
{
27+
return .server(host: host, port: port)
28+
}
29+
}
30+
return nil
31+
}
32+
33+
if let httpProxy = getProxyFromEnv(keys: ["http_proxy", "HTTP_PROXY"]) {
34+
proxy = httpProxy
35+
}
36+
if let httpsProxy = getProxyFromEnv(keys: ["https_proxy", "HTTPS_PROXY"]) {
37+
proxy = httpsProxy
38+
}
39+
40+
if proxy != nil {
41+
self.httpClient = HTTPClient(eventLoopGroupProvider: .singleton, configuration: HTTPClient.Configuration(proxy: proxy))
42+
} else {
43+
self.httpClient = HTTPClient.shared
44+
}
45+
}
46+
47+
deinit {
48+
if httpClient !== HTTPClient.shared {
49+
try? httpClient.syncShutdown()
50+
}
51+
}
52+
1453
public func execute(_ request: HTTPClientRequest, timeout: TimeAmount) async throws -> HTTPClientResponse {
15-
try await HTTPClient.shared.execute(request, timeout: timeout)
54+
try await self.httpClient.execute(request, timeout: timeout)
1655
}
1756
}
1857

Tests/SwiftlyTests/SwiftlyTests.swift

-44
Original file line numberDiff line numberDiff line change
@@ -17,51 +17,7 @@ struct SwiftlyTestError: LocalizedError {
1717
let message: String
1818
}
1919

20-
var proxyExecutorInstalled = false
21-
22-
/// An `HTTPRequestExecutor` backed by an `HTTPClient` that can take http proxy
23-
/// information from the environment in either HTTP_PROXY or HTTPS_PROXY
24-
class ProxyHTTPRequestExecutorImpl: HTTPRequestExecutor {
25-
let httpClient: HTTPClient
26-
public init() {
27-
var proxy: HTTPClient.Configuration.Proxy?
28-
29-
let environment = ProcessInfo.processInfo.environment
30-
let httpProxy = environment["HTTP_PROXY"]
31-
if let httpProxy, let url = URL(string: httpProxy), let host = url.host, let port = url.port {
32-
proxy = .server(host: host, port: port)
33-
}
34-
35-
let httpsProxy = environment["HTTPS_PROXY"]
36-
if let httpsProxy, let url = URL(string: httpsProxy), let host = url.host, let port = url.port {
37-
proxy = .server(host: host, port: port)
38-
}
39-
40-
if proxy != nil {
41-
self.httpClient = HTTPClient(eventLoopGroupProvider: .singleton, configuration: HTTPClient.Configuration(proxy: proxy))
42-
} else {
43-
self.httpClient = HTTPClient.shared
44-
}
45-
}
46-
47-
public func execute(_ request: HTTPClientRequest, timeout: TimeAmount) async throws -> HTTPClientResponse {
48-
try await self.httpClient.execute(request, timeout: timeout)
49-
}
50-
51-
deinit {
52-
if httpClient !== HTTPClient.shared {
53-
try? httpClient.syncShutdown()
54-
}
55-
}
56-
}
57-
5820
class SwiftlyTests: XCTestCase {
59-
override class func setUp() {
60-
if !proxyExecutorInstalled {
61-
SwiftlyCore.httpRequestExecutor = ProxyHTTPRequestExecutorImpl()
62-
}
63-
}
64-
6521
override class func tearDown() {
6622
#if os(Linux)
6723
let deleteTestGPGKeys = Process()

0 commit comments

Comments
 (0)