| 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 #import("dart:io"); | |
| 6 | |
| 7 class HttpParserTest { | |
| 8 static void runAllTests() { | |
| 9 testParseRequest(); | |
| 10 testParseResponse(); | |
| 11 } | |
| 12 | |
| 13 static void _testParseRequest(String request, | |
| 14 String expectedMethod, | |
| 15 String expectedUri, | |
| 16 [int expectedContentLength = 0, | |
| 17 int expectedBytesReceived = 0, | |
| 18 Map expectedHeaders = null, | |
| 19 bool chunked = false]) { | |
| 20 HttpParser httpParser; | |
| 21 bool headersCompleteCalled; | |
| 22 bool dataEndCalled; | |
| 23 String method; | |
| 24 String uri; | |
| 25 Map headers; | |
| 26 int contentLength; | |
| 27 int bytesReceived; | |
| 28 | |
| 29 void reset() { | |
| 30 httpParser = new HttpParser(); | |
| 31 httpParser.requestStart = (m, u) { method = m; uri = u; }; | |
| 32 httpParser.responseStart = (s, r) { Expect.fail("Expected request"); }; | |
| 33 httpParser.headerReceived = (f, v) { | |
| 34 Expect.isFalse(headersCompleteCalled); | |
| 35 headers[f] = v; | |
| 36 }; | |
| 37 httpParser.headersComplete = () { | |
| 38 Expect.isFalse(headersCompleteCalled); | |
| 39 if (!chunked) { | |
| 40 Expect.equals(expectedContentLength, httpParser.contentLength); | |
| 41 } else { | |
| 42 Expect.equals(-1, httpParser.contentLength); | |
| 43 } | |
| 44 if (expectedHeaders != null) { | |
| 45 expectedHeaders.forEach( | |
| 46 (String name, String value) => | |
| 47 Expect.equals(value, headers[name])); | |
| 48 } | |
| 49 headersCompleteCalled = true; | |
| 50 }; | |
| 51 httpParser.dataReceived = (List<int> data) { | |
| 52 Expect.isTrue(headersCompleteCalled); | |
| 53 bytesReceived += data.length; | |
| 54 }; | |
| 55 httpParser.dataEnd = () => dataEndCalled = true; | |
| 56 | |
| 57 headersCompleteCalled = false; | |
| 58 dataEndCalled = false; | |
| 59 method = null; | |
| 60 uri = null; | |
| 61 headers = new Map(); | |
| 62 bytesReceived = 0; | |
| 63 } | |
| 64 | |
| 65 void checkExpectations() { | |
| 66 Expect.equals(expectedMethod, method); | |
| 67 Expect.equals(expectedUri, uri); | |
| 68 Expect.isTrue(headersCompleteCalled); | |
| 69 Expect.equals(expectedBytesReceived, bytesReceived); | |
| 70 Expect.isTrue(dataEndCalled); | |
| 71 } | |
| 72 | |
| 73 void testWrite(List<int> requestData, [int chunkSize = -1]) { | |
| 74 if (chunkSize == -1) chunkSize = requestData.length; | |
| 75 reset(); | |
| 76 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | |
| 77 int remaining = requestData.length - pos; | |
| 78 int writeLength = Math.min(chunkSize, remaining); | |
| 79 httpParser.writeList(requestData, pos, writeLength); | |
| 80 } | |
| 81 checkExpectations(); | |
| 82 } | |
| 83 | |
| 84 void testWriteAll(List<int> requestData) { | |
| 85 reset(); | |
| 86 httpParser.writeList(requestData, 0, requestData.length); | |
| 87 checkExpectations(); | |
| 88 } | |
| 89 | |
| 90 // Test parsing the request three times delivering the data in | |
| 91 // different chunks. | |
| 92 List<int> requestData = request.charCodes(); | |
| 93 testWrite(requestData); | |
| 94 testWrite(requestData, 10); | |
| 95 testWrite(requestData, 1); | |
| 96 } | |
| 97 | |
| 98 static void _testParseResponse(String response, | |
| 99 int expectedStatusCode, | |
| 100 String expectedReasonPhrase, | |
| 101 [int expectedContentLength = 0, | |
| 102 int expectedBytesReceived = 0, | |
| 103 Map expectedHeaders = null, | |
| 104 bool chunked = false]) { | |
| 105 HttpParser httpParser; | |
| 106 bool headersCompleteCalled; | |
| 107 bool dataEndCalled; | |
| 108 int statusCode; | |
| 109 String reasonPhrase; | |
| 110 Map headers; | |
| 111 int contentLength; | |
| 112 int bytesReceived; | |
| 113 | |
| 114 void reset() { | |
| 115 httpParser = new HttpParser(); | |
| 116 httpParser.requestStart = (m, u) => Expect.fail("Expected response"); | |
| 117 httpParser.responseStart = (s, r) { | |
| 118 statusCode = s; | |
| 119 reasonPhrase = r; | |
| 120 }; | |
| 121 httpParser.headerReceived = (f, v) { | |
| 122 Expect.isFalse(headersCompleteCalled); | |
| 123 headers[f] = v; | |
| 124 }; | |
| 125 httpParser.headersComplete = () { | |
| 126 Expect.isFalse(headersCompleteCalled); | |
| 127 if (!chunked) { | |
| 128 Expect.equals(expectedContentLength, httpParser.contentLength); | |
| 129 } else { | |
| 130 Expect.equals(-1, httpParser.contentLength); | |
| 131 } | |
| 132 if (expectedHeaders != null) { | |
| 133 expectedHeaders.forEach((String name, String value) { | |
| 134 Expect.equals(value, headers[name]); | |
| 135 }); | |
| 136 } | |
| 137 headersCompleteCalled = true; | |
| 138 }; | |
| 139 httpParser.dataReceived = (List<int> data) { | |
| 140 Expect.isTrue(headersCompleteCalled); | |
| 141 bytesReceived += data.length; | |
| 142 }; | |
| 143 httpParser.dataEnd = () => dataEndCalled = true; | |
| 144 | |
| 145 headersCompleteCalled = false; | |
| 146 dataEndCalled = false; | |
| 147 statusCode = -1; | |
| 148 reasonPhrase = null; | |
| 149 headers = new Map(); | |
| 150 bytesReceived = 0; | |
| 151 } | |
| 152 | |
| 153 void checkExpectations() { | |
| 154 Expect.equals(expectedStatusCode, statusCode); | |
| 155 Expect.equals(expectedReasonPhrase, reasonPhrase); | |
| 156 Expect.isTrue(headersCompleteCalled); | |
| 157 Expect.equals(expectedBytesReceived, bytesReceived); | |
| 158 Expect.isTrue(dataEndCalled); | |
| 159 } | |
| 160 | |
| 161 void testWrite(List<int> requestData, [int chunkSize = -1]) { | |
| 162 if (chunkSize == -1) chunkSize = requestData.length; | |
| 163 reset(); | |
| 164 for (int pos = 0; pos < requestData.length; pos += chunkSize) { | |
| 165 int remaining = requestData.length - pos; | |
| 166 int writeLength = Math.min(chunkSize, remaining); | |
| 167 httpParser.writeList(requestData, pos, writeLength); | |
| 168 } | |
| 169 checkExpectations(); | |
| 170 } | |
| 171 | |
| 172 void testWriteAll(List<int> requestData) { | |
| 173 reset(); | |
| 174 httpParser.writeList(requestData, 0, requestData.length); | |
| 175 checkExpectations(); | |
| 176 } | |
| 177 | |
| 178 // Test parsing the request three times delivering the data in | |
| 179 // different chunks. | |
| 180 List<int> responseData = response.charCodes(); | |
| 181 testWrite(responseData); | |
| 182 testWrite(responseData, 10); | |
| 183 testWrite(responseData, 1); | |
| 184 } | |
| 185 | |
| 186 static void testParseRequest() { | |
| 187 String request; | |
| 188 Map headers; | |
| 189 request = "GET / HTTP/1.1\r\n\r\n"; | |
| 190 _testParseRequest(request, "GET", "/"); | |
| 191 | |
| 192 request = "POST / HTTP/1.1\r\n\r\n"; | |
| 193 _testParseRequest(request, "POST", "/"); | |
| 194 | |
| 195 request = "GET /index.html HTTP/1.1\r\n\r\n"; | |
| 196 _testParseRequest(request, "GET", "/index.html"); | |
| 197 | |
| 198 request = "POST /index.html HTTP/1.1\r\n\r\n"; | |
| 199 _testParseRequest(request, "POST", "/index.html"); | |
| 200 | |
| 201 request = "H /index.html HTTP/1.1\r\n\r\n"; | |
| 202 _testParseRequest(request, "H", "/index.html"); | |
| 203 | |
| 204 request = "HT /index.html HTTP/1.1\r\n\r\n"; | |
| 205 _testParseRequest(request, "HT", "/index.html"); | |
| 206 | |
| 207 request = "HTT /index.html HTTP/1.1\r\n\r\n"; | |
| 208 _testParseRequest(request, "HTT", "/index.html"); | |
| 209 | |
| 210 request = "HTTP /index.html HTTP/1.1\r\n\r\n"; | |
| 211 _testParseRequest(request, "HTTP", "/index.html"); | |
| 212 | |
| 213 request = """ | |
| 214 POST /test HTTP/1.1\r | |
| 215 AAA: AAA\r | |
| 216 Content-Length: 0\r | |
| 217 \r | |
| 218 """; | |
| 219 _testParseRequest(request, "POST", "/test"); | |
| 220 | |
| 221 request = """ | |
| 222 POST /test HTTP/1.1\r | |
| 223 content-length: 0\r | |
| 224 \r | |
| 225 """; | |
| 226 _testParseRequest(request, "POST", "/test"); | |
| 227 | |
| 228 request = """ | |
| 229 POST /test HTTP/1.1\r | |
| 230 Header-A: AAA\r | |
| 231 X-Header-B: bbb\r | |
| 232 \r | |
| 233 """; | |
| 234 headers = new Map(); | |
| 235 headers["header-a"] = "AAA"; | |
| 236 headers["x-header-b"] = "bbb"; | |
| 237 _testParseRequest(request, "POST", "/test", 0, 0, headers); | |
| 238 | |
| 239 request = """ | |
| 240 POST /test HTTP/1.1\r | |
| 241 Header-A: AAA\r | |
| 242 X-Header-B:\t \t bbb\r | |
| 243 \r | |
| 244 """; | |
| 245 headers = new Map(); | |
| 246 headers["header-a"] = "AAA"; | |
| 247 headers["x-header-b"] = "bbb"; | |
| 248 _testParseRequest(request, "POST", "/test", 0, 0, headers); | |
| 249 | |
| 250 request = """ | |
| 251 POST /test HTTP/1.1\r | |
| 252 Header-A: AA\r | |
| 253 A\r | |
| 254 X-Header-B: b\r | |
| 255 b\r | |
| 256 \t b\r | |
| 257 \r | |
| 258 """; | |
| 259 headers = new Map(); | |
| 260 headers["header-a"] = "AAA"; | |
| 261 headers["x-header-b"] = "bbb"; | |
| 262 _testParseRequest(request, "POST", "/test", 0, 0, headers); | |
| 263 | |
| 264 request = """ | |
| 265 POST /test HTTP/1.1\r | |
| 266 Content-Length: 10\r | |
| 267 \r | |
| 268 0123456789"""; | |
| 269 _testParseRequest(request, "POST", "/test", 10, 10); | |
| 270 | |
| 271 // Test chunked encoding. | |
| 272 request = """ | |
| 273 POST /test HTTP/1.1\r | |
| 274 Transfer-Encoding: chunked\r | |
| 275 \r | |
| 276 5\r | |
| 277 01234\r | |
| 278 5\r | |
| 279 56789\r | |
| 280 0\r\n\r\n"""; | |
| 281 _testParseRequest(request, "POST", "/test", -1, 10, null, true); | |
| 282 | |
| 283 // Test mixing chunked encoding and content length (content length | |
| 284 // is ignored). | |
| 285 request = """ | |
| 286 POST /test HTTP/1.1\r | |
| 287 Content-Length: 7\r | |
| 288 Transfer-Encoding: chunked\r | |
| 289 \r | |
| 290 5\r | |
| 291 01234\r | |
| 292 5\r | |
| 293 56789\r | |
| 294 0\r\n\r\n"""; | |
| 295 _testParseRequest(request, "POST", "/test", -1, 10, null, true); | |
| 296 | |
| 297 // Test mixing chunked encoding and content length (content length | |
| 298 // is ignored). | |
| 299 request = """ | |
| 300 POST /test HTTP/1.1\r | |
| 301 Transfer-Encoding: chunked\r | |
| 302 Content-Length: 3\r | |
| 303 \r | |
| 304 5\r | |
| 305 01234\r | |
| 306 5\r | |
| 307 56789\r | |
| 308 0\r\n\r\n"""; | |
| 309 _testParseRequest(request, "POST", "/test", -1, 10, null, true); | |
| 310 | |
| 311 // Test upper and lower case hex digits in chunked encoding. | |
| 312 request = """ | |
| 313 POST /test HTTP/1.1\r | |
| 314 Transfer-Encoding: chunked\r | |
| 315 \r | |
| 316 1E\r | |
| 317 012345678901234567890123456789\r | |
| 318 1e\r | |
| 319 012345678901234567890123456789\r | |
| 320 0\r\n\r\n"""; | |
| 321 _testParseRequest(request, "POST", "/test", -1, 60, null, true); | |
| 322 } | |
| 323 | |
| 324 static void testParseResponse() { | |
| 325 String response; | |
| 326 Map headers; | |
| 327 response = "HTTP/1.1 200 OK\r\n\r\n"; | |
| 328 _testParseResponse(response, 200, "OK"); | |
| 329 | |
| 330 response = "HTTP/1.1 404 Not found\r\n\r\n"; | |
| 331 _testParseResponse(response, 404, "Not found"); | |
| 332 | |
| 333 response = "HTTP/1.1 500 Server error\r\n\r\n"; | |
| 334 _testParseResponse(response, 500, "Server error"); | |
| 335 | |
| 336 // Test content. | |
| 337 response = """ | |
| 338 HTTP/1.1 200 OK\r | |
| 339 Content-Length: 20\r | |
| 340 \r | |
| 341 01234567890123456789"""; | |
| 342 | |
| 343 _testParseResponse(response, 200, "OK", 20, 20); | |
| 344 // Test upper and lower case hex digits in chunked encoding. | |
| 345 response = """ | |
| 346 HTTP/1.1 200 OK\r | |
| 347 Transfer-Encoding: chunked\r | |
| 348 \r | |
| 349 1A\r | |
| 350 01234567890123456789012345\r | |
| 351 1f\r | |
| 352 0123456789012345678901234567890\r | |
| 353 0\r\n\r\n"""; | |
| 354 _testParseResponse(response, 200, "OK", -1, 57, null, true); | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 | |
| 359 void main() { | |
| 360 HttpParserTest.runAllTests(); | |
| 361 } | |
| OLD | NEW |