@@ -42,32 +42,14 @@ class RequestValidationTests: XCTestCase {
4242 XCTAssertEqual ( headers. first ( name: " Content-Length " ) , " 200 " )
4343 }
4444
45- func testChunkedEncodingDoesNotHaveContentLengthHeader( ) {
46- var headers = HTTPHeaders ( [
47- ( " Content-Length " , " 200 " ) ,
48- ( " Transfer-Encoding " , " chunked " ) ,
49- ] )
50- var buffer = ByteBufferAllocator ( ) . buffer ( capacity: 200 )
51- buffer. writeBytes ( [ UInt8] ( repeating: 12 , count: 200 ) )
52- XCTAssertNoThrow ( try headers. validate ( method: . PUT, body: . byteBuffer( buffer) ) )
53-
54- // https://tools.ietf.org/html/rfc7230#section-3.3.2
55- // A sender MUST NOT send a Content-Length header field in any message
56- // that contains a Transfer-Encoding header field.
57-
58- XCTAssertNil ( headers. first ( name: " Content-Length " ) )
59- XCTAssertEqual ( headers. first ( name: " Transfer-Encoding " ) , " chunked " )
60- }
61-
6245 func testTRACERequestMustNotHaveBody( ) {
63- var headers = HTTPHeaders ( [
64- ( " Content-Length " , " 200 " ) ,
65- ( " Transfer-Encoding " , " chunked " ) ,
66- ] )
67- var buffer = ByteBufferAllocator ( ) . buffer ( capacity: 200 )
68- buffer. writeBytes ( [ UInt8] ( repeating: 12 , count: 200 ) )
69- XCTAssertThrowsError ( try headers. validate ( method: . TRACE, body: . byteBuffer( buffer) ) ) {
70- XCTAssertEqual ( $0 as? HTTPClientError , . traceRequestWithBody)
46+ for header in [ ( " Content-Length " , " 200 " ) , ( " Transfer-Encoding " , " chunked " ) ] {
47+ var headers = HTTPHeaders ( [ header] )
48+ var buffer = ByteBufferAllocator ( ) . buffer ( capacity: 200 )
49+ buffer. writeBytes ( [ UInt8] ( repeating: 12 , count: 200 ) )
50+ XCTAssertThrowsError ( try headers. validate ( method: . TRACE, body: . byteBuffer( buffer) ) ) {
51+ XCTAssertEqual ( $0 as? HTTPClientError , . traceRequestWithBody)
52+ }
7153 }
7254 }
7355
@@ -105,13 +87,181 @@ class RequestValidationTests: XCTestCase {
10587 XCTAssertNoThrow ( try headers. validate ( method: . GET, body: nil ) )
10688 }
10789
108- func testMultipleContentLengthOnNilStreamLength( ) {
109- var headers = HTTPHeaders ( [ ( " Content-Length " , " 1 " ) , ( " Content-Length " , " 2 " ) ] )
110- var buffer = ByteBufferAllocator ( ) . buffer ( capacity: 10 )
111- buffer. writeBytes ( [ UInt8] ( repeating: 12 , count: 10 ) )
112- let body : HTTPClient . Body = . stream { writer in
113- writer. write ( . byteBuffer( buffer) )
90+ // MARK: - Content-Length/Transfer-Encoding Matrix
91+
92+ // Method kind User sets Body Expectation
93+ // ----------------------------------------------------------------------------------
94+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE nothing nil Neither CL nor chunked
95+ // other nothing nil CL=0
96+ func testNoHeadersNoBody( ) throws {
97+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
98+ var headers : HTTPHeaders = . init( )
99+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
100+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
101+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
102+ }
103+
104+ for method : HTTPMethod in [ . POST, . PUT] {
105+ var headers : HTTPHeaders = . init( )
106+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
107+ XCTAssertEqual ( headers [ " content-length " ] . first, " 0 " )
108+ XCTAssertFalse ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
109+ }
110+ }
111+
112+ // Method kind User sets Body Expectation
113+ // --------------------------------------------------------------------------------------
114+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE nothing not nil CL or chunked
115+ // other nothing not nil CL or chunked
116+ func testNoHeadersHasBody( ) throws {
117+ // Body length is known
118+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT] {
119+ var headers : HTTPHeaders = . init( )
120+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
121+ XCTAssertEqual ( headers [ " content-length " ] . first, " 1 " )
122+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
123+ }
124+
125+ // Body length is _not_ known
126+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT] {
127+ var headers : HTTPHeaders = . init( )
128+ let body : HTTPClient . Body = . stream { writer in
129+ writer. write ( . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) )
130+ }
131+ XCTAssertNoThrow ( try headers. validate ( method: method, body: body) )
132+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
133+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
134+ }
135+
136+ // Body length is known
137+ for method : HTTPMethod in [ . POST, . PUT] {
138+ var headers : HTTPHeaders = . init( )
139+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
140+ XCTAssertEqual ( headers [ " content-length " ] . first, " 1 " )
141+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
142+ }
143+
144+ // Body length is _not_ known
145+ for method : HTTPMethod in [ . POST, . PUT] {
146+ var headers : HTTPHeaders = . init( )
147+ let body : HTTPClient . Body = . stream { writer in
148+ writer. write ( . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) )
149+ }
150+ XCTAssertNoThrow ( try headers. validate ( method: method, body: body) )
151+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
152+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
153+ }
154+ }
155+
156+ // Method kind User sets Body Expectation
157+ // ------------------------------------------------------------------------------
158+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE content-length nil Neither CL nor chunked
159+ // other content-length nil CL=0
160+ func testContentLengthHeaderNoBody( ) throws {
161+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
162+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
163+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
164+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
165+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
166+ }
167+
168+ for method : HTTPMethod in [ . POST, . PUT] {
169+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
170+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
171+ XCTAssertEqual ( headers [ " content-length " ] . first, " 0 " )
172+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
173+ }
174+ }
175+
176+ // Method kind User sets Body Expectation
177+ // --------------------------------------------------------------------------
178+ // .GET, .HEAD, .DELETE, .CONNECT content-length not nil CL=1
179+ // other content-length nit nil CL=1
180+ func testContentLengthHeaderHasBody( ) throws {
181+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT] {
182+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
183+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
184+ XCTAssertEqual ( headers [ " content-length " ] . first, " 1 " )
185+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
186+ }
187+
188+ for method : HTTPMethod in [ . POST, . PUT] {
189+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
190+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
191+ XCTAssertEqual ( headers [ " content-length " ] . first, " 1 " )
192+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
193+ }
194+ }
195+
196+ // Method kind User sets Body Expectation
197+ // ------------------------------------------------------------------------------------------
198+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE transfer-encoding: chunked nil nil
199+ // other transfer-encoding: chunked nil nil
200+ func testTransferEncodingHeaderNoBody( ) throws {
201+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
202+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
203+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
204+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
205+ XCTAssertFalse ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
206+ }
207+
208+ for method : HTTPMethod in [ . POST, . PUT] {
209+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
210+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
211+ XCTAssertEqual ( headers [ " content-length " ] . first, " 0 " )
212+ XCTAssertFalse ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
213+ }
214+ }
215+
216+ // Method kind User sets Body Expectation
217+ // --------------------------------------------------------------------------------------
218+ // .GET, .HEAD, .DELETE, .CONNECT transfer-encoding: chunked not nil chunked
219+ // other transfer-encoding: chunked not nil chunked
220+ func testTransferEncodingHeaderHasBody( ) throws {
221+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT] {
222+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
223+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
224+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
225+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
226+ }
227+
228+ for method : HTTPMethod in [ . POST, . PUT] {
229+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
230+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
231+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
232+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
233+ }
234+ }
235+
236+ // Method kind User sets Body Expectation
237+ // ---------------------------------------------------------------------------------------
238+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE CL & chunked (illegal) nil throws error
239+ // other CL & chunked (illegal) nil throws error
240+ func testBothHeadersNoBody( ) throws {
241+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
242+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
243+ XCTAssertThrowsError ( try headers. validate ( method: method, body: nil ) )
244+ }
245+
246+ for method : HTTPMethod in [ . POST, . PUT] {
247+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
248+ XCTAssertThrowsError ( try headers. validate ( method: method, body: nil ) )
249+ }
250+ }
251+
252+ // Method kind User sets Body Expectation
253+ // -------------------------------------------------------------------------------------------
254+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE CL & chunked (illegal) not nil throws error
255+ // other CL & chunked (illegal) not nil throws error
256+ func testBothHeadersHasBody( ) throws {
257+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
258+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
259+ XCTAssertThrowsError ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
260+ }
261+
262+ for method : HTTPMethod in [ . POST, . PUT] {
263+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
264+ XCTAssertThrowsError ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
114265 }
115- XCTAssertThrowsError ( try headers. validate ( method: . PUT, body: body) )
116266 }
117267}
0 commit comments