From 5ebd2bddf3eb790722782e438d203d6e48298ebf Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Mon, 12 Aug 2019 15:26:01 +0100 Subject: [PATCH 01/11] add NIO event loop as an argument for execute --- Sources/AsyncHTTPClient/HTTPClient.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index 18114323b..dd667e4a3 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -180,7 +180,17 @@ public class HTTPClient { /// - deadline: Point in time by which the request must complete. public func execute(request: Request, delegate: T, deadline: NIODeadline? = nil) -> Task { let eventLoop = self.eventLoopGroup.next() + return self.execute(request: request, delegate: delegate, eventLoop: eventLoop, deadline: deadline) + } + /// Execute arbitrary HTTP request and handle response processing using provided delegate. + /// + /// - parameters: + /// - request: HTTP request to execute. + /// - delegate: Delegate to process response parts. + /// - eventLoop: NIO Event Loop to use. + /// - deadline: Point in time by which the request must complete. + public func execute(request: Request, delegate: T, eventLoop: EventLoop, deadline: NIODeadline? = nil) -> Task { let redirectHandler: RedirectHandler? if self.configuration.followRedirects { redirectHandler = RedirectHandler(request: request) { newRequest in From 99fed140b14305586124d057f2113c336c184d1c Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Mon, 12 Aug 2019 15:48:54 +0100 Subject: [PATCH 02/11] review fix: add to np-delegate method as well --- Sources/AsyncHTTPClient/HTTPClient.swift | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index dd667e4a3..3b6e76736 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -172,6 +172,17 @@ public class HTTPClient { return self.execute(request: request, delegate: accumulator, deadline: deadline).futureResult } + /// Execute arbitrary HTTP request using specified URL. + /// + /// - parameters: + /// - request: HTTP request to execute. + /// - eventLoop: NIO Event Loop to use. + /// - deadline: Point in time by which the request must complete. + public func execute(request: Request, eventLoop: EventLoop, deadline: NIODeadline? = nil) -> EventLoopFuture { + let accumulator = ResponseAccumulator(request: request) + return self.execute(request: request, delegate: accumulator, eventLoop: eventLoop, deadline: deadline).futureResult + } + /// Execute arbitrary HTTP request and handle response processing using provided delegate. /// /// - parameters: From cd81083dfadfc8c2fbddcd64b81178abb21ca613 Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Thu, 15 Aug 2019 20:23:10 +0100 Subject: [PATCH 03/11] Resolve confict --- .../HTTPClientTests.swift | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index ecd6c6209..513426362 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -484,4 +484,41 @@ class HTTPClientTests: XCTestCase { } } } + + func testEventLoopArgument() throws { + let httpBin = HttpBin() + let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1) + let httpClient = HTTPClient(eventLoopGroupProvider: .shared(eventLoopGroup)) + defer { + try! eventLoopGroup.syncShutdownGracefully() + httpBin.shutdown() + } + + class EventLoopValidatingDelegate: HTTPClientResponseDelegate { + typealias Response = Bool + + let eventLoop: EventLoop + var result = false + + init(eventLoop: EventLoop) { + self.eventLoop = eventLoop + } + + func didReceiveHead(task: HTTPClient.Task, _ head: HTTPResponseHead) -> EventLoopFuture { + self.result = task.eventLoop === self.eventLoop + return task.eventLoop.makeSucceededFuture(()) + } + + func didFinishRequest(task: HTTPClient.Task) throws -> Bool { + return result + } + } + + let eventLoop = eventLoopGroup.next() + let delegate = EventLoopValidatingDelegate(eventLoop: eventLoop) + let request = try HTTPClient.Request(url: "http://localhost:\(httpBin.port)/get") + let response = try httpClient.execute(request: request, delegate: delegate, eventLoop: eventLoop).wait() + + XCTAssertEqual(true, response) + } } From b8ccbd54c759a961a8a2de75ca458505d4dd6fa8 Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Thu, 15 Aug 2019 20:28:20 +0100 Subject: [PATCH 04/11] add missing linux test --- Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift index cb33ba8ed..93f66905b 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests+XCTest.swift @@ -53,6 +53,7 @@ extension HTTPClientTests { ("testNoResponseWithIgnoreErrorForSSLUncleanShutdown", testNoResponseWithIgnoreErrorForSSLUncleanShutdown), ("testWrongContentLengthForSSLUncleanShutdown", testWrongContentLengthForSSLUncleanShutdown), ("testWrongContentLengthWithIgnoreErrorForSSLUncleanShutdown", testWrongContentLengthWithIgnoreErrorForSSLUncleanShutdown), + ("testEventLoopArgument", testEventLoopArgument), ] } } From 3aea5a2919afcb6cd6f41c73569bb6eab0aa34f6 Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Thu, 15 Aug 2019 20:31:10 +0100 Subject: [PATCH 05/11] fix formatting --- Tests/AsyncHTTPClientTests/HTTPClientTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 513426362..9f97261bd 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -510,7 +510,7 @@ class HTTPClientTests: XCTestCase { } func didFinishRequest(task: HTTPClient.Task) throws -> Bool { - return result + return result } } From b7078e84ee4708f28be38342d14a1a0c3316a123 Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Thu, 15 Aug 2019 20:44:00 +0100 Subject: [PATCH 06/11] missing self --- Tests/AsyncHTTPClientTests/HTTPClientTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index 9f97261bd..b3dfd2302 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -510,7 +510,7 @@ class HTTPClientTests: XCTestCase { } func didFinishRequest(task: HTTPClient.Task) throws -> Bool { - return result + return self.result } } From db2653254127580e4e7daecc9ddf7487a7b6dffb Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Sun, 18 Aug 2019 11:55:28 +0100 Subject: [PATCH 07/11] review fix: add event loop preference argument instead of eventloop --- Sources/AsyncHTTPClient/HTTPClient.swift | 36 ++++++++++++++++--- .../HTTPClientTests.swift | 2 +- 2 files changed, 32 insertions(+), 6 deletions(-) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index 19170e64a..053d06979 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -176,11 +176,11 @@ public class HTTPClient { /// /// - parameters: /// - request: HTTP request to execute. - /// - eventLoop: NIO Event Loop to use. + /// - eventLoop: NIO Event Loop preferrence. /// - deadline: Point in time by which the request must complete. - public func execute(request: Request, eventLoop: EventLoop, deadline: NIODeadline? = nil) -> EventLoopFuture { + public func execute(request: Request, eventLoopPreferrence: EventLoop, deadline: NIODeadline? = nil) -> EventLoopFuture { let accumulator = ResponseAccumulator(request: request) - return self.execute(request: request, delegate: accumulator, eventLoop: eventLoop, deadline: deadline).futureResult + return self.execute(request: request, delegate: accumulator, eventLoop: eventLoopPreferrence, deadline: deadline).futureResult } /// Execute arbitrary HTTP request and handle response processing using provided delegate. @@ -199,9 +199,19 @@ public class HTTPClient { /// - parameters: /// - request: HTTP request to execute. /// - delegate: Delegate to process response parts. - /// - eventLoop: NIO Event Loop to use. + /// - eventLoop: NIO Event Loop preferrence. /// - deadline: Point in time by which the request must complete. - public func execute(request: Request, delegate: T, eventLoop: EventLoop, deadline: NIODeadline? = nil) -> Task { + public func execute(request: Request, delegate: T, eventLoop: EventLoopPreferrence, deadline: NIODeadline? = nil) -> Task { + switch eventLoop.preferrence { + case .indifferent: + return self.execute(request: request, delegate: delegate, eventLoop: self.eventLoopGroup.next(), deadline: deadline) + case .prefers(let preferred): + return self.execute(request: request, delegate: delegate, eventLoop: preferred, deadline: deadline) + } + + } + + private func execute(request: Request, delegate: T, eventLoop: EventLoop, deadline: NIODeadline? = nil) -> Task { let redirectHandler: RedirectHandler? if self.configuration.followRedirects { redirectHandler = RedirectHandler(request: request) { newRequest in @@ -333,6 +343,22 @@ public class HTTPClient { case createNew } + /// Specifies how the library will treat event loop passed by the user. + public struct EventLoopPreferrence { + enum Preferrence { + /// Event Loop will be selected by the library. + case indifferent + /// Library will try to use provided event loop if possible. + case prefers(EventLoop) + } + var preferrence: Preferrence + + /// Event Loop will be selected by the library. + public static let indifferent = EventLoopPreferrence(preferrence: .indifferent) + /// Library will try to use provided event loop if possible. + public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreferrence { EventLoopPreferrence(preferrence: .prefers(eventLoop)) } + } + /// Timeout configuration public struct Timeout { /// Specifies connect timeout. diff --git a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift index b3dfd2302..c9b85e957 100644 --- a/Tests/AsyncHTTPClientTests/HTTPClientTests.swift +++ b/Tests/AsyncHTTPClientTests/HTTPClientTests.swift @@ -517,7 +517,7 @@ class HTTPClientTests: XCTestCase { let eventLoop = eventLoopGroup.next() let delegate = EventLoopValidatingDelegate(eventLoop: eventLoop) let request = try HTTPClient.Request(url: "http://localhost:\(httpBin.port)/get") - let response = try httpClient.execute(request: request, delegate: delegate, eventLoop: eventLoop).wait() + let response = try httpClient.execute(request: request, delegate: delegate, eventLoop: .prefers(eventLoop)).wait() XCTAssertEqual(true, response) } From 082cfebc105b79d009b320ccf30c55ed1eb56fe0 Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Sun, 18 Aug 2019 11:57:12 +0100 Subject: [PATCH 08/11] formatting --- Sources/AsyncHTTPClient/HTTPClient.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index 053d06979..a6d9cee08 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -208,7 +208,6 @@ public class HTTPClient { case .prefers(let preferred): return self.execute(request: request, delegate: delegate, eventLoop: preferred, deadline: deadline) } - } private func execute(request: Request, delegate: T, eventLoop: EventLoop, deadline: NIODeadline? = nil) -> Task { @@ -351,6 +350,7 @@ public class HTTPClient { /// Library will try to use provided event loop if possible. case prefers(EventLoop) } + var preferrence: Preferrence /// Event Loop will be selected by the library. From 3b3091830d80ef81810fa0451b53d1f982c549cc Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Mon, 19 Aug 2019 12:30:41 +0100 Subject: [PATCH 09/11] review fix: spelling --- Sources/AsyncHTTPClient/HTTPClient.swift | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index a6d9cee08..ef316abe8 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -176,11 +176,11 @@ public class HTTPClient { /// /// - parameters: /// - request: HTTP request to execute. - /// - eventLoop: NIO Event Loop preferrence. + /// - eventLoop: NIO Event Loop preference. /// - deadline: Point in time by which the request must complete. - public func execute(request: Request, eventLoopPreferrence: EventLoop, deadline: NIODeadline? = nil) -> EventLoopFuture { + public func execute(request: Request, eventLoop: EventLoopPreference, deadline: NIODeadline? = nil) -> EventLoopFuture { let accumulator = ResponseAccumulator(request: request) - return self.execute(request: request, delegate: accumulator, eventLoop: eventLoopPreferrence, deadline: deadline).futureResult + return self.execute(request: request, delegate: accumulator, eventLoop: eventLoop, deadline: deadline).futureResult } /// Execute arbitrary HTTP request and handle response processing using provided delegate. @@ -199,10 +199,10 @@ public class HTTPClient { /// - parameters: /// - request: HTTP request to execute. /// - delegate: Delegate to process response parts. - /// - eventLoop: NIO Event Loop preferrence. + /// - eventLoop: NIO Event Loop preference. /// - deadline: Point in time by which the request must complete. - public func execute(request: Request, delegate: T, eventLoop: EventLoopPreferrence, deadline: NIODeadline? = nil) -> Task { - switch eventLoop.preferrence { + public func execute(request: Request, delegate: T, eventLoop: EventLoopPreference, deadline: NIODeadline? = nil) -> Task { + switch eventLoop.preference { case .indifferent: return self.execute(request: request, delegate: delegate, eventLoop: self.eventLoopGroup.next(), deadline: deadline) case .prefers(let preferred): @@ -343,20 +343,20 @@ public class HTTPClient { } /// Specifies how the library will treat event loop passed by the user. - public struct EventLoopPreferrence { - enum Preferrence { + public struct EventLoopPreference { + enum Preference { /// Event Loop will be selected by the library. case indifferent /// Library will try to use provided event loop if possible. case prefers(EventLoop) } - var preferrence: Preferrence + var preference: Preference /// Event Loop will be selected by the library. - public static let indifferent = EventLoopPreferrence(preferrence: .indifferent) + public static let indifferent = EventLoopPreference(preference: .indifferent) /// Library will try to use provided event loop if possible. - public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreferrence { EventLoopPreferrence(preferrence: .prefers(eventLoop)) } + public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreference { EventLoopPreference(preference: .prefers(eventLoop)) } } /// Timeout configuration From 1036075077adeac15ca9dcb237a1d74bed18e330 Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Mon, 19 Aug 2019 12:39:28 +0100 Subject: [PATCH 10/11] fix compilation error --- Sources/AsyncHTTPClient/HTTPClient.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index ef316abe8..23000a4ca 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -356,7 +356,9 @@ public class HTTPClient { /// Event Loop will be selected by the library. public static let indifferent = EventLoopPreference(preference: .indifferent) /// Library will try to use provided event loop if possible. - public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreference { EventLoopPreference(preference: .prefers(eventLoop)) } + public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreference { + return EventLoopPreference(preference: .prefers(eventLoop)) + } } /// Timeout configuration From 1b7e97ecd32eaf21ca14014370ad0bb72368c8dc Mon Sep 17 00:00:00 2001 From: Artem Redkin Date: Tue, 20 Aug 2019 10:23:48 +0100 Subject: [PATCH 11/11] review fixes: make preference argument not explicit and add precondition that EL must be part of ELG --- Sources/AsyncHTTPClient/HTTPClient.swift | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Sources/AsyncHTTPClient/HTTPClient.swift b/Sources/AsyncHTTPClient/HTTPClient.swift index 23000a4ca..949b09e70 100644 --- a/Sources/AsyncHTTPClient/HTTPClient.swift +++ b/Sources/AsyncHTTPClient/HTTPClient.swift @@ -206,6 +206,7 @@ public class HTTPClient { case .indifferent: return self.execute(request: request, delegate: delegate, eventLoop: self.eventLoopGroup.next(), deadline: deadline) case .prefers(let preferred): + precondition(self.eventLoopGroup.makeIterator().contains { $0 === preferred }, "Provided EventLoop must be part of clients EventLoopGroup.") return self.execute(request: request, delegate: delegate, eventLoop: preferred, deadline: deadline) } } @@ -353,11 +354,15 @@ public class HTTPClient { var preference: Preference + init(_ preference: Preference) { + self.preference = preference + } + /// Event Loop will be selected by the library. - public static let indifferent = EventLoopPreference(preference: .indifferent) + public static let indifferent = EventLoopPreference(.indifferent) /// Library will try to use provided event loop if possible. public static func prefers(_ eventLoop: EventLoop) -> EventLoopPreference { - return EventLoopPreference(preference: .prefers(eventLoop)) + return EventLoopPreference(.prefers(eventLoop)) } }