Skip to content

Commit 3cdb063

Browse files
committed
review comments
1 parent 13e3d6b commit 3cdb063

File tree

2 files changed

+60
-48
lines changed

2 files changed

+60
-48
lines changed

Diff for: Sources/NIOHTTPClient/HTTPClientProxyHandler.swift

+48-34
Original file line numberDiff line numberDiff line change
@@ -25,52 +25,66 @@ internal final class HTTPClientProxyHandler: ChannelDuplexHandler, RemovableChan
2525
typealias OutboundIn = HTTPClientRequestPart
2626
typealias OutboundOut = HTTPClientRequestPart
2727

28-
enum BufferItem {
28+
enum WriteItem {
2929
case write(NIOAny, EventLoopPromise<Void>?)
3030
case flush
3131
}
3232

33+
enum ReadState {
34+
case awaitingResponse
35+
case connecting
36+
}
37+
3338
private let host: String
3439
private let port: Int
3540
private var onConnect: (Channel) -> EventLoopFuture<Void>
36-
private var buffer: [BufferItem]
41+
private var writeBuffer: CircularBuffer<WriteItem>
42+
private var readBuffer: CircularBuffer<NIOAny>
43+
private var readState: ReadState
3744

3845
init(host: String, port: Int, onConnect: @escaping (Channel) -> EventLoopFuture<Void>) {
3946
self.host = host
4047
self.port = port
4148
self.onConnect = onConnect
42-
self.buffer = []
49+
self.writeBuffer = .init()
50+
self.readBuffer = .init()
51+
self.readState = .awaitingResponse
4352
}
4453

4554
func channelRead(context: ChannelHandlerContext, data: NIOAny) {
46-
let res = self.unwrapInboundIn(data)
47-
switch res {
48-
case .head(let head):
49-
switch head.status.code {
50-
case 200..<300:
51-
// Any 2xx (Successful) response indicates that the sender (and all
52-
// inbound proxies) will switch to tunnel mode immediately after the
53-
// blank line that concludes the successful response's header section
55+
switch self.readState {
56+
case .awaitingResponse:
57+
let res = self.unwrapInboundIn(data)
58+
switch res {
59+
case .head(let head):
60+
switch head.status.code {
61+
case 200..<300:
62+
// Any 2xx (Successful) response indicates that the sender (and all
63+
// inbound proxies) will switch to tunnel mode immediately after the
64+
// blank line that concludes the successful response's header section
65+
break
66+
default:
67+
// Any response other than a successful response
68+
// indicates that the tunnel has not yet been formed and that the
69+
// connection remains governed by HTTP.
70+
context.fireErrorCaught(HTTPClientErrors.InvalidProxyResponseError())
71+
}
72+
case .end:
73+
_ = self.handleConnect(context: context)
74+
case .body:
5475
break
55-
default:
56-
// Any response other than a successful response
57-
// indicates that the tunnel has not yet been formed and that the
58-
// connection remains governed by HTTP.
59-
context.fireErrorCaught(HTTPClientErrors.InvalidProxyResponseError())
6076
}
61-
case .end:
62-
_ = self.handleConnect(context: context)
63-
case .body:
64-
break
77+
case .connecting:
78+
self.readBuffer.append(data)
6579
}
6680
}
6781

6882
func write(context: ChannelHandlerContext, data: NIOAny, promise: EventLoopPromise<Void>?) {
69-
self.buffer.append(.write(data, promise))
83+
self.writeBuffer.append(.write(data, promise))
7084
}
7185

7286
func flush(context: ChannelHandlerContext) {
73-
self.buffer.append(.flush)
87+
self.writeBuffer.append(.flush)
7488
}
7589

7690
func channelActive(context: ChannelHandlerContext) {
@@ -82,18 +96,18 @@ internal final class HTTPClientProxyHandler: ChannelDuplexHandler, RemovableChan
8296

8397
private func handleConnect(context: ChannelHandlerContext) -> EventLoopFuture<Void> {
8498
return self.onConnect(context.channel).flatMap {
85-
while self.buffer.count > 0 {
86-
// make a copy of the current buffer and clear it in case any
87-
// calls to context.write cause more requests to be buffered
88-
let buffer = self.buffer
89-
self.buffer = []
90-
buffer.forEach { item in
91-
switch item {
92-
case .flush:
93-
context.flush()
94-
case .write(let data, let promise):
95-
context.write(data, promise: promise)
96-
}
99+
// forward any buffered reads
100+
while !self.readBuffer.isEmpty {
101+
context.fireChannelRead(self.readBuffer.removeFirst())
102+
}
103+
104+
// calls to context.write may be re-entrant
105+
while !self.writeBuffer.isEmpty {
106+
switch self.writeBuffer.removeFirst() {
107+
case .flush:
108+
context.flush()
109+
case .write(let data, let promise):
110+
context.write(data, promise: promise)
97111
}
98112
}
99113
return context.pipeline.removeHandler(self)

Diff for: Sources/NIOHTTPClient/SwiftNIOHTTP.swift

+12-14
Original file line numberDiff line numberDiff line change
@@ -180,20 +180,9 @@ public class HTTPClient {
180180
}
181181

182182
let task = HTTPTask(future: promise.futureResult)
183-
184-
let host: String
185-
let port: Int
186-
187-
switch self.configuration.proxy {
188-
case .none:
189-
host = request.host
190-
port = request.port
191-
case .some(let proxy):
192-
host = proxy.host
193-
port = proxy.port
194-
}
195-
196-
bootstrap.connect(host: host, port: port)
183+
184+
let address = self.resolveAddress(request: request, proxy: self.configuration.proxy)
185+
bootstrap.connect(host: address.0, port: address.1)
197186
.map { channel in
198187
task.setChannel(channel)
199188
}
@@ -206,6 +195,15 @@ public class HTTPClient {
206195

207196
return task
208197
}
198+
199+
private func resolveAddress(request: HTTPRequest, proxy:HTTPClientProxy?) -> (String, Int) {
200+
switch self.configuration.proxy {
201+
case .none:
202+
return (request.host, request.port)
203+
case .some(let proxy):
204+
return (proxy.host, proxy.port)
205+
}
206+
}
209207
}
210208

211209
private extension ChannelPipeline {

0 commit comments

Comments
 (0)