Skip to content

Commit cd55229

Browse files
committed
tests
1 parent 69539a0 commit cd55229

File tree

2 files changed

+339
-24
lines changed

2 files changed

+339
-24
lines changed

Diff for: Sources/AsyncHTTPClient/ConnectionPool/HTTPRequestStateMachine.swift

+41-17
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,9 @@ struct HTTPRequestStateMachine {
9393

9494
case sendRequestHead(HTTPRequestHead, startBody: Bool)
9595
case sendBodyPart(IOData)
96-
case sendRequestEnd
96+
/// If the server has replied, with a status of 200...300 before all data was sent, a request is considered succeeded,
97+
/// as soon as we wrote the request end onto the wire. In this case the succeedRequest property is set.
98+
case sendRequestEnd(succeedRequest: FinalStreamAction?)
9799

98100
case pauseRequestBodyStream
99101
case resumeRequestBodyStream
@@ -111,11 +113,9 @@ struct HTTPRequestStateMachine {
111113
private var state: State = .initialized
112114

113115
private var isChannelWritable: Bool
114-
private let idleReadTimeout: TimeAmount?
115116

116-
init(isChannelWritable: Bool, idleReadTimeout: TimeAmount?) {
117+
init(isChannelWritable: Bool) {
117118
self.isChannelWritable = isChannelWritable
118-
self.idleReadTimeout = idleReadTimeout
119119
}
120120

121121
mutating func startRequest(head: HTTPRequestHead, metadata: RequestFramingMetadata) -> Action {
@@ -301,8 +301,7 @@ struct HTTPRequestStateMachine {
301301
switch self.state {
302302
case .initialized,
303303
.waitForChannelToBecomeWritable,
304-
.running(.endSent, _),
305-
.finished:
304+
.running(.endSent, _):
306305
preconditionFailure("A request body stream end is only expected if we are in state request streaming. Invalid state: \(self.state)")
307306

308307
case .running(.streaming(let expectedBodyLength, let sentBodyBytes, _), .waitingForHead):
@@ -313,7 +312,7 @@ struct HTTPRequestStateMachine {
313312
}
314313

315314
self.state = .running(.endSent, .waitingForHead)
316-
return .sendRequestEnd
315+
return .sendRequestEnd(succeedRequest: nil)
317316

318317
case .running(.streaming(let expectedBodyLength, let sentBodyBytes, _), .receivingBody(let head, let streamState)):
319318
assert(head.status.code < 300)
@@ -325,7 +324,7 @@ struct HTTPRequestStateMachine {
325324
}
326325

327326
self.state = .running(.endSent, .receivingBody(head, streamState))
328-
return .sendRequestEnd
327+
return .sendRequestEnd(succeedRequest: nil)
329328

330329
case .running(.streaming(let expectedBodyLength, let sentBodyBytes, _), .endReceived):
331330
if let expected = expectedBodyLength, expected != sentBodyBytes {
@@ -335,10 +334,22 @@ struct HTTPRequestStateMachine {
335334
}
336335

337336
self.state = .finished
338-
return .succeedRequest(.none)
337+
return .sendRequestEnd(succeedRequest: .some(.none))
339338

340339
case .failed:
341340
return .wait
341+
342+
case .finished:
343+
// A request may be finished, before we have send all parts. This might be the case if
344+
// the server responded with an HTTP status code that is equal or larger to 300
345+
// (Redirection, Client Error or Server Error). In those cases we pause the request body
346+
// stream as soon as we have received the response head and we succeed the request as
347+
// when response end is received. This may mean, that we succeed a request, even though
348+
// we have not sent all it's body parts.
349+
350+
// We may still receive something, here because of potential race conditions with the
351+
// producing thread.
352+
return .wait
342353
}
343354
}
344355

@@ -376,23 +387,23 @@ struct HTTPRequestStateMachine {
376387
// MARK: - Response
377388

378389
mutating func receivedHTTPResponseHead(_ head: HTTPResponseHead) -> Action {
390+
guard head.status.code >= 200 else {
391+
// we ignore any leading 1xx headers... No state change needed.
392+
return .wait
393+
}
394+
379395
switch self.state {
380396
case .initialized, .waitForChannelToBecomeWritable:
381397
preconditionFailure("How can we receive a response head before sending a request head ourselves")
382398

383399
case .running(.streaming(let expectedBodyLength, let sentBodyBytes, producer: .paused), .waitingForHead):
384400
self.state = .running(
385-
.streaming(expectedBodyLength: expectedBodyLength, sentBodyBytes: sentBodyBytes, producer: .producing),
401+
.streaming(expectedBodyLength: expectedBodyLength, sentBodyBytes: sentBodyBytes, producer: .paused),
386402
.receivingBody(head, .downstreamIsConsuming(readPending: false))
387403
)
388404
return .forwardResponseHead(head, pauseRequestBodyStream: false)
389405

390406
case .running(.streaming(let expectedBodyLength, let sentBodyBytes, producer: .producing), .waitingForHead):
391-
guard head.status.code >= 200 else {
392-
// we ignore any leading 1xx headers... No state change needed.
393-
return .wait
394-
}
395-
396407
if head.status.code >= 300 {
397408
self.state = .running(
398409
.streaming(expectedBodyLength: expectedBodyLength, sentBodyBytes: sentBodyBytes, producer: .paused),
@@ -450,12 +461,25 @@ struct HTTPRequestStateMachine {
450461
case .running(_, .waitingForHead):
451462
preconditionFailure("How can we receive a response end, if we haven't a received a head. Invalid state: \(self.state)")
452463

453-
case .running(.streaming(let expectedBodyLength, let sentBodyBytes, let producerState), .receivingBody(let head, _)) where head.status.code < 300:
464+
case .running(.streaming(let expectedBodyLength, let sentBodyBytes, let producerState), .receivingBody(let head, let consumerState)) where head.status.code < 300:
454465
self.state = .running(
455466
.streaming(expectedBodyLength: expectedBodyLength, sentBodyBytes: sentBodyBytes, producer: producerState),
456467
.endReceived
457468
)
458-
return .wait
469+
470+
switch consumerState {
471+
case .downstreamHasDemand, .downstreamIsConsuming(readPending: false):
472+
return .wait
473+
case .downstreamIsConsuming(readPending: true):
474+
// If we have a received a read event before, we must ensure that the read event
475+
// eventually gets onto the channel pipeline again. The end of the request gives
476+
// us an opportunity for this clean up task.
477+
// It is very unlikely that we can see this in the real world. If we have swallowed
478+
// a read event we don't expect to receive further data from the channel incl.
479+
// response ends.
480+
481+
return .read
482+
}
459483

460484
case .running(.streaming(_, _, let producerState), .receivingBody(let head, _)):
461485
assert(head.status.code >= 300)

0 commit comments

Comments
 (0)