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

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

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

Powered by Google App Engine
This is Rietveld 408576698