| OLD | NEW |
| 1 // Copyright (c) 2013, 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 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 | 9 |
| 10 import 'dart:convert' show HtmlEscape; | 10 import 'dart:convert' show HtmlEscape; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 /// as the default. This will serve file lib/BAR from the package PAZ. | 55 /// as the default. This will serve file lib/BAR from the package PAZ. |
| 56 /// /ws: This will upgrade the connection to a WebSocket connection and echo | 56 /// /ws: This will upgrade the connection to a WebSocket connection and echo |
| 57 /// all data back to the client. | 57 /// all data back to the client. |
| 58 /// | 58 /// |
| 59 /// In case a path does not refer to a file but rather to a directory, a | 59 /// In case a path does not refer to a file but rather to a directory, a |
| 60 /// directory listing will be displayed. | 60 /// directory listing will be displayed. |
| 61 | 61 |
| 62 const PREFIX_BUILDDIR = 'root_build'; | 62 const PREFIX_BUILDDIR = 'root_build'; |
| 63 const PREFIX_DARTDIR = 'root_dart'; | 63 const PREFIX_DARTDIR = 'root_dart'; |
| 64 | 64 |
| 65 main(List<String> arguments) { | 65 void main(List<String> arguments) { |
| 66 // This script is in [dart]/tools/testing/dart. | 66 // This script is in [dart]/tools/testing/dart. |
| 67 TestUtils.setDartDirUri(Platform.script.resolve('../../..')); | 67 TestUtils.setDartDirUri(Platform.script.resolve('../../..')); |
| 68 /** Convenience method for local testing. */ | 68 /** Convenience method for local testing. */ |
| 69 var parser = new ArgParser(); | 69 var parser = new ArgParser(); |
| 70 parser.addOption('port', | 70 parser.addOption('port', |
| 71 abbr: 'p', | 71 abbr: 'p', |
| 72 help: 'The main server port we wish to respond to requests.', | 72 help: 'The main server port we wish to respond to requests.', |
| 73 defaultsTo: '0'); | 73 defaultsTo: '0'); |
| 74 parser.addOption('crossOriginPort', | 74 parser.addOption('crossOriginPort', |
| 75 abbr: 'c', | 75 abbr: 'c', |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 static final _HARMLESS_REQUEST_PATH_ENDINGS = [ | 114 static final _HARMLESS_REQUEST_PATH_ENDINGS = [ |
| 115 "/apple-touch-icon.png", | 115 "/apple-touch-icon.png", |
| 116 "/apple-touch-icon-precomposed.png", | 116 "/apple-touch-icon-precomposed.png", |
| 117 "/favicon.ico", | 117 "/favicon.ico", |
| 118 "/foo", | 118 "/foo", |
| 119 "/bar", | 119 "/bar", |
| 120 "/NonExistingFile", | 120 "/NonExistingFile", |
| 121 "IntentionallyMissingFile", | 121 "IntentionallyMissingFile", |
| 122 ]; | 122 ]; |
| 123 | 123 |
| 124 List _serverList = []; | 124 final List<HttpServer> _serverList = []; |
| 125 Uri _buildDirectory = null; | 125 Uri _buildDirectory; |
| 126 Uri _dartDirectory = null; | 126 Uri _dartDirectory; |
| 127 Uri _packageRoot; | 127 Uri _packageRoot; |
| 128 Uri _packages; | 128 Uri _packages; |
| 129 final bool useContentSecurityPolicy; | 129 final bool useContentSecurityPolicy; |
| 130 final String runtime; | 130 final String runtime; |
| 131 DispatchingServer _server; | 131 DispatchingServer _server; |
| 132 SyncPackageResolver _resolver; | 132 SyncPackageResolver _resolver; |
| 133 | 133 |
| 134 TestingServers(String buildDirectory, this.useContentSecurityPolicy, | 134 TestingServers(String buildDirectory, this.useContentSecurityPolicy, |
| 135 [String this.runtime = 'none', | 135 [String this.runtime = 'none', |
| 136 String dartDirectory, | 136 String dartDirectory, |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 | 210 |
| 211 void _onError(e) { | 211 void _onError(e) { |
| 212 DebugLogger.error('HttpServer: an error occured', e); | 212 DebugLogger.error('HttpServer: an error occured', e); |
| 213 } | 213 } |
| 214 | 214 |
| 215 Future _startHttpServer(String host, {int port: 0, int allowedPort: -1}) { | 215 Future _startHttpServer(String host, {int port: 0, int allowedPort: -1}) { |
| 216 return HttpServer.bind(host, port).then((HttpServer httpServer) { | 216 return HttpServer.bind(host, port).then((HttpServer httpServer) { |
| 217 var server = new DispatchingServer(httpServer, _onError, _sendNotFound); | 217 var server = new DispatchingServer(httpServer, _onError, _sendNotFound); |
| 218 server.addHandler('/echo', _handleEchoRequest); | 218 server.addHandler('/echo', _handleEchoRequest); |
| 219 server.addHandler('/ws', _handleWebSocketRequest); | 219 server.addHandler('/ws', _handleWebSocketRequest); |
| 220 fileHandler(request) { | 220 fileHandler(HttpRequest request) { |
| 221 _handleFileOrDirectoryRequest(request, allowedPort); | 221 _handleFileOrDirectoryRequest(request, allowedPort); |
| 222 } | 222 } |
| 223 | 223 |
| 224 server.addHandler('/$PREFIX_BUILDDIR', fileHandler); | 224 server.addHandler('/$PREFIX_BUILDDIR', fileHandler); |
| 225 server.addHandler('/$PREFIX_DARTDIR', fileHandler); | 225 server.addHandler('/$PREFIX_DARTDIR', fileHandler); |
| 226 server.addHandler('/packages', fileHandler); | 226 server.addHandler('/packages', fileHandler); |
| 227 _serverList.add(httpServer); | 227 _serverList.add(httpServer); |
| 228 return server; | 228 return server; |
| 229 }); | 229 }); |
| 230 } | 230 } |
| 231 | 231 |
| 232 _handleFileOrDirectoryRequest(HttpRequest request, int allowedPort) async { | 232 Future _handleFileOrDirectoryRequest( |
| 233 HttpRequest request, int allowedPort) async { |
| 233 // Enable browsers to cache file/directory responses. | 234 // Enable browsers to cache file/directory responses. |
| 234 var response = request.response; | 235 var response = request.response; |
| 235 response.headers | 236 response.headers |
| 236 .set("Cache-Control", "max-age=$_CACHE_EXPIRATION_IN_SECONDS"); | 237 .set("Cache-Control", "max-age=$_CACHE_EXPIRATION_IN_SECONDS"); |
| 237 var path = _getFileUriFromRequestUri(request.uri); | 238 var path = _getFileUriFromRequestUri(request.uri); |
| 238 if (path != null) { | 239 if (path != null) { |
| 239 var file = new File.fromUri(path); | 240 var file = new File.fromUri(path); |
| 240 var directory = new Directory.fromUri(path); | 241 var directory = new Directory.fromUri(path); |
| 241 if (await file.exists()) { | 242 if (await file.exists()) { |
| 242 _sendFileContent(request, response, allowedPort, file); | 243 _sendFileContent(request, response, allowedPort, file); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 305 if (pathSegments[0] == PREFIX_BUILDDIR) { | 306 if (pathSegments[0] == PREFIX_BUILDDIR) { |
| 306 return _buildDirectory.resolve(pathSegments.skip(1).join('/')); | 307 return _buildDirectory.resolve(pathSegments.skip(1).join('/')); |
| 307 } | 308 } |
| 308 if (pathSegments[0] == PREFIX_DARTDIR) { | 309 if (pathSegments[0] == PREFIX_DARTDIR) { |
| 309 return _dartDirectory.resolve(pathSegments.skip(1).join('/')); | 310 return _dartDirectory.resolve(pathSegments.skip(1).join('/')); |
| 310 } | 311 } |
| 311 return null; | 312 return null; |
| 312 } | 313 } |
| 313 | 314 |
| 314 Future<List<_Entry>> _listDirectory(Directory directory) { | 315 Future<List<_Entry>> _listDirectory(Directory directory) { |
| 315 var completer = new Completer(); | 316 var completer = new Completer<List<_Entry>>(); |
| 316 var entries = []; | 317 var entries = <_Entry>[]; |
| 317 | 318 |
| 318 directory.list().listen((FileSystemEntity fse) { | 319 directory.list().listen((FileSystemEntity fse) { |
| 319 var segments = fse.uri.pathSegments; | 320 var segments = fse.uri.pathSegments; |
| 320 if (fse is File) { | 321 if (fse is File) { |
| 321 var filename = segments.last; | 322 var filename = segments.last; |
| 322 entries.add(new _Entry(filename, filename)); | 323 entries.add(new _Entry(filename, filename)); |
| 323 } else if (fse is Directory) { | 324 } else if (fse is Directory) { |
| 324 var dirname = segments[segments.length - 2]; | 325 var dirname = segments[segments.length - 2]; |
| 325 entries.add(new _Entry(dirname, '$dirname/')); | 326 entries.add(new _Entry(dirname, '$dirname/')); |
| 326 } | 327 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 360 response.done.catchError((e) { | 361 response.done.catchError((e) { |
| 361 DebugLogger.warning( | 362 DebugLogger.warning( |
| 362 'HttpServer: error while closing the response stream', e); | 363 'HttpServer: error while closing the response stream', e); |
| 363 }); | 364 }); |
| 364 } | 365 } |
| 365 | 366 |
| 366 void _sendFileContent( | 367 void _sendFileContent( |
| 367 HttpRequest request, HttpResponse response, int allowedPort, File file) { | 368 HttpRequest request, HttpResponse response, int allowedPort, File file) { |
| 368 if (allowedPort != -1) { | 369 if (allowedPort != -1) { |
| 369 var headerOrigin = request.headers.value('Origin'); | 370 var headerOrigin = request.headers.value('Origin'); |
| 370 var allowedOrigin; | 371 String allowedOrigin; |
| 371 if (headerOrigin != null) { | 372 if (headerOrigin != null) { |
| 372 var origin = Uri.parse(headerOrigin); | 373 var origin = Uri.parse(headerOrigin); |
| 373 // Allow loading from http://*:$allowedPort in browsers. | 374 // Allow loading from http://*:$allowedPort in browsers. |
| 374 allowedOrigin = '${origin.scheme}://${origin.host}:${allowedPort}'; | 375 allowedOrigin = '${origin.scheme}://${origin.host}:${allowedPort}'; |
| 375 } else { | 376 } else { |
| 376 // IE10 appears to be bugged and is not sending the Origin header | 377 // IE10 appears to be bugged and is not sending the Origin header |
| 377 // when making CORS requests to the same domain but different port. | 378 // when making CORS requests to the same domain but different port. |
| 378 allowedOrigin = '*'; | 379 allowedOrigin = '*'; |
| 379 } | 380 } |
| 380 | 381 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 class _Entry implements Comparable<_Entry> { | 464 class _Entry implements Comparable<_Entry> { |
| 464 final String name; | 465 final String name; |
| 465 final String displayName; | 466 final String displayName; |
| 466 | 467 |
| 467 _Entry(this.name, this.displayName); | 468 _Entry(this.name, this.displayName); |
| 468 | 469 |
| 469 int compareTo(_Entry other) { | 470 int compareTo(_Entry other) { |
| 470 return name.compareTo(other.name); | 471 return name.compareTo(other.name); |
| 471 } | 472 } |
| 472 } | 473 } |
| OLD | NEW |