Chromium Code Reviews| OLD | NEW |
|---|---|
| 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'; |
| 11 import 'test_suite.dart'; // For TestUtils. | 11 import 'test_suite.dart'; // For TestUtils. |
| 12 // 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 |
| 13 // 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? |
| 14 // See discussion on https://codereview.chromium.org/11931025/. | 14 // See discussion on https://codereview.chromium.org/11931025/. |
| 15 import 'vendored_pkg/args/args.dart'; | 15 import 'vendored_pkg/args/args.dart'; |
| 16 import 'utils.dart'; | 16 import 'utils.dart'; |
| 17 | 17 |
| 18 | 18 |
| 19 /// Interface of the HTTP server: | 19 /// Interface of the HTTP server: |
| 20 /// | 20 /// |
| 21 /// /echo: This will stream the data received in the request stream back | 21 /// /echo: This will stream the data received in the request stream back |
| 22 /// to the client. | 22 /// to the client. |
| 23 /// /root_dart/X: This will serve the corresponding file from the dart | 23 /// /root_dart/X: This will serve the corresponding file from the dart |
| 24 /// directory (i.e. '$DartDirectory/X'). | 24 /// directory (i.e. '$DartDirectory/X'). |
| 25 /// /root_build/X: This will serve the corresponding file from the build | 25 /// /root_build/X: This will serve the corresponding file from the build |
| 26 /// directory (i.e. '$BuildDirectory/X'). | 26 /// directory (i.e. '$BuildDirectory/X'). |
| 27 /// /FOO/packages/BAR: This will serve the corresponding file from the packages | 27 /// /FOO/packages/BAR: This will serve the corresponding file from the packages |
| 28 /// directory (i.e. '$BuildDirectory/packages/BAR') | 28 /// directory (i.e. '$BuildDirectory/packages/BAR') |
| 29 /// | 29 /// |
| 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. |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 44 help: 'The main server port we wish to respond to requests.', | 44 help: 'The main server port we wish to respond to requests.', |
| 45 defaultsTo: '0'); | 45 defaultsTo: '0'); |
| 46 parser.addOption('crossOriginPort', abbr: 'c', | 46 parser.addOption('crossOriginPort', abbr: 'c', |
| 47 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.', |
| 48 defaultsTo: '0'); | 48 defaultsTo: '0'); |
| 49 parser.addFlag('help', abbr: 'h', negatable: false, | 49 parser.addFlag('help', abbr: 'h', negatable: false, |
| 50 help: 'Print this usage information.'); | 50 help: 'Print this usage information.'); |
| 51 parser.addOption('build-directory', help: 'The build directory to use.'); | 51 parser.addOption('build-directory', help: 'The build directory to use.'); |
| 52 parser.addOption('network', help: 'The network interface to use.', | 52 parser.addOption('network', help: 'The network interface to use.', |
| 53 defaultsTo: '127.0.0.1'); | 53 defaultsTo: '127.0.0.1'); |
| 54 parser.addFlag('csp', help: 'Use Content Security Policy restrictions.', | |
| 55 defaultsTo: false); | |
| 54 var args = parser.parse(new Options().arguments); | 56 var args = parser.parse(new Options().arguments); |
| 55 if (args['help']) { | 57 if (args['help']) { |
| 56 print(parser.getUsage()); | 58 print(parser.getUsage()); |
| 57 } else { | 59 } else { |
| 58 // Pretend we're running test.dart so that TestUtils doesn't get confused | 60 // Pretend we're running test.dart so that TestUtils doesn't get confused |
| 59 // about the "current directory." This is only used if we're trying to run | 61 // about the "current directory." This is only used if we're trying to run |
| 60 // this file independently for local testing. | 62 // this file independently for local testing. |
| 61 TestUtils.testScriptPath = new Path(new Options().script) | 63 TestUtils.testScriptPath = new Path(new Options().script) |
| 62 .directoryPath | 64 .directoryPath |
| 63 .join(new Path('../../test.dart')) | 65 .join(new Path('../../test.dart')) |
| 64 .canonicalize() | 66 .canonicalize() |
| 65 .toNativePath(); | 67 .toNativePath(); |
| 66 var servers = new TestingServers(new Path(args['build-directory'])); | 68 var servers = new TestingServers(new Path(args['build-directory']), |
| 69 args['csp']); | |
| 67 var port = int.parse(args['port']); | 70 var port = int.parse(args['port']); |
| 68 var crossOriginPort = int.parse(args['crossOriginPort']); | 71 var crossOriginPort = int.parse(args['crossOriginPort']); |
| 69 servers.startServers(args['network'], | 72 servers.startServers(args['network'], |
| 70 port: port, | 73 port: port, |
| 71 crossOriginPort: crossOriginPort); | 74 crossOriginPort: crossOriginPort); |
| 72 DebugLogger.info('Server listening on port ${servers.port}'); | 75 DebugLogger.info('Server listening on port ${servers.port}'); |
| 73 DebugLogger.info('Server listening on port ${servers.crossOriginPort}'); | 76 DebugLogger.info('Server listening on port ${servers.crossOriginPort}'); |
| 74 } | 77 } |
| 75 } | 78 } |
| 76 | 79 |
| 77 /** | 80 /** |
| 78 * Runs a set of servers that are initialized specifically for the needs of our | 81 * Runs a set of servers that are initialized specifically for the needs of our |
| 79 * test framework, such as dealing with package-root. | 82 * test framework, such as dealing with package-root. |
| 80 */ | 83 */ |
| 81 class TestingServers { | 84 class TestingServers { |
| 82 List _serverList = []; | 85 List _serverList = []; |
| 83 Path _buildDirectory = null; | 86 Path _buildDirectory = null; |
| 87 final bool useContentSecurityPolicy; | |
| 84 | 88 |
| 85 TestingServers(Path buildDirectory) { | 89 TestingServers(Path buildDirectory, this.useContentSecurityPolicy) { |
| 86 _buildDirectory = TestUtils.absolutePath(buildDirectory); | 90 _buildDirectory = TestUtils.absolutePath(buildDirectory); |
| 87 } | 91 } |
| 88 | 92 |
| 89 int get port => _serverList[0].port; | 93 int get port => _serverList[0].port; |
| 90 int get crossOriginPort => _serverList[1].port; | 94 int get crossOriginPort => _serverList[1].port; |
| 91 | 95 |
| 92 /** | 96 /** |
| 93 * [startServers] will start two Http servers. | 97 * [startServers] will start two Http servers. |
| 94 * The first server listens on [port] and sets | 98 * The first server listens on [port] and sets |
| 95 * "Access-Control-Allow-Origin: *" | 99 * "Access-Control-Allow-Origin: *" |
| 96 * The second server listens on [crossOriginPort] and sets | 100 * The second server listens on [crossOriginPort] and sets |
| 97 * "Access-Control-Allow-Origin: client:port1 | 101 * "Access-Control-Allow-Origin: client:port1 |
| 98 * "Access-Control-Allow-Credentials: true" | 102 * "Access-Control-Allow-Credentials: true" |
| 99 */ | 103 */ |
| 100 void startServers(String host, {int port: 0, int crossOriginPort: 0}) { | 104 void startServers(String host, {int port: 0, int crossOriginPort: 0}) { |
| 101 _startHttpServer(host, port: port); | 105 _startHttpServer(host, port: port); |
| 102 _startHttpServer(host, | 106 _startHttpServer(host, |
| 103 port: crossOriginPort, | 107 port: crossOriginPort, |
| 104 allowedPort:_serverList[0].port); | 108 allowedPort:_serverList[0].port); |
| 105 } | 109 } |
| 106 | 110 |
| 107 String httpServerCommandline() { | 111 String httpServerCommandline() { |
| 108 var dart = TestUtils.dartTestExecutable.toNativePath(); | 112 var dart = TestUtils.dartTestExecutable.toNativePath(); |
| 109 var dartDir = TestUtils.dartDir(); | 113 var dartDir = TestUtils.dartDir(); |
| 110 var script = dartDir.join(new Path("tools/testing/dart/http_server.dart")); | 114 var script = dartDir.join(new Path("tools/testing/dart/http_server.dart")); |
| 111 var buildDirectory = _buildDirectory.toNativePath(); | 115 var buildDirectory = _buildDirectory.toNativePath(); |
| 116 var csp = useContentSecurityPolicy ? '--csp ' : ''; | |
| 112 | 117 |
| 113 return '$dart $script -p $port -c $crossOriginPort ' | 118 return '$dart $script -p $port -c $crossOriginPort $csp' |
| 114 '--build-directory=$buildDirectory'; | 119 '--build-directory=$buildDirectory'; |
| 115 } | 120 } |
| 116 | 121 |
| 117 void stopServers() { | 122 void stopServers() { |
| 118 for (var server in _serverList) { | 123 for (var server in _serverList) { |
| 119 server.close(); | 124 server.close(); |
| 120 } | 125 } |
| 121 } | 126 } |
| 122 | 127 |
| 123 void _startHttpServer(String host, {int port: 0, int allowedPort: -1}) { | 128 void _startHttpServer(String host, {int port: 0, int allowedPort: -1}) { |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 267 // Allow loading from http://*:$allowedPort in browsers. | 272 // Allow loading from http://*:$allowedPort in browsers. |
| 268 var allowedOrigin = | 273 var allowedOrigin = |
| 269 '${origin.scheme}://${origin.domain}:${allowedPort}'; | 274 '${origin.scheme}://${origin.domain}:${allowedPort}'; |
| 270 response.headers.set("Access-Control-Allow-Origin", allowedOrigin); | 275 response.headers.set("Access-Control-Allow-Origin", allowedOrigin); |
| 271 response.headers.set('Access-Control-Allow-Credentials', 'true'); | 276 response.headers.set('Access-Control-Allow-Credentials', 'true'); |
| 272 } else { | 277 } else { |
| 273 // No allowedPort specified. Allow from anywhere (but cross-origin | 278 // No allowedPort specified. Allow from anywhere (but cross-origin |
| 274 // requests *with credentials* will fail because you can't use "*"). | 279 // requests *with credentials* will fail because you can't use "*"). |
| 275 response.headers.set("Access-Control-Allow-Origin", "*"); | 280 response.headers.set("Access-Control-Allow-Origin", "*"); |
| 276 } | 281 } |
| 282 if (useContentSecurityPolicy) { | |
| 283 // Chrome respects the standardized Content-Security-Policy header, but | |
|
ricow1
2013/02/28 08:36:07
but whereas -> whereas
| |
| 284 // whereas Firefox and IE10 use X-Content-Security-Policy. Safari still | |
| 285 // uses the WebKit- prefixed version. | |
| 286 for (var header in ["Content-Security-Policy", | |
| 287 "X-Content-Security-Policy", | |
| 288 "X-WebKit-CSP"]) { | |
| 289 response.headers.set(header, "script-src 'self'; object-src 'self'"); | |
| 290 } | |
| 291 } | |
| 277 if (path.filename.endsWith('.html')) { | 292 if (path.filename.endsWith('.html')) { |
| 278 response.headers.set('Content-Type', 'text/html'); | 293 response.headers.set('Content-Type', 'text/html'); |
| 279 } else if (path.filename.endsWith('.js')) { | 294 } else if (path.filename.endsWith('.js')) { |
| 280 response.headers.set('Content-Type', 'application/javascript'); | 295 response.headers.set('Content-Type', 'application/javascript'); |
| 281 } else if (path.filename.endsWith('.dart')) { | 296 } else if (path.filename.endsWith('.dart')) { |
| 282 response.headers.set('Content-Type', 'application/dart'); | 297 response.headers.set('Content-Type', 'application/dart'); |
| 283 } | 298 } |
| 284 file.openInputStream().pipe(response.outputStream); | 299 file.openInputStream().pipe(response.outputStream); |
| 285 } | 300 } |
| 286 | 301 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 308 class _Entry { | 323 class _Entry { |
| 309 final String name; | 324 final String name; |
| 310 final String displayName; | 325 final String displayName; |
| 311 | 326 |
| 312 _Entry(this.name, this.displayName); | 327 _Entry(this.name, this.displayName); |
| 313 | 328 |
| 314 int compareTo(_Entry other) { | 329 int compareTo(_Entry other) { |
| 315 return name.compareTo(other.name); | 330 return name.compareTo(other.name); |
| 316 } | 331 } |
| 317 } | 332 } |
| OLD | NEW |