@@ -18,11 +18,25 @@ import NIOFoundationCompat
1818import NIOHTTP1
1919import NIOHTTPCompression
2020import NIOSSL
21+ import NIOTestUtils
2122import XCTest
2223
2324class HTTPClientTests : XCTestCase {
2425 typealias Request = HTTPClient . Request
2526
27+ var group : EventLoopGroup !
28+
29+ override func setUp( ) {
30+ XCTAssertNil ( self . group)
31+ self . group = MultiThreadedEventLoopGroup ( numberOfThreads: 1 )
32+ }
33+
34+ override func tearDown( ) {
35+ XCTAssertNotNil ( self . group)
36+ XCTAssertNoThrow ( try self . group. syncShutdownGracefully ( ) )
37+ self . group = nil
38+ }
39+
2640 func testRequestURI( ) throws {
2741 let request1 = try Request ( url: " https://someserver.com:8888/some/path?foo=bar " )
2842 XCTAssertEqual ( request1. url. host, " someserver.com " )
@@ -658,4 +672,172 @@ class HTTPClientTests: XCTestCase {
658672 XCTAssertEqual ( error as! HTTPClientError , HTTPClientError . redirectLimitReached)
659673 }
660674 }
675+
676+ func testWorksWith500Error( ) {
677+ let web = NIOHTTP1TestServer ( group: self . group)
678+ defer {
679+ XCTAssertNoThrow ( try web. stop ( ) )
680+ }
681+
682+ let httpClient = HTTPClient ( eventLoopGroupProvider: . shared( self . group) )
683+ defer {
684+ XCTAssertNoThrow ( try httpClient. syncShutdown ( ) )
685+ }
686+ let result = httpClient. get ( url: " http://localhost: \( web. serverPort) /foo " )
687+
688+ XCTAssertNoThrow ( XCTAssertEqual ( . head( . init( version: . init( major: 1 , minor: 1 ) ,
689+ method: . GET,
690+ uri: " /foo " ,
691+ headers: HTTPHeaders ( [ ( " Host " , " localhost " ) ,
692+ // The following line can be removed once we
693+ // have a connection pool.
694+ ( " Connection " , " close " ) ,
695+ ( " Content-Length " , " 0 " ) ] ) ) ) ,
696+ try web. readInbound ( ) ) )
697+ XCTAssertNoThrow ( XCTAssertEqual ( . end( nil ) ,
698+ try web. readInbound ( ) ) )
699+ XCTAssertNoThrow ( try web. writeOutbound ( . head( . init( version: . init( major: 1 , minor: 1 ) ,
700+ status: . internalServerError) ) ) )
701+ XCTAssertNoThrow ( try web. writeOutbound ( . end( nil ) ) )
702+
703+ var response : HTTPClient . Response ?
704+ XCTAssertNoThrow ( response = try result. wait ( ) )
705+ XCTAssertEqual ( . internalServerError, response? . status)
706+ XCTAssertNil ( response? . body)
707+ }
708+
709+ func testWorksWithHTTP10Response( ) {
710+ let web = NIOHTTP1TestServer ( group: self . group)
711+ defer {
712+ XCTAssertNoThrow ( try web. stop ( ) )
713+ }
714+
715+ let httpClient = HTTPClient ( eventLoopGroupProvider: . shared( self . group) )
716+ defer {
717+ XCTAssertNoThrow ( try httpClient. syncShutdown ( ) )
718+ }
719+ let result = httpClient. get ( url: " http://localhost: \( web. serverPort) /foo " )
720+
721+ XCTAssertNoThrow ( XCTAssertEqual ( . head( . init( version: . init( major: 1 , minor: 1 ) ,
722+ method: . GET,
723+ uri: " /foo " ,
724+ headers: HTTPHeaders ( [ ( " Host " , " localhost " ) ,
725+ // The following line can be removed once we
726+ // have a connection pool.
727+ ( " Connection " , " close " ) ,
728+ ( " Content-Length " , " 0 " ) ] ) ) ) ,
729+ try web. readInbound ( ) ) )
730+ XCTAssertNoThrow ( XCTAssertEqual ( . end( nil ) ,
731+ try web. readInbound ( ) ) )
732+ XCTAssertNoThrow ( try web. writeOutbound ( . head( . init( version: . init( major: 1 , minor: 0 ) ,
733+ status: . internalServerError) ) ) )
734+ XCTAssertNoThrow ( try web. writeOutbound ( . end( nil ) ) )
735+
736+ var response : HTTPClient . Response ?
737+ XCTAssertNoThrow ( response = try result. wait ( ) )
738+ XCTAssertEqual ( . internalServerError, response? . status)
739+ XCTAssertNil ( response? . body)
740+ }
741+
742+ func testWorksWhenServerClosesConnectionAfterReceivingRequest( ) {
743+ let web = NIOHTTP1TestServer ( group: self . group)
744+
745+ let httpClient = HTTPClient ( eventLoopGroupProvider: . shared( self . group) )
746+ defer {
747+ XCTAssertNoThrow ( try httpClient. syncShutdown ( ) )
748+ }
749+ let result = httpClient. get ( url: " http://localhost: \( web. serverPort) /foo " )
750+
751+ XCTAssertNoThrow ( XCTAssertEqual ( . head( . init( version: . init( major: 1 , minor: 1 ) ,
752+ method: . GET,
753+ uri: " /foo " ,
754+ headers: HTTPHeaders ( [ ( " Host " , " localhost " ) ,
755+ // The following line can be removed once we
756+ // have a connection pool.
757+ ( " Connection " , " close " ) ,
758+ ( " Content-Length " , " 0 " ) ] ) ) ) ,
759+ try web. readInbound ( ) ) )
760+ XCTAssertNoThrow ( XCTAssertEqual ( . end( nil ) ,
761+ try web. readInbound ( ) ) )
762+ XCTAssertNoThrow ( try web. stop ( ) )
763+
764+ XCTAssertThrowsError ( try result. wait ( ) ) { error in
765+ XCTAssertEqual ( HTTPClientError . remoteConnectionClosed, error as? HTTPClientError )
766+ }
767+ }
768+
769+ func testSubsequentRequestsWorkWithServerSendingConnectionClose( ) {
770+ let web = NIOHTTP1TestServer ( group: self . group)
771+ defer {
772+ XCTAssertNoThrow ( try web. stop ( ) )
773+ }
774+
775+ let httpClient = HTTPClient ( eventLoopGroupProvider: . shared( self . group) )
776+ defer {
777+ XCTAssertNoThrow ( try httpClient. syncShutdown ( ) )
778+ }
779+
780+ for _ in 0 ..< 10 {
781+ let result = httpClient. get ( url: " http://localhost: \( web. serverPort) /foo " )
782+
783+ XCTAssertNoThrow ( XCTAssertEqual ( . head( . init( version: . init( major: 1 , minor: 1 ) ,
784+ method: . GET,
785+ uri: " /foo " ,
786+ headers: HTTPHeaders ( [ ( " Host " , " localhost " ) ,
787+ // The following line can be removed once
788+ // we have a connection pool.
789+ ( " Connection " , " close " ) ,
790+ ( " Content-Length " , " 0 " ) ] ) ) ) ,
791+ try web. readInbound ( ) ) )
792+ XCTAssertNoThrow ( XCTAssertEqual ( . end( nil ) ,
793+ try web. readInbound ( ) ) )
794+ XCTAssertNoThrow ( try web. writeOutbound ( . head( . init( version: . init( major: 1 , minor: 0 ) ,
795+ status: . ok,
796+ headers: HTTPHeaders ( [ ( " connection " , " close " ) ] ) ) ) ) )
797+ XCTAssertNoThrow ( try web. writeOutbound ( . end( nil ) ) )
798+
799+ var response : HTTPClient . Response ?
800+ XCTAssertNoThrow ( response = try result. wait ( ) )
801+ XCTAssertEqual ( . ok, response? . status)
802+ XCTAssertNil ( response? . body)
803+ }
804+ }
805+
806+ func testSubsequentRequestsWorkWithServerAlternatingBetweenKeepAliveAndClose( ) {
807+ let web = NIOHTTP1TestServer ( group: self . group)
808+ defer {
809+ XCTAssertNoThrow ( try web. stop ( ) )
810+ }
811+
812+ let httpClient = HTTPClient ( eventLoopGroupProvider: . shared( self . group) )
813+ defer {
814+ XCTAssertNoThrow ( try httpClient. syncShutdown ( ) )
815+ }
816+
817+ for i in 0 ..< 10 {
818+ let result = httpClient. get ( url: " http://localhost: \( web. serverPort) /foo " )
819+
820+ XCTAssertNoThrow ( XCTAssertEqual ( . head( . init( version: . init( major: 1 , minor: 1 ) ,
821+ method: . GET,
822+ uri: " /foo " ,
823+ headers: HTTPHeaders ( [ ( " Host " , " localhost " ) ,
824+ // The following line can be removed once
825+ // we have a connection pool.
826+ ( " Connection " , " close " ) ,
827+ ( " Content-Length " , " 0 " ) ] ) ) ) ,
828+ try web. readInbound ( ) ) )
829+ XCTAssertNoThrow ( XCTAssertEqual ( . end( nil ) ,
830+ try web. readInbound ( ) ) )
831+ XCTAssertNoThrow ( try web. writeOutbound ( . head( . init( version: . init( major: 1 , minor: 0 ) ,
832+ status: . ok,
833+ headers: HTTPHeaders ( [ ( " connection " ,
834+ i % 2 == 0 ? " close " : " keep-alive " ) ] ) ) ) ) )
835+ XCTAssertNoThrow ( try web. writeOutbound ( . end( nil ) ) )
836+
837+ var response : HTTPClient . Response ?
838+ XCTAssertNoThrow ( response = try result. wait ( ) )
839+ XCTAssertEqual ( . ok, response? . status)
840+ XCTAssertNil ( response? . body)
841+ }
842+ }
661843}
0 commit comments