OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:math'; | 6 import 'dart:math'; |
7 import 'dart:scalarlist'; | 7 import 'dart:scalarlist'; |
| 8 import 'dart:isolate'; |
| 9 import 'dart:uri'; |
8 | 10 |
| 11 part '../../../sdk/lib/io/io_stream_consumer.dart'; |
9 part '../../../sdk/lib/io/http.dart'; | 12 part '../../../sdk/lib/io/http.dart'; |
| 13 part '../../../sdk/lib/io/http_impl.dart'; |
10 part '../../../sdk/lib/io/http_headers.dart'; | 14 part '../../../sdk/lib/io/http_headers.dart'; |
11 part '../../../sdk/lib/io/http_parser.dart'; | 15 part '../../../sdk/lib/io/http_parser.dart'; |
| 16 part '../../../sdk/lib/io/socket.dart'; |
12 | 17 |
13 class HttpParserTest { | 18 class HttpParserTest { |
14 static void runAllTests() { | 19 static void runAllTests() { |
15 testParseRequest(); | 20 testParseRequest(); |
16 testParseResponse(); | 21 testParseResponse(); |
17 testParseInvalidRequest(); | 22 testParseInvalidRequest(); |
18 testParseInvalidResponse(); | 23 testParseInvalidResponse(); |
19 } | 24 } |
20 | 25 |
21 static void _testParseRequest(String request, | 26 static void _testParseRequest(String request, |
22 String expectedMethod, | 27 String expectedMethod, |
23 String expectedUri, | 28 String expectedUri, |
24 {int expectedContentLength: 0, | 29 {int expectedTransferLength: 0, |
25 int expectedBytesReceived: 0, | 30 int expectedBytesReceived: 0, |
26 Map expectedHeaders: null, | 31 Map expectedHeaders: null, |
27 bool chunked: false, | 32 bool chunked: false, |
28 bool upgrade: false, | 33 bool upgrade: false, |
29 int unparsedLength: 0, | 34 int unparsedLength: 0, |
30 bool connectionClose: false, | 35 bool connectionClose: false, |
31 String expectedVersion: "1.1"}) { | 36 String expectedVersion: "1.1"}) { |
32 _HttpParser httpParser; | 37 StreamController controller; |
33 bool headersCompleteCalled; | 38 void reset() { |
34 bool dataEndCalled; | 39 _HttpParser httpParser = new _HttpParser.requestParser(); |
35 String method; | 40 controller = new StreamController(); |
36 String uri; | 41 var port1 = new ReceivePort(); |
37 String version; | 42 var port2 = new ReceivePort(); |
38 HttpHeaders headers; | |
39 int contentLength; | |
40 int bytesReceived; | |
41 | 43 |
42 void reset() { | 44 String method; |
43 httpParser = new _HttpParser.requestParser(); | 45 Uri uri; |
44 httpParser.requestStart = (m, u, v, h, b) { | 46 HttpHeaders headers; |
45 method = m; | 47 int contentLength; |
46 uri = u; | 48 int bytesReceived; |
47 version = v; | 49 int unparsedBytesReceived; |
48 headers = h; | 50 bool upgraded; |
49 headersCompleteCalled = true; | 51 |
| 52 controller.stream.pipe(httpParser); |
| 53 var subscription = httpParser.listen((incoming) { |
| 54 method = incoming.method; |
| 55 uri = incoming.uri; |
| 56 headers = incoming.headers; |
| 57 upgraded = incoming.upgraded; |
| 58 Expect.equals(upgrade, upgraded); |
| 59 |
50 if (!chunked) { | 60 if (!chunked) { |
51 Expect.equals(expectedContentLength, httpParser.contentLength); | 61 Expect.equals(expectedTransferLength, incoming.transferLength); |
52 } else { | 62 } else { |
53 Expect.equals(-1, httpParser.contentLength); | 63 Expect.equals(-1, incoming.transferLength); |
54 } | 64 } |
55 if (expectedHeaders != null) { | 65 if (expectedHeaders != null) { |
56 expectedHeaders.forEach( | 66 expectedHeaders.forEach( |
57 (String name, String value) => | 67 (String name, String value) => |
58 Expect.equals(value, headers[name][0])); | 68 Expect.equals(value, headers[name][0])); |
59 } | 69 } |
60 Expect.equals(upgrade, httpParser.upgrade); | 70 incoming.listen( |
61 Expect.equals(connectionClose, !httpParser.persistentConnection); | 71 (List<int> data) { |
62 headersCompleteCalled = true; | 72 Expect.isFalse(upgraded); |
63 }; | 73 bytesReceived += data.length; |
64 httpParser.responseStart = (s, r, v, h, b) { | 74 }, |
65 Expect.fail("Expected request"); | 75 onDone: () { |
66 }; | 76 Expect.isFalse(upgraded); |
67 httpParser.dataReceived = (List<int> data) { | 77 port2.close(); |
68 Expect.isTrue(headersCompleteCalled); | 78 }); |
69 bytesReceived += data.length; | |
70 }; | |
71 httpParser.dataEnd = (close) { | |
72 Expect.isFalse(close); | |
73 dataEndCalled = true; | |
74 }; | |
75 httpParser.closed = () { }; | |
76 | 79 |
77 headersCompleteCalled = false; | 80 if (upgraded) { |
78 dataEndCalled = false; | 81 port1.close(); |
| 82 httpParser.detachIncoming().listen( |
| 83 (List<int> data) { |
| 84 unparsedBytesReceived += data.length; |
| 85 }, |
| 86 onDone: () { |
| 87 Expect.equals(unparsedLength, unparsedBytesReceived); |
| 88 port2.close(); |
| 89 }); |
| 90 } |
| 91 |
| 92 incoming.dataDone.then((_) { |
| 93 port1.close(); |
| 94 Expect.isFalse(upgraded); |
| 95 Expect.equals(expectedMethod, method); |
| 96 Expect.stringEquals(expectedUri, uri.toString()); |
| 97 Expect.equals(expectedVersion, headers.protocolVersion); |
| 98 if (upgrade) { |
| 99 Expect.equals(0, bytesReceived); |
| 100 // port1 is closed by the listener on the detached data. |
| 101 } else { |
| 102 Expect.equals(expectedBytesReceived, bytesReceived); |
| 103 } |
| 104 }); |
| 105 }); |
| 106 |
79 method = null; | 107 method = null; |
80 uri = null; | 108 uri = null; |
81 headers = null; | 109 headers = null; |
82 bytesReceived = 0; | 110 bytesReceived = 0; |
| 111 unparsedBytesReceived = 0; |
| 112 upgraded = false; |
83 } | 113 } |
84 | 114 |
85 void testWrite(List<int> requestData, [int chunkSize = -1]) { | 115 void testWrite(List<int> requestData, [int chunkSize = -1]) { |
86 if (chunkSize == -1) chunkSize = requestData.length; | 116 if (chunkSize == -1) chunkSize = requestData.length; |
87 reset(); | 117 reset(); |
88 int written = 0; | |
89 int unparsed; | |
90 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | 118 for (int pos = 0; pos < requestData.length; pos += chunkSize) { |
91 int remaining = requestData.length - pos; | 119 int remaining = requestData.length - pos; |
92 int writeLength = min(chunkSize, remaining); | 120 int writeLength = min(chunkSize, remaining); |
93 written += writeLength; | 121 controller.add(requestData.getRange(pos, writeLength)); |
94 httpParser.streamData(requestData.getRange(pos, writeLength)); | |
95 unparsed = httpParser.readUnparsedData().length; | |
96 if (httpParser.upgrade) { | |
97 unparsed += requestData.length - written; | |
98 break; | |
99 } else { | |
100 Expect.equals(0, unparsed); | |
101 } | |
102 } | 122 } |
103 Expect.equals(expectedMethod, method); | 123 controller.close(); |
104 Expect.equals(expectedUri, uri); | |
105 Expect.equals(expectedVersion, version); | |
106 Expect.isTrue(headersCompleteCalled); | |
107 Expect.equals(expectedBytesReceived, bytesReceived); | |
108 if (!upgrade) Expect.isTrue(dataEndCalled); | |
109 if (unparsedLength == 0) { | |
110 Expect.equals(0, unparsed); | |
111 } else { | |
112 Expect.equals(unparsedLength, unparsed); | |
113 } | |
114 } | 124 } |
115 | 125 |
116 // Test parsing the request three times delivering the data in | 126 // Test parsing the request three times delivering the data in |
117 // different chunks. | 127 // different chunks. |
118 List<int> requestData = request.charCodes; | 128 List<int> requestData = request.charCodes; |
119 testWrite(requestData); | 129 testWrite(requestData); |
120 testWrite(requestData, 10); | 130 testWrite(requestData, 10); |
121 testWrite(requestData, 1); | 131 testWrite(requestData, 1); |
122 } | 132 } |
123 | 133 |
124 static void _testParseInvalidRequest(String request) { | 134 static void _testParseInvalidRequest(String request) { |
125 _HttpParser httpParser; | 135 _HttpParser httpParser; |
126 bool errorCalled; | 136 bool errorCalled; |
| 137 StreamController controller; |
127 | 138 |
128 void reset() { | 139 void reset() { |
129 httpParser = new _HttpParser.requestParser(); | 140 httpParser = new _HttpParser.requestParser(); |
130 httpParser.responseStart = (s, r, v, h, b) { | 141 controller = new StreamController(); |
| 142 var port = new ReceivePort(); |
| 143 controller.stream.pipe(httpParser); |
| 144 var subscription = httpParser.listen((incoming) { |
131 Expect.fail("Expected request"); | 145 Expect.fail("Expected request"); |
132 }; | 146 }); |
133 httpParser.error = (e) { | 147 subscription.onError((e) { |
134 errorCalled = true; | 148 errorCalled = true; |
135 }; | 149 }); |
136 httpParser.closed = () { }; | 150 subscription.onDone(() { |
137 | 151 port.close(); |
| 152 Expect.isTrue(errorCalled); |
| 153 }); |
138 errorCalled = false; | 154 errorCalled = false; |
139 } | 155 } |
140 | 156 |
141 void testWrite(List<int> requestData, [int chunkSize = -1]) { | 157 void testWrite(List<int> requestData, [int chunkSize = -1]) { |
142 if (chunkSize == -1) chunkSize = requestData.length; | 158 if (chunkSize == -1) chunkSize = requestData.length; |
143 reset(); | 159 reset(); |
144 for (int pos = 0; | 160 for (int pos = 0; |
145 pos < requestData.length && !errorCalled; | 161 pos < requestData.length && !errorCalled; |
146 pos += chunkSize) { | 162 pos += chunkSize) { |
147 int remaining = requestData.length - pos; | 163 int remaining = requestData.length - pos; |
148 int writeLength = min(chunkSize, remaining); | 164 int writeLength = min(chunkSize, remaining); |
149 httpParser.streamData(requestData.getRange(pos, writeLength)); | 165 controller.add(requestData.getRange(pos, writeLength)); |
150 } | 166 } |
151 Expect.isTrue(errorCalled); | 167 controller.close(); |
152 } | 168 } |
153 | 169 |
154 // Test parsing the request three times delivering the data in | 170 // Test parsing the request three times delivering the data in |
155 // different chunks. | 171 // different chunks. |
156 List<int> requestData = request.charCodes; | 172 List<int> requestData = request.charCodes; |
157 testWrite(requestData); | 173 testWrite(requestData); |
158 testWrite(requestData, 10); | 174 testWrite(requestData, 10); |
159 testWrite(requestData, 1); | 175 testWrite(requestData, 1); |
160 } | 176 } |
161 | 177 |
162 static void _testParseResponse(String response, | 178 static void _testParseResponse(String response, |
163 int expectedStatusCode, | 179 int expectedStatusCode, |
164 String expectedReasonPhrase, | 180 String expectedReasonPhrase, |
165 {int expectedContentLength: -1, | 181 {int expectedTransferLength: 0, |
166 int expectedBytesReceived: 0, | 182 int expectedBytesReceived: 0, |
167 Map expectedHeaders: null, | 183 Map expectedHeaders: null, |
168 bool chunked: false, | 184 bool chunked: false, |
169 bool close: false, | 185 bool close: false, |
170 String responseToMethod: null, | 186 String responseToMethod: null, |
171 bool connectionClose: false, | 187 bool connectionClose: false, |
172 bool upgrade: false, | 188 bool upgrade: false, |
173 int unparsedLength: 0, | 189 int unparsedLength: 0, |
174 String expectedVersion: "1.1"}) { | 190 String expectedVersion: "1.1"}) { |
175 _HttpParser httpParser; | 191 _HttpParser httpParser; |
176 bool headersCompleteCalled; | 192 bool headersCompleteCalled; |
177 bool dataEndCalled; | 193 bool dataEndCalled; |
178 bool dataEndClose; | 194 bool dataEndClose; |
179 int statusCode; | 195 int statusCode; |
180 String reasonPhrase; | 196 String reasonPhrase; |
181 String version; | |
182 HttpHeaders headers; | 197 HttpHeaders headers; |
183 int contentLength; | 198 int contentLength; |
184 int bytesReceived; | 199 int bytesReceived; |
| 200 StreamController controller; |
| 201 bool upgraded; |
185 | 202 |
186 void reset() { | 203 void reset() { |
187 httpParser = new _HttpParser.responseParser(); | 204 httpParser = new _HttpParser.responseParser(); |
188 if (responseToMethod != null) { | 205 controller = new StreamController(); |
189 httpParser.responseToMethod = responseToMethod; | 206 var port = new ReceivePort(); |
190 } | 207 controller.stream.pipe(httpParser); |
191 httpParser.requestStart = (m, u, v, h, b) { | 208 var subscription = httpParser.listen((incoming) { |
192 Expect.fail("Expected response"); | 209 port.close(); |
193 }; | 210 statusCode = incoming.statusCode; |
194 httpParser.responseStart = (s, r, v, h, b) { | 211 reasonPhrase = incoming.reasonPhrase; |
195 statusCode = s; | 212 headers = incoming.headers; |
196 reasonPhrase = r; | |
197 version = v; | |
198 headers = h; | |
199 Expect.isFalse(headersCompleteCalled); | 213 Expect.isFalse(headersCompleteCalled); |
200 if (!chunked && !close) { | 214 if (!chunked && !close) { |
201 Expect.equals(expectedContentLength, httpParser.contentLength); | 215 Expect.equals(expectedTransferLength, incoming.transferLength); |
202 } else { | 216 } else { |
203 Expect.equals(-1, httpParser.contentLength); | 217 Expect.equals(-1, incoming.transferLength); |
204 } | 218 } |
205 if (expectedHeaders != null) { | 219 if (expectedHeaders != null) { |
206 expectedHeaders.forEach((String name, String value) { | 220 expectedHeaders.forEach((String name, String value) { |
207 Expect.equals(value, headers[name][0]); | 221 Expect.equals(value, headers[name][0]); |
208 }); | 222 }); |
209 } | 223 } |
210 Expect.equals(upgrade, httpParser.upgrade); | 224 Expect.equals(upgrade, httpParser.upgrade); |
211 headersCompleteCalled = true; | 225 headersCompleteCalled = true; |
212 }; | 226 incoming.listen( |
213 httpParser.dataReceived = (List<int> data) { | 227 (List<int> data) { |
| 228 Expect.isTrue(headersCompleteCalled); |
| 229 bytesReceived += data.length; |
| 230 }, |
| 231 onDone: () { |
| 232 dataEndCalled = true; |
| 233 dataEndClose = close; |
| 234 }); |
| 235 }); |
| 236 |
| 237 subscription.onDone(() { |
| 238 Expect.equals(expectedVersion, headers.protocolVersion); |
| 239 Expect.equals(expectedStatusCode, statusCode); |
| 240 Expect.equals(expectedReasonPhrase, reasonPhrase); |
214 Expect.isTrue(headersCompleteCalled); | 241 Expect.isTrue(headersCompleteCalled); |
215 bytesReceived += data.length; | 242 Expect.equals(expectedBytesReceived, bytesReceived); |
216 }; | 243 if (!upgrade) { |
217 httpParser.dataEnd = (close) { | 244 Expect.isTrue(dataEndCalled); |
218 dataEndCalled = true; | 245 if (close) Expect.isTrue(dataEndClose); |
219 dataEndClose = close; | 246 Expect.equals(dataEndClose, connectionClose); |
220 }; | 247 } |
221 httpParser.closed = () { }; | 248 }); |
222 | 249 |
223 headersCompleteCalled = false; | 250 headersCompleteCalled = false; |
224 dataEndCalled = false; | 251 dataEndCalled = false; |
225 dataEndClose = null; | 252 dataEndClose = null; |
226 statusCode = -1; | 253 statusCode = -1; |
227 reasonPhrase = null; | 254 reasonPhrase = null; |
228 headers = null; | 255 headers = null; |
229 bytesReceived = 0; | 256 bytesReceived = 0; |
230 } | 257 } |
231 | 258 |
232 void testWrite(List<int> requestData, [int chunkSize = -1]) { | 259 void testWrite(List<int> requestData, [int chunkSize = -1]) { |
233 if (chunkSize == -1) chunkSize = requestData.length; | 260 if (chunkSize == -1) chunkSize = requestData.length; |
234 reset(); | 261 reset(); |
235 int written = 0; | |
236 int unparsed; | |
237 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | 262 for (int pos = 0; pos < requestData.length; pos += chunkSize) { |
238 int remaining = requestData.length - pos; | 263 int remaining = requestData.length - pos; |
239 int writeLength = min(chunkSize, remaining); | 264 int writeLength = min(chunkSize, remaining); |
240 written += writeLength; | 265 controller.add(requestData.getRange(pos, writeLength)); |
241 httpParser.streamData(requestData.getRange(pos, writeLength)); | 266 |
242 unparsed = httpParser.readUnparsedData().length; | |
243 if (httpParser.upgrade) { | |
244 unparsed += requestData.length - written; | |
245 break; | |
246 } else { | |
247 Expect.equals(0, unparsed); | |
248 } | |
249 } | 267 } |
250 if (close) httpParser.streamDone(); | 268 if (close) controller.close(); |
251 Expect.equals(expectedVersion, version); | |
252 Expect.equals(expectedStatusCode, statusCode); | |
253 Expect.equals(expectedReasonPhrase, reasonPhrase); | |
254 Expect.isTrue(headersCompleteCalled); | |
255 Expect.equals(expectedBytesReceived, bytesReceived); | |
256 if (!upgrade) { | |
257 Expect.isTrue(dataEndCalled); | |
258 if (close) Expect.isTrue(dataEndClose); | |
259 Expect.equals(dataEndClose, connectionClose); | |
260 } | |
261 if (unparsedLength == 0) { | |
262 Expect.equals(0, unparsed); | |
263 } else { | |
264 Expect.equals(unparsedLength, unparsed); | |
265 } | |
266 } | 269 } |
267 | 270 |
268 // Test parsing the request three times delivering the data in | 271 // Test parsing the request three times delivering the data in |
269 // different chunks. | 272 // different chunks. |
270 List<int> responseData = response.charCodes; | 273 List<int> responseData = response.charCodes; |
271 testWrite(responseData); | 274 testWrite(responseData); |
272 testWrite(responseData, 10); | 275 testWrite(responseData, 10); |
273 testWrite(responseData, 1); | 276 testWrite(responseData, 1); |
274 } | 277 } |
275 | 278 |
276 static void _testParseInvalidResponse(String response, [bool close = false]) { | 279 static void _testParseInvalidResponse(String response, [bool close = false]) { |
277 _HttpParser httpParser; | 280 _HttpParser httpParser; |
278 bool errorCalled; | 281 bool errorCalled; |
| 282 StreamController controller; |
279 | 283 |
280 void reset() { | 284 void reset() { |
281 httpParser = new _HttpParser.responseParser(); | 285 httpParser = new _HttpParser.responseParser(); |
282 httpParser.requestStart = (m, u, v, h, b) { | 286 controller = new StreamController(); |
283 Expect.fail("Expected response"); | 287 var port = new ReceivePort(); |
284 }; | 288 controller.stream.pipe(httpParser); |
285 httpParser.error = (e) => errorCalled = true; | 289 var subscription = httpParser.listen((incoming) { |
286 httpParser.closed = () { }; | 290 incoming.listen( |
287 | 291 (data) {}, |
| 292 onError: (e) { |
| 293 Expect.isFalse(errorCalled); |
| 294 errorCalled = true; |
| 295 }); |
| 296 }); |
| 297 subscription.onError((e) { |
| 298 Expect.isFalse(errorCalled); |
| 299 errorCalled = true; |
| 300 }); |
| 301 subscription.onDone(() { |
| 302 port.close(); |
| 303 Expect.isTrue(errorCalled); |
| 304 }); |
288 errorCalled = false; | 305 errorCalled = false; |
289 } | 306 } |
290 | 307 |
291 void testWrite(List<int> requestData, [int chunkSize = -1]) { | 308 void testWrite(List<int> requestData, [int chunkSize = -1]) { |
292 if (chunkSize == -1) chunkSize = requestData.length; | 309 if (chunkSize == -1) chunkSize = requestData.length; |
293 reset(); | 310 reset(); |
294 for (int pos = 0; | 311 for (int pos = 0; |
295 pos < requestData.length && !errorCalled; | 312 pos < requestData.length && !errorCalled; |
296 pos += chunkSize) { | 313 pos += chunkSize) { |
297 int remaining = requestData.length - pos; | 314 int remaining = requestData.length - pos; |
298 int writeLength = min(chunkSize, remaining); | 315 int writeLength = min(chunkSize, remaining); |
299 httpParser.streamData(requestData.getRange(pos, writeLength)); | 316 controller.add(requestData.getRange(pos, writeLength)); |
300 } | 317 } |
301 if (close) httpParser.streamDone(); | 318 controller.close(); |
302 Expect.isTrue(errorCalled); | |
303 } | 319 } |
304 | 320 |
305 // Test parsing the request three times delivering the data in | 321 // Test parsing the request three times delivering the data in |
306 // different chunks. | 322 // different chunks. |
307 List<int> responseData = response.charCodes; | 323 List<int> responseData = response.charCodes; |
308 testWrite(responseData); | 324 testWrite(responseData); |
309 testWrite(responseData, 10); | 325 testWrite(responseData, 10); |
310 testWrite(responseData, 1); | 326 testWrite(responseData, 1); |
311 } | 327 } |
312 | 328 |
313 static void testParseRequest() { | 329 static void testParseRequest() { |
314 String request; | 330 String request; |
315 Map headers; | 331 Map headers; |
316 var methods = [ | 332 var methods = [ |
317 // RFC 2616 methods. | 333 // RFC 2616 methods. |
318 "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", | 334 "OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT", |
319 // WebDAV methods from RFC 4918. | 335 // WebDAV methods from RFC 4918. |
320 "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", | 336 "PROPFIND", "PROPPATCH", "MKCOL", "COPY", "MOVE", "LOCK", "UNLOCK", |
321 // WebDAV methods from RFC 5323. | 337 // WebDAV methods from RFC 5323. |
322 "SEARCH", | 338 "SEARCH", |
323 // Methods with HTTP prefix. | 339 // Methods with HTTP prefix. |
324 "H", "HT", "HTT", "HTTP", "HX", "HTX", "HTTX", "HTTPX"]; | 340 "H", "HT", "HTT", "HTTP", "HX", "HTX", "HTTX", "HTTPX"]; |
325 methods.forEach((method) { | 341 methods.forEach((method) { |
326 request = "$method / HTTP/1.1\r\n\r\n"; | 342 request = "$method / HTTP/1.1\r\n\r\n"; |
327 _testParseRequest(request, method, "/"); | 343 _testParseRequest(request, method, "/"); |
328 request = "$method /index.html HTTP/1.1\r\n\r\n"; | 344 request = "$method /index.html HTTP/1.1\r\n\r\n"; |
329 _testParseRequest(request, method, "/index.html"); | 345 _testParseRequest(request, method, "/index.html"); |
330 }); | 346 }); |
331 | 347 |
| 348 |
332 request = "GET / HTTP/1.0\r\n\r\n"; | 349 request = "GET / HTTP/1.0\r\n\r\n"; |
333 _testParseRequest(request, "GET", "/", | 350 _testParseRequest(request, "GET", "/", |
334 expectedVersion: "1.0", | 351 expectedVersion: "1.0", |
335 connectionClose: true); | 352 connectionClose: true); |
336 | 353 |
337 request = "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"; | 354 request = "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"; |
338 _testParseRequest(request, "GET", "/", expectedVersion: "1.0"); | 355 _testParseRequest(request, "GET", "/", expectedVersion: "1.0"); |
339 | 356 |
340 request = """ | 357 request = """ |
341 POST /test HTTP/1.1\r | 358 POST /test HTTP/1.1\r |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
399 _testParseRequest(request, "POST", "/test", expectedHeaders: headers); | 416 _testParseRequest(request, "POST", "/test", expectedHeaders: headers); |
400 | 417 |
401 request = """ | 418 request = """ |
402 POST /test HTTP/1.1\r | 419 POST /test HTTP/1.1\r |
403 Content-Length: 10\r | 420 Content-Length: 10\r |
404 \r | 421 \r |
405 0123456789"""; | 422 0123456789"""; |
406 _testParseRequest(request, | 423 _testParseRequest(request, |
407 "POST", | 424 "POST", |
408 "/test", | 425 "/test", |
409 expectedContentLength: 10, | 426 expectedTransferLength: 10, |
410 expectedBytesReceived: 10); | 427 expectedBytesReceived: 10); |
411 | 428 |
412 // Test connection close header. | 429 // Test connection close header. |
413 request = "GET /test HTTP/1.1\r\nConnection: close\r\n\r\n"; | 430 request = "GET /test HTTP/1.1\r\nConnection: close\r\n\r\n"; |
414 _testParseRequest(request, "GET", "/test", connectionClose: true); | 431 _testParseRequest(request, "GET", "/test", connectionClose: true); |
415 | 432 |
416 // Test chunked encoding. | 433 // Test chunked encoding. |
417 request = """ | 434 request = """ |
418 POST /test HTTP/1.1\r | 435 POST /test HTTP/1.1\r |
419 Transfer-Encoding: chunked\r | 436 Transfer-Encoding: chunked\r |
420 \r | 437 \r |
421 5\r | 438 5\r |
422 01234\r | 439 01234\r |
423 5\r | 440 5\r |
424 56789\r | 441 56789\r |
425 0\r\n\r\n"""; | 442 0\r\n\r\n"""; |
426 _testParseRequest(request, | 443 _testParseRequest(request, |
427 "POST", | 444 "POST", |
428 "/test", | 445 "/test", |
429 expectedContentLength: -1, | 446 expectedTransferLength: -1, |
430 expectedBytesReceived: 10, | 447 expectedBytesReceived: 10, |
431 chunked: true); | 448 chunked: true); |
432 | 449 |
433 // Test mixing chunked encoding and content length (content length | 450 // Test mixing chunked encoding and content length (content length |
434 // is ignored). | 451 // is ignored). |
435 request = """ | 452 request = """ |
436 POST /test HTTP/1.1\r | 453 POST /test HTTP/1.1\r |
437 Content-Length: 7\r | 454 Content-Length: 7\r |
438 Transfer-Encoding: chunked\r | 455 Transfer-Encoding: chunked\r |
439 \r | 456 \r |
440 5\r | 457 5\r |
441 01234\r | 458 01234\r |
442 5\r | 459 5\r |
443 56789\r | 460 56789\r |
444 0\r\n\r\n"""; | 461 0\r\n\r\n"""; |
445 _testParseRequest(request, | 462 _testParseRequest(request, |
446 "POST", | 463 "POST", |
447 "/test", | 464 "/test", |
448 expectedContentLength: -1, | 465 expectedTransferLength: -1, |
449 expectedBytesReceived: 10, | 466 expectedBytesReceived: 10, |
450 chunked: true); | 467 chunked: true); |
451 | 468 |
452 // Test mixing chunked encoding and content length (content length | 469 // Test mixing chunked encoding and content length (content length |
453 // is ignored). | 470 // is ignored). |
454 request = """ | 471 request = """ |
455 POST /test HTTP/1.1\r | 472 POST /test HTTP/1.1\r |
456 Transfer-Encoding: chunked\r | 473 Transfer-Encoding: chunked\r |
457 Content-Length: 3\r | 474 Content-Length: 3\r |
458 \r | 475 \r |
459 5\r | 476 5\r |
460 01234\r | 477 01234\r |
461 5\r | 478 5\r |
462 56789\r | 479 56789\r |
463 0\r\n\r\n"""; | 480 0\r\n\r\n"""; |
464 _testParseRequest(request, | 481 _testParseRequest(request, |
465 "POST", | 482 "POST", |
466 "/test", | 483 "/test", |
467 expectedContentLength: -1, | 484 expectedTransferLength: -1, |
468 expectedBytesReceived: 10, | 485 expectedBytesReceived: 10, |
469 chunked: true); | 486 chunked: true); |
470 | 487 |
471 // Test upper and lower case hex digits in chunked encoding. | 488 // Test upper and lower case hex digits in chunked encoding. |
472 request = """ | 489 request = """ |
473 POST /test HTTP/1.1\r | 490 POST /test HTTP/1.1\r |
474 Transfer-Encoding: chunked\r | 491 Transfer-Encoding: chunked\r |
475 \r | 492 \r |
476 1E\r | 493 1E\r |
477 012345678901234567890123456789\r | 494 012345678901234567890123456789\r |
478 1e\r | 495 1e\r |
479 012345678901234567890123456789\r | 496 012345678901234567890123456789\r |
480 0\r\n\r\n"""; | 497 0\r\n\r\n"""; |
481 _testParseRequest(request, | 498 _testParseRequest(request, |
482 "POST", | 499 "POST", |
483 "/test", | 500 "/test", |
484 expectedContentLength: -1, | 501 expectedTransferLength: -1, |
485 expectedBytesReceived: 60, | 502 expectedBytesReceived: 60, |
486 chunked: true); | 503 chunked: true); |
487 | 504 |
488 // Test chunk extensions in chunked encoding. | 505 // Test chunk extensions in chunked encoding. |
489 request = """ | 506 request = """ |
490 POST /test HTTP/1.1\r | 507 POST /test HTTP/1.1\r |
491 Transfer-Encoding: chunked\r | 508 Transfer-Encoding: chunked\r |
492 \r | 509 \r |
493 1E;xxx\r | 510 1E;xxx\r |
494 012345678901234567890123456789\r | 511 012345678901234567890123456789\r |
495 1E;yyy=zzz\r | 512 1E;yyy=zzz\r |
496 012345678901234567890123456789\r | 513 012345678901234567890123456789\r |
497 0\r\n\r\n"""; | 514 0\r\n\r\n"""; |
498 _testParseRequest(request, | 515 _testParseRequest(request, |
499 "POST", | 516 "POST", |
500 "/test", | 517 "/test", |
501 expectedContentLength: -1, | 518 expectedTransferLength: -1, |
502 expectedBytesReceived: 60, | 519 expectedBytesReceived: 60, |
503 chunked: true); | 520 chunked: true); |
504 | 521 |
505 // Test HTTP upgrade. | 522 // Test HTTP upgrade. |
506 request = """ | 523 request = """ |
507 GET /irc HTTP/1.1\r | 524 GET /irc HTTP/1.1\r |
508 Upgrade: irc/1.2\r | 525 Upgrade: irc/1.2\r |
509 Connection: Upgrade\r | 526 Connection: Upgrade\r |
510 \r\n\x01\x01\x01\x01\x01\x02\x02\x02\x02\xFF"""; | 527 \r\n\x01\x01\x01\x01\x01\x02\x02\x02\x02\xFF"""; |
511 headers = new Map(); | 528 headers = new Map(); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
579 "/chat", | 596 "/chat", |
580 expectedHeaders: headers, | 597 expectedHeaders: headers, |
581 upgrade: true, | 598 upgrade: true, |
582 unparsedLength: 7); | 599 unparsedLength: 7); |
583 } | 600 } |
584 | 601 |
585 static void testParseResponse() { | 602 static void testParseResponse() { |
586 String response; | 603 String response; |
587 Map headers; | 604 Map headers; |
588 response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n"; | 605 response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n"; |
589 _testParseResponse(response, 100, "Continue", expectedContentLength: 0); | 606 _testParseResponse(response, 100, "Continue"); |
| 607 |
| 608 response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n"; |
| 609 _testParseResponse(response, 100, "Continue"); |
590 | 610 |
591 response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n"; | 611 response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n"; |
592 _testParseResponse(response, | 612 _testParseResponse(response, |
593 100, | 613 100, |
594 "Continue", | 614 "Continue", |
595 expectedContentLength: 10, | 615 expectedTransferLength: 10, |
596 expectedBytesReceived: 0); | 616 expectedBytesReceived: 0); |
597 | 617 |
598 response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n" | 618 response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n" |
599 "Connection: Close\r\n\r\n"; | 619 "Connection: Close\r\n\r\n"; |
600 _testParseResponse(response, | 620 _testParseResponse(response, |
601 200, | 621 200, |
602 "OK", | 622 "OK", |
603 expectedContentLength: 0, | |
604 connectionClose: true); | 623 connectionClose: true); |
605 | 624 |
606 response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n"; | 625 response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n"; |
607 _testParseResponse(response, | 626 _testParseResponse(response, |
608 200, | 627 200, |
609 "OK", | 628 "OK", |
610 expectedContentLength: 0, | |
611 expectedVersion: "1.0", | 629 expectedVersion: "1.0", |
612 connectionClose: true); | 630 connectionClose: true); |
613 | 631 |
614 response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n" | 632 response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n" |
615 "Connection: Keep-Alive\r\n\r\n"; | 633 "Connection: Keep-Alive\r\n\r\n"; |
616 _testParseResponse(response, | 634 _testParseResponse(response, |
617 200, | 635 200, |
618 "OK", | 636 "OK", |
619 expectedContentLength: 0, | |
620 expectedVersion: "1.0"); | 637 expectedVersion: "1.0"); |
621 | 638 |
622 response = "HTTP/1.1 204 No Content\r\nContent-Length: 11\r\n\r\n"; | 639 response = "HTTP/1.1 204 No Content\r\nContent-Length: 11\r\n\r\n"; |
623 _testParseResponse(response, | 640 _testParseResponse(response, |
624 204, | 641 204, |
625 "No Content", | 642 "No Content", |
626 expectedContentLength: 11, | 643 expectedTransferLength: 11, |
627 expectedBytesReceived: 0); | 644 expectedBytesReceived: 0); |
628 | 645 |
629 response = "HTTP/1.1 304 Not Modified\r\nContent-Length: 12\r\n\r\n"; | 646 response = "HTTP/1.1 304 Not Modified\r\nContent-Length: 12\r\n\r\n"; |
630 _testParseResponse(response, | 647 _testParseResponse(response, |
631 304, | 648 304, |
632 "Not Modified", | 649 "Not Modified", |
633 expectedContentLength: 12, | 650 expectedTransferLength: 12, |
634 expectedBytesReceived: 0); | 651 expectedBytesReceived: 0); |
635 | 652 |
636 response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"; | 653 response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"; |
637 _testParseResponse(response, 200, "OK", expectedContentLength: 0); | 654 _testParseResponse(response, 200, "OK"); |
638 | 655 |
639 response = "HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n"; | 656 response = "HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n"; |
640 _testParseResponse(response, 404, "Not found", expectedContentLength: 0); | 657 _testParseResponse(response, 404, "Not found"); |
641 | 658 |
642 response = "HTTP/1.1 500 Server error\r\nContent-Length: 0\r\n\r\n"; | 659 response = "HTTP/1.1 500 Server error\r\nContent-Length: 0\r\n\r\n"; |
643 _testParseResponse(response, 500, "Server error", expectedContentLength: 0); | 660 _testParseResponse(response, 500, "Server error"); |
644 | 661 |
645 // Test response to HEAD request. | 662 // Test response to HEAD request. |
646 response = """ | 663 response = """ |
647 HTTP/1.1 200 OK\r | 664 HTTP/1.1 200 OK\r |
648 Content-Length: 20\r | 665 Content-Length: 20\r |
649 Content-Type: text/html\r | 666 Content-Type: text/html\r |
650 \r\n"""; | 667 \r\n"""; |
651 headers = new Map(); | 668 headers = new Map(); |
652 headers["content-length"] = "20"; | 669 headers["content-length"] = "20"; |
653 headers["content-type"] = "text/html"; | 670 headers["content-type"] = "text/html"; |
654 _testParseResponse(response, | 671 _testParseResponse(response, |
655 200, | 672 200, |
656 "OK", | 673 "OK", |
657 responseToMethod: "HEAD", | 674 responseToMethod: "HEAD", |
658 expectedContentLength: 20, | 675 expectedTransferLength: 20, |
659 expectedBytesReceived: 0, | 676 expectedBytesReceived: 0, |
660 expectedHeaders: headers); | 677 expectedHeaders: headers); |
661 | 678 |
662 // Test content. | 679 // Test content. |
663 response = """ | 680 response = """ |
664 HTTP/1.1 200 OK\r | 681 HTTP/1.1 200 OK\r |
665 Content-Length: 20\r | 682 Content-Length: 20\r |
666 \r | 683 \r |
667 01234567890123456789"""; | 684 01234567890123456789"""; |
668 _testParseResponse(response, | 685 _testParseResponse(response, |
669 200, | 686 200, |
670 "OK", | 687 "OK", |
671 expectedContentLength: 20, | 688 expectedTransferLength: 20, |
672 expectedBytesReceived: 20); | 689 expectedBytesReceived: 20); |
673 | 690 |
674 // Test upper and lower case hex digits in chunked encoding. | 691 // Test upper and lower case hex digits in chunked encoding. |
675 response = """ | 692 response = """ |
676 HTTP/1.1 200 OK\r | 693 HTTP/1.1 200 OK\r |
677 Transfer-Encoding: chunked\r | 694 Transfer-Encoding: chunked\r |
678 \r | 695 \r |
679 1A\r | 696 1A\r |
680 01234567890123456789012345\r | 697 01234567890123456789012345\r |
681 1f\r | 698 1f\r |
682 0123456789012345678901234567890\r | 699 0123456789012345678901234567890\r |
683 0\r\n\r\n"""; | 700 0\r\n\r\n"""; |
684 _testParseResponse(response, | 701 _testParseResponse(response, |
685 200, | 702 200, |
686 "OK", | 703 "OK", |
687 expectedContentLength: -1, | 704 expectedTransferLength: -1, |
688 expectedBytesReceived: 57, | 705 expectedBytesReceived: 57, |
689 chunked: true); | 706 chunked: true); |
690 | 707 |
691 // Test connection close header. | 708 // Test connection close header. |
692 response = """ | 709 response = """ |
693 HTTP/1.1 200 OK\r | 710 HTTP/1.1 200 OK\r |
694 Content-Length: 0\r | 711 Content-Length: 0\r |
695 Connection: close\r | 712 Connection: close\r |
696 \r\n"""; | 713 \r\n"""; |
697 _testParseResponse(response, | 714 _testParseResponse(response, |
698 200, | 715 200, |
699 "OK", | 716 "OK", |
700 expectedContentLength: 0, | |
701 connectionClose: true); | 717 connectionClose: true); |
702 | 718 |
703 // Test HTTP response without any transfer length indications | 719 // Test HTTP response without any transfer length indications |
704 // where closing the connections indicates end of body. | 720 // where closing the connections indicates end of body. |
705 response = """ | 721 response = """ |
706 HTTP/1.1 200 OK\r | 722 HTTP/1.1 200 OK\r |
707 \r | 723 \r |
708 01234567890123456789012345 | 724 01234567890123456789012345 |
709 0123456789012345678901234567890 | 725 0123456789012345678901234567890 |
710 """; | 726 """; |
711 _testParseResponse(response, | 727 _testParseResponse(response, |
712 200, | 728 200, |
713 "OK", | 729 "OK", |
714 expectedContentLength: -1, | 730 expectedTransferLength: -1, |
715 expectedBytesReceived: 59, | 731 expectedBytesReceived: 59, |
716 close: true, | 732 close: true, |
717 connectionClose: true); | 733 connectionClose: true); |
718 | 734 |
719 // Test HTTP upgrade. | 735 // Test HTTP upgrade. |
720 response = """ | 736 response = """ |
721 HTTP/1.1 101 Switching Protocols\r | 737 HTTP/1.1 101 Switching Protocols\r |
722 Upgrade: irc/1.2\r | 738 Upgrade: irc/1.2\r |
723 Connection: Upgrade\r | 739 Connection: Upgrade\r |
724 \r\n"""; | 740 \r\n"""; |
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
858 0123456789012345678901234567890\r | 874 0123456789012345678901234567890\r |
859 0\r\n\r\n"""; | 875 0\r\n\r\n"""; |
860 _testParseInvalidResponse(response); | 876 _testParseInvalidResponse(response); |
861 } | 877 } |
862 } | 878 } |
863 | 879 |
864 | 880 |
865 void main() { | 881 void main() { |
866 HttpParserTest.runAllTests(); | 882 HttpParserTest.runAllTests(); |
867 } | 883 } |
OLD | NEW |