OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 // VMOptions= | 5 // VMOptions= |
6 // VMOptions=--short_socket_read | 6 // VMOptions=--short_socket_read |
7 // VMOptions=--short_socket_write | 7 // VMOptions=--short_socket_write |
8 // VMOptions=--short_socket_read --short_socket_write | 8 // VMOptions=--short_socket_read --short_socket_write |
9 | 9 |
10 import "dart:isolate"; | 10 import "dart:isolate"; |
11 import "dart:io"; | 11 import "dart:io"; |
12 | 12 |
13 class TestServerMain { | 13 class IsolatedHttpServer { |
14 TestServerMain() | 14 IsolatedHttpServer() |
15 : _statusPort = new ReceivePort(), | 15 : _statusPort = new ReceivePort(), |
16 _serverPort = null { | 16 _serverPort = null { |
17 _serverPort = spawnFunction(startTestServer); | 17 _serverPort = spawnFunction(startIsolatedHttpServer); |
18 } | 18 } |
19 | 19 |
20 void setServerStartedHandler(void startedCallback(int port)) { | 20 void setServerStartedHandler(void startedCallback(int port)) { |
21 _startedCallback = startedCallback; | 21 _startedCallback = startedCallback; |
22 } | 22 } |
23 | 23 |
24 void start() { | 24 void start() { |
25 // Handle status messages from the server. | 25 // Handle status messages from the server. |
26 _statusPort.receive((var status, SendPort replyTo) { | 26 _statusPort.receive((var status, SendPort replyTo) { |
27 if (status.isStarted) { | 27 if (status.isStarted) { |
28 _startedCallback(status.port); | 28 _startedCallback(status.port); |
29 } | 29 } |
30 }); | 30 }); |
31 | 31 |
32 // Send server start message to the server. | 32 // Send server start message to the server. |
33 var command = new TestServerCommand.start(); | 33 var command = new IsolatedHttpServerCommand.start(); |
34 _serverPort.send(command, _statusPort.toSendPort()); | 34 _serverPort.send(command, _statusPort.toSendPort()); |
35 } | 35 } |
36 | 36 |
37 void shutdown() { | 37 void shutdown() { |
38 // Send server stop message to the server. | 38 // Send server stop message to the server. |
39 _serverPort.send(new TestServerCommand.stop(), _statusPort.toSendPort()); | 39 _serverPort.send(new IsolatedHttpServerCommand.stop(), |
| 40 _statusPort.toSendPort()); |
40 _statusPort.close(); | 41 _statusPort.close(); |
41 } | 42 } |
42 | 43 |
43 void chunkedEncoding() { | 44 void chunkedEncoding() { |
44 // Send chunked encoding message to the server. | 45 // Send chunked encoding message to the server. |
45 _serverPort.send( | 46 _serverPort.send( |
46 new TestServerCommand.chunkedEncoding(), _statusPort.toSendPort()); | 47 new IsolatedHttpServerCommand.chunkedEncoding(), |
| 48 _statusPort.toSendPort()); |
47 } | 49 } |
48 | 50 |
49 ReceivePort _statusPort; // Port for receiving messages from the server. | 51 ReceivePort _statusPort; // Port for receiving messages from the server. |
50 SendPort _serverPort; // Port for sending messages to the server. | 52 SendPort _serverPort; // Port for sending messages to the server. |
51 var _startedCallback; | 53 var _startedCallback; |
52 } | 54 } |
53 | 55 |
54 | 56 |
55 class TestServerCommand { | 57 class IsolatedHttpServerCommand { |
56 static const START = 0; | 58 static const START = 0; |
57 static const STOP = 1; | 59 static const STOP = 1; |
58 static const CHUNKED_ENCODING = 2; | 60 static const CHUNKED_ENCODING = 2; |
59 | 61 |
60 TestServerCommand.start() : _command = START; | 62 IsolatedHttpServerCommand.start() : _command = START; |
61 TestServerCommand.stop() : _command = STOP; | 63 IsolatedHttpServerCommand.stop() : _command = STOP; |
62 TestServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING; | 64 IsolatedHttpServerCommand.chunkedEncoding() : _command = CHUNKED_ENCODING; |
63 | 65 |
64 bool get isStart => _command == START; | 66 bool get isStart => _command == START; |
65 bool get isStop => _command == STOP; | 67 bool get isStop => _command == STOP; |
66 bool get isChunkedEncoding => _command == CHUNKED_ENCODING; | 68 bool get isChunkedEncoding => _command == CHUNKED_ENCODING; |
67 | 69 |
68 int _command; | 70 int _command; |
69 } | 71 } |
70 | 72 |
71 | 73 |
72 class TestServerStatus { | 74 class IsolatedHttpServerStatus { |
73 static const STARTED = 0; | 75 static const STARTED = 0; |
74 static const STOPPED = 1; | 76 static const STOPPED = 1; |
75 static const ERROR = 2; | 77 static const ERROR = 2; |
76 | 78 |
77 TestServerStatus.started(this._port) : _state = STARTED; | 79 IsolatedHttpServerStatus.started(this._port) : _state = STARTED; |
78 TestServerStatus.stopped() : _state = STOPPED; | 80 IsolatedHttpServerStatus.stopped() : _state = STOPPED; |
79 TestServerStatus.error() : _state = ERROR; | 81 IsolatedHttpServerStatus.error() : _state = ERROR; |
80 | 82 |
81 bool get isStarted => _state == STARTED; | 83 bool get isStarted => _state == STARTED; |
82 bool get isStopped => _state == STOPPED; | 84 bool get isStopped => _state == STOPPED; |
83 bool get isError => _state == ERROR; | 85 bool get isError => _state == ERROR; |
84 | 86 |
85 int get port => _port; | 87 int get port => _port; |
86 | 88 |
87 int _state; | 89 int _state; |
88 int _port; | 90 int _port; |
89 } | 91 } |
90 | 92 |
91 | 93 |
92 void startTestServer() { | 94 void startIsolatedHttpServer() { |
93 var server = new TestServer(); | 95 var server = new TestServer(); |
94 server.init(); | 96 server.init(); |
95 port.receive(server.dispatch); | 97 port.receive(server.dispatch); |
96 } | 98 } |
97 | 99 |
98 class TestServer { | 100 class TestServer { |
99 // Echo the request content back to the response. | 101 // Echo the request content back to the response. |
100 void _echoHandler(HttpRequest request, HttpResponse response) { | 102 void _echoHandler(HttpRequest request) { |
| 103 var response = request.response; |
101 Expect.equals("POST", request.method); | 104 Expect.equals("POST", request.method); |
102 response.contentLength = request.contentLength; | 105 response.contentLength = request.contentLength; |
103 request.inputStream.pipe(response.outputStream); | 106 request.pipe(response); |
104 } | 107 } |
105 | 108 |
106 // Return a 404. | 109 // Return a 404. |
107 void _notFoundHandler(HttpRequest request, HttpResponse response) { | 110 void _notFoundHandler(HttpRequest request) { |
| 111 var response = request.response; |
108 response.statusCode = HttpStatus.NOT_FOUND; | 112 response.statusCode = HttpStatus.NOT_FOUND; |
109 response.headers.set("Content-Type", "text/html; charset=UTF-8"); | 113 response.headers.set("Content-Type", "text/html; charset=UTF-8"); |
110 response.outputStream.writeString("Page not found"); | 114 response.addString("Page not found"); |
111 response.outputStream.close(); | 115 response.close(); |
112 } | 116 } |
113 | 117 |
114 | 118 |
115 void init() { | 119 void init() { |
116 // Setup request handlers. | 120 // Setup request handlers. |
117 _requestHandlers = new Map(); | 121 _requestHandlers = new Map(); |
118 _requestHandlers["/echo"] = (HttpRequest request, HttpResponse response) { | 122 _requestHandlers["/echo"] = _echoHandler; |
119 _echoHandler(request, response); | |
120 }; | |
121 } | 123 } |
122 | 124 |
123 void dispatch(message, SendPort replyTo) { | 125 void dispatch(message, SendPort replyTo) { |
124 if (message.isStart) { | 126 if (message.isStart) { |
125 _server = new HttpServer(); | |
126 try { | 127 try { |
127 _server.listen("127.0.0.1", 0); | 128 HttpServer.bind().then((server) { |
128 _server.defaultRequestHandler = (HttpRequest req, HttpResponse rsp) { | 129 _server = server; |
129 _requestReceivedHandler(req, rsp); | 130 _server.listen(_requestReceivedHandler); |
130 }; | 131 replyTo.send( |
131 replyTo.send(new TestServerStatus.started(_server.port), null); | 132 new IsolatedHttpServerStatus.started(_server.port), null); |
| 133 }); |
132 } catch (e) { | 134 } catch (e) { |
133 replyTo.send(new TestServerStatus.error(), null); | 135 replyTo.send(new IsolatedHttpServerStatus.error(), null); |
134 } | 136 } |
135 } else if (message.isStop) { | 137 } else if (message.isStop) { |
136 _server.close(); | 138 _server.close(); |
137 port.close(); | 139 port.close(); |
138 replyTo.send(new TestServerStatus.stopped(), null); | 140 replyTo.send(new IsolatedHttpServerStatus.stopped(), null); |
139 } else if (message.isChunkedEncoding) { | 141 } else if (message.isChunkedEncoding) { |
140 _chunkedEncoding = true; | 142 _chunkedEncoding = true; |
141 } | 143 } |
142 } | 144 } |
143 | 145 |
144 void _requestReceivedHandler(HttpRequest request, HttpResponse response) { | 146 void _requestReceivedHandler(HttpRequest request) { |
145 var requestHandler =_requestHandlers[request.path]; | 147 var requestHandler =_requestHandlers[request.uri.path]; |
146 if (requestHandler != null) { | 148 if (requestHandler != null) { |
147 requestHandler(request, response); | 149 requestHandler(request); |
148 } else { | 150 } else { |
149 _notFoundHandler(request, response); | 151 _notFoundHandler(request); |
150 } | 152 } |
151 } | 153 } |
152 | 154 |
153 HttpServer _server; // HTTP server instance. | 155 HttpServer _server; // HTTP server instance. |
154 Map _requestHandlers; | 156 Map _requestHandlers; |
155 bool _chunkedEncoding = false; | 157 bool _chunkedEncoding = false; |
156 } | 158 } |
157 | 159 |
158 void testReadInto(bool chunkedEncoding) { | 160 void testRead(bool chunkedEncoding) { |
159 String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | 161 String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
160 final int kMessageCount = 10; | 162 final int kMessageCount = 10; |
161 | 163 |
162 TestServerMain testServerMain = new TestServerMain(); | 164 IsolatedHttpServer server = new IsolatedHttpServer(); |
163 | 165 |
164 void runTest(int port) { | 166 void runTest(int port) { |
165 int count = 0; | 167 int count = 0; |
166 HttpClient httpClient = new HttpClient(); | 168 HttpClient httpClient = new HttpClient(); |
167 void sendRequest() { | 169 void sendRequest() { |
168 HttpClientConnection conn = | 170 httpClient.post("127.0.0.1", port, "/echo") |
169 httpClient.post("127.0.0.1", port, "/echo"); | 171 .then((request) { |
170 conn.onRequest = (HttpClientRequest request) { | 172 if (chunkedEncoding) { |
171 if (chunkedEncoding) { | 173 request.addString(data.substring(0, 10)); |
172 request.outputStream.writeString(data.substring(0, 10)); | 174 request.addString(data.substring(10, data.length)); |
173 request.outputStream.writeString(data.substring(10, data.length)); | 175 } else { |
174 } else { | 176 request.contentLength = data.length; |
175 request.contentLength = data.length; | 177 request.add(data.charCodes); |
176 request.outputStream.write(data.charCodes); | 178 } |
177 } | 179 return request.close(); |
178 request.outputStream.close(); | 180 }) |
179 }; | 181 .then((response) { |
180 conn.onResponse = (HttpClientResponse response) { | 182 Expect.equals(HttpStatus.OK, response.statusCode); |
181 Expect.equals(HttpStatus.OK, response.statusCode); | 183 List<int> body = new List<int>(); |
182 InputStream stream = response.inputStream; | 184 response.listen( |
183 List<int> body = new List<int>(); | 185 body.addAll, |
184 stream.onData = () { | 186 onDone: () { |
185 List tmp = new List.fixedLength(3); | 187 Expect.equals(data, new String.fromCharCodes(body)); |
186 int bytes = stream.readInto(tmp); | 188 count++; |
187 body.addAll(tmp.getRange(0, bytes)); | 189 if (count < kMessageCount) { |
188 }; | 190 sendRequest(); |
189 stream.onClosed = () { | 191 } else { |
190 Expect.equals(data, new String.fromCharCodes(body)); | 192 httpClient.close(); |
191 count++; | 193 server.shutdown(); |
192 if (count < kMessageCount) { | 194 } |
193 sendRequest(); | 195 }); |
194 } else { | 196 }); |
195 httpClient.shutdown(); | |
196 testServerMain.shutdown(); | |
197 } | |
198 }; | |
199 }; | |
200 } | 197 } |
201 | |
202 sendRequest(); | 198 sendRequest(); |
203 } | 199 } |
204 | 200 |
205 testServerMain.setServerStartedHandler(runTest); | 201 server.setServerStartedHandler(runTest); |
206 if (chunkedEncoding) { | 202 if (chunkedEncoding) { |
207 testServerMain.chunkedEncoding(); | 203 server.chunkedEncoding(); |
208 } | 204 } |
209 testServerMain.start(); | 205 server.start(); |
210 } | |
211 | |
212 void testReadShort(bool chunkedEncoding) { | |
213 String data = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | |
214 final int kMessageCount = 10; | |
215 | |
216 TestServerMain testServerMain = new TestServerMain(); | |
217 | |
218 void runTest(int port) { | |
219 int count = 0; | |
220 HttpClient httpClient = new HttpClient(); | |
221 void sendRequest() { | |
222 HttpClientConnection conn = | |
223 httpClient.post("127.0.0.1", port, "/echo"); | |
224 conn.onRequest = (HttpClientRequest request) { | |
225 if (chunkedEncoding) { | |
226 request.outputStream.writeString(data.substring(0, 10)); | |
227 request.outputStream.writeString(data.substring(10, data.length)); | |
228 } else { | |
229 request.contentLength = data.length; | |
230 request.outputStream.write(data.charCodes); | |
231 } | |
232 request.outputStream.close(); | |
233 }; | |
234 conn.onResponse = (HttpClientResponse response) { | |
235 Expect.equals(HttpStatus.OK, response.statusCode); | |
236 InputStream stream = response.inputStream; | |
237 List<int> body = new List<int>(); | |
238 stream.onData = () { | |
239 List tmp = stream.read(2); | |
240 body.addAll(tmp); | |
241 }; | |
242 stream.onClosed = () { | |
243 Expect.equals(data, new String.fromCharCodes(body)); | |
244 count++; | |
245 if (count < kMessageCount) { | |
246 sendRequest(); | |
247 } else { | |
248 httpClient.shutdown(); | |
249 testServerMain.shutdown(); | |
250 } | |
251 }; | |
252 }; | |
253 } | |
254 | |
255 sendRequest(); | |
256 } | |
257 | |
258 testServerMain.setServerStartedHandler(runTest); | |
259 if (chunkedEncoding) { | |
260 testServerMain.chunkedEncoding(); | |
261 } | |
262 testServerMain.start(); | |
263 } | 206 } |
264 | 207 |
265 void main() { | 208 void main() { |
266 testReadInto(true); | 209 testRead(true); |
267 testReadInto(false); | 210 testRead(false); |
268 testReadShort(true); | |
269 testReadShort(false); | |
270 } | 211 } |
OLD | NEW |