Skip to content

Commit e275cce

Browse files
committed
Merge branch 'dn-fix-file-download-thread-leak' of github.com:dnadoba/async-http-client into dn-fix-file-download-thread-leak
2 parents 33566e7 + 734b1c9 commit e275cce

File tree

6 files changed

+86
-4
lines changed

6 files changed

+86
-4
lines changed

Sources/AsyncHTTPClient/AsyncAwait/HTTPClient+execute.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ extension HTTPClient {
134134
request: request,
135135
requestOptions: .init(idleReadTimeout: nil),
136136
logger: logger,
137-
connectionDeadline: deadline,
137+
connectionDeadline: .now() + (self.configuration.timeout.connectionCreationTimeout),
138138
preferredEventLoop: eventLoop,
139139
responseContinuation: continuation
140140
)

Sources/AsyncHTTPClient/HTTPClient.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ public class HTTPClient {
634634
eventLoopPreference: eventLoopPreference,
635635
task: task,
636636
redirectHandler: redirectHandler,
637-
connectionDeadline: .now() + (self.configuration.timeout.connect ?? .seconds(10)),
637+
connectionDeadline: .now() + (self.configuration.timeout.connectionCreationTimeout),
638638
requestOptions: .fromClientConfiguration(self.configuration),
639639
delegate: delegate
640640
)

Tests/AsyncHTTPClientTests/AsyncAwaitEndToEndTests+XCTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ extension AsyncAwaitEndToEndTests {
3838
("testCanceling", testCanceling),
3939
("testDeadline", testDeadline),
4040
("testImmediateDeadline", testImmediateDeadline),
41+
("testConnectTimeout", testConnectTimeout),
4142
("testSelfSignedCertificateIsRejectedWithCorrectErrorIfRequestDeadlineIsExceeded", testSelfSignedCertificateIsRejectedWithCorrectErrorIfRequestDeadlineIsExceeded),
4243
("testInvalidURL", testInvalidURL),
4344
("testRedirectChangesHostHeader", testRedirectChangesHostHeader),

Tests/AsyncHTTPClientTests/AsyncAwaitEndToEndTests.swift

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,27 @@ private func makeDefaultHTTPClient(
3434
}
3535

3636
final class AsyncAwaitEndToEndTests: XCTestCase {
37+
var clientGroup: EventLoopGroup!
38+
var serverGroup: EventLoopGroup!
39+
40+
override func setUp() {
41+
XCTAssertNil(self.clientGroup)
42+
XCTAssertNil(self.serverGroup)
43+
44+
self.clientGroup = getDefaultEventLoopGroup(numberOfThreads: 1)
45+
self.serverGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
46+
}
47+
48+
override func tearDown() {
49+
XCTAssertNotNil(self.clientGroup)
50+
XCTAssertNoThrow(try self.clientGroup.syncShutdownGracefully())
51+
self.clientGroup = nil
52+
53+
XCTAssertNotNil(self.serverGroup)
54+
XCTAssertNoThrow(try self.serverGroup.syncShutdownGracefully())
55+
self.serverGroup = nil
56+
}
57+
3758
func testSimpleGet() {
3859
#if compiler(>=5.5.2) && canImport(_Concurrency)
3960
guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return }
@@ -394,6 +415,65 @@ final class AsyncAwaitEndToEndTests: XCTestCase {
394415
#endif
395416
}
396417

418+
func testConnectTimeout() {
419+
#if compiler(>=5.5.2) && canImport(_Concurrency)
420+
guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return }
421+
XCTAsyncTest(timeout: 60) {
422+
#if os(Linux)
423+
// 198.51.100.254 is reserved for documentation only and therefore should not accept any TCP connection
424+
let url = "http://198.51.100.254/get"
425+
#else
426+
// on macOS we can use the TCP backlog behaviour when the queue is full to simulate a non reachable server.
427+
// this makes this test a bit more stable if `198.51.100.254` actually responds to connection attempt.
428+
// The backlog behaviour on Linux can not be used to simulate a non-reachable server.
429+
// Linux sends a `SYN/ACK` back even if the `backlog` queue is full as it has two queues.
430+
// The second queue is not limit by `ChannelOptions.backlog` but by `/proc/sys/net/ipv4/tcp_max_syn_backlog`.
431+
432+
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
433+
defer {
434+
XCTAssertNoThrow(try group.syncShutdownGracefully())
435+
}
436+
437+
let serverChannel = try await ServerBootstrap(group: self.serverGroup)
438+
.serverChannelOption(ChannelOptions.backlog, value: 1)
439+
.serverChannelOption(ChannelOptions.autoRead, value: false)
440+
.bind(host: "127.0.0.1", port: 0)
441+
.get()
442+
defer {
443+
XCTAssertNoThrow(try serverChannel.close().wait())
444+
}
445+
let port = serverChannel.localAddress!.port!
446+
let firstClientChannel = try ClientBootstrap(group: self.serverGroup)
447+
.connect(host: "127.0.0.1", port: port)
448+
.wait()
449+
defer {
450+
XCTAssertNoThrow(try firstClientChannel.close().wait())
451+
}
452+
let url = "http://localhost:\(port)/get"
453+
#endif
454+
455+
let httpClient = HTTPClient(eventLoopGroupProvider: .shared(self.clientGroup),
456+
configuration: .init(timeout: .init(connect: .milliseconds(100), read: .milliseconds(150))))
457+
458+
defer {
459+
XCTAssertNoThrow(try httpClient.syncShutdown())
460+
}
461+
462+
let request = HTTPClientRequest(url: url)
463+
let start = NIODeadline.now()
464+
await XCTAssertThrowsError(try await httpClient.execute(request, deadline: .now() + .seconds(30))) {
465+
XCTAssertEqualTypeAndValue($0, HTTPClientError.connectTimeout)
466+
let end = NIODeadline.now()
467+
let duration = end - start
468+
469+
// We give ourselves 10x slack in order to be confident that even on slow machines this assertion passes.
470+
// It's 30x smaller than our other timeout though.
471+
XCTAssertLessThan(duration, .seconds(1))
472+
}
473+
}
474+
#endif
475+
}
476+
397477
func testSelfSignedCertificateIsRejectedWithCorrectErrorIfRequestDeadlineIsExceeded() {
398478
#if compiler(>=5.5.2) && canImport(_Concurrency)
399479
guard #available(macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) else { return }

docker/docker-compose.2004.main.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ services:
1010

1111
test:
1212
image: async-http-client:20.04-main
13-
environment: []
13+
environment:
14+
- IMPORT_CHECK_ARG=--explicit-target-dependency-import-check error
1415
#- SANITIZER_ARG=--sanitize=thread
1516

1617
shell:

docker/docker-compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ services:
2828

2929
test:
3030
<<: *common
31-
command: /bin/bash -xcl "swift test --parallel -Xswiftc -warnings-as-errors --enable-test-discovery $${SANITIZER_ARG-}"
31+
command: /bin/bash -xcl "swift test --parallel -Xswiftc -warnings-as-errors --enable-test-discovery $${SANITIZER_ARG-} $${IMPORT_CHECK_ARG-}"
3232

3333
# util
3434

0 commit comments

Comments
 (0)