@@ -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,178 @@ 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 chunked
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
+ // TODO: This should be CL=0 ??? https://tools.ietf.org/html/rfc7230#section-3.3.2
108
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
109
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
110
+ }
111
+ }
112
+
113
+ // Method kind User sets Body Expectation
114
+ // --------------------------------------------------------------------------------------
115
+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE nothing not nil Neither CL nor chunked
116
+ // other nothing not nil chunked
117
+ func testNoHeadersHasBody( ) throws {
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
+
122
+ // TODO: Logically, this should be a Content-Length: 1
123
+
124
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
125
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
126
+ }
127
+
128
+ for method : HTTPMethod in [ . POST, . PUT] {
129
+ var headers : HTTPHeaders = . init( )
130
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
131
+
132
+ // TODO: Logically, this should be a Content-Length: 1 since we know size, or chunked if we don't
133
+
134
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
135
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
136
+ }
137
+
138
+ for method : HTTPMethod in [ . POST, . PUT] {
139
+ var headers : HTTPHeaders = . init( )
140
+ let body : HTTPClient . Body = . stream { writer in
141
+ writer. write ( . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) )
142
+ }
143
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: body) )
144
+
145
+ // TODO: Logically, this should be a Content-Length: 1 since we know size, or chunked if we don't
146
+
147
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
148
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
149
+ }
150
+ }
151
+
152
+ // Method kind User sets Body Expectation
153
+ // ------------------------------------------------------------------------------
154
+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE content-length nil CL=0
155
+ // other content-length nil CL=0
156
+ func testContentLengthHeaderNoBody( ) throws {
157
+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
158
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
159
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
160
+ // TODO: this should be Neither CL nor chunked https://tools.ietf.org/html/rfc7230#section-3.3.2
161
+ XCTAssertEqual ( headers [ " content-length " ] . first, " 0 " )
162
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
163
+ }
164
+
165
+ for method : HTTPMethod in [ . POST, . PUT] {
166
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
167
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
168
+ XCTAssertEqual ( headers [ " content-length " ] . first, " 0 " )
169
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
170
+ }
171
+ }
172
+
173
+ // Method kind User sets Body Expectation
174
+ // ----------------------------------------------------------------------------------
175
+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE content-length not nil CL=1
176
+ // other content-length nit nil CL=1
177
+ func testContentLengthHeaderHasBody( ) throws {
178
+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT] {
179
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
180
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
181
+ XCTAssertEqual ( headers [ " content-length " ] . first, " 1 " )
182
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
183
+ }
184
+
185
+ for method : HTTPMethod in [ . POST, . PUT] {
186
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) ] )
187
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
188
+ XCTAssertEqual ( headers [ " content-length " ] . first, " 1 " )
189
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . isEmpty)
190
+ }
191
+ }
192
+
193
+ // Method kind User sets Body Expectation
194
+ // ------------------------------------------------------------------------------------------
195
+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE transfer-encoding: chunked nil chunked
196
+ // other transfer-encoding: chunked nil chunked
197
+ func testTransferEncodingHeaderNoBody( ) throws {
198
+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
199
+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
200
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
201
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
202
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
203
+ }
204
+
205
+ for method : HTTPMethod in [ . POST, . PUT] {
206
+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
207
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: nil ) )
208
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
209
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
210
+ }
211
+ }
212
+
213
+ // Method kind User sets Body Expectation
214
+ // --------------------------------------------------------------------------------------
215
+ // .GET, .HEAD, .DELETE, .CONNECT transfer-encoding: chunked not nil chunked
216
+ // other transfer-encoding: chunked not nil chunked
217
+ func testTransferEncodingHeaderHasBody( ) throws {
218
+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT] {
219
+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
220
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
221
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
222
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
223
+ }
224
+
225
+ for method : HTTPMethod in [ . POST, . PUT] {
226
+ var headers : HTTPHeaders = . init( [ ( " Transfer-Encoding " , " chunked " ) ] )
227
+ XCTAssertNoThrow ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
228
+ XCTAssertTrue ( headers [ " content-length " ] . isEmpty)
229
+ XCTAssertTrue ( headers [ " transfer-encoding " ] . contains ( " chunked " ) )
230
+ }
231
+ }
232
+
233
+ // Method kind User sets Body Expectation
234
+ // ---------------------------------------------------------------------------------------
235
+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE CL & chunked (illegal) nil throws error
236
+ // other CL & chunked (illegal) nil throws error
237
+ func testBothHeadersNoBody( ) throws {
238
+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
239
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
240
+ XCTAssertThrowsError ( try headers. validate ( method: method, body: nil ) )
241
+ }
242
+
243
+ for method : HTTPMethod in [ . POST, . PUT] {
244
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
245
+ XCTAssertThrowsError ( try headers. validate ( method: method, body: nil ) )
246
+ }
247
+ }
248
+
249
+ // Method kind User sets Body Expectation
250
+ // -------------------------------------------------------------------------------------------
251
+ // .GET, .HEAD, .DELETE, .CONNECT, .TRACE CL & chunked (illegal) not nil throws error
252
+ // other CL & chunked (illegal) not nil throws error
253
+ func testBothHeadersHasBody( ) throws {
254
+ for method : HTTPMethod in [ . GET, . HEAD, . DELETE, . CONNECT, . TRACE] {
255
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
256
+ XCTAssertThrowsError ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
257
+ }
258
+
259
+ for method : HTTPMethod in [ . POST, . PUT] {
260
+ var headers : HTTPHeaders = . init( [ ( " Content-Length " , " 1 " ) , ( " Transfer-Encoding " , " chunked " ) ] )
261
+ XCTAssertThrowsError ( try headers. validate ( method: method, body: . byteBuffer( ByteBuffer ( bytes: [ 0 ] ) ) ) )
114
262
}
115
- XCTAssertThrowsError ( try headers. validate ( method: . PUT, body: body) )
116
263
}
117
264
}
0 commit comments