@@ -111,6 +111,7 @@ internal final class HTTPClient {
111
111
}
112
112
113
113
internal struct Response : Equatable {
114
+ public var version : HTTPVersion
114
115
public var status : HTTPResponseStatus
115
116
public var headers : HTTPHeaders
116
117
public var body : ByteBuffer ?
@@ -150,7 +151,20 @@ private final class HTTPHandler: ChannelDuplexHandler {
150
151
if let body = request. body {
151
152
head. headers. add ( name: " Content-Length " , value: String ( body. readableBytes) )
152
153
}
153
- head. headers. add ( name: " Connection " , value: self . keepAlive ? " keep-alive " : " close " )
154
+ // We don't add a "Connection" header here if we want to keep the connection open,
155
+ // HTTP/1.1 defines specifies the following in RFC 2616, Section 8.1.2.1:
156
+ //
157
+ // An HTTP/1.1 server MAY assume that a HTTP/1.1 client intends to
158
+ // maintain a persistent connection unless a Connection header including
159
+ // the connection-token "close" was sent in the request. If the server
160
+ // chooses to close the connection immediately after sending the
161
+ // response, it SHOULD send a Connection header including the
162
+ // connection-token close.
163
+ //
164
+ // See also UnaryHandler.channelRead below.
165
+ if !self . keepAlive {
166
+ head. headers. add ( name: " Connection " , value: " close " )
167
+ }
154
168
155
169
context. write ( self . wrapOutboundOut ( HTTPClientRequestPart . head ( head) ) ) . flatMap { _ -> EventLoopFuture < Void > in
156
170
if let body = request. body {
@@ -184,10 +198,10 @@ private final class HTTPHandler: ChannelDuplexHandler {
184
198
case . end:
185
199
switch self . readState {
186
200
case . head( let head) :
187
- context. fireChannelRead ( wrapInboundOut ( HTTPClient . Response ( status: head. status, headers: head. headers, body: nil ) ) )
201
+ context. fireChannelRead ( wrapInboundOut ( HTTPClient . Response ( version : head . version , status: head. status, headers: head. headers, body: nil ) ) )
188
202
self . readState = . idle
189
203
case . body( let head, let body) :
190
- context. fireChannelRead ( wrapInboundOut ( HTTPClient . Response ( status: head. status, headers: head. headers, body: body) ) )
204
+ context. fireChannelRead ( wrapInboundOut ( HTTPClient . Response ( version : head . version , status: head. status, headers: head. headers, body: body) ) )
191
205
self . readState = . idle
192
206
default :
193
207
preconditionFailure ( " invalid read state \( self . readState) " )
@@ -238,8 +252,14 @@ private final class UnaryHandler: ChannelDuplexHandler {
238
252
guard let pending = self . pending else {
239
253
preconditionFailure ( " invalid state, no pending request " )
240
254
}
241
- let serverKeepAlive = response. headers. first ( name: " connection " ) ? . lowercased ( ) == " keep-alive "
242
- if !self . keepAlive || !serverKeepAlive {
255
+
256
+ // As defined in RFC 2616 Section 8.1.2:
257
+ // [...] unless otherwise indicated, the client SHOULD assume
258
+ // that the server will maintain a persistent connection, even
259
+ // after error responses from the server.
260
+ let serverCloseConnection = response. headers. first ( name: " connection " ) ? . lowercased ( ) == " close "
261
+
262
+ if !self . keepAlive || serverCloseConnection || response. version != . init( major: 1 , minor: 1 ) {
243
263
pending. promise. futureResult. whenComplete { _ in
244
264
_ = context. channel. close ( )
245
265
}
0 commit comments