| 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 // VMOptions= | |
| 6 // VMOptions=--short_socket_read | |
| 7 // VMOptions=--short_socket_write | |
| 8 // VMOptions=--short_socket_read --short_socket_write | |
| 9 | |
| 10 #import("dart:isolate"); | |
| 11 #import("dart:io"); | |
| 12 | |
| 13 class TestServerMain { | |
| 14 TestServerMain() | |
| 15 : _statusPort = new ReceivePort(), | |
| 16 _serverPort = null { | |
| 17 new TestServer().spawn().then((SendPort port) { | |
| 18 _serverPort = port; | |
| 19 }); | |
| 20 } | |
| 21 | |
| 22 void setServerStartedHandler(void startedCallback(int port)) { | |
| 23 _startedCallback = startedCallback; | |
| 24 } | |
| 25 | |
| 26 void start() { | |
| 27 // Handle status messages from the server. | |
| 28 _statusPort.receive((var status, SendPort replyTo) { | |
| 29 if (status.isStarted) { | |
| 30 _startedCallback(status.port); | |
| 31 } | |
| 32 }); | |
| 33 | |
| 34 // Send server start message to the server. | |
| 35 var command = new TestServerCommand.start(); | |
| 36 _serverPort.send(command, _statusPort.toSendPort()); | |
| 37 } | |
| 38 | |
| 39 void shutdown() { | |
| 40 // Send server stop message to the server. | |
| 41 _serverPort.send(new TestServerCommand.stop(), _statusPort.toSendPort()); | |
| 42 _statusPort.close(); | |
| 43 } | |
| 44 | |
| 45 void chunkedEncoding() { | |
| 46 // Send chunked encoding message to the server. | |
| 47 _serverPort.send( | |
| 48 new TestServerCommand.chunkedEncoding(), _statusPort.toSendPort()); | |
| 49 } | |
| 50 | |
| 51 ReceivePort _statusPort; // Port for receiving messages from the server. | |
| 52 SendPort _serverPort; // Port for sending messages to the server. | |
| 53 var _startedCallback; | |
| 54 } | |
| 55 | |
| 56 | |
| 57 class TestServerCommand { | |
| 58 static final START = 0; | |
| 59 static final STOP = 1; | |
| 60 static final CHUNKED_ENCODING = 2; | |
| 61 | |
| 62 TestServerCommand.start() : _command = START; | |
| 63 TestServerCommand.stop() : _command = STOP; | |
| 64 TestServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING; | |
| 65 | |
| 66 bool get isStart() => _command == START; | |
| 67 bool get isStop() => _command == STOP; | |
| 68 bool get isChunkedEncoding() => _command == CHUNKED_ENCODING; | |
| 69 | |
| 70 int _command; | |
| 71 } | |
| 72 | |
| 73 | |
| 74 class TestServerStatus { | |
| 75 static final STARTED = 0; | |
| 76 static final STOPPED = 1; | |
| 77 static final ERROR = 2; | |
| 78 | |
| 79 TestServerStatus.started(this._port) : _state = STARTED; | |
| 80 TestServerStatus.stopped() : _state = STOPPED; | |
| 81 TestServerStatus.error() : _state = ERROR; | |
| 82 | |
| 83 bool get isStarted() => _state == STARTED; | |
| 84 bool get isStopped() => _state == STOPPED; | |
| 85 bool get isError() => _state == ERROR; | |
| 86 | |
| 87 int get port() => _port; | |
| 88 | |
| 89 int _state; | |
| 90 int _port; | |
| 91 } | |
| 92 | |
| 93 | |
| 94 class TestServer extends Isolate { | |
| 95 // Echo the request content back to the response. | |
| 96 void _echoHandler(HttpRequest request, HttpResponse response) { | |
| 97 Expect.equals("POST", request.method); | |
| 98 response.contentLength = request.contentLength; | |
| 99 request.inputStream.pipe(response.outputStream); | |
| 100 } | |
| 101 | |
| 102 // Echo the request content back to the response. | |
| 103 void _zeroToTenHandler(HttpRequest request, HttpResponse response) { | |
| 104 Expect.equals("GET", request.method); | |
| 105 request.inputStream.onData = () {}; | |
| 106 request.inputStream.onClosed = () { | |
| 107 response.outputStream.writeString("01234567890"); | |
| 108 response.outputStream.close(); | |
| 109 }; | |
| 110 } | |
| 111 | |
| 112 // Return a 404. | |
| 113 void _notFoundHandler(HttpRequest request, HttpResponse response) { | |
| 114 response.statusCode = HttpStatus.NOT_FOUND; | |
| 115 response.headers.set("Content-Type", "text/html; charset=UTF-8"); | |
| 116 response.outputStream.writeString("Page not found"); | |
| 117 response.outputStream.close(); | |
| 118 } | |
| 119 | |
| 120 // Return a 301 with a custom reason phrase. | |
| 121 void _reasonForMovingHandler(HttpRequest request, HttpResponse response) { | |
| 122 response.statusCode = HttpStatus.MOVED_PERMANENTLY; | |
| 123 response.reasonPhrase = "Don't come looking here any more"; | |
| 124 response.outputStream.close(); | |
| 125 } | |
| 126 | |
| 127 // Check the "Host" header. | |
| 128 void _hostHandler(HttpRequest request, HttpResponse response) { | |
| 129 Expect.equals(1, request.headers["Host"].length); | |
| 130 Expect.equals("www.dartlang.org:1234", request.headers["Host"][0]); | |
| 131 Expect.equals("www.dartlang.org", request.headers.host); | |
| 132 Expect.equals(1234, request.headers.port); | |
| 133 response.statusCode = HttpStatus.OK; | |
| 134 response.outputStream.close(); | |
| 135 } | |
| 136 | |
| 137 // Set the "Expires" header using the expires property. | |
| 138 void _expires1Handler(HttpRequest request, HttpResponse response) { | |
| 139 Date date = | |
| 140 new Date.withTimeZone( | |
| 141 1999, Date.JUN, 11, 18, 46, 53, 0, new TimeZone.utc()); | |
| 142 response.headers.expires = date; | |
| 143 Expect.equals(date, response.headers.expires); | |
| 144 response.outputStream.close(); | |
| 145 } | |
| 146 | |
| 147 // Set the "Expires" header. | |
| 148 void _expires2Handler(HttpRequest request, HttpResponse response) { | |
| 149 response.headers.set("Expires", "Fri, 11 Jun 1999 18:46:53 GMT"); | |
| 150 Date date = | |
| 151 new Date.withTimeZone( | |
| 152 1999, Date.JUN, 11, 18, 46, 53, 0, new TimeZone.utc()); | |
| 153 Expect.equals(date, response.headers.expires); | |
| 154 response.outputStream.close(); | |
| 155 } | |
| 156 | |
| 157 void main() { | |
| 158 // Setup request handlers. | |
| 159 _requestHandlers = new Map(); | |
| 160 _requestHandlers["/echo"] = (HttpRequest request, HttpResponse response) { | |
| 161 _echoHandler(request, response); | |
| 162 }; | |
| 163 _requestHandlers["/0123456789"] = | |
| 164 (HttpRequest request, HttpResponse response) { | |
| 165 _zeroToTenHandler(request, response); | |
| 166 }; | |
| 167 _requestHandlers["/reasonformoving"] = | |
| 168 (HttpRequest request, HttpResponse response) { | |
| 169 _reasonForMovingHandler(request, response); | |
| 170 }; | |
| 171 _requestHandlers["/host"] = | |
| 172 (HttpRequest request, HttpResponse response) { | |
| 173 _hostHandler(request, response); | |
| 174 }; | |
| 175 _requestHandlers["/expires1"] = | |
| 176 (HttpRequest request, HttpResponse response) { | |
| 177 _expires1Handler(request, response); | |
| 178 }; | |
| 179 _requestHandlers["/expires2"] = | |
| 180 (HttpRequest request, HttpResponse response) { | |
| 181 _expires2Handler(request, response); | |
| 182 }; | |
| 183 | |
| 184 this.port.receive((var message, SendPort replyTo) { | |
| 185 if (message.isStart) { | |
| 186 _server = new HttpServer(); | |
| 187 try { | |
| 188 _server.listen("127.0.0.1", 0); | |
| 189 _server.defaultRequestHandler = (HttpRequest req, HttpResponse rsp) { | |
| 190 _requestReceivedHandler(req, rsp); | |
| 191 }; | |
| 192 replyTo.send(new TestServerStatus.started(_server.port), null); | |
| 193 } catch (var e) { | |
| 194 replyTo.send(new TestServerStatus.error(), null); | |
| 195 } | |
| 196 } else if (message.isStop) { | |
| 197 _server.close(); | |
| 198 this.port.close(); | |
| 199 replyTo.send(new TestServerStatus.stopped(), null); | |
| 200 } else if (message.isChunkedEncoding) { | |
| 201 _chunkedEncoding = true; | |
| 202 } | |
| 203 }); | |
| 204 } | |
| 205 | |
| 206 void _requestReceivedHandler(HttpRequest request, HttpResponse response) { | |
| 207 var requestHandler =_requestHandlers[request.path]; | |
| 208 if (requestHandler != null) { | |
| 209 requestHandler(request, response); | |
| 210 } else { | |
| 211 _notFoundHandler(request, response); | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 HttpServer _server; // HTTP server instance. | |
| 216 Map _requestHandlers; | |
| 217 bool _chunkedEncoding = false; | |
| 218 } | |
| 219 | |
| 220 | |
| 221 void testStartStop() { | |
| 222 TestServerMain testServerMain = new TestServerMain(); | |
| 223 testServerMain.setServerStartedHandler((int port) { | |
| 224 testServerMain.shutdown(); | |
| 225 }); | |
| 226 testServerMain.start(); | |
| 227 } | |
| 228 | |
| 229 | |
| 230 void testGET() { | |
| 231 TestServerMain testServerMain = new TestServerMain(); | |
| 232 testServerMain.setServerStartedHandler((int port) { | |
| 233 HttpClient httpClient = new HttpClient(); | |
| 234 HttpClientConnection conn = | |
| 235 httpClient.get("127.0.0.1", port, "/0123456789"); | |
| 236 conn.onResponse = (HttpClientResponse response) { | |
| 237 Expect.equals(HttpStatus.OK, response.statusCode); | |
| 238 StringInputStream stream = new StringInputStream(response.inputStream); | |
| 239 StringBuffer body = new StringBuffer(); | |
| 240 stream.onData = () => body.add(stream.read()); | |
| 241 stream.onClosed = () { | |
| 242 Expect.equals("01234567890", body.toString()); | |
| 243 httpClient.shutdown(); | |
| 244 testServerMain.shutdown(); | |
| 245 }; | |
| 246 }; | |
| 247 }); | |
| 248 testServerMain.start(); | |
| 249 } | |
| 250 | |
| 251 | |
| 252 void testPOST(bool chunkedEncoding) { | |
| 253 String data = "ABCDEFGHIJKLMONPQRSTUVWXYZ"; | |
| 254 final int kMessageCount = 10; | |
| 255 | |
| 256 TestServerMain testServerMain = new TestServerMain(); | |
| 257 | |
| 258 void runTest(int port) { | |
| 259 int count = 0; | |
| 260 HttpClient httpClient = new HttpClient(); | |
| 261 void sendRequest() { | |
| 262 HttpClientConnection conn = | |
| 263 httpClient.post("127.0.0.1", port, "/echo"); | |
| 264 conn.onRequest = (HttpClientRequest request) { | |
| 265 if (chunkedEncoding) { | |
| 266 request.outputStream.writeString(data.substring(0, 10)); | |
| 267 request.outputStream.writeString(data.substring(10, data.length)); | |
| 268 } else { | |
| 269 request.contentLength = data.length; | |
| 270 request.outputStream.write(data.charCodes()); | |
| 271 } | |
| 272 request.outputStream.close(); | |
| 273 }; | |
| 274 conn.onResponse = (HttpClientResponse response) { | |
| 275 Expect.equals(HttpStatus.OK, response.statusCode); | |
| 276 StringInputStream stream = new StringInputStream(response.inputStream); | |
| 277 StringBuffer body = new StringBuffer(); | |
| 278 stream.onData = () => body.add(stream.read()); | |
| 279 stream.onClosed = () { | |
| 280 Expect.equals(data, body.toString()); | |
| 281 count++; | |
| 282 if (count < kMessageCount) { | |
| 283 sendRequest(); | |
| 284 } else { | |
| 285 httpClient.shutdown(); | |
| 286 testServerMain.shutdown(); | |
| 287 } | |
| 288 }; | |
| 289 }; | |
| 290 } | |
| 291 | |
| 292 sendRequest(); | |
| 293 } | |
| 294 | |
| 295 testServerMain.setServerStartedHandler(runTest); | |
| 296 if (chunkedEncoding) { | |
| 297 testServerMain.chunkedEncoding(); | |
| 298 } | |
| 299 testServerMain.start(); | |
| 300 } | |
| 301 | |
| 302 | |
| 303 void testReadInto(bool chunkedEncoding) { | |
| 304 String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
| 305 final int kMessageCount = 10; | |
| 306 | |
| 307 TestServerMain testServerMain = new TestServerMain(); | |
| 308 | |
| 309 void runTest(int port) { | |
| 310 int count = 0; | |
| 311 HttpClient httpClient = new HttpClient(); | |
| 312 void sendRequest() { | |
| 313 HttpClientConnection conn = | |
| 314 httpClient.post("127.0.0.1", port, "/echo"); | |
| 315 conn.onRequest = (HttpClientRequest request) { | |
| 316 if (chunkedEncoding) { | |
| 317 request.outputStream.writeString(data.substring(0, 10)); | |
| 318 request.outputStream.writeString(data.substring(10, data.length)); | |
| 319 } else { | |
| 320 request.contentLength = data.length; | |
| 321 request.outputStream.write(data.charCodes()); | |
| 322 } | |
| 323 request.outputStream.close(); | |
| 324 }; | |
| 325 conn.onResponse = (HttpClientResponse response) { | |
| 326 Expect.equals(HttpStatus.OK, response.statusCode); | |
| 327 InputStream stream = response.inputStream; | |
| 328 List<int> body = new List<int>(); | |
| 329 stream.onData = () { | |
| 330 List tmp = new List(3); | |
| 331 int bytes = stream.readInto(tmp); | |
| 332 body.addAll(tmp.getRange(0, bytes)); | |
| 333 }; | |
| 334 stream.onClosed = () { | |
| 335 Expect.equals(data, new String.fromCharCodes(body)); | |
| 336 count++; | |
| 337 if (count < kMessageCount) { | |
| 338 sendRequest(); | |
| 339 } else { | |
| 340 httpClient.shutdown(); | |
| 341 testServerMain.shutdown(); | |
| 342 } | |
| 343 }; | |
| 344 }; | |
| 345 } | |
| 346 | |
| 347 sendRequest(); | |
| 348 } | |
| 349 | |
| 350 testServerMain.setServerStartedHandler(runTest); | |
| 351 if (chunkedEncoding) { | |
| 352 testServerMain.chunkedEncoding(); | |
| 353 } | |
| 354 testServerMain.start(); | |
| 355 } | |
| 356 | |
| 357 | |
| 358 void testReadShort(bool chunkedEncoding) { | |
| 359 String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
| 360 final int kMessageCount = 10; | |
| 361 | |
| 362 TestServerMain testServerMain = new TestServerMain(); | |
| 363 | |
| 364 void runTest(int port) { | |
| 365 int count = 0; | |
| 366 HttpClient httpClient = new HttpClient(); | |
| 367 void sendRequest() { | |
| 368 HttpClientConnection conn = | |
| 369 httpClient.post("127.0.0.1", port, "/echo"); | |
| 370 conn.onRequest = (HttpClientRequest request) { | |
| 371 if (chunkedEncoding) { | |
| 372 request.outputStream.writeString(data.substring(0, 10)); | |
| 373 request.outputStream.writeString(data.substring(10, data.length)); | |
| 374 } else { | |
| 375 request.contentLength = data.length; | |
| 376 request.outputStream.write(data.charCodes()); | |
| 377 } | |
| 378 request.outputStream.close(); | |
| 379 }; | |
| 380 conn.onResponse = (HttpClientResponse response) { | |
| 381 Expect.equals(HttpStatus.OK, response.statusCode); | |
| 382 InputStream stream = response.inputStream; | |
| 383 List<int> body = new List<int>(); | |
| 384 stream.onData = () { | |
| 385 List tmp = stream.read(2); | |
| 386 body.addAll(tmp); | |
| 387 }; | |
| 388 stream.onClosed = () { | |
| 389 Expect.equals(data, new String.fromCharCodes(body)); | |
| 390 count++; | |
| 391 if (count < kMessageCount) { | |
| 392 sendRequest(); | |
| 393 } else { | |
| 394 httpClient.shutdown(); | |
| 395 testServerMain.shutdown(); | |
| 396 } | |
| 397 }; | |
| 398 }; | |
| 399 } | |
| 400 | |
| 401 sendRequest(); | |
| 402 } | |
| 403 | |
| 404 testServerMain.setServerStartedHandler(runTest); | |
| 405 if (chunkedEncoding) { | |
| 406 testServerMain.chunkedEncoding(); | |
| 407 } | |
| 408 testServerMain.start(); | |
| 409 } | |
| 410 | |
| 411 | |
| 412 void test404() { | |
| 413 TestServerMain testServerMain = new TestServerMain(); | |
| 414 testServerMain.setServerStartedHandler((int port) { | |
| 415 HttpClient httpClient = new HttpClient(); | |
| 416 HttpClientConnection conn = | |
| 417 httpClient.get("127.0.0.1", port, "/thisisnotfound"); | |
| 418 conn.onResponse = (HttpClientResponse response) { | |
| 419 Expect.equals(HttpStatus.NOT_FOUND, response.statusCode); | |
| 420 httpClient.shutdown(); | |
| 421 testServerMain.shutdown(); | |
| 422 }; | |
| 423 }); | |
| 424 testServerMain.start(); | |
| 425 } | |
| 426 | |
| 427 | |
| 428 void testReasonPhrase() { | |
| 429 TestServerMain testServerMain = new TestServerMain(); | |
| 430 testServerMain.setServerStartedHandler((int port) { | |
| 431 HttpClient httpClient = new HttpClient(); | |
| 432 HttpClientConnection conn = | |
| 433 httpClient.get("127.0.0.1", port, "/reasonformoving"); | |
| 434 conn.onResponse = (HttpClientResponse response) { | |
| 435 Expect.equals(HttpStatus.MOVED_PERMANENTLY, response.statusCode); | |
| 436 Expect.equals("Don't come looking here any more", response.reasonPhrase); | |
| 437 httpClient.shutdown(); | |
| 438 testServerMain.shutdown(); | |
| 439 }; | |
| 440 }); | |
| 441 testServerMain.start(); | |
| 442 } | |
| 443 | |
| 444 | |
| 445 void testHost() { | |
| 446 TestServerMain testServerMain = new TestServerMain(); | |
| 447 testServerMain.setServerStartedHandler((int port) { | |
| 448 HttpClient httpClient = new HttpClient(); | |
| 449 HttpClientConnection conn = | |
| 450 httpClient.get("127.0.0.1", port, "/host"); | |
| 451 conn.onRequest = (HttpClientRequest request) { | |
| 452 Expect.equals("127.0.0.1:$port", request.headers["host"][0]); | |
| 453 request.headers.host = "www.dartlang.com"; | |
| 454 Expect.equals("www.dartlang.com:$port", request.headers["host"][0]); | |
| 455 Expect.equals("www.dartlang.com", request.headers.host); | |
| 456 Expect.equals(port, request.headers.port); | |
| 457 request.headers.port = 1234; | |
| 458 Expect.equals("www.dartlang.com:1234", request.headers["host"][0]); | |
| 459 Expect.equals(1234, request.headers.port); | |
| 460 request.headers.port = HttpClient.DEFAULT_HTTP_PORT; | |
| 461 Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port); | |
| 462 Expect.equals("www.dartlang.com", request.headers["host"][0]); | |
| 463 request.headers.set("Host", "www.dartlang.org"); | |
| 464 Expect.equals("www.dartlang.org", request.headers.host); | |
| 465 Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port); | |
| 466 request.headers.set("Host", "www.dartlang.org:"); | |
| 467 Expect.equals("www.dartlang.org", request.headers.host); | |
| 468 Expect.equals(HttpClient.DEFAULT_HTTP_PORT, request.headers.port); | |
| 469 request.headers.set("Host", "www.dartlang.org:1234"); | |
| 470 Expect.equals("www.dartlang.org", request.headers.host); | |
| 471 Expect.equals(1234, request.headers.port); | |
| 472 request.outputStream.close(); | |
| 473 }; | |
| 474 conn.onResponse = (HttpClientResponse response) { | |
| 475 Expect.equals(HttpStatus.OK, response.statusCode); | |
| 476 httpClient.shutdown(); | |
| 477 testServerMain.shutdown(); | |
| 478 }; | |
| 479 }); | |
| 480 testServerMain.start(); | |
| 481 } | |
| 482 | |
| 483 void testExpires() { | |
| 484 TestServerMain testServerMain = new TestServerMain(); | |
| 485 testServerMain.setServerStartedHandler((int port) { | |
| 486 int responses = 0; | |
| 487 HttpClient httpClient = new HttpClient(); | |
| 488 | |
| 489 void processResponse(HttpClientResponse response) { | |
| 490 Expect.equals(HttpStatus.OK, response.statusCode); | |
| 491 Expect.equals("Fri, 11 Jun 1999 18:46:53 GMT", | |
| 492 response.headers["expires"][0]); | |
| 493 Expect.equals( | |
| 494 new Date.withTimeZone( | |
| 495 1999, Date.JUN, 11, 18, 46, 53, 0, new TimeZone.utc()), | |
| 496 response.headers.expires); | |
| 497 responses++; | |
| 498 if (responses == 2) { | |
| 499 httpClient.shutdown(); | |
| 500 testServerMain.shutdown(); | |
| 501 } | |
| 502 } | |
| 503 | |
| 504 HttpClientConnection conn1 = httpClient.get("127.0.0.1", port, "/expires1"); | |
| 505 conn1.onResponse = (HttpClientResponse response) { | |
| 506 processResponse(response); | |
| 507 }; | |
| 508 HttpClientConnection conn2 = httpClient.get("127.0.0.1", port, "/expires2"); | |
| 509 conn2.onResponse = (HttpClientResponse response) { | |
| 510 processResponse(response); | |
| 511 }; | |
| 512 }); | |
| 513 testServerMain.start(); | |
| 514 } | |
| 515 | |
| 516 | |
| 517 void main() { | |
| 518 testStartStop(); | |
| 519 testGET(); | |
| 520 testPOST(true); | |
| 521 testPOST(false); | |
| 522 testReadInto(true); | |
| 523 testReadInto(false); | |
| 524 testReadShort(true); | |
| 525 testReadShort(false); | |
| 526 test404(); | |
| 527 testReasonPhrase(); | |
| 528 testHost(); | |
| 529 testExpires(); | |
| 530 } | |
| OLD | NEW |