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

Side by Side Diff: tools/testing/dart/http_server.dart

Issue 12340021: Start two http servers for every configuration (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 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 | « tools/test-runtime.dart ('k') | tools/testing/dart/test_progress.dart » ('j') | 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 library http_server; 5 library http_server;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:io'; 8 import 'dart:io';
9 import 'dart:isolate'; 9 import 'dart:isolate';
10 import 'dart:uri'; 10 import 'dart:uri';
(...skipping 19 matching lines...) Expand all
30 /// In case a path does not refer to a file but rather to a directory, a 30 /// In case a path does not refer to a file but rather to a directory, a
31 /// directory listing will be displayed. 31 /// directory listing will be displayed.
32 32
33 const PREFIX_BUILDDIR = 'root_build'; 33 const PREFIX_BUILDDIR = 'root_build';
34 const PREFIX_DARTDIR = 'root_dart'; 34 const PREFIX_DARTDIR = 'root_dart';
35 35
36 // TODO(kustermann,ricow): We could change this to the following scheme: 36 // TODO(kustermann,ricow): We could change this to the following scheme:
37 // http://host:port/root_packages/X -> $BuildDir/packages/X 37 // http://host:port/root_packages/X -> $BuildDir/packages/X
38 // Issue: 8368 38 // Issue: 8368
39 39
40
41 main() { 40 main() {
42 /** Convenience method for local testing. */ 41 /** Convenience method for local testing. */
43 var parser = new ArgParser(); 42 var parser = new ArgParser();
44 parser.addOption('port', abbr: 'p', 43 parser.addOption('port', abbr: 'p',
45 help: 'The main server port we wish to respond to requests.', 44 help: 'The main server port we wish to respond to requests.',
46 defaultsTo: '0'); 45 defaultsTo: '0');
47 parser.addOption('crossOriginPort', abbr: 'c', 46 parser.addOption('crossOriginPort', abbr: 'c',
48 help: 'A different port that accepts request from the main server port.', 47 help: 'A different port that accepts request from the main server port.',
49 defaultsTo: '0'); 48 defaultsTo: '0');
50 parser.addOption('mode', abbr: 'm', help: 'Testing mode.',
51 defaultsTo: 'release');
52 parser.addOption('arch', abbr: 'a', help: 'Testing architecture.',
53 defaultsTo: 'ia32');
54 parser.addFlag('help', abbr: 'h', negatable: false, 49 parser.addFlag('help', abbr: 'h', negatable: false,
55 help: 'Print this usage information.'); 50 help: 'Print this usage information.');
56 parser.addOption('package-root', help: 'The package root to use.'); 51 parser.addOption('build-directory', help: 'The package root to use.');
ricow1 2013/02/25 11:42:56 Update option help text
kustermann 2013/02/25 11:51:22 Done.
57 parser.addOption('network', help: 'The network interface to use.', 52 parser.addOption('network', help: 'The network interface to use.',
58 defaultsTo: '127.0.0.1'); 53 defaultsTo: '127.0.0.1');
59 var args = parser.parse(new Options().arguments); 54 var args = parser.parse(new Options().arguments);
60 if (args['help']) { 55 if (args['help']) {
61 print(parser.getUsage()); 56 print(parser.getUsage());
62 } else { 57 } else {
63 // Pretend we're running test.dart so that TestUtils doesn't get confused 58 // Pretend we're running test.dart so that TestUtils doesn't get confused
64 // about the "current directory." This is only used if we're trying to run 59 // about the "current directory." This is only used if we're trying to run
65 // this file independently for local testing. 60 // this file independently for local testing.
66 TestUtils.testScriptPath = new Path(new Options().script) 61 TestUtils.testScriptPath = new Path(new Options().script)
67 .directoryPath 62 .directoryPath
68 .join(new Path('../../test.dart')) 63 .join(new Path('../../test.dart'))
69 .canonicalize() 64 .canonicalize()
70 .toNativePath(); 65 .toNativePath();
71 // Note: args['package-root'] is always the build directory. We have the 66 var servers = new TestingServers(new Path(args['build-directory']));
72 // implicit assumption that it contains the 'packages' subdirectory. 67 var port = int.parse(args['port']);
73 // TODO: We should probably rename 'package-root' to 'build-directory'. 68 var crossOriginPort = int.parse(args['crossOriginPort']);
74 TestingServerRunner._packageRootDir = new Path(args['package-root']); 69 servers.startServers(args['network'],
75 TestingServerRunner._buildDirectory = new Path(args['package-root']); 70 port: port,
76 var network = args['network']; 71 crossOriginPort: crossOriginPort);
77 TestingServerRunner.startHttpServer(network, 72 DebugLogger.info('Server listening on port ${servers.port}');
78 port: int.parse(args['port'])); 73 DebugLogger.info('Server listening on port ${servers.crossOriginPort}');
79 print('Server listening on port '
80 '${TestingServerRunner.serverList[0].port}.');
81 TestingServerRunner.startHttpServer(network,
82 allowedPort: TestingServerRunner.serverList[0].port, port:
83 int.parse(args['crossOriginPort']));
84 print(
85 'Server listening on port ${TestingServerRunner.serverList[1].port}.');
86 } 74 }
87 } 75 }
76
88 /** 77 /**
89 * Runs a set of servers that are initialized specifically for the needs of our 78 * Runs a set of servers that are initialized specifically for the needs of our
90 * test framework, such as dealing with package-root. 79 * test framework, such as dealing with package-root.
91 */ 80 */
92 class TestingServerRunner { 81 class TestingServers {
93 static List serverList = []; 82 List _serverList = [];
94 static Path _packageRootDir = null; 83 Path _buildDirectory = null;
95 static Path _buildDirectory = null;
96 84
97 // Added as a getter so that the function will be called again each time the 85 TestingServers(Path buildDirectory) {
98 // default request handler closure is executed. 86 _buildDirectory = TestUtils.absolutePath(buildDirectory);
99 static Path get packageRootDir => _packageRootDir;
100 static Path get buildDirectory => _buildDirectory;
101
102 static setPackageRootDir(Map configuration) {
103 _packageRootDir = TestUtils.absolutePath(
104 new Path(TestUtils.buildDir(configuration)));
105 } 87 }
106 88
107 static setBuildDir(Map configuration) { 89 int get port => _serverList[0].port;
108 _buildDirectory = TestUtils.absolutePath( 90 int get crossOriginPort => _serverList[1].port;
109 new Path(TestUtils.buildDir(configuration))); 91
92 /**
93 * [startHttpServer] will start two Http servers.
ricow1 2013/02/25 11:42:56 startHttpServer -> startServers
kustermann 2013/02/25 11:51:22 Done.
94 * The first server listens on [port] and sets
95 * "Access-Control-Allow-Origin: *"
96 * The second server listens on [crossOriginPort] and sets
97 * "Access-Control-Allow-Origin: client:port1
98 * "Access-Control-Allow-Credentials: true"
99 */
100 void startServers(String host, {int port: 0, int crossOriginPort: 0}) {
101 _startHttpServer(host, port: port);
102 _startHttpServer(host,
103 port: crossOriginPort,
104 allowedPort:_serverList[0].port);
110 } 105 }
111 106
112 static startHttpServer(String host, {int allowedPort:-1, int port: 0}) { 107 String httpServerCommandline() {
108 var dart = TestUtils.dartTestExecutable.toNativePath();
109 var dartDir = TestUtils.dartDir();
110 var script = dartDir.join(new Path("tools/testing/dart/http_server.dart"));
111 var buildDirectory = _buildDirectory.toNativePath();
112
113 return '$dart $script -p $port -c $crossOriginPort '
114 '--build-directory=$buildDirectory';
115 }
116
117 void stopServers() {
118 for (var server in _serverList) {
119 server.close();
120 }
121 }
122
123 void _startHttpServer(String host, {int port: 0, int allowedPort: -1}) {
113 var httpServer = new HttpServer(); 124 var httpServer = new HttpServer();
114 httpServer.onError = (e) { 125 httpServer.onError = (e) {
115 DebugLogger.error('HttpServer: an error occured: $e'); 126 DebugLogger.error('HttpServer: an error occured: $e');
116 }; 127 };
117 httpServer.defaultRequestHandler = (request, response) { 128 httpServer.defaultRequestHandler = (request, response) {
118 handleFileOrDirectoryRequest(request, response, allowedPort); 129 _handleFileOrDirectoryRequest(request, response, allowedPort);
119 }; 130 };
120 httpServer.addRequestHandler( 131 httpServer.addRequestHandler(
121 (req) => req.path == "/echo", handleEchoRequest); 132 (req) => req.path == "/echo", _handleEchoRequest);
122 133
123 httpServer.listen(host, port); 134 httpServer.listen(host, port);
124 serverList.add(httpServer); 135 _serverList.add(httpServer);
125 } 136 }
126 137
127 138 void _handleFileOrDirectoryRequest(HttpRequest request,
128 static void handleFileOrDirectoryRequest(HttpRequest request, 139 HttpResponse response,
129 HttpResponse response, 140 int allowedPort) {
130 int allowedPort) { 141 var path = _getFilePathFromRequestPath(request.path);
131 var path = getFilePathFromRequestPath(request.path);
132 if (path != null) { 142 if (path != null) {
133 var file = new File.fromPath(path); 143 var file = new File.fromPath(path);
134 file.exists().then((exists) { 144 file.exists().then((exists) {
135 if (exists) { 145 if (exists) {
136 sendFileContent(request, response, allowedPort, path, file); 146 _sendFileContent(request, response, allowedPort, path, file);
137 } else { 147 } else {
138 var directory = new Directory.fromPath(path); 148 var directory = new Directory.fromPath(path);
139 directory.exists().then((exists) { 149 directory.exists().then((exists) {
140 if (exists) { 150 if (exists) {
141 listDirectory(directory).then((entries) { 151 _listDirectory(directory).then((entries) {
142 sendDirectoryListing(entries, request, response); 152 _sendDirectoryListing(entries, request, response);
143 }); 153 });
144 } else { 154 } else {
145 sendNotFound(request, response); 155 _sendNotFound(request, response);
146 } 156 }
147 }); 157 });
148 } 158 }
149 }); 159 });
150 } else { 160 } else {
151 if (request.path == '/') { 161 if (request.path == '/') {
152 var entries = [new _Entry('root_dart', 'root_dart/'), 162 var entries = [new _Entry('root_dart', 'root_dart/'),
153 new _Entry('root_build', 'root_build/'), 163 new _Entry('root_build', 'root_build/'),
154 new _Entry('echo', 'echo')]; 164 new _Entry('echo', 'echo')];
155 sendDirectoryListing(entries, request, response); 165 _sendDirectoryListing(entries, request, response);
156 } else { 166 } else {
157 sendNotFound(request, response); 167 _sendNotFound(request, response);
158 } 168 }
159 } 169 }
160 } 170 }
161 171
162 static void handleEchoRequest(HttpRequest request, HttpResponse response) { 172 void _handleEchoRequest(HttpRequest request, HttpResponse response) {
163 response.headers.set("Access-Control-Allow-Origin", "*"); 173 response.headers.set("Access-Control-Allow-Origin", "*");
164 request.inputStream.pipe(response.outputStream); 174 request.inputStream.pipe(response.outputStream);
165 } 175 }
166 176
167 static Path getFilePathFromRequestPath(String urlRequestPath) { 177 Path _getFilePathFromRequestPath(String urlRequestPath) {
168 // Go to the top of the file to see an explanation of the URL path scheme. 178 // Go to the top of the file to see an explanation of the URL path scheme.
169 var requestPath = new Path(urlRequestPath.substring(1)).canonicalize(); 179 var requestPath = new Path(urlRequestPath.substring(1)).canonicalize();
170 var pathSegments = requestPath.segments(); 180 var pathSegments = requestPath.segments();
171 if (pathSegments.length > 0) { 181 if (pathSegments.length > 0) {
172 var basePath; 182 var basePath;
173 var relativePath; 183 var relativePath;
174 if (pathSegments[0] == PREFIX_BUILDDIR) { 184 if (pathSegments[0] == PREFIX_BUILDDIR) {
175 basePath = _buildDirectory; 185 basePath = _buildDirectory;
176 relativePath = new Path( 186 relativePath = new Path(
177 pathSegments.getRange(1, pathSegments.length - 1).join('/')); 187 pathSegments.getRange(1, pathSegments.length - 1).join('/'));
178 } else if (pathSegments[0] == PREFIX_DARTDIR) { 188 } else if (pathSegments[0] == PREFIX_DARTDIR) {
179 basePath = TestUtils.dartDir(); 189 basePath = TestUtils.dartDir();
180 relativePath = new Path( 190 relativePath = new Path(
181 pathSegments.getRange(1, pathSegments.length - 1).join('/')); 191 pathSegments.getRange(1, pathSegments.length - 1).join('/'));
182 } 192 }
183 var packagesDirName = 'packages'; 193 var packagesDirName = 'packages';
184 var packagesIndex = pathSegments.indexOf(packagesDirName); 194 var packagesIndex = pathSegments.indexOf(packagesDirName);
185 if (packagesIndex != -1) { 195 if (packagesIndex != -1) {
186 var start = packagesIndex + 1; 196 var start = packagesIndex + 1;
187 var length = pathSegments.length - start; 197 var length = pathSegments.length - start;
188 basePath = _packageRootDir.append(packagesDirName); 198 basePath = _buildDirectory.append(packagesDirName);
189 relativePath = new Path( 199 relativePath = new Path(
190 pathSegments.getRange(start, length).join('/')); 200 pathSegments.getRange(start, length).join('/'));
191 } 201 }
192 if (basePath != null && relativePath != null) { 202 if (basePath != null && relativePath != null) {
193 return basePath.join(relativePath); 203 return basePath.join(relativePath);
194 } 204 }
195 } 205 }
196 return null; 206 return null;
197 } 207 }
198 208
199 static Future<List<_Entry>> listDirectory(Directory directory) { 209 Future<List<_Entry>> _listDirectory(Directory directory) {
200 var completer = new Completer(); 210 var completer = new Completer();
201 var entries = []; 211 var entries = [];
202 212
203 directory.list() 213 directory.list()
204 ..onFile = (filepath) { 214 ..onFile = (filepath) {
205 var filename = new Path(filepath).filename; 215 var filename = new Path(filepath).filename;
206 entries.add(new _Entry(filename, filename)); 216 entries.add(new _Entry(filename, filename));
207 } 217 }
208 ..onDir = (dirpath) { 218 ..onDir = (dirpath) {
209 var filename = new Path(dirpath).filename; 219 var filename = new Path(dirpath).filename;
210 entries.add(new _Entry(filename, '$filename/')); 220 entries.add(new _Entry(filename, '$filename/'));
211 } 221 }
212 ..onDone = (_) { 222 ..onDone = (_) {
213 completer.complete(entries); 223 completer.complete(entries);
214 }; 224 };
215 return completer.future; 225 return completer.future;
216 } 226 }
217 227
218 /** 228 void _sendDirectoryListing(List<_Entry> entries,
219 * Sends a simple listing of all the files and sub-directories within 229 HttpRequest request,
220 * directory. 230 HttpResponse response) {
221 *
222 * This is intended to make it easier to browse tests when manually running
223 * tests against this test server.
224 */
225 static void sendDirectoryListing(entries,
226 HttpRequest request,
227 HttpResponse response) {
228 response.headers.set('Content-Type', 'text/html'); 231 response.headers.set('Content-Type', 'text/html');
229 var header = '''<!DOCTYPE html> 232 var header = '''<!DOCTYPE html>
230 <html> 233 <html>
231 <head> 234 <head>
232 <title>${request.path}</title> 235 <title>${request.path}</title>
233 </head> 236 </head>
234 <body> 237 <body>
235 <code> 238 <code>
236 <div>${request.path}</div> 239 <div>${request.path}</div>
237 <hr/> 240 <hr/>
238 <ul>'''; 241 <ul>''';
239 var footer = ''' 242 var footer = '''
240 </ul> 243 </ul>
241 </code> 244 </code>
242 </body> 245 </body>
243 </html>'''; 246 </html>''';
244 247
245 248
246 entries.sort(); 249 entries.sort();
247 response.outputStream.writeString(header); 250 response.outputStream.writeString(header);
248 for (var entry in entries) { 251 for (var entry in entries) {
249 response.outputStream.writeString( 252 response.outputStream.writeString(
250 '<li><a href="${new Path(request.path).append(entry.name)}">' 253 '<li><a href="${new Path(request.path).append(entry.name)}">'
251 '${entry.displayName}</a></li>'); 254 '${entry.displayName}</a></li>');
252 } 255 }
253 response.outputStream.writeString(footer); 256 response.outputStream.writeString(footer);
254 response.outputStream.close(); 257 response.outputStream.close();
255 } 258 }
256 259
257 static void sendFileContent(HttpRequest request, 260 void _sendFileContent(HttpRequest request,
258 HttpResponse response, 261 HttpResponse response,
259 int allowedPort, 262 int allowedPort,
260 Path path, 263 Path path,
261 File file) { 264 File file) {
262 if (allowedPort != -1) { 265 if (allowedPort != -1) {
263 var origin = new Uri(request.headers.value('Origin')); 266 var origin = new Uri(request.headers.value('Origin'));
264 // Allow loading from http://*:$allowedPort in browsers. 267 // Allow loading from http://*:$allowedPort in browsers.
265 var allowedOrigin = 268 var allowedOrigin =
266 '${origin.scheme}://${origin.domain}:${allowedPort}'; 269 '${origin.scheme}://${origin.domain}:${allowedPort}';
267 response.headers.set("Access-Control-Allow-Origin", allowedOrigin); 270 response.headers.set("Access-Control-Allow-Origin", allowedOrigin);
268 response.headers.set('Access-Control-Allow-Credentials', 'true'); 271 response.headers.set('Access-Control-Allow-Credentials', 'true');
269 } else { 272 } else {
270 // No allowedPort specified. Allow from anywhere (but cross-origin 273 // No allowedPort specified. Allow from anywhere (but cross-origin
271 // requests *with credentials* will fail because you can't use "*"). 274 // requests *with credentials* will fail because you can't use "*").
272 response.headers.set("Access-Control-Allow-Origin", "*"); 275 response.headers.set("Access-Control-Allow-Origin", "*");
273 } 276 }
274 if (path.filename.endsWith('.html')) { 277 if (path.filename.endsWith('.html')) {
275 response.headers.set('Content-Type', 'text/html'); 278 response.headers.set('Content-Type', 'text/html');
276 } else if (path.filename.endsWith('.js')) { 279 } else if (path.filename.endsWith('.js')) {
277 response.headers.set('Content-Type', 'application/javascript'); 280 response.headers.set('Content-Type', 'application/javascript');
278 } else if (path.filename.endsWith('.dart')) { 281 } else if (path.filename.endsWith('.dart')) {
279 response.headers.set('Content-Type', 'application/dart'); 282 response.headers.set('Content-Type', 'application/dart');
280 } 283 }
281 file.openInputStream().pipe(response.outputStream); 284 file.openInputStream().pipe(response.outputStream);
282 } 285 }
283 286
284 static void sendNotFound(HttpRequest request, HttpResponse response) { 287 void _sendNotFound(HttpRequest request, HttpResponse response) {
285 // NOTE: Since some tests deliberately try to access non-existent files. 288 // NOTE: Since some tests deliberately try to access non-existent files.
286 // We might want to remove this warning (otherwise it will show 289 // We might want to remove this warning (otherwise it will show
287 // up in the debug.log every time). 290 // up in the debug.log every time).
288 DebugLogger.warning('HttpServer: could not find file for request path: ' 291 DebugLogger.warning('HttpServer: could not find file for request path: '
289 '"${request.path}"'); 292 '"${request.path}"');
290 response.statusCode = HttpStatus.NOT_FOUND; 293 response.statusCode = HttpStatus.NOT_FOUND;
291 try { 294 try {
292 response.outputStream.close(); 295 response.outputStream.close();
293 } catch (e) { 296 } catch (e) {
294 if (e is StreamException) { 297 if (e is StreamException) {
295 DebugLogger.warning('HttpServer: error while closing the response ' 298 DebugLogger.warning('HttpServer: error while closing the response '
296 'stream: $e'); 299 'stream: $e');
297 } else { 300 } else {
298 throw e; 301 throw e;
299 } 302 }
300 } 303 }
301 } 304 }
302
303 static terminateHttpServers() {
304 for (var server in serverList) server.close();
305 }
306 } 305 }
307 306
308 // Helper class for displaying directory listings. 307 // Helper class for displaying directory listings.
309 class _Entry { 308 class _Entry {
310 final String name; 309 final String name;
311 final String displayName; 310 final String displayName;
312 311
313 _Entry(this.name, this.displayName); 312 _Entry(this.name, this.displayName);
314 313
315 int compareTo(_Entry other) { 314 int compareTo(_Entry other) {
316 return name.compareTo(other.name); 315 return name.compareTo(other.name);
317 } 316 }
318 } 317 }
OLDNEW
« no previous file with comments | « tools/test-runtime.dart ('k') | tools/testing/dart/test_progress.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698