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 |