@@ -292,14 +292,26 @@ class HTTPDecoderLengthTest: XCTestCase {
292
292
try assertIgnoresLengthFields ( requestMethod: . GET, responseStatus: . notModified, responseFramingField: . neither)
293
293
}
294
294
295
- private func assertRequestTransferEncodingHasNoBody ( transferEncodingHeader: String ) throws {
295
+ private func assertRequestTransferEncodingInError ( transferEncodingHeader: String ) throws {
296
296
XCTAssertNoThrow ( try channel. pipeline. addHandler ( ByteToMessageHandler ( HTTPRequestDecoder ( ) ) ) . wait ( ) )
297
297
298
298
let handler = MessageEndHandler < HTTPRequestHead , ByteBuffer > ( )
299
299
XCTAssertNoThrow ( try channel. pipeline. addHandler ( handler) . wait ( ) )
300
300
301
301
// Send a GET with the appropriate Transfer Encoding header.
302
- XCTAssertNoThrow ( try channel. writeInbound ( ByteBuffer ( string: " POST / HTTP/1.1 \r \n Transfer-Encoding: \( transferEncodingHeader) \r \n \r \n " ) ) )
302
+ XCTAssertThrowsError ( try channel. writeInbound ( ByteBuffer ( string: " POST / HTTP/1.1 \r \n Transfer-Encoding: \( transferEncodingHeader) \r \n \r \n " ) ) ) { error in
303
+ XCTAssertEqual ( error as? HTTPParserError , . unknown)
304
+ }
305
+ }
306
+
307
+ func testMultipleTEWithChunkedLastWorksFine( ) throws {
308
+ XCTAssertNoThrow ( try channel. pipeline. addHandler ( ByteToMessageHandler ( HTTPRequestDecoder ( ) ) ) . wait ( ) )
309
+
310
+ let handler = MessageEndHandler < HTTPRequestHead , ByteBuffer > ( )
311
+ XCTAssertNoThrow ( try channel. pipeline. addHandler ( handler) . wait ( ) )
312
+
313
+ // Send a GET with the appropriate Transfer Encoding header.
314
+ XCTAssertNoThrow ( try channel. writeInbound ( ByteBuffer ( string: " POST / HTTP/1.1 \r \n Transfer-Encoding: gzip, chunked \r \n \r \n 0 \r \n \r \n " ) ) )
303
315
304
316
// We should have a request, no body, and immediately see end of request.
305
317
XCTAssert ( handler. seenHead)
@@ -309,22 +321,12 @@ class HTTPDecoderLengthTest: XCTestCase {
309
321
XCTAssertTrue ( try channel. finish ( ) . isClean)
310
322
}
311
323
312
- func testMultipleTEWithChunkedLastHasNoBodyOnRequest( ) throws {
313
- // This is not quite right: RFC 7230 should allow this as chunked. However, http_parser
314
- // does not, so we don't either.
315
- try assertRequestTransferEncodingHasNoBody ( transferEncodingHeader: " gzip, chunked " )
316
- }
317
-
318
324
func testMultipleTEWithChunkedFirstHasNoBodyOnRequest( ) throws {
319
- // Here http_parser is again wrong: strictly this should 400. Again, though,
320
- // if http_parser doesn't support this neither do we.
321
- try assertRequestTransferEncodingHasNoBody ( transferEncodingHeader: " chunked, gzip " )
325
+ try assertRequestTransferEncodingInError ( transferEncodingHeader: " chunked, gzip " )
322
326
}
323
327
324
328
func testMultipleTEWithChunkedInTheMiddleHasNoBodyOnRequest( ) throws {
325
- // Here http_parser is again wrong: strictly this should 400. Again, though,
326
- // if http_parser doesn't support this neither do we.
327
- try assertRequestTransferEncodingHasNoBody ( transferEncodingHeader: " gzip, chunked, deflate " )
329
+ try assertRequestTransferEncodingInError ( transferEncodingHeader: " gzip, chunked, deflate " )
328
330
}
329
331
330
332
private func assertResponseTransferEncodingHasBodyTerminatedByEOF( transferEncodingHeader: String , eofMechanism: EOFMechanism ) throws {
@@ -366,10 +368,51 @@ class HTTPDecoderLengthTest: XCTestCase {
366
368
XCTAssertTrue ( try channel. finish ( ) . isClean)
367
369
}
368
370
371
+ private func assertResponseTransferEncodingHasBodyTerminatedByEndOfChunk( transferEncodingHeader: String , eofMechanism: EOFMechanism ) throws {
372
+ XCTAssertNoThrow ( try channel. pipeline. addHandler ( HTTPRequestEncoder ( ) ) . wait ( ) )
373
+ XCTAssertNoThrow ( try channel. pipeline. addHandler ( ByteToMessageHandler ( HTTPResponseDecoder ( ) ) ) . wait ( ) )
374
+
375
+ let handler = MessageEndHandler < HTTPResponseHead , ByteBuffer > ( )
376
+ XCTAssertNoThrow ( try channel. pipeline. addHandler ( handler) . wait ( ) )
377
+
378
+ // Prime the decoder with a request and consume it.
379
+ XCTAssertTrue ( try channel. writeOutbound ( HTTPClientRequestPart . head ( HTTPRequestHead ( version: . init( major: 1 , minor: 1 ) ,
380
+ method: . GET,
381
+ uri: " / " ) ) ) . isFull)
382
+ XCTAssertNoThrow ( XCTAssertNotNil ( try channel. readOutbound ( as: ByteBuffer . self) ) )
383
+
384
+ // Send a 200 with the appropriate Transfer Encoding header. We should see the request.
385
+ XCTAssertNoThrow ( try channel. writeInbound ( ByteBuffer ( string: " HTTP/1.1 200 OK \r \n Transfer-Encoding: \( transferEncodingHeader) \r \n \r \n " ) ) )
386
+ XCTAssert ( handler. seenHead)
387
+ XCTAssertFalse ( handler. seenBody)
388
+ XCTAssertFalse ( handler. seenEnd)
389
+
390
+ // Now send body. Note that this *is* chunk encoded. We should also see a body.
391
+ XCTAssertNoThrow ( try channel. writeInbound ( ByteBuffer ( string: " 9 \r \n caribbean \r \n " ) ) )
392
+ XCTAssert ( handler. seenHead)
393
+ XCTAssert ( handler. seenBody)
394
+ XCTAssertFalse ( handler. seenEnd)
395
+
396
+ // Now send EOF. This should error, as we're expecting the end chunk.
397
+ if case . halfClosure = eofMechanism {
398
+ channel. pipeline. fireUserInboundEventTriggered ( ChannelEvent . inputClosed)
399
+ } else {
400
+ channel. pipeline. fireChannelInactive ( )
401
+ }
402
+
403
+ XCTAssert ( handler. seenHead)
404
+ XCTAssert ( handler. seenBody)
405
+ XCTAssertFalse ( handler. seenEnd)
406
+
407
+ XCTAssertThrowsError ( try channel. throwIfErrorCaught ( ) ) { error in
408
+ XCTAssertEqual ( error as? HTTPParserError , . invalidEOFState)
409
+ }
410
+
411
+ XCTAssertTrue ( try channel. finish ( ) . isClean)
412
+ }
413
+
369
414
func testMultipleTEWithChunkedLastHasEOFBodyOnResponseWithChannelInactive( ) throws {
370
- // This is not right: RFC 7230 should allow this as chunked, but http_parser instead parses it as
371
- // EOF-terminated. We can't easily override that, so we don't.
372
- try assertResponseTransferEncodingHasBodyTerminatedByEOF ( transferEncodingHeader: " gzip, chunked " , eofMechanism: . channelInactive)
415
+ try assertResponseTransferEncodingHasBodyTerminatedByEndOfChunk ( transferEncodingHeader: " gzip, chunked " , eofMechanism: . channelInactive)
373
416
}
374
417
375
418
func testMultipleTEWithChunkedFirstHasEOFBodyOnResponseWithChannelInactive( ) throws {
@@ -383,9 +426,7 @@ class HTTPDecoderLengthTest: XCTestCase {
383
426
}
384
427
385
428
func testMultipleTEWithChunkedLastHasEOFBodyOnResponseWithHalfClosure( ) throws {
386
- // This is not right: RFC 7230 should allow this as chunked, but http_parser instead parses it as
387
- // EOF-terminated. We can't easily override that, so we don't.
388
- try assertResponseTransferEncodingHasBodyTerminatedByEOF ( transferEncodingHeader: " gzip, chunked " , eofMechanism: . halfClosure)
429
+ try assertResponseTransferEncodingHasBodyTerminatedByEndOfChunk ( transferEncodingHeader: " gzip, chunked " , eofMechanism: . halfClosure)
389
430
}
390
431
391
432
func testMultipleTEWithChunkedFirstHasEOFBodyOnResponseWithHalfClosure( ) throws {
0 commit comments