@@ -292,14 +292,26 @@ class HTTPDecoderLengthTest: XCTestCase {
292292 try assertIgnoresLengthFields ( requestMethod: . GET, responseStatus: . notModified, responseFramingField: . neither)
293293 }
294294
295- private func assertRequestTransferEncodingHasNoBody ( transferEncodingHeader: String ) throws {
295+ private func assertRequestTransferEncodingInError ( transferEncodingHeader: String ) throws {
296296 XCTAssertNoThrow ( try channel. pipeline. addHandler ( ByteToMessageHandler ( HTTPRequestDecoder ( ) ) ) . wait ( ) )
297297
298298 let handler = MessageEndHandler < HTTPRequestHead , ByteBuffer > ( )
299299 XCTAssertNoThrow ( try channel. pipeline. addHandler ( handler) . wait ( ) )
300300
301301 // 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 " ) ) )
303315
304316 // We should have a request, no body, and immediately see end of request.
305317 XCTAssert ( handler. seenHead)
@@ -309,22 +321,12 @@ class HTTPDecoderLengthTest: XCTestCase {
309321 XCTAssertTrue ( try channel. finish ( ) . isClean)
310322 }
311323
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-
318324 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 " )
322326 }
323327
324328 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 " )
328330 }
329331
330332 private func assertResponseTransferEncodingHasBodyTerminatedByEOF( transferEncodingHeader: String , eofMechanism: EOFMechanism ) throws {
@@ -366,10 +368,51 @@ class HTTPDecoderLengthTest: XCTestCase {
366368 XCTAssertTrue ( try channel. finish ( ) . isClean)
367369 }
368370
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+
369414 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)
373416 }
374417
375418 func testMultipleTEWithChunkedFirstHasEOFBodyOnResponseWithChannelInactive( ) throws {
@@ -383,9 +426,7 @@ class HTTPDecoderLengthTest: XCTestCase {
383426 }
384427
385428 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)
389430 }
390431
391432 func testMultipleTEWithChunkedFirstHasEOFBodyOnResponseWithHalfClosure( ) throws {
0 commit comments