| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 #source("../../../../runtime/bin/http_parser.dart"); | |
| 6 | |
| 7 class HttpParserTest { | |
| 8 static void runAllTests() { | |
| 9 testParseRequest(); | |
| 10 testParseResponse(); | |
| 11 testParseInvalidRequest(); | |
| 12 testParseInvalidResponse(); | |
| 13 } | |
| 14 | |
| 15 static void _testParseRequest(String request, | |
| 16 String expectedMethod, | |
| 17 String expectedUri, | |
| 18 [int expectedContentLength = -1, | |
| 19 int expectedBytesReceived = 0, | |
| 20 Map expectedHeaders = null, | |
| 21 bool chunked = false, | |
| 22 bool upgrade = false, | |
| 23 int unparsedLength = 0, | |
| 24 bool connectionClose = false, | |
| 25 String expectedVersion = "1.1"]) { | |
| 26 _HttpParser httpParser; | |
| 27 bool headersCompleteCalled; | |
| 28 bool dataEndCalled; | |
| 29 String method; | |
| 30 String uri; | |
| 31 String version; | |
| 32 Map headers; | |
| 33 int contentLength; | |
| 34 int bytesReceived; | |
| 35 | |
| 36 void reset() { | |
| 37 httpParser = new _HttpParser(); | |
| 38 httpParser.requestStart = (m, u, v) { method = m; uri = u; version = v; }; | |
| 39 httpParser.responseStart = (s, r, v) { Expect.fail("Expected request"); }; | |
| 40 httpParser.headerReceived = (f, v) { | |
| 41 Expect.isFalse(headersCompleteCalled); | |
| 42 headers[f] = v; | |
| 43 }; | |
| 44 httpParser.headersComplete = () { | |
| 45 Expect.isFalse(headersCompleteCalled); | |
| 46 if (!chunked) { | |
| 47 Expect.equals(expectedContentLength, httpParser.contentLength); | |
| 48 } else { | |
| 49 Expect.equals(-1, httpParser.contentLength); | |
| 50 } | |
| 51 if (expectedHeaders != null) { | |
| 52 expectedHeaders.forEach( | |
| 53 (String name, String value) => | |
| 54 Expect.equals(value, headers[name])); | |
| 55 } | |
| 56 Expect.equals(upgrade, httpParser.upgrade); | |
| 57 Expect.equals(connectionClose, !httpParser.persistentConnection); | |
| 58 headersCompleteCalled = true; | |
| 59 }; | |
| 60 httpParser.dataReceived = (List<int> data) { | |
| 61 Expect.isTrue(headersCompleteCalled); | |
| 62 bytesReceived += data.length; | |
| 63 }; | |
| 64 httpParser.dataEnd = (close) { | |
| 65 Expect.isFalse(close); | |
| 66 dataEndCalled = true; | |
| 67 }; | |
| 68 | |
| 69 headersCompleteCalled = false; | |
| 70 dataEndCalled = false; | |
| 71 method = null; | |
| 72 uri = null; | |
| 73 headers = new Map(); | |
| 74 bytesReceived = 0; | |
| 75 } | |
| 76 | |
| 77 void testWrite(List<int> requestData, [int chunkSize = -1]) { | |
| 78 if (chunkSize == -1) chunkSize = requestData.length; | |
| 79 reset(); | |
| 80 int written = 0; | |
| 81 int unparsed; | |
| 82 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | |
| 83 int remaining = requestData.length - pos; | |
| 84 int writeLength = Math.min(chunkSize, remaining); | |
| 85 written += writeLength; | |
| 86 int parsed = httpParser.writeList(requestData, pos, writeLength); | |
| 87 unparsed = writeLength - parsed; | |
| 88 if (httpParser.upgrade) { | |
| 89 unparsed += requestData.length - written; | |
| 90 break; | |
| 91 } else { | |
| 92 Expect.equals(0, unparsed); | |
| 93 } | |
| 94 } | |
| 95 Expect.equals(expectedMethod, method); | |
| 96 Expect.equals(expectedUri, uri); | |
| 97 Expect.equals(expectedVersion, version); | |
| 98 Expect.isTrue(headersCompleteCalled); | |
| 99 Expect.equals(expectedBytesReceived, bytesReceived); | |
| 100 if (!upgrade) Expect.isTrue(dataEndCalled); | |
| 101 if (unparsedLength == 0) { | |
| 102 Expect.equals(0, unparsed); | |
| 103 } else { | |
| 104 Expect.equals(unparsedLength, unparsed); | |
| 105 } | |
| 106 } | |
| 107 | |
| 108 // Test parsing the request three times delivering the data in | |
| 109 // different chunks. | |
| 110 List<int> requestData = request.charCodes(); | |
| 111 testWrite(requestData); | |
| 112 testWrite(requestData, 10); | |
| 113 testWrite(requestData, 1); | |
| 114 } | |
| 115 | |
| 116 static void _testParseInvalidRequest(String request) { | |
| 117 _HttpParser httpParser; | |
| 118 bool errorCalled; | |
| 119 | |
| 120 void reset() { | |
| 121 httpParser = new _HttpParser(); | |
| 122 httpParser.responseStart = (s, r) { Expect.fail("Expected request"); }; | |
| 123 httpParser.error = (e) { | |
| 124 errorCalled = true; | |
| 125 }; | |
| 126 | |
| 127 errorCalled = false; | |
| 128 } | |
| 129 | |
| 130 void testWrite(List<int> requestData, [int chunkSize = -1]) { | |
| 131 if (chunkSize == -1) chunkSize = requestData.length; | |
| 132 reset(); | |
| 133 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | |
| 134 int remaining = requestData.length - pos; | |
| 135 int writeLength = Math.min(chunkSize, remaining); | |
| 136 httpParser.writeList(requestData, pos, writeLength); | |
| 137 } | |
| 138 Expect.isTrue(errorCalled); | |
| 139 } | |
| 140 | |
| 141 // Test parsing the request three times delivering the data in | |
| 142 // different chunks. | |
| 143 List<int> requestData = request.charCodes(); | |
| 144 testWrite(requestData); | |
| 145 testWrite(requestData, 10); | |
| 146 testWrite(requestData, 1); | |
| 147 } | |
| 148 | |
| 149 static void _testParseResponse(String response, | |
| 150 int expectedStatusCode, | |
| 151 String expectedReasonPhrase, | |
| 152 [int expectedContentLength = -1, | |
| 153 int expectedBytesReceived = 0, | |
| 154 Map expectedHeaders = null, | |
| 155 bool chunked = false, | |
| 156 bool close = false, | |
| 157 String responseToMethod = null, | |
| 158 bool connectionClose = false, | |
| 159 bool upgrade = false, | |
| 160 int unparsedLength = 0, | |
| 161 String expectedVersion = "1.1"]) { | |
| 162 _HttpParser httpParser; | |
| 163 bool headersCompleteCalled; | |
| 164 bool dataEndCalled; | |
| 165 bool dataEndClose; | |
| 166 int statusCode; | |
| 167 String reasonPhrase; | |
| 168 String version; | |
| 169 Map headers; | |
| 170 int contentLength; | |
| 171 int bytesReceived; | |
| 172 | |
| 173 void reset() { | |
| 174 httpParser = new _HttpParser(); | |
| 175 if (responseToMethod != null) { | |
| 176 httpParser.responseToMethod = responseToMethod; | |
| 177 } | |
| 178 httpParser.requestStart = (m, u, v) => Expect.fail("Expected response"); | |
| 179 httpParser.responseStart = (s, r, v) { | |
| 180 statusCode = s; | |
| 181 reasonPhrase = r; | |
| 182 version = v; | |
| 183 }; | |
| 184 httpParser.headerReceived = (f, v) { | |
| 185 Expect.isFalse(headersCompleteCalled); | |
| 186 headers[f] = v; | |
| 187 }; | |
| 188 httpParser.headersComplete = () { | |
| 189 Expect.isFalse(headersCompleteCalled); | |
| 190 if (!chunked && !close) { | |
| 191 Expect.equals(expectedContentLength, httpParser.contentLength); | |
| 192 } else { | |
| 193 Expect.equals(-1, httpParser.contentLength); | |
| 194 } | |
| 195 if (expectedHeaders != null) { | |
| 196 expectedHeaders.forEach((String name, String value) { | |
| 197 Expect.equals(value, headers[name]); | |
| 198 }); | |
| 199 } | |
| 200 Expect.equals(upgrade, httpParser.upgrade); | |
| 201 headersCompleteCalled = true; | |
| 202 }; | |
| 203 httpParser.dataReceived = (List<int> data) { | |
| 204 Expect.isTrue(headersCompleteCalled); | |
| 205 bytesReceived += data.length; | |
| 206 }; | |
| 207 httpParser.dataEnd = (close) { | |
| 208 dataEndCalled = true; | |
| 209 dataEndClose = close; | |
| 210 }; | |
| 211 | |
| 212 headersCompleteCalled = false; | |
| 213 dataEndCalled = false; | |
| 214 dataEndClose = null; | |
| 215 statusCode = -1; | |
| 216 reasonPhrase = null; | |
| 217 headers = new Map(); | |
| 218 bytesReceived = 0; | |
| 219 } | |
| 220 | |
| 221 void testWrite(List<int> requestData, [int chunkSize = -1]) { | |
| 222 if (chunkSize == -1) chunkSize = requestData.length; | |
| 223 reset(); | |
| 224 int written = 0; | |
| 225 int unparsed; | |
| 226 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | |
| 227 int remaining = requestData.length - pos; | |
| 228 int writeLength = Math.min(chunkSize, remaining); | |
| 229 written += writeLength; | |
| 230 int parsed = httpParser.writeList(requestData, pos, writeLength); | |
| 231 unparsed = writeLength - parsed; | |
| 232 if (httpParser.upgrade) { | |
| 233 unparsed += requestData.length - written; | |
| 234 break; | |
| 235 } else { | |
| 236 Expect.equals(0, unparsed); | |
| 237 } | |
| 238 } | |
| 239 if (close) httpParser.connectionClosed(); | |
| 240 Expect.equals(expectedVersion, version); | |
| 241 Expect.equals(expectedStatusCode, statusCode); | |
| 242 Expect.equals(expectedReasonPhrase, reasonPhrase); | |
| 243 Expect.isTrue(headersCompleteCalled); | |
| 244 Expect.equals(expectedBytesReceived, bytesReceived); | |
| 245 if (!upgrade) { | |
| 246 Expect.isTrue(dataEndCalled); | |
| 247 if (close) Expect.isTrue(dataEndClose); | |
| 248 Expect.equals(dataEndClose, connectionClose); | |
| 249 } | |
| 250 if (unparsedLength == 0) { | |
| 251 Expect.equals(0, unparsed); | |
| 252 } else { | |
| 253 Expect.equals(unparsedLength, unparsed); | |
| 254 } | |
| 255 } | |
| 256 | |
| 257 // Test parsing the request three times delivering the data in | |
| 258 // different chunks. | |
| 259 List<int> responseData = response.charCodes(); | |
| 260 testWrite(responseData); | |
| 261 testWrite(responseData, 10); | |
| 262 testWrite(responseData, 1); | |
| 263 } | |
| 264 | |
| 265 static void _testParseInvalidResponse(String response, [bool close = false]) { | |
| 266 _HttpParser httpParser; | |
| 267 bool errorCalled; | |
| 268 | |
| 269 void reset() { | |
| 270 httpParser = new _HttpParser(); | |
| 271 httpParser.requestStart = (m, u) => Expect.fail("Expected response"); | |
| 272 httpParser.error = (e) => errorCalled = true; | |
| 273 | |
| 274 errorCalled = false; | |
| 275 } | |
| 276 | |
| 277 void testWrite(List<int> requestData, [int chunkSize = -1]) { | |
| 278 if (chunkSize == -1) chunkSize = requestData.length; | |
| 279 reset(); | |
| 280 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | |
| 281 int remaining = requestData.length - pos; | |
| 282 int writeLength = Math.min(chunkSize, remaining); | |
| 283 httpParser.writeList(requestData, pos, writeLength); | |
| 284 } | |
| 285 if (close) httpParser.connectionClosed(); | |
| 286 Expect.isTrue(errorCalled); | |
| 287 } | |
| 288 | |
| 289 // Test parsing the request three times delivering the data in | |
| 290 // different chunks. | |
| 291 List<int> responseData = response.charCodes(); | |
| 292 testWrite(responseData); | |
| 293 testWrite(responseData, 10); | |
| 294 testWrite(responseData, 1); | |
| 295 } | |
| 296 | |
| 297 static void testParseRequest() { | |
| 298 String request; | |
| 299 Map headers; | |
| 300 request = "GET / HTTP/1.1\r\n\r\n"; | |
| 301 _testParseRequest(request, "GET", "/"); | |
| 302 | |
| 303 request = "POST / HTTP/1.1\r\n\r\n"; | |
| 304 _testParseRequest(request, "POST", "/"); | |
| 305 | |
| 306 request = "GET /index.html HTTP/1.1\r\n\r\n"; | |
| 307 _testParseRequest(request, "GET", "/index.html"); | |
| 308 | |
| 309 request = "POST /index.html HTTP/1.1\r\n\r\n"; | |
| 310 _testParseRequest(request, "POST", "/index.html"); | |
| 311 | |
| 312 request = "H /index.html HTTP/1.1\r\n\r\n"; | |
| 313 _testParseRequest(request, "H", "/index.html"); | |
| 314 | |
| 315 request = "HT /index.html HTTP/1.1\r\n\r\n"; | |
| 316 _testParseRequest(request, "HT", "/index.html"); | |
| 317 | |
| 318 request = "HTT /index.html HTTP/1.1\r\n\r\n"; | |
| 319 _testParseRequest(request, "HTT", "/index.html"); | |
| 320 | |
| 321 request = "HTTP /index.html HTTP/1.1\r\n\r\n"; | |
| 322 _testParseRequest(request, "HTTP", "/index.html"); | |
| 323 | |
| 324 request = "GET / HTTP/1.0\r\n\r\n"; | |
| 325 _testParseRequest(request, "GET", "/", expectedVersion: "1.0", connectionClo
se: true); | |
| 326 | |
| 327 request = "GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n"; | |
| 328 _testParseRequest(request, "GET", "/", expectedVersion: "1.0"); | |
| 329 | |
| 330 request = """ | |
| 331 POST /test HTTP/1.1\r | |
| 332 AAA: AAA\r | |
| 333 \r | |
| 334 """; | |
| 335 _testParseRequest(request, "POST", "/test"); | |
| 336 | |
| 337 request = """ | |
| 338 POST /test HTTP/1.1\r | |
| 339 \r | |
| 340 """; | |
| 341 _testParseRequest(request, "POST", "/test"); | |
| 342 | |
| 343 request = """ | |
| 344 POST /test HTTP/1.1\r | |
| 345 Header-A: AAA\r | |
| 346 X-Header-B: bbb\r | |
| 347 \r | |
| 348 """; | |
| 349 headers = new Map(); | |
| 350 headers["header-a"] = "AAA"; | |
| 351 headers["x-header-b"] = "bbb"; | |
| 352 _testParseRequest(request, "POST", "/test", expectedHeaders: headers); | |
| 353 | |
| 354 request = """ | |
| 355 POST /test HTTP/1.1\r | |
| 356 Empty-Header-1:\r | |
| 357 Empty-Header-2:\r | |
| 358 \r | |
| 359 \r | |
| 360 """; | |
| 361 headers = new Map(); | |
| 362 headers["empty-header-1"] = ""; | |
| 363 headers["empty-header-2"] = ""; | |
| 364 _testParseRequest(request, "POST", "/test", expectedHeaders: headers); | |
| 365 | |
| 366 request = """ | |
| 367 POST /test HTTP/1.1\r | |
| 368 Header-A: AAA\r | |
| 369 X-Header-B:\t \t bbb\r | |
| 370 \r | |
| 371 """; | |
| 372 headers = new Map(); | |
| 373 headers["header-a"] = "AAA"; | |
| 374 headers["x-header-b"] = "bbb"; | |
| 375 _testParseRequest(request, "POST", "/test", expectedHeaders: headers); | |
| 376 | |
| 377 request = """ | |
| 378 POST /test HTTP/1.1\r | |
| 379 Header-A: AA\r | |
| 380 A\r | |
| 381 X-Header-B: b\r | |
| 382 b\r | |
| 383 \t b\r | |
| 384 \r | |
| 385 """; | |
| 386 headers = new Map(); | |
| 387 headers["header-a"] = "AAA"; | |
| 388 headers["x-header-b"] = "bbb"; | |
| 389 _testParseRequest(request, "POST", "/test", expectedHeaders: headers); | |
| 390 | |
| 391 request = """ | |
| 392 POST /test HTTP/1.1\r | |
| 393 Content-Length: 10\r | |
| 394 \r | |
| 395 0123456789"""; | |
| 396 _testParseRequest(request, | |
| 397 "POST", | |
| 398 "/test", | |
| 399 expectedContentLength: 10, | |
| 400 expectedBytesReceived: 10); | |
| 401 | |
| 402 // Test connection close header. | |
| 403 request = "GET /test HTTP/1.1\r\nConnection: close\r\n\r\n"; | |
| 404 _testParseRequest(request, "GET", "/test", connectionClose: true); | |
| 405 | |
| 406 // Test chunked encoding. | |
| 407 request = """ | |
| 408 POST /test HTTP/1.1\r | |
| 409 Transfer-Encoding: chunked\r | |
| 410 \r | |
| 411 5\r | |
| 412 01234\r | |
| 413 5\r | |
| 414 56789\r | |
| 415 0\r\n\r\n"""; | |
| 416 _testParseRequest(request, | |
| 417 "POST", | |
| 418 "/test", | |
| 419 expectedContentLength: -1, | |
| 420 expectedBytesReceived: 10, | |
| 421 chunked: true); | |
| 422 | |
| 423 // Test mixing chunked encoding and content length (content length | |
| 424 // is ignored). | |
| 425 request = """ | |
| 426 POST /test HTTP/1.1\r | |
| 427 Content-Length: 7\r | |
| 428 Transfer-Encoding: chunked\r | |
| 429 \r | |
| 430 5\r | |
| 431 01234\r | |
| 432 5\r | |
| 433 56789\r | |
| 434 0\r\n\r\n"""; | |
| 435 _testParseRequest(request, | |
| 436 "POST", | |
| 437 "/test", | |
| 438 expectedContentLength: -1, | |
| 439 expectedBytesReceived: 10, | |
| 440 chunked: true); | |
| 441 | |
| 442 // Test mixing chunked encoding and content length (content length | |
| 443 // is ignored). | |
| 444 request = """ | |
| 445 POST /test HTTP/1.1\r | |
| 446 Transfer-Encoding: chunked\r | |
| 447 Content-Length: 3\r | |
| 448 \r | |
| 449 5\r | |
| 450 01234\r | |
| 451 5\r | |
| 452 56789\r | |
| 453 0\r\n\r\n"""; | |
| 454 _testParseRequest(request, | |
| 455 "POST", | |
| 456 "/test", | |
| 457 expectedContentLength: -1, | |
| 458 expectedBytesReceived: 10, | |
| 459 chunked: true); | |
| 460 | |
| 461 // Test upper and lower case hex digits in chunked encoding. | |
| 462 request = """ | |
| 463 POST /test HTTP/1.1\r | |
| 464 Transfer-Encoding: chunked\r | |
| 465 \r | |
| 466 1E\r | |
| 467 012345678901234567890123456789\r | |
| 468 1e\r | |
| 469 012345678901234567890123456789\r | |
| 470 0\r\n\r\n"""; | |
| 471 _testParseRequest(request, | |
| 472 "POST", | |
| 473 "/test", | |
| 474 expectedContentLength: -1, | |
| 475 expectedBytesReceived: 60, | |
| 476 chunked: true); | |
| 477 | |
| 478 // Test chunk extensions in chunked encoding. | |
| 479 request = """ | |
| 480 POST /test HTTP/1.1\r | |
| 481 Transfer-Encoding: chunked\r | |
| 482 \r | |
| 483 1E;xxx\r | |
| 484 012345678901234567890123456789\r | |
| 485 1E;yyy=zzz\r | |
| 486 012345678901234567890123456789\r | |
| 487 0\r\n\r\n"""; | |
| 488 _testParseRequest(request, | |
| 489 "POST", | |
| 490 "/test", | |
| 491 expectedContentLength: -1, | |
| 492 expectedBytesReceived: 60, | |
| 493 chunked: true); | |
| 494 | |
| 495 // Test HTTP upgrade. | |
| 496 request = """ | |
| 497 GET /irc HTTP/1.1\r | |
| 498 Upgrade: irc/1.2\r | |
| 499 Connection: Upgrade\r | |
| 500 \r\n\x01\x01\x01\x01\x01\x02\x02\x02\x02\xFF"""; | |
| 501 headers = new Map(); | |
| 502 headers["upgrade"] = "irc/1.2"; | |
| 503 _testParseRequest(request, | |
| 504 "GET", | |
| 505 "/irc", | |
| 506 expectedHeaders: headers, | |
| 507 upgrade: true, | |
| 508 unparsedLength: 10); | |
| 509 | |
| 510 // Test HTTP upgrade with protocol data. | |
| 511 request = """ | |
| 512 GET /irc HTTP/1.1\r | |
| 513 Upgrade: irc/1.2\r | |
| 514 Connection: Upgrade\r | |
| 515 \r\n"""; | |
| 516 headers = new Map(); | |
| 517 headers["upgrade"] = "irc/1.2"; | |
| 518 _testParseRequest(request, | |
| 519 "GET", | |
| 520 "/irc", | |
| 521 expectedHeaders: headers, | |
| 522 upgrade: true); | |
| 523 | |
| 524 // Test websocket upgrade. | |
| 525 request = """ | |
| 526 GET /chat HTTP/1.1\r | |
| 527 Host: server.example.com\r | |
| 528 Upgrade: websocket\r | |
| 529 Connection: Upgrade\r | |
| 530 Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r | |
| 531 Origin: http://example.com\r | |
| 532 Sec-WebSocket-Version: 13\r | |
| 533 \r\n"""; | |
| 534 headers = new Map(); | |
| 535 headers["host"] = "server.example.com"; | |
| 536 headers["upgrade"] = "websocket"; | |
| 537 headers["sec-websocket-key"] = "dGhlIHNhbXBsZSBub25jZQ=="; | |
| 538 headers["origin"] = "http://example.com"; | |
| 539 headers["sec-websocket-version"] = "13"; | |
| 540 _testParseRequest(request, | |
| 541 "GET", | |
| 542 "/chat", | |
| 543 expectedHeaders: headers, | |
| 544 upgrade: true); | |
| 545 | |
| 546 | |
| 547 // Test websocket upgrade with protocol data. NOTE: When using the | |
| 548 // WebSocket protocol this should never happen as the client | |
| 549 // should not send protocol data before processing the request | |
| 550 // part of the opening handshake. However the HTTP parser should | |
| 551 // still handle this. | |
| 552 request = """ | |
| 553 GET /chat HTTP/1.1\r | |
| 554 Host: server.example.com\r | |
| 555 Upgrade: websocket\r | |
| 556 Connection: Upgrade\r | |
| 557 Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r | |
| 558 Origin: http://example.com\r | |
| 559 Sec-WebSocket-Version: 13\r | |
| 560 \r\n0123456"""; | |
| 561 headers = new Map(); | |
| 562 headers["host"] = "server.example.com"; | |
| 563 headers["upgrade"] = "websocket"; | |
| 564 headers["sec-websocket-key"] = "dGhlIHNhbXBsZSBub25jZQ=="; | |
| 565 headers["origin"] = "http://example.com"; | |
| 566 headers["sec-websocket-version"] = "13"; | |
| 567 _testParseRequest(request, | |
| 568 "GET", | |
| 569 "/chat", | |
| 570 expectedHeaders: headers, | |
| 571 upgrade: true, | |
| 572 unparsedLength: 7); | |
| 573 } | |
| 574 | |
| 575 static void testParseResponse() { | |
| 576 String response; | |
| 577 Map headers; | |
| 578 response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n"; | |
| 579 _testParseResponse(response, 100, "Continue", expectedContentLength: 0); | |
| 580 | |
| 581 response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n"; | |
| 582 _testParseResponse(response, | |
| 583 100, | |
| 584 "Continue", | |
| 585 expectedContentLength: 10, | |
| 586 expectedBytesReceived: 0); | |
| 587 | |
| 588 response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: Close\r\n\r\
n"; | |
| 589 _testParseResponse(response, | |
| 590 200, | |
| 591 "OK", | |
| 592 expectedContentLength: 0, | |
| 593 connectionClose: true); | |
| 594 | |
| 595 response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\n\r\n"; | |
| 596 _testParseResponse(response, | |
| 597 200, | |
| 598 "OK", | |
| 599 expectedContentLength: 0, | |
| 600 expectedVersion: "1.0", | |
| 601 connectionClose: true); | |
| 602 | |
| 603 response = "HTTP/1.0 200 OK\r\nContent-Length: 0\r\nConnection: Keep-Alive\r
\n\r\n"; | |
| 604 _testParseResponse(response, 200, "OK", expectedContentLength: 0, expectedVe
rsion: "1.0"); | |
| 605 | |
| 606 response = "HTTP/1.1 204 No Content\r\nContent-Length: 11\r\n\r\n"; | |
| 607 _testParseResponse(response, | |
| 608 204, | |
| 609 "No Content", | |
| 610 expectedContentLength: 11, | |
| 611 expectedBytesReceived: 0); | |
| 612 | |
| 613 response = "HTTP/1.1 304 Not Modified\r\nContent-Length: 12\r\n\r\n"; | |
| 614 _testParseResponse(response, | |
| 615 304, | |
| 616 "Not Modified", | |
| 617 expectedContentLength: 12, | |
| 618 expectedBytesReceived: 0); | |
| 619 | |
| 620 response = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"; | |
| 621 _testParseResponse(response, 200, "OK", expectedContentLength: 0); | |
| 622 | |
| 623 response = "HTTP/1.1 404 Not found\r\nContent-Length: 0\r\n\r\n"; | |
| 624 _testParseResponse(response, 404, "Not found", expectedContentLength: 0); | |
| 625 | |
| 626 response = "HTTP/1.1 500 Server error\r\nContent-Length: 0\r\n\r\n"; | |
| 627 _testParseResponse(response, 500, "Server error", expectedContentLength: 0); | |
| 628 | |
| 629 // Test response to HEAD request. | |
| 630 response = """ | |
| 631 HTTP/1.1 200 OK\r | |
| 632 Content-Length: 20\r | |
| 633 Content-Type: text/html\r | |
| 634 \r\n"""; | |
| 635 headers = new Map(); | |
| 636 headers["content-length"] = "20"; | |
| 637 headers["content-type"] = "text/html"; | |
| 638 _testParseResponse(response, | |
| 639 200, | |
| 640 "OK", | |
| 641 responseToMethod: "HEAD", | |
| 642 expectedContentLength: 20, | |
| 643 expectedBytesReceived: 0, | |
| 644 expectedHeaders: headers); | |
| 645 | |
| 646 // Test content. | |
| 647 response = """ | |
| 648 HTTP/1.1 200 OK\r | |
| 649 Content-Length: 20\r | |
| 650 \r | |
| 651 01234567890123456789"""; | |
| 652 _testParseResponse(response, | |
| 653 200, | |
| 654 "OK", | |
| 655 expectedContentLength: 20, | |
| 656 expectedBytesReceived: 20); | |
| 657 | |
| 658 // Test upper and lower case hex digits in chunked encoding. | |
| 659 response = """ | |
| 660 HTTP/1.1 200 OK\r | |
| 661 Transfer-Encoding: chunked\r | |
| 662 \r | |
| 663 1A\r | |
| 664 01234567890123456789012345\r | |
| 665 1f\r | |
| 666 0123456789012345678901234567890\r | |
| 667 0\r\n\r\n"""; | |
| 668 _testParseResponse(response, | |
| 669 200, | |
| 670 "OK", | |
| 671 expectedContentLength: -1, | |
| 672 expectedBytesReceived: 57, | |
| 673 chunked: true); | |
| 674 | |
| 675 // Test connection close header. | |
| 676 response = """ | |
| 677 HTTP/1.1 200 OK\r | |
| 678 Content-Length: 0\r | |
| 679 Connection: close\r | |
| 680 \r\n"""; | |
| 681 _testParseResponse(response, | |
| 682 200, | |
| 683 "OK", | |
| 684 expectedContentLength: 0, | |
| 685 connectionClose: true); | |
| 686 | |
| 687 // Test HTTP response without any transfer length indications | |
| 688 // where closing the connections indicates end of body. | |
| 689 response = """ | |
| 690 HTTP/1.1 200 OK\r | |
| 691 \r | |
| 692 01234567890123456789012345 | |
| 693 0123456789012345678901234567890 | |
| 694 """; | |
| 695 _testParseResponse(response, | |
| 696 200, | |
| 697 "OK", | |
| 698 expectedContentLength: -1, | |
| 699 expectedBytesReceived: 59, | |
| 700 close: true, | |
| 701 connectionClose: true); | |
| 702 | |
| 703 // Test HTTP upgrade. | |
| 704 response = """ | |
| 705 HTTP/1.1 101 Switching Protocols\r | |
| 706 Upgrade: irc/1.2\r | |
| 707 Connection: Upgrade\r | |
| 708 \r\n"""; | |
| 709 headers = new Map(); | |
| 710 headers["upgrade"] = "irc/1.2"; | |
| 711 _testParseResponse(response, | |
| 712 101, | |
| 713 "Switching Protocols", | |
| 714 expectedHeaders: headers, | |
| 715 upgrade: true); | |
| 716 | |
| 717 // Test HTTP upgrade with protocol data. | |
| 718 response = """ | |
| 719 HTTP/1.1 101 Switching Protocols\r | |
| 720 Upgrade: irc/1.2\r | |
| 721 Connection: Upgrade\r | |
| 722 \r\n\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xA0\xB0\xC0\xD0\xE0\xF0"""; | |
| 723 headers = new Map(); | |
| 724 headers["upgrade"] = "irc/1.2"; | |
| 725 _testParseResponse(response, | |
| 726 101, | |
| 727 "Switching Protocols", | |
| 728 expectedHeaders: headers, | |
| 729 upgrade: true, | |
| 730 unparsedLength: 16); | |
| 731 | |
| 732 // Test websocket upgrade. | |
| 733 response = """ | |
| 734 HTTP/1.1 101 Switching Protocols\r | |
| 735 Upgrade: websocket\r | |
| 736 Connection: Upgrade\r | |
| 737 Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r | |
| 738 \r\n"""; | |
| 739 headers = new Map(); | |
| 740 headers["upgrade"] = "websocket"; | |
| 741 headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="; | |
| 742 _testParseResponse(response, | |
| 743 101, | |
| 744 "Switching Protocols", | |
| 745 expectedHeaders: headers, | |
| 746 upgrade: true); | |
| 747 | |
| 748 // Test websocket upgrade with protocol data. | |
| 749 response = """ | |
| 750 HTTP/1.1 101 Switching Protocols\r | |
| 751 Upgrade: websocket\r | |
| 752 Connection: Upgrade\r | |
| 753 Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r | |
| 754 \r\nABCD"""; | |
| 755 headers = new Map(); | |
| 756 headers["upgrade"] = "websocket"; | |
| 757 headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="; | |
| 758 _testParseResponse(response, | |
| 759 101, | |
| 760 "Switching Protocols", | |
| 761 expectedHeaders: headers, | |
| 762 upgrade: true, | |
| 763 unparsedLength: 4); | |
| 764 } | |
| 765 | |
| 766 static void testParseInvalidRequest() { | |
| 767 String request; | |
| 768 request = "GET /\r\n\r\n"; | |
| 769 _testParseInvalidRequest(request); | |
| 770 | |
| 771 request = "GET / \r\n\r\n"; | |
| 772 _testParseInvalidRequest(request); | |
| 773 | |
| 774 request = "/ HTTP/1.1\r\n\r\n"; | |
| 775 _testParseInvalidRequest(request); | |
| 776 | |
| 777 request = "GET HTTP/1.1\r\n\r\n"; | |
| 778 _testParseInvalidRequest(request); | |
| 779 | |
| 780 request = " / HTTP/1.1\r\n\r\n"; | |
| 781 _testParseInvalidRequest(request); | |
| 782 | |
| 783 request = "@ / HTTP/1.1\r\n\r\n"; | |
| 784 _testParseInvalidRequest(request); | |
| 785 | |
| 786 request = "GET / TTP/1.1\r\n\r\n"; | |
| 787 _testParseInvalidRequest(request); | |
| 788 | |
| 789 request = "GET / HTTP/1.\r\n\r\n"; | |
| 790 _testParseInvalidRequest(request); | |
| 791 | |
| 792 request = "GET / HTTP/1.1\r\nKeep-Alive: False\r\nbadheader\r\n\r\n"; | |
| 793 _testParseInvalidRequest(request); | |
| 794 } | |
| 795 | |
| 796 static void testParseInvalidResponse() { | |
| 797 String response; | |
| 798 | |
| 799 response = "HTTP/1.1\r\nContent-Length: 0\r\n\r\n"; | |
| 800 _testParseInvalidResponse(response); | |
| 801 | |
| 802 response = "HTTP/1.1 \r\nContent-Length: 0\r\n\r\n"; | |
| 803 _testParseInvalidResponse(response); | |
| 804 | |
| 805 response = "HTTP/1.1 200\r\nContent-Length: 0\r\n\r\n"; | |
| 806 _testParseInvalidResponse(response); | |
| 807 | |
| 808 response = "HTTP/1.1 200 \r\nContent-Length: 0\r\n\r\n"; | |
| 809 _testParseInvalidResponse(response); | |
| 810 | |
| 811 response = "HTTP/1.1 OK\r\nContent-Length: 0\r\n\r\n"; | |
| 812 _testParseInvalidResponse(response); | |
| 813 | |
| 814 response = "200 OK\r\nContent-Length: 0\r\n\r\n"; | |
| 815 _testParseInvalidResponse(response); | |
| 816 | |
| 817 response = "HTTP/1. 200 OK\r\nContent-Length: 0\r\n\r\n"; | |
| 818 _testParseInvalidResponse(response); | |
| 819 | |
| 820 response = "HTTP/1.1 200 O\rK\r\nContent-Length: 0\r\n\r\n"; | |
| 821 _testParseInvalidResponse(response); | |
| 822 | |
| 823 response = "HTTP/1.1 000 OK\r\nContent-Length: 0\r\n\r\n"; | |
| 824 _testParseInvalidResponse(response); | |
| 825 | |
| 826 response = "HTTP/1.1 999 Server Error\r\nContent-Length: 0\r\n\r\n"; | |
| 827 _testParseInvalidResponse(response); | |
| 828 | |
| 829 response = "HTTP/1.1 200 OK\r\nContent-Length: x\r\n\r\n"; | |
| 830 _testParseInvalidResponse(response); | |
| 831 | |
| 832 response = "HTTP/1.1 200 OK\r\nbadheader\r\n\r\n"; | |
| 833 _testParseInvalidResponse(response); | |
| 834 | |
| 835 response = """ | |
| 836 HTTP/1.1 200 OK\r | |
| 837 Transfer-Encoding: chunked\r | |
| 838 \r | |
| 839 1A\r | |
| 840 01234567890123456789012345\r | |
| 841 1g\r | |
| 842 0123456789012345678901234567890\r | |
| 843 0\r\n\r\n"""; | |
| 844 _testParseInvalidResponse(response); | |
| 845 } | |
| 846 } | |
| 847 | |
| 848 | |
| 849 void main() { | |
| 850 HttpParserTest.runAllTests(); | |
| 851 } | |
| OLD | NEW |