@@ -16,6 +16,7 @@ import AsyncHTTPClient
1616import NIO
1717import NIOFoundationCompat
1818import NIOHTTP1
19+ import NIOSSL
1920import XCTest
2021
2122class HTTPClientTests : XCTestCase {
@@ -346,4 +347,141 @@ class HTTPClientTests: XCTestCase {
346347 XCTAssertEqual ( . ok, response. status)
347348 XCTAssertEqual ( " 12344321 " , data. data)
348349 }
350+
351+ func testNoContentLengthForSSLUncleanShutdown( ) throws {
352+ let httpBin = HttpBinForSSLUncleanShutdown ( )
353+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
354+ configuration: HTTPClient . Configuration ( certificateVerification: . none) )
355+
356+ defer {
357+ try ! httpClient. syncShutdown ( )
358+ httpBin. shutdown ( )
359+ }
360+
361+ XCTAssertThrowsError ( try httpClient. get ( url: " https://localhost: \( httpBin. port) /nocontentlength " ) . wait ( ) , " Should fail " ) { error in
362+ guard case let error = error as? NIOSSLError , error == . uncleanShutdown else {
363+ return XCTFail ( " Should fail with NIOSSLError.uncleanShutdown " )
364+ }
365+ }
366+ }
367+
368+ func testNoContentLengthWithIgnoreErrorForSSLUncleanShutdown( ) throws {
369+ let httpBin = HttpBinForSSLUncleanShutdown ( )
370+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
371+ configuration: HTTPClient . Configuration ( certificateVerification: . none, ignoreUncleanSSLShutdown: true ) )
372+
373+ defer {
374+ try ! httpClient. syncShutdown ( )
375+ httpBin. shutdown ( )
376+ }
377+
378+ let response = try httpClient. get ( url: " https://localhost: \( httpBin. port) /nocontentlength " ) . wait ( )
379+ let bytes = response. body. flatMap { $0. getData ( at: 0 , length: $0. readableBytes) }
380+ let string = String ( decoding: bytes!, as: UTF8 . self)
381+
382+ XCTAssertEqual ( . ok, response. status)
383+ XCTAssertEqual ( " foo " , string)
384+ }
385+
386+ func testCorrectContentLengthForSSLUncleanShutdown( ) throws {
387+ let httpBin = HttpBinForSSLUncleanShutdown ( )
388+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
389+ configuration: HTTPClient . Configuration ( certificateVerification: . none) )
390+
391+ defer {
392+ try ! httpClient. syncShutdown ( )
393+ httpBin. shutdown ( )
394+ }
395+
396+ let response = try httpClient. get ( url: " https://localhost: \( httpBin. port) / " ) . wait ( )
397+ let bytes = response. body. flatMap { $0. getData ( at: 0 , length: $0. readableBytes) }
398+ let string = String ( decoding: bytes!, as: UTF8 . self)
399+
400+ XCTAssertEqual ( . notFound, response. status)
401+ XCTAssertEqual ( " Not Found " , string)
402+ }
403+
404+ func testNoContentForSSLUncleanShutdown( ) throws {
405+ let httpBin = HttpBinForSSLUncleanShutdown ( )
406+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
407+ configuration: HTTPClient . Configuration ( certificateVerification: . none) )
408+
409+ defer {
410+ try ! httpClient. syncShutdown ( )
411+ httpBin. shutdown ( )
412+ }
413+
414+ let response = try httpClient. get ( url: " https://localhost: \( httpBin. port) /nocontent " ) . wait ( )
415+
416+ XCTAssertEqual ( . noContent, response. status)
417+ XCTAssertEqual ( response. body, nil )
418+ }
419+
420+ func testNoResponseForSSLUncleanShutdown( ) throws {
421+ let httpBin = HttpBinForSSLUncleanShutdown ( )
422+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
423+ configuration: HTTPClient . Configuration ( certificateVerification: . none) )
424+
425+ defer {
426+ try ! httpClient. syncShutdown ( )
427+ httpBin. shutdown ( )
428+ }
429+
430+ XCTAssertThrowsError ( try httpClient. get ( url: " https://localhost: \( httpBin. port) /noresponse " ) . wait ( ) , " Should fail " ) { error in
431+ guard case let error = error as? NIOSSLError , error == . uncleanShutdown else {
432+ return XCTFail ( " Should fail with NIOSSLError.uncleanShutdown " )
433+ }
434+ }
435+ }
436+
437+ func testNoResponseWithIgnoreErrorForSSLUncleanShutdown( ) throws {
438+ let httpBin = HttpBinForSSLUncleanShutdown ( )
439+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
440+ configuration: HTTPClient . Configuration ( certificateVerification: . none, ignoreUncleanSSLShutdown: true ) )
441+
442+ defer {
443+ try ! httpClient. syncShutdown ( )
444+ httpBin. shutdown ( )
445+ }
446+
447+ XCTAssertThrowsError ( try httpClient. get ( url: " https://localhost: \( httpBin. port) /noresponse " ) . wait ( ) , " Should fail " ) { error in
448+ guard case let error = error as? NIOSSLError , error == . uncleanShutdown else {
449+ return XCTFail ( " Should fail with NIOSSLError.uncleanShutdown " )
450+ }
451+ }
452+ }
453+
454+ func testWrongContentLengthForSSLUncleanShutdown( ) throws {
455+ let httpBin = HttpBinForSSLUncleanShutdown ( )
456+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
457+ configuration: HTTPClient . Configuration ( certificateVerification: . none) )
458+
459+ defer {
460+ try ! httpClient. syncShutdown ( )
461+ httpBin. shutdown ( )
462+ }
463+
464+ XCTAssertThrowsError ( try httpClient. get ( url: " https://localhost: \( httpBin. port) /wrongcontentlength " ) . wait ( ) , " Should fail " ) { error in
465+ guard case let error = error as? NIOSSLError , error == . uncleanShutdown else {
466+ return XCTFail ( " Should fail with NIOSSLError.uncleanShutdown " )
467+ }
468+ }
469+ }
470+
471+ func testWrongContentLengthWithIgnoreErrorForSSLUncleanShutdown( ) throws {
472+ let httpBin = HttpBinForSSLUncleanShutdown ( )
473+ let httpClient = HTTPClient ( eventLoopGroupProvider: . createNew,
474+ configuration: HTTPClient . Configuration ( certificateVerification: . none, ignoreUncleanSSLShutdown: true ) )
475+
476+ defer {
477+ try ! httpClient. syncShutdown ( )
478+ httpBin. shutdown ( )
479+ }
480+
481+ XCTAssertThrowsError ( try httpClient. get ( url: " https://localhost: \( httpBin. port) /wrongcontentlength " ) . wait ( ) , " Should fail " ) { error in
482+ guard case let error = error as? HTTPParserError , error == . invalidEOFState else {
483+ return XCTFail ( " Should fail with HTTPParserError.invalidEOFState " )
484+ }
485+ }
486+ }
349487}
0 commit comments