// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:io'; import 'package:http_server/http_server.dart' as http_server; import 'package:route/server.dart'; import 'package:path/path.dart'; import 'package:http_server/http_server.dart'; /* * This program serves a visualization of a JavaScript source map file generated * by dart2js or pub. * * Usage: dart source_map_viewer.dart . * * The default system browser is started and pointed to the viewer if * available. */ Uri sourceMapFile; void main(List args) { if (args.length != 1) { print('One argument expected; the source map file.'); exit(-1); return; } File mapFile = new File(args[0]); if (!mapFile.existsSync()) { print('Map file not found at ${args[0]}'); exit(-2); return; } sourceMapFile = toUri(mapFile.path); startServer(); } // Sends the content of the file requested in the path parameter. void handleFile(HttpRequest request) { String path = request.uri.queryParameters["path"]; if (path == null) { request.response.close(); return; } // Prevent path traversal and absolute path injection. // Source references in source maps are relative to the map file; there is // no legitimate reason for a /file request to escape the map's directory. if (path.contains('..') || path.startsWith('/') || path.startsWith('file:')) { request.response.statusCode = HttpStatus.FORBIDDEN; request.response.close(); return; } Uri uri = sourceMapFile.resolve(path); new File.fromUri(uri) .openRead() .cast>() .pipe(request.response) .catchError((e) { print("Error: $e"); request.response.close(); }); } // Sends back the name of the source map file. void handleSourceMapFile(HttpRequest request) { request.response.write(basename(sourceMapFile.path)); request.response.close(); } // Starts an HttpServer rooted in [dir] with two special routes, /file and /map. // // /file takes a parameter [path] and serves the content of the specified file // in path relative to [dir] // // /map serves the name of the map file such that its content can be requested // with a /file request as above. void startServer() { String root = fromUri(Platform.script.resolve('../build/web/')); Directory directory = new Directory(root); if (!directory.existsSync()) { print("Directory '$root' does not exist. " "Run 'pub build' to generate the output."); exit(-1); } // Use port 0 to get an ephemeral port. int port = 0; HttpServer.bind(InternetAddress.loopbackIPv4, port).then((server) { port = server.port; print("Source mapping server is running on " "'http://${server.address.address}:$port/'"); Router router = new Router(server) ..serve('/file').listen(handleFile) ..serve('/map').listen(handleSourceMapFile); // Set up default handler. This will serve files from our 'build' // directory. Disable jail root, as packages are local symlinks. VirtualDirectory virDir = new http_server.VirtualDirectory(root) ..jailRoot = false ..allowDirectoryListing = true; virDir.directoryHandler = (dir, request) { // Redirect directory requests to index.html files. Uri indexUri = new Uri.file(dir.path).resolve('display.html'); virDir.serveFile(new File(indexUri.toFilePath()), request); }; // Add an error page handler. virDir.errorPageHandler = (HttpRequest request) { print("Resource not found: ${request.uri.path}"); request.response.statusCode = HttpStatus.NOT_FOUND; request.response.close(); }; // Serve everything not routed elsewhere through the virtual directory. virDir.serve(router.defaultStream); // Start the system' default browser startBrowser('http://${server.address.address}:$port/'); }); } startBrowser(String url) { String command; if (Platform.isWindows) { command = 'cmd.exe /C start'; } else if (Platform.isMacOS) { command = 'open'; } else { String xdg = '/usr/bin/xdg-open'; if (new File(xdg).existsSync()) { command = xdg; } else { command = '/usr/bin/google-chrome'; } } print('Starting browser: ${command} ${url}'); Process.run(command, ['$url']).then((ProcessResult result) { if (result.exitCode != 0) { print(result.stderr); } }); }