Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(67)

Side by Side Diff: tests/standalone/src/io/HttpParserTest.dart

Issue 10068013: Add basic handling to connection upgrade to the HTTP parser (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/http_parser.dart ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 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 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 #source("../../../../runtime/bin/http_parser.dart"); 5 #source("../../../../runtime/bin/http_parser.dart");
6 6
7 class HttpParserTest { 7 class HttpParserTest {
8 static void runAllTests() { 8 static void runAllTests() {
9 testParseRequest(); 9 testParseRequest();
10 testParseResponse(); 10 testParseResponse();
11 testParseInvalidRequest(); 11 testParseInvalidRequest();
12 testParseInvalidResponse(); 12 testParseInvalidResponse();
13 } 13 }
14 14
15 static void _testParseRequest(String request, 15 static void _testParseRequest(String request,
16 String expectedMethod, 16 String expectedMethod,
17 String expectedUri, 17 String expectedUri,
18 [int expectedContentLength = -1, 18 [int expectedContentLength = -1,
19 int expectedBytesReceived = 0, 19 int expectedBytesReceived = 0,
20 Map expectedHeaders = null, 20 Map expectedHeaders = null,
21 bool chunked = false]) { 21 bool chunked = false,
22 bool upgrade = false,
23 int unparsedLength = 0]) {
22 _HttpParser httpParser; 24 _HttpParser httpParser;
23 bool headersCompleteCalled; 25 bool headersCompleteCalled;
24 bool dataEndCalled; 26 bool dataEndCalled;
25 String method; 27 String method;
26 String uri; 28 String uri;
27 Map headers; 29 Map headers;
28 int contentLength; 30 int contentLength;
29 int bytesReceived; 31 int bytesReceived;
30 32
31 void reset() { 33 void reset() {
32 httpParser = new _HttpParser(); 34 httpParser = new _HttpParser();
33 httpParser.requestStart = (m, u) { method = m; uri = u; }; 35 httpParser.requestStart = (m, u) { method = m; uri = u; };
34 httpParser.responseStart = (s, r) { Expect.fail("Expected request"); }; 36 httpParser.responseStart = (s, r) { Expect.fail("Expected request"); };
35 httpParser.headerReceived = (f, v) { 37 httpParser.headerReceived = (f, v) {
36 Expect.isFalse(headersCompleteCalled); 38 Expect.isFalse(headersCompleteCalled);
37 headers[f] = v; 39 headers[f] = v;
38 }; 40 };
39 httpParser.headersComplete = () { 41 httpParser.headersComplete = () {
40 Expect.isFalse(headersCompleteCalled); 42 Expect.isFalse(headersCompleteCalled);
41 if (!chunked) { 43 if (!chunked) {
42 Expect.equals(expectedContentLength, httpParser.contentLength); 44 Expect.equals(expectedContentLength, httpParser.contentLength);
43 } else { 45 } else {
44 Expect.equals(-1, httpParser.contentLength); 46 Expect.equals(-1, httpParser.contentLength);
45 } 47 }
46 if (expectedHeaders != null) { 48 if (expectedHeaders != null) {
47 expectedHeaders.forEach( 49 expectedHeaders.forEach(
48 (String name, String value) => 50 (String name, String value) =>
49 Expect.equals(value, headers[name])); 51 Expect.equals(value, headers[name]));
50 } 52 }
53 Expect.equals(upgrade, httpParser.upgrade);
51 headersCompleteCalled = true; 54 headersCompleteCalled = true;
52 }; 55 };
53 httpParser.dataReceived = (List<int> data) { 56 httpParser.dataReceived = (List<int> data) {
54 Expect.isTrue(headersCompleteCalled); 57 Expect.isTrue(headersCompleteCalled);
55 bytesReceived += data.length; 58 bytesReceived += data.length;
56 }; 59 };
57 httpParser.dataEnd = (close) { 60 httpParser.dataEnd = (close) {
58 Expect.isFalse(close); 61 Expect.isFalse(close);
59 dataEndCalled = true; 62 dataEndCalled = true;
60 }; 63 };
61 64
62 headersCompleteCalled = false; 65 headersCompleteCalled = false;
63 dataEndCalled = false; 66 dataEndCalled = false;
64 method = null; 67 method = null;
65 uri = null; 68 uri = null;
66 headers = new Map(); 69 headers = new Map();
67 bytesReceived = 0; 70 bytesReceived = 0;
68 } 71 }
69 72
70 void testWrite(List<int> requestData, [int chunkSize = -1]) { 73 void testWrite(List<int> requestData, [int chunkSize = -1]) {
71 if (chunkSize == -1) chunkSize = requestData.length; 74 if (chunkSize == -1) chunkSize = requestData.length;
72 reset(); 75 reset();
76 int written = 0;
77 int unparsed;
73 for (int pos = 0; pos < requestData.length; pos += chunkSize) { 78 for (int pos = 0; pos < requestData.length; pos += chunkSize) {
74 int remaining = requestData.length - pos; 79 int remaining = requestData.length - pos;
75 int writeLength = Math.min(chunkSize, remaining); 80 int writeLength = Math.min(chunkSize, remaining);
76 httpParser.writeList(requestData, pos, writeLength); 81 written += writeLength;
82 int parsed = httpParser.writeList(requestData, pos, writeLength);
83 unparsed = writeLength - parsed;
84 if (httpParser.upgrade) {
85 unparsed += requestData.length - written;
86 break;
87 } else {
88 Expect.equals(0, unparsed);
89 }
77 } 90 }
78 Expect.equals(expectedMethod, method); 91 Expect.equals(expectedMethod, method);
79 Expect.equals(expectedUri, uri); 92 Expect.equals(expectedUri, uri);
80 Expect.isTrue(headersCompleteCalled); 93 Expect.isTrue(headersCompleteCalled);
81 Expect.equals(expectedBytesReceived, bytesReceived); 94 Expect.equals(expectedBytesReceived, bytesReceived);
82 Expect.isTrue(dataEndCalled); 95 if (!upgrade) Expect.isTrue(dataEndCalled);
96 if (unparsedLength == 0) {
97 Expect.equals(0, unparsed);
98 } else {
99 Expect.equals(unparsedLength, unparsed);
100 }
83 } 101 }
84 102
85 // Test parsing the request three times delivering the data in 103 // Test parsing the request three times delivering the data in
86 // different chunks. 104 // different chunks.
87 List<int> requestData = request.charCodes(); 105 List<int> requestData = request.charCodes();
88 testWrite(requestData); 106 testWrite(requestData);
89 testWrite(requestData, 10); 107 testWrite(requestData, 10);
90 testWrite(requestData, 1); 108 testWrite(requestData, 1);
91 } 109 }
92 110
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 143
126 static void _testParseResponse(String response, 144 static void _testParseResponse(String response,
127 int expectedStatusCode, 145 int expectedStatusCode,
128 String expectedReasonPhrase, 146 String expectedReasonPhrase,
129 [int expectedContentLength = -1, 147 [int expectedContentLength = -1,
130 int expectedBytesReceived = 0, 148 int expectedBytesReceived = 0,
131 Map expectedHeaders = null, 149 Map expectedHeaders = null,
132 bool chunked = false, 150 bool chunked = false,
133 bool close = false, 151 bool close = false,
134 String responseToMethod = null, 152 String responseToMethod = null,
135 bool connectionClose = false]) { 153 bool connectionClose = false,
154 bool upgrade = false,
155 int unparsedLength = 0]) {
136 _HttpParser httpParser; 156 _HttpParser httpParser;
137 bool headersCompleteCalled; 157 bool headersCompleteCalled;
138 bool dataEndCalled; 158 bool dataEndCalled;
139 bool dataEndClose; 159 bool dataEndClose;
140 int statusCode; 160 int statusCode;
141 String reasonPhrase; 161 String reasonPhrase;
142 Map headers; 162 Map headers;
143 int contentLength; 163 int contentLength;
144 int bytesReceived; 164 int bytesReceived;
145 165
(...skipping 16 matching lines...) Expand all
162 if (!chunked && !close) { 182 if (!chunked && !close) {
163 Expect.equals(expectedContentLength, httpParser.contentLength); 183 Expect.equals(expectedContentLength, httpParser.contentLength);
164 } else { 184 } else {
165 Expect.equals(-1, httpParser.contentLength); 185 Expect.equals(-1, httpParser.contentLength);
166 } 186 }
167 if (expectedHeaders != null) { 187 if (expectedHeaders != null) {
168 expectedHeaders.forEach((String name, String value) { 188 expectedHeaders.forEach((String name, String value) {
169 Expect.equals(value, headers[name]); 189 Expect.equals(value, headers[name]);
170 }); 190 });
171 } 191 }
192 Expect.equals(upgrade, httpParser.upgrade);
172 headersCompleteCalled = true; 193 headersCompleteCalled = true;
173 }; 194 };
174 httpParser.dataReceived = (List<int> data) { 195 httpParser.dataReceived = (List<int> data) {
175 Expect.isTrue(headersCompleteCalled); 196 Expect.isTrue(headersCompleteCalled);
176 bytesReceived += data.length; 197 bytesReceived += data.length;
177 }; 198 };
178 httpParser.dataEnd = (close) { 199 httpParser.dataEnd = (close) {
179 dataEndCalled = true; 200 dataEndCalled = true;
180 dataEndClose = close; 201 dataEndClose = close;
181 }; 202 };
182 203
183 headersCompleteCalled = false; 204 headersCompleteCalled = false;
184 dataEndCalled = false; 205 dataEndCalled = false;
185 dataEndClose = null; 206 dataEndClose = null;
186 statusCode = -1; 207 statusCode = -1;
187 reasonPhrase = null; 208 reasonPhrase = null;
188 headers = new Map(); 209 headers = new Map();
189 bytesReceived = 0; 210 bytesReceived = 0;
190 } 211 }
191 212
192 void testWrite(List<int> requestData, [int chunkSize = -1]) { 213 void testWrite(List<int> requestData, [int chunkSize = -1]) {
193 if (chunkSize == -1) chunkSize = requestData.length; 214 if (chunkSize == -1) chunkSize = requestData.length;
194 reset(); 215 reset();
216 int written = 0;
217 int unparsed;
195 for (int pos = 0; pos < requestData.length; pos += chunkSize) { 218 for (int pos = 0; pos < requestData.length; pos += chunkSize) {
196 int remaining = requestData.length - pos; 219 int remaining = requestData.length - pos;
197 int writeLength = Math.min(chunkSize, remaining); 220 int writeLength = Math.min(chunkSize, remaining);
198 httpParser.writeList(requestData, pos, writeLength); 221 written += writeLength;
222 int parsed = httpParser.writeList(requestData, pos, writeLength);
223 unparsed = writeLength - parsed;
224 if (httpParser.upgrade) {
225 unparsed += requestData.length - written;
226 break;
227 } else {
228 Expect.equals(0, unparsed);
229 }
199 } 230 }
200 if (close) httpParser.connectionClosed(); 231 if (close) httpParser.connectionClosed();
201 Expect.equals(expectedStatusCode, statusCode); 232 Expect.equals(expectedStatusCode, statusCode);
202 Expect.equals(expectedReasonPhrase, reasonPhrase); 233 Expect.equals(expectedReasonPhrase, reasonPhrase);
203 Expect.isTrue(headersCompleteCalled); 234 Expect.isTrue(headersCompleteCalled);
204 Expect.equals(expectedBytesReceived, bytesReceived); 235 Expect.equals(expectedBytesReceived, bytesReceived);
205 Expect.isTrue(dataEndCalled); 236 if (!upgrade) {
206 if (close) Expect.isTrue(dataEndClose); 237 Expect.isTrue(dataEndCalled);
207 Expect.equals(dataEndClose, connectionClose); 238 if (close) Expect.isTrue(dataEndClose);
239 Expect.equals(dataEndClose, connectionClose);
240 }
241 if (unparsedLength == 0) {
242 Expect.equals(0, unparsed);
243 } else {
244 Expect.equals(unparsedLength, unparsed);
245 }
208 } 246 }
209 247
210 // Test parsing the request three times delivering the data in 248 // Test parsing the request three times delivering the data in
211 // different chunks. 249 // different chunks.
212 List<int> responseData = response.charCodes(); 250 List<int> responseData = response.charCodes();
213 testWrite(responseData); 251 testWrite(responseData);
214 testWrite(responseData, 10); 252 testWrite(responseData, 10);
215 testWrite(responseData, 1); 253 testWrite(responseData, 1);
216 } 254 }
217 255
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
343 _testParseRequest(request, 381 _testParseRequest(request,
344 "POST", 382 "POST",
345 "/test", 383 "/test",
346 expectedContentLength: 10, 384 expectedContentLength: 10,
347 expectedBytesReceived: 10); 385 expectedBytesReceived: 10);
348 386
349 // Test connection close header. 387 // Test connection close header.
350 request = """ 388 request = """
351 GET /test HTTP/1.1\r 389 GET /test HTTP/1.1\r
352 Connection: close\r 390 Connection: close\r
353 \r 391 \r\n""";
354 """;
355 _testParseRequest(request, "GET", "/test"); 392 _testParseRequest(request, "GET", "/test");
356 393
357 // Test chunked encoding. 394 // Test chunked encoding.
358 request = """ 395 request = """
359 POST /test HTTP/1.1\r 396 POST /test HTTP/1.1\r
360 Transfer-Encoding: chunked\r 397 Transfer-Encoding: chunked\r
361 \r 398 \r
362 5\r 399 5\r
363 01234\r 400 01234\r
364 5\r 401 5\r
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 012345678901234567890123456789\r 472 012345678901234567890123456789\r
436 1E;yyy=zzz\r 473 1E;yyy=zzz\r
437 012345678901234567890123456789\r 474 012345678901234567890123456789\r
438 0\r\n\r\n"""; 475 0\r\n\r\n""";
439 _testParseRequest(request, 476 _testParseRequest(request,
440 "POST", 477 "POST",
441 "/test", 478 "/test",
442 expectedContentLength: -1, 479 expectedContentLength: -1,
443 expectedBytesReceived: 60, 480 expectedBytesReceived: 60,
444 chunked: true); 481 chunked: true);
482
483 // Test HTTP upgrade.
484 request = """
485 GET /irc HTTP/1.1\r
486 Upgrade: irc/1.2\r
487 Connection: Upgrade\r
488 \r\n\x01\x01\x01\x01\x01\x02\x02\x02\x02\xFF""";
489 headers = new Map();
490 headers["upgrade"] = "irc/1.2";
491 _testParseRequest(request,
492 "GET",
493 "/irc",
494 expectedHeaders: headers,
495 upgrade: true,
496 unparsedLength: 10);
497
498 // Test HTTP upgrade with protocol data.
499 request = """
500 GET /irc HTTP/1.1\r
501 Upgrade: irc/1.2\r
502 Connection: Upgrade\r
503 \r\n""";
504 headers = new Map();
505 headers["upgrade"] = "irc/1.2";
506 _testParseRequest(request,
507 "GET",
508 "/irc",
509 expectedHeaders: headers,
510 upgrade: true);
511
512 // Test websocket upgrade.
513 request = """
514 GET /chat HTTP/1.1\r
515 Host: server.example.com\r
516 Upgrade: websocket\r
517 Connection: Upgrade\r
518 Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r
519 Origin: http://example.com\r
520 Sec-WebSocket-Version: 13\r
521 \r\n""";
522 headers = new Map();
523 headers["host"] = "server.example.com";
524 headers["upgrade"] = "websocket";
525 headers["sec-websocket-key"] = "dGhlIHNhbXBsZSBub25jZQ==";
526 headers["origin"] = "http://example.com";
527 headers["sec-websocket-version"] = "13";
528 _testParseRequest(request,
529 "GET",
530 "/chat",
531 expectedHeaders: headers,
532 upgrade: true);
533
534
535 // Test websocket upgrade with protocol data. NOTE: When using the
536 // WebSocket protocol this should never happen as the client
537 // should not send protocol data before processing the request
538 // part of the opening handshake. However the HTTP parser should
539 // still handle this.
540 request = """
541 GET /chat HTTP/1.1\r
542 Host: server.example.com\r
543 Upgrade: websocket\r
544 Connection: Upgrade\r
545 Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r
546 Origin: http://example.com\r
547 Sec-WebSocket-Version: 13\r
548 \r\n0123456""";
549 headers = new Map();
550 headers["host"] = "server.example.com";
551 headers["upgrade"] = "websocket";
552 headers["sec-websocket-key"] = "dGhlIHNhbXBsZSBub25jZQ==";
553 headers["origin"] = "http://example.com";
554 headers["sec-websocket-version"] = "13";
555 _testParseRequest(request,
556 "GET",
557 "/chat",
558 expectedHeaders: headers,
559 upgrade: true,
560 unparsedLength: 7);
445 } 561 }
446 562
447 static void testParseResponse() { 563 static void testParseResponse() {
448 String response; 564 String response;
449 Map headers; 565 Map headers;
450 response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n"; 566 response = "HTTP/1.1 100 Continue\r\nContent-Length: 0\r\n\r\n";
451 _testParseResponse(response, 100, "Continue", expectedContentLength: 0); 567 _testParseResponse(response, 100, "Continue", expectedContentLength: 0);
452 568
453 response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n"; 569 response = "HTTP/1.1 100 Continue\r\nContent-Length: 10\r\n\r\n";
454 _testParseResponse(response, 570 _testParseResponse(response,
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 "OK", 640 "OK",
525 expectedContentLength: -1, 641 expectedContentLength: -1,
526 expectedBytesReceived: 57, 642 expectedBytesReceived: 57,
527 chunked: true); 643 chunked: true);
528 644
529 // Test connection close header. 645 // Test connection close header.
530 response = """ 646 response = """
531 HTTP/1.1 200 OK\r 647 HTTP/1.1 200 OK\r
532 Content-Length: 0\r 648 Content-Length: 0\r
533 Connection: close\r 649 Connection: close\r
534 \r 650 \r\n""";
535 """;
536 _testParseResponse(response, 651 _testParseResponse(response,
537 200, 652 200,
538 "OK", 653 "OK",
539 expectedContentLength: 0, 654 expectedContentLength: 0,
540 connectionClose: true); 655 connectionClose: true);
541 656
542 // Test HTTP response without any transfer length indications 657 // Test HTTP response without any transfer length indications
543 // where closing the connections indicates end of body. 658 // where closing the connections indicates end of body.
544 response = """ 659 response = """
545 HTTP/1.1 200 OK\r 660 HTTP/1.1 200 OK\r
546 \r 661 \r
547 01234567890123456789012345 662 01234567890123456789012345
548 0123456789012345678901234567890 663 0123456789012345678901234567890
549 """; 664 """;
550 _testParseResponse(response, 665 _testParseResponse(response,
551 200, 666 200,
552 "OK", 667 "OK",
553 expectedContentLength: -1, 668 expectedContentLength: -1,
554 expectedBytesReceived: 59, 669 expectedBytesReceived: 59,
555 close: true, 670 close: true,
556 connectionClose: true); 671 connectionClose: true);
672
673 // Test HTTP upgrade.
674 response = """
675 HTTP/1.1 101 Switching Protocols\r
676 Upgrade: irc/1.2\r
677 Connection: Upgrade\r
678 \r\n""";
679 headers = new Map();
680 headers["upgrade"] = "irc/1.2";
681 _testParseResponse(response,
682 101,
683 "Switching Protocols",
684 expectedHeaders: headers,
685 upgrade: true);
686
687 // Test HTTP upgrade with protocol data.
688 response = """
689 HTTP/1.1 101 Switching Protocols\r
690 Upgrade: irc/1.2\r
691 Connection: Upgrade\r
692 \r\n\x00\x10\x20\x30\x40\x50\x60\x70\x80\x90\xA0\xB0\xC0\xD0\xE0\xF0""";
693 headers = new Map();
694 headers["upgrade"] = "irc/1.2";
695 _testParseResponse(response,
696 101,
697 "Switching Protocols",
698 expectedHeaders: headers,
699 upgrade: true,
700 unparsedLength: 16);
701
702 // Test websocket upgrade.
703 response = """
704 HTTP/1.1 101 Switching Protocols\r
705 Upgrade: websocket\r
706 Connection: Upgrade\r
707 Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r
708 \r\n""";
709 headers = new Map();
710 headers["upgrade"] = "websocket";
711 headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=";
712 _testParseResponse(response,
713 101,
714 "Switching Protocols",
715 expectedHeaders: headers,
716 upgrade: true);
717
718 // Test websocket upgrade with protocol data.
719 response = """
720 HTTP/1.1 101 Switching Protocols\r
721 Upgrade: websocket\r
722 Connection: Upgrade\r
723 Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r
724 \r\nABCD""";
725 headers = new Map();
726 headers["upgrade"] = "websocket";
727 headers["sec-websocket-accept"] = "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=";
728 _testParseResponse(response,
729 101,
730 "Switching Protocols",
731 expectedHeaders: headers,
732 upgrade: true,
733 unparsedLength: 4);
557 } 734 }
558 735
559 static void testParseInvalidRequest() { 736 static void testParseInvalidRequest() {
560 String request; 737 String request;
561 request = "GET /\r\n\r\n"; 738 request = "GET /\r\n\r\n";
562 _testParseInvalidRequest(request); 739 _testParseInvalidRequest(request);
563 740
564 request = "GET / \r\n\r\n"; 741 request = "GET / \r\n\r\n";
565 _testParseInvalidRequest(request); 742 _testParseInvalidRequest(request);
566 743
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 0123456789012345678901234567890\r 816 0123456789012345678901234567890\r
640 0\r\n\r\n"""; 817 0\r\n\r\n""";
641 _testParseInvalidResponse(response); 818 _testParseInvalidResponse(response);
642 } 819 }
643 } 820 }
644 821
645 822
646 void main() { 823 void main() {
647 HttpParserTest.runAllTests(); 824 HttpParserTest.runAllTests();
648 } 825 }
OLDNEW
« no previous file with comments | « runtime/bin/http_parser.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698