@@ -42,32 +42,14 @@ class RequestValidationTests: XCTestCase {
42
42
XCTAssertEqual ( headers. first ( name: " Content-Length " ) , " 200 " )
43
43
}
44
44
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
-
62
45
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
+ }
71
53
}
72
54
}
73
55
@@ -105,13 +87,181 @@ class RequestValidationTests: XCTestCase {
105
87
XCTAssertNoThrow ( try headers. validate ( method: . GET, body: nil ) )
106
88
}
107
89
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 ] ) ) ) )
114
265
}
115
- XCTAssertThrowsError ( try headers. validate ( method: . PUT, body: body) )
116
266
}
117
267
}
0 commit comments