| OLD | NEW | 
|    1 // Copyright (c) 2015, the Dart project authors.  Please see the AUTHORS file |    1 // Copyright (c) 2015, 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 part of vmservice_io; |    5 part of vmservice_io; | 
|    6  |    6  | 
 |    7 _sanitizeWindowsPath(path) { | 
 |    8   // For Windows we need to massage the paths a bit according to | 
 |    9   // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx | 
 |   10   // | 
 |   11   // Convert | 
 |   12   // C:\one\two\three | 
 |   13   // to | 
 |   14   // /C:/one/two/three | 
 |   15  | 
 |   16   if (_isWindows == false) { | 
 |   17     // Do nothing when not running Windows. | 
 |   18     return path; | 
 |   19   } | 
 |   20  | 
 |   21   var fixedPath = "${path.replaceAll('\\', '/')}"; | 
 |   22  | 
 |   23   if ((path.length > 2) && (path[1] == ':')) { | 
 |   24     // Path begins with a drive letter. | 
 |   25     return '/$fixedPath'; | 
 |   26   } | 
 |   27  | 
 |   28   return fixedPath; | 
 |   29 } | 
 |   30  | 
 |   31 _trimWindowsPath(path) { | 
 |   32   // Convert /X:/ to X:/. | 
 |   33   if (_isWindows == false) { | 
 |   34     // Do nothing when not running Windows. | 
 |   35     return path; | 
 |   36   } | 
 |   37   if (!path.startsWith('/') || (path.length < 3)) { | 
 |   38     return path; | 
 |   39   } | 
 |   40   // Match '/?:'. | 
 |   41   if ((path[0] == '/') && (path[2] == ':')) { | 
 |   42     // Remove leading '/'. | 
 |   43     return path.substring(1); | 
 |   44   } | 
 |   45   return path; | 
 |   46 } | 
 |   47  | 
 |   48 // Ensure we have a trailing slash character. | 
 |   49 _enforceTrailingSlash(uri) { | 
 |   50   if (!uri.endsWith('/')) { | 
 |   51     return '$uri/'; | 
 |   52   } | 
 |   53   return uri; | 
 |   54 } | 
 |   55  | 
 |   56 // State associated with the isolate that is used for loading. | 
 |   57 class IsolateLoaderState extends IsolateEmbedderData { | 
 |   58   IsolateLoaderState(this.isolateId); | 
 |   59  | 
 |   60   final int isolateId; | 
 |   61  | 
 |   62   SendPort sp; | 
 |   63  | 
 |   64   void init(String packageRootFlag, | 
 |   65             String packagesConfigFlag, | 
 |   66             String workingDirectory, | 
 |   67             String rootScript) { | 
 |   68     // _workingDirectory must be set first. | 
 |   69     _workingDirectory = new Uri.directory(workingDirectory); | 
 |   70     if (rootScript != null) { | 
 |   71       _rootScript = Uri.parse(rootScript); | 
 |   72     } | 
 |   73     // If the --package-root flag was passed. | 
 |   74     if (packageRootFlag != null) { | 
 |   75       _setPackageRoot(packageRootFlag); | 
 |   76     } | 
 |   77     // If the --packages flag was passed. | 
 |   78     if (packagesConfigFlag != null) { | 
 |   79       _setPackagesConfig(packagesConfigFlag); | 
 |   80     } | 
 |   81   } | 
 |   82  | 
 |   83   void cleanup() { | 
 |   84     if (_packagesPort != null) { | 
 |   85       _packagesPort.close(); | 
 |   86       _packagesPort = null; | 
 |   87     } | 
 |   88   } | 
 |   89  | 
 |   90   // The working directory when the embedder started. | 
 |   91   Uri _workingDirectory; | 
 |   92  | 
 |   93   // The root script's uri. | 
 |   94   Uri _rootScript; | 
 |   95  | 
 |   96   bool _traceLoading = false; | 
 |   97  | 
 |   98   // Packages are either resolved looking up in a map or resolved from within a | 
 |   99   // package root. | 
 |  100   bool get _packagesReady => (_packageRoot != null) || | 
 |  101                              (_packageMap != null) || | 
 |  102                              (_packageError != null); | 
 |  103  | 
 |  104   // Error string set if there was an error resolving package configuration. | 
 |  105   // For example not finding a .packages file or packages/ directory, malformed | 
 |  106   // .packages file or any other related error. | 
 |  107   String _packageError = null; | 
 |  108  | 
 |  109   // The directory to look in to resolve "package:" scheme URIs. By default it | 
 |  110   // is the 'packages' directory right next to the script. | 
 |  111   Uri _packageRoot = null; | 
 |  112  | 
 |  113   // The map describing how certain package names are mapped to Uris. | 
 |  114   Uri _packageConfig = null; | 
 |  115   Map<String, Uri> _packageMap = null; | 
 |  116  | 
 |  117   _setPackageRoot(String packageRoot) { | 
 |  118     packageRoot = _enforceTrailingSlash(packageRoot); | 
 |  119     if (packageRoot.startsWith('file:') || | 
 |  120         packageRoot.startsWith('http:') || | 
 |  121         packageRoot.startsWith('https:')) { | 
 |  122       _packageRoot = _workingDirectory.resolve(packageRoot); | 
 |  123     } else { | 
 |  124       packageRoot = _sanitizeWindowsPath(packageRoot); | 
 |  125       packageRoot = _trimWindowsPath(packageRoot); | 
 |  126       _packageRoot = _workingDirectory.resolveUri(new Uri.file(packageRoot)); | 
 |  127     } | 
 |  128   } | 
 |  129  | 
 |  130   _setPackagesConfig(String packagesParam) { | 
 |  131     var packagesName = _sanitizeWindowsPath(packagesParam); | 
 |  132     var packagesUri = Uri.parse(packagesName); | 
 |  133     if (packagesUri.scheme == '') { | 
 |  134       // Script does not have a scheme, assume that it is a path, | 
 |  135       // resolve it against the working directory. | 
 |  136       packagesUri = _workingDirectory.resolveUri(packagesUri); | 
 |  137     } | 
 |  138     _requestPackagesMap(packagesUri); | 
 |  139     _pendingPackageLoads.add(() { | 
 |  140       // Dummy action. | 
 |  141     }); | 
 |  142   } | 
 |  143  | 
 |  144   // Handling of access to the package root or package map from user code. | 
 |  145   _triggerPackageResolution(action) { | 
 |  146     if (_packagesReady) { | 
 |  147       // Packages are ready. Execute the action now. | 
 |  148       action(); | 
 |  149     } else { | 
 |  150       if (_pendingPackageLoads.isEmpty) { | 
 |  151         // Package resolution has not been setup yet, and this is the first | 
 |  152         // request for package resolution & loading. | 
 |  153         _requestPackagesMap(); | 
 |  154       } | 
 |  155       // Register the action for when the package resolution is ready. | 
 |  156       _pendingPackageLoads.add(action); | 
 |  157     } | 
 |  158   } | 
 |  159  | 
 |  160   // A list of callbacks which should be invoked after the package map has been | 
 |  161   // loaded. | 
 |  162   List<Function> _pendingPackageLoads = []; | 
 |  163  | 
 |  164   // Given a uri with a 'package' scheme, return a Uri that is prefixed with | 
 |  165   // the package root. | 
 |  166   Uri _resolvePackageUri(Uri uri) { | 
 |  167     assert(uri.scheme == "package"); | 
 |  168     assert(_packagesReady); | 
 |  169  | 
 |  170     if (!uri.host.isEmpty) { | 
 |  171       var path = '${uri.host}${uri.path}'; | 
 |  172       var right = 'package:$path'; | 
 |  173       var wrong = 'package://$path'; | 
 |  174  | 
 |  175       throw "URIs using the 'package:' scheme should look like " | 
 |  176             "'$right', not '$wrong'."; | 
 |  177     } | 
 |  178  | 
 |  179     if (_traceLoading) { | 
 |  180       _log('Resolving package with uri path: ${uri.path}'); | 
 |  181     } | 
 |  182     var resolvedUri; | 
 |  183     if (_packageError != null) { | 
 |  184       if (_traceLoading) { | 
 |  185         _log("Resolving package with pending resolution error: $_packageError"); | 
 |  186       } | 
 |  187       throw _packageError; | 
 |  188     } else if (_packageRoot != null) { | 
 |  189       resolvedUri = _packageRoot.resolve(uri.path); | 
 |  190     } else { | 
 |  191       var packageName = uri.pathSegments[0]; | 
 |  192       var mapping = _packageMap[packageName]; | 
 |  193       if (_traceLoading) { | 
 |  194         _log("Mapped '$packageName' package to '$mapping'"); | 
 |  195       } | 
 |  196       if (mapping == null) { | 
 |  197         throw "No mapping for '$packageName' package when resolving '$uri'."; | 
 |  198       } | 
 |  199       var path; | 
 |  200       if (uri.path.length > packageName.length) { | 
 |  201         path = uri.path.substring(packageName.length + 1); | 
 |  202       } else { | 
 |  203         // Handle naked package resolution to the default package name: | 
 |  204         // package:foo is equivalent to package:foo/foo.dart | 
 |  205         assert(uri.path.length == packageName.length); | 
 |  206         path = "$packageName.dart"; | 
 |  207       } | 
 |  208       if (_traceLoading) { | 
 |  209         _log("Path to be resolved in package: $path"); | 
 |  210       } | 
 |  211       resolvedUri = mapping.resolve(path); | 
 |  212     } | 
 |  213     if (_traceLoading) { | 
 |  214       _log("Resolved '$uri' to '$resolvedUri'."); | 
 |  215     } | 
 |  216     return resolvedUri; | 
 |  217   } | 
 |  218  | 
 |  219   RawReceivePort _packagesPort; | 
 |  220  | 
 |  221   void _requestPackagesMap([Uri packageConfig]) { | 
 |  222     assert(_packagesPort == null); | 
 |  223     assert(_rootScript != null); | 
 |  224     // Create a port to receive the packages map on. | 
 |  225     _packagesPort = new RawReceivePort(_handlePackagesReply); | 
 |  226     var sp = _packagesPort.sendPort; | 
 |  227  | 
 |  228     if (packageConfig != null) { | 
 |  229       // Explicitly specified .packages path. | 
 |  230       _handlePackagesRequest(sp, | 
 |  231                              _traceLoading, | 
 |  232                              -2, | 
 |  233                              packageConfig); | 
 |  234     } else { | 
 |  235       // Search for .packages or packages/ starting at the root script. | 
 |  236       _handlePackagesRequest(sp, | 
 |  237                              _traceLoading, | 
 |  238                              -1, | 
 |  239                              _rootScript); | 
 |  240     } | 
 |  241  | 
 |  242     if (_traceLoading) { | 
 |  243       _log("Requested packages map for '$_rootScript'."); | 
 |  244     } | 
 |  245   } | 
 |  246  | 
 |  247   void _handlePackagesReply(msg) { | 
 |  248     assert(_packagesPort != null); | 
 |  249     // Make sure to close the _packagePort before any other action. | 
 |  250     _packagesPort.close(); | 
 |  251     _packagesPort = null; | 
 |  252  | 
 |  253     if (_traceLoading) { | 
 |  254       _log("Got packages reply: $msg"); | 
 |  255     } | 
 |  256     if (msg is String) { | 
 |  257       if (_traceLoading) { | 
 |  258         _log("Got failure response on package port: '$msg'"); | 
 |  259       } | 
 |  260       // Remember the error message. | 
 |  261       _packageError = msg; | 
 |  262     } else if (msg is List) { | 
 |  263       if (msg.length == 1) { | 
 |  264         if (_traceLoading) { | 
 |  265           _log("Received package root: '${msg[0]}'"); | 
 |  266         } | 
 |  267         _packageRoot = Uri.parse(msg[0]); | 
 |  268       } else { | 
 |  269         // First entry contains the location of the loaded .packages file. | 
 |  270         assert((msg.length % 2) == 0); | 
 |  271         assert(msg.length >= 2); | 
 |  272         assert(msg[1] == null); | 
 |  273         _packageConfig = Uri.parse(msg[0]); | 
 |  274         _packageMap = new Map<String, Uri>(); | 
 |  275         for (var i = 2; i < msg.length; i+=2) { | 
 |  276           // TODO(iposva): Complain about duplicate entries. | 
 |  277           _packageMap[msg[i]] = Uri.parse(msg[i+1]); | 
 |  278         } | 
 |  279         if (_traceLoading) { | 
 |  280           _log("Setup package map: $_packageMap"); | 
 |  281         } | 
 |  282       } | 
 |  283     } else { | 
 |  284       _packageError = "Bad type of packages reply: ${msg.runtimeType}"; | 
 |  285       if (_traceLoading) { | 
 |  286         _log(_packageError); | 
 |  287       } | 
 |  288     } | 
 |  289  | 
 |  290     // Resolve all pending package loads now that we know how to resolve them. | 
 |  291     while (_pendingPackageLoads.length > 0) { | 
 |  292       // Order does not matter as we queue all of the requests up right now. | 
 |  293       var req = _pendingPackageLoads.removeLast(); | 
 |  294       // Call the registered closure, to handle the delayed action. | 
 |  295       req(); | 
 |  296     } | 
 |  297     // Reset the pending package loads to empty. So that we eventually can | 
 |  298     // finish loading. | 
 |  299     _pendingPackageLoads = []; | 
 |  300   } | 
 |  301  | 
 |  302 } | 
 |  303  | 
|    7 _log(msg) { |  304 _log(msg) { | 
|    8   print("% $msg"); |  305   print("% $msg"); | 
|    9 } |  306 } | 
|   10  |  307  | 
|   11 var _httpClient; |  308 var _httpClient; | 
|   12  |  309  | 
|   13 // Send a response to the requesting isolate. |  310 // Send a response to the requesting isolate. | 
|   14 void _sendResourceResponse(SendPort sp, int id, dynamic data) { |  311 void _sendResourceResponse(SendPort sp, | 
 |  312                            int tag, | 
 |  313                            Uri uri, | 
 |  314                            String libraryUrl, | 
 |  315                            dynamic data) { | 
|   15   assert((data is List<int>) || (data is String)); |  316   assert((data is List<int>) || (data is String)); | 
|   16   var msg = new List(2); |  317   var msg = new List(4); | 
|   17   msg[0] = id; |  318   if (data is String) { | 
|   18   msg[1] = data; |  319     // We encountered an error, flip the sign of the tag to indicate that. | 
 |  320     tag = -tag; | 
 |  321     if (libraryUrl == null) { | 
 |  322       data = 'Could not load "$uri": $data'; | 
 |  323     } else { | 
 |  324       data = 'Could not import "$uri" from "$libraryUrl": $data'; | 
 |  325     } | 
 |  326   } | 
 |  327   msg[0] = tag; | 
 |  328   msg[1] = uri.toString(); | 
 |  329   msg[2] = libraryUrl; | 
 |  330   msg[3] = data; | 
|   19   sp.send(msg); |  331   sp.send(msg); | 
|   20 } |  332 } | 
|   21  |  333  | 
|   22 void _loadHttp(SendPort sp, int id, Uri uri) { |  334 void _loadHttp(SendPort sp, | 
 |  335                int tag, | 
 |  336                Uri uri, | 
 |  337                Uri resolvedUri, | 
 |  338                String libraryUrl) { | 
|   23   if (_httpClient == null) { |  339   if (_httpClient == null) { | 
|   24     _httpClient = new HttpClient()..maxConnectionsPerHost = 6; |  340     _httpClient = new HttpClient()..maxConnectionsPerHost = 6; | 
|   25   } |  341   } | 
|   26   _httpClient.getUrl(uri) |  342   _httpClient.getUrl(resolvedUri) | 
|   27     .then((HttpClientRequest request) => request.close()) |  343     .then((HttpClientRequest request) => request.close()) | 
|   28     .then((HttpClientResponse response) { |  344     .then((HttpClientResponse response) { | 
|   29       var builder = new BytesBuilder(copy: false); |  345       var builder = new BytesBuilder(copy: false); | 
|   30       response.listen( |  346       response.listen( | 
|   31           builder.add, |  347           builder.add, | 
|   32           onDone: () { |  348           onDone: () { | 
|   33             if (response.statusCode != 200) { |  349             if (response.statusCode != 200) { | 
|   34               var msg = "Failure getting $uri:\n" |  350               var msg = "Failure getting $resolvedUri:\n" | 
|   35                         "  ${response.statusCode} ${response.reasonPhrase}"; |  351                         "  ${response.statusCode} ${response.reasonPhrase}"; | 
|   36               _sendResourceResponse(sp, id, msg); |  352               _sendResourceResponse(sp, tag, uri, libraryUrl, msg); | 
|   37             } else { |  353             } else { | 
|   38               _sendResourceResponse(sp, id, builder.takeBytes()); |  354               _sendResourceResponse(sp, tag, uri, libraryUrl, | 
 |  355                                     builder.takeBytes()); | 
|   39             } |  356             } | 
|   40           }, |  357           }, | 
|   41           onError: (e) { |  358           onError: (e) { | 
|   42             _sendResourceResponse(sp, id, e.toString()); |  359             _sendResourceResponse(sp, tag, uri, libraryUrl, e.toString()); | 
|   43           }); |  360           }); | 
|   44     }) |  361     }) | 
|   45     .catchError((e) { |  362     .catchError((e) { | 
|   46       _sendResourceResponse(sp, id, e.toString()); |  363       _sendResourceResponse(sp, tag, uri, libraryUrl, e.toString()); | 
|   47     }); |  364     }); | 
|   48   // It's just here to push an event on the event loop so that we invoke the |  365   // It's just here to push an event on the event loop so that we invoke the | 
|   49   // scheduled microtasks. |  366   // scheduled microtasks. | 
|   50   Timer.run(() {}); |  367   Timer.run(() {}); | 
|   51 } |  368 } | 
|   52  |  369  | 
|   53 void _loadFile(SendPort sp, int id, Uri uri) { |  370 void _loadFile(SendPort sp, | 
|   54   var path = uri.toFilePath(); |  371                int tag, | 
 |  372                Uri uri, | 
 |  373                Uri resolvedUri, | 
 |  374                String libraryUrl) { | 
 |  375   var path = resolvedUri.toFilePath(); | 
|   55   var sourceFile = new File(path); |  376   var sourceFile = new File(path); | 
|   56   sourceFile.readAsBytes().then((data) { |  377   sourceFile.readAsBytes().then((data) { | 
|   57     _sendResourceResponse(sp, id, data); |  378     _sendResourceResponse(sp, tag, uri, libraryUrl, data); | 
|   58   }, |  379   }, | 
|   59   onError: (e) { |  380   onError: (e) { | 
|   60     _sendResourceResponse(sp, id, e.toString()); |  381     _sendResourceResponse(sp, tag, uri, libraryUrl, e.toString()); | 
|   61   }); |  382   }); | 
|   62 } |  383 } | 
|   63  |  384  | 
|   64 void _loadDataUri(SendPort sp, int id, Uri uri) { |  385 void _loadDataUri(SendPort sp, | 
 |  386                   int tag, | 
 |  387                   Uri uri, | 
 |  388                   Uri resolvedUri, | 
 |  389                   String libraryUrl) { | 
|   65   try { |  390   try { | 
|   66     var mime = uri.data.mimeType; |  391     var mime = uri.data.mimeType; | 
|   67     if ((mime != "application/dart") && |  392     if ((mime != "application/dart") && | 
|   68         (mime != "text/plain")) { |  393         (mime != "text/plain")) { | 
|   69       throw "MIME-type must be application/dart or text/plain: $mime given."; |  394       throw "MIME-type must be application/dart or text/plain: $mime given."; | 
|   70     } |  395     } | 
|   71     var charset = uri.data.charset; |  396     var charset = uri.data.charset; | 
|   72     if ((charset != "utf-8") && |  397     if ((charset != "utf-8") && | 
|   73         (charset != "US-ASCII")) { |  398         (charset != "US-ASCII")) { | 
|   74       // The C++ portion of the embedder assumes UTF-8. |  399       // The C++ portion of the embedder assumes UTF-8. | 
|   75       throw "Only utf-8 or US-ASCII encodings are supported: $charset given."; |  400       throw "Only utf-8 or US-ASCII encodings are supported: $charset given."; | 
|   76     } |  401     } | 
|   77     _sendResourceResponse(sp, id, uri.data.contentAsBytes()); |  402     _sendResourceResponse(sp, tag, uri, libraryUrl, uri.data.contentAsBytes()); | 
|   78   } catch (e) { |  403   } catch (e) { | 
|   79     _sendResourceResponse(sp, id, "Invalid data uri ($uri):\n  $e"); |  404     _sendResourceResponse(sp, tag, uri, libraryUrl, | 
 |  405                           "Invalid data uri ($uri):\n  $e"); | 
|   80   } |  406   } | 
|   81 } |  407 } | 
|   82  |  408  | 
|   83 _handleResourceRequest(SendPort sp, bool traceLoading, int id, Uri resource) { |  409 // Loading a package URI needs to first map the package name to a loadable | 
|   84   if (resource.scheme == 'file') { |  410 // URI. | 
|   85     _loadFile(sp, id, resource); |  411 _loadPackage(IsolateLoaderState loaderState, | 
|   86   } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) { |  412              SendPort sp, | 
|   87     _loadHttp(sp, id, resource); |  413              bool traceLoading, | 
|   88   } else if ((resource.scheme == 'data')) { |  414              int tag, | 
|   89     _loadDataUri(sp, id, resource); |  415              Uri uri, | 
 |  416              Uri resolvedUri, | 
 |  417              String libraryUrl) { | 
 |  418   if (loaderState._packagesReady) { | 
 |  419     var resolvedUri; | 
 |  420     try { | 
 |  421       resolvedUri = loaderState._resolvePackageUri(uri); | 
 |  422     } catch (e, s) { | 
 |  423       if (traceLoading) { | 
 |  424         _log("Exception ($e) when resolving package URI: $uri"); | 
 |  425       } | 
 |  426       // Report error. | 
 |  427       _sendResourceResponse(sp, | 
 |  428                             tag, | 
 |  429                             uri, | 
 |  430                             libraryUrl, | 
 |  431                             e.toString()); | 
 |  432       return; | 
 |  433     } | 
 |  434     // Recursively call with the new resolved uri. | 
 |  435     _handleResourceRequest(loaderState, | 
 |  436                            sp, | 
 |  437                            traceLoading, | 
 |  438                            tag, | 
 |  439                            uri, | 
 |  440                            resolvedUri, | 
 |  441                            libraryUrl); | 
|   90   } else { |  442   } else { | 
|   91     _sendResourceResponse(sp, id, |  443     if (loaderState._pendingPackageLoads.isEmpty) { | 
|   92                           'Unknown scheme (${resource.scheme}) for $resource'); |  444       // Package resolution has not been setup yet, and this is the first | 
 |  445       // request for package resolution & loading. | 
 |  446       loaderState._requestPackagesMap(); | 
 |  447     } | 
 |  448     // Register the action of loading this package once the package resolution | 
 |  449     // is ready. | 
 |  450     loaderState._pendingPackageLoads.add(() { | 
 |  451       _handleResourceRequest(loaderState, | 
 |  452                              sp, | 
 |  453                              traceLoading, | 
 |  454                              tag, | 
 |  455                              uri, | 
 |  456                              uri, | 
 |  457                              libraryUrl); | 
 |  458     }); | 
 |  459     if (traceLoading) { | 
 |  460       _log("Pending package load of '$uri': " | 
 |  461            "${loaderState._pendingPackageLoads.length} pending"); | 
 |  462     } | 
|   93   } |  463   } | 
|   94 } |  464 } | 
|   95  |  465  | 
 |  466 // TODO(johnmccutchan): This and most other top level functions in this file | 
 |  467 // should be turned into methods on the IsolateLoaderState class. | 
 |  468 _handleResourceRequest(IsolateLoaderState loaderState, | 
 |  469                        SendPort sp, | 
 |  470                        bool traceLoading, | 
 |  471                        int tag, | 
 |  472                        Uri uri, | 
 |  473                        Uri resolvedUri, | 
 |  474                        String libraryUrl) { | 
 |  475   if (resolvedUri.scheme == 'file') { | 
 |  476     _loadFile(sp, tag, uri, resolvedUri, libraryUrl); | 
 |  477   } else if ((resolvedUri.scheme == 'http') || | 
 |  478              (resolvedUri.scheme == 'https')) { | 
 |  479     _loadHttp(sp, tag, uri, resolvedUri, libraryUrl); | 
 |  480   } else if ((resolvedUri.scheme == 'data')) { | 
 |  481     _loadDataUri(sp, tag, uri, resolvedUri, libraryUrl); | 
 |  482   } else if ((resolvedUri.scheme == 'package')) { | 
 |  483     _loadPackage(loaderState, | 
 |  484                  sp, | 
 |  485                  traceLoading, | 
 |  486                  tag, | 
 |  487                  uri, | 
 |  488                  resolvedUri, | 
 |  489                  libraryUrl); | 
 |  490   } else { | 
 |  491     _sendResourceResponse(sp, tag, | 
 |  492                           uri, | 
 |  493                           libraryUrl, | 
 |  494                           'Unknown scheme (${resolvedUri.scheme}) for ' | 
 |  495                           '$resolvedUri'); | 
 |  496   } | 
 |  497 } | 
|   96  |  498  | 
|   97 // Handling of packages requests. Finding and parsing of .packages file or |  499 // Handling of packages requests. Finding and parsing of .packages file or | 
|   98 // packages/ directories. |  500 // packages/ directories. | 
|   99 const _LF    = 0x0A; |  501 const _LF    = 0x0A; | 
|  100 const _CR    = 0x0D; |  502 const _CR    = 0x0D; | 
|  101 const _SPACE = 0x20; |  503 const _SPACE = 0x20; | 
|  102 const _HASH  = 0x23; |  504 const _HASH  = 0x23; | 
|  103 const _DOT   = 0x2E; |  505 const _DOT   = 0x2E; | 
|  104 const _COLON = 0x3A; |  506 const _COLON = 0x3A; | 
|  105 const _DEL   = 0x7F; |  507 const _DEL   = 0x7F; | 
| (...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  322     } |  724     } | 
|  323     sp.send("Could not resolve a package location for base at $base"); |  725     sp.send("Could not resolve a package location for base at $base"); | 
|  324   } catch (e, s) { |  726   } catch (e, s) { | 
|  325     if (traceLoading) { |  727     if (traceLoading) { | 
|  326       _log("Error loading packages: $e\n$s"); |  728       _log("Error loading packages: $e\n$s"); | 
|  327     } |  729     } | 
|  328     sp.send("Uncaught error ($e) loading packages file."); |  730     sp.send("Uncaught error ($e) loading packages file."); | 
|  329   } |  731   } | 
|  330 } |  732 } | 
|  331  |  733  | 
|  332  |  | 
|  333 Future<bool> _loadHttpPackagesFile(SendPort sp, |  734 Future<bool> _loadHttpPackagesFile(SendPort sp, | 
|  334                                    bool traceLoading, |  735                                    bool traceLoading, | 
|  335                                    Uri resource) async { |  736                                    Uri resource) async { | 
|  336   try { |  737   try { | 
|  337     if (_httpClient == null) { |  738     if (_httpClient == null) { | 
|  338       _httpClient = new HttpClient()..maxConnectionsPerHost = 6; |  739       _httpClient = new HttpClient()..maxConnectionsPerHost = 6; | 
|  339     } |  740     } | 
|  340     if (traceLoading) { |  741     if (traceLoading) { | 
|  341       _log("Fetching packages file from '$resource'."); |  742       _log("Fetching packages file from '$resource'."); | 
|  342     } |  743     } | 
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  379         (charset != "US-ASCII")) { |  780         (charset != "US-ASCII")) { | 
|  380       // The C++ portion of the embedder assumes UTF-8. |  781       // The C++ portion of the embedder assumes UTF-8. | 
|  381       throw "Only utf-8 or US-ASCII encodings are supported: $charset given."; |  782       throw "Only utf-8 or US-ASCII encodings are supported: $charset given."; | 
|  382     } |  783     } | 
|  383     _parsePackagesFile(sp, traceLoading, resource, data.contentAsBytes()); |  784     _parsePackagesFile(sp, traceLoading, resource, data.contentAsBytes()); | 
|  384   } catch (e) { |  785   } catch (e) { | 
|  385     sp.send("Uncaught error ($e) loading packages data."); |  786     sp.send("Uncaught error ($e) loading packages data."); | 
|  386   } |  787   } | 
|  387 } |  788 } | 
|  388  |  789  | 
|  389  |  790 // This code used to exist in a second isolate and so it uses a SendPort to | 
 |  791 // report it's return value. This could be refactored so that it returns it's | 
 |  792 // value and the caller could wait on the future rather than a message on | 
 |  793 // SendPort. | 
|  390 _handlePackagesRequest(SendPort sp, |  794 _handlePackagesRequest(SendPort sp, | 
|  391                        bool traceLoading, |  795                        bool traceLoading, | 
|  392                        int id, |  796                        int tag, | 
|  393                        Uri resource) async { |  797                        Uri resource) async { | 
|  394   try { |  798   try { | 
|  395     if (id == -1) { |  799     if (tag == -1) { | 
|  396       if (resource.scheme == 'file') { |  800       if (resource.scheme == 'file') { | 
|  397         _findPackagesFile(sp, traceLoading, resource); |  801         _findPackagesFile(sp, traceLoading, resource); | 
|  398       } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) { |  802       } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) { | 
|  399         // Try to load the .packages file next to the resource. |  803         // Try to load the .packages file next to the resource. | 
|  400         var packagesUri = resource.resolve(".packages"); |  804         var packagesUri = resource.resolve(".packages"); | 
|  401         var exists = await _loadHttpPackagesFile(sp, traceLoading, packagesUri); |  805         var exists = await _loadHttpPackagesFile(sp, traceLoading, packagesUri); | 
|  402         if (!exists) { |  806         if (!exists) { | 
|  403           // If the loading of the .packages file failed for http/https based |  807           // If the loading of the .packages file failed for http/https based | 
|  404           // scripts then setup the package root. |  808           // scripts then setup the package root. | 
|  405           var packageRoot = resource.resolve('packages/'); |  809           var packageRoot = resource.resolve('packages/'); | 
|  406           sp.send([packageRoot.toString()]); |  810           sp.send([packageRoot.toString()]); | 
|  407         } |  811         } | 
|  408       } else { |  812       } else { | 
|  409         sp.send("Unsupported scheme used to locate .packages file: " |  813         sp.send("Unsupported scheme used to locate .packages file: " | 
|  410                 "'$resource'."); |  814                 "'$resource'."); | 
|  411       } |  815       } | 
|  412     } else if (id == -2) { |  816     } else if (tag == -2) { | 
|  413       if (traceLoading) { |  817       if (traceLoading) { | 
|  414         _log("Handling load of packages map: '$resource'."); |  818         _log("Handling load of packages map: '$resource'."); | 
|  415       } |  819       } | 
|  416       if (resource.scheme == 'file') { |  820       if (resource.scheme == 'file') { | 
|  417         var exists = await new File.fromUri(resource).exists(); |  821         var exists = await new File.fromUri(resource).exists(); | 
|  418         if (exists) { |  822         if (exists) { | 
|  419           _loadPackagesFile(sp, traceLoading, resource); |  823           _loadPackagesFile(sp, traceLoading, resource); | 
|  420         } else { |  824         } else { | 
|  421           sp.send("Packages file '$resource' not found."); |  825           sp.send("Packages file '$resource' not found."); | 
|  422         } |  826         } | 
|  423       } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) { |  827       } else if ((resource.scheme == 'http') || (resource.scheme == 'https')) { | 
|  424         var exists = await _loadHttpPackagesFile(sp, traceLoading, resource); |  828         var exists = await _loadHttpPackagesFile(sp, traceLoading, resource); | 
|  425         if (!exists) { |  829         if (!exists) { | 
|  426           sp.send("Packages file '$resource' not found."); |  830           sp.send("Packages file '$resource' not found."); | 
|  427         } |  831         } | 
|  428       } else if (resource.scheme == 'data') { |  832       } else if (resource.scheme == 'data') { | 
|  429         _loadPackagesData(sp, traceLoading, resource); |  833         _loadPackagesData(sp, traceLoading, resource); | 
|  430       } else { |  834       } else { | 
|  431         sp.send("Unknown scheme (${resource.scheme}) for package file at " |  835         sp.send("Unknown scheme (${resource.scheme}) for package file at " | 
|  432                 "'$resource'."); |  836                 "'$resource'."); | 
|  433       } |  837       } | 
|  434     } else { |  838     } else { | 
|  435       sp.send("Unknown packages request id: $id for '$resource'."); |  839       sp.send("Unknown packages request tag: $tag for '$resource'."); | 
|  436     } |  840     } | 
|  437   } catch (e, s) { |  841   } catch (e, s) { | 
|  438     if (traceLoading) { |  842     if (traceLoading) { | 
|  439       _log("Error handling packages request: $e\n$s"); |  843       _log("Error handling packages request: $e\n$s"); | 
|  440     } |  844     } | 
|  441     sp.send("Uncaught error ($e) handling packages request."); |  845     sp.send("Uncaught error ($e) handling packages request."); | 
|  442   } |  846   } | 
|  443 } |  847 } | 
|  444  |  848  | 
 |  849 // Shutdown all active loaders by sending an error message. | 
 |  850 void shutdownLoaders() { | 
 |  851   String message = 'Service shutdown'; | 
 |  852   if (_httpClient != null) { | 
 |  853     _httpClient.close(force: true); | 
 |  854     _httpClient = null; | 
 |  855   } | 
 |  856   isolateEmbedderData.values.toList().forEach((IsolateLoaderState ils) { | 
 |  857     ils.cleanup(); | 
 |  858     assert(ils.sp != null); | 
 |  859     _sendResourceResponse(ils.sp, 1, null, null, message); | 
 |  860   }); | 
 |  861 } | 
 |  862  | 
 |  863 // See Dart_LibraryTag in dart_api.h | 
 |  864 const _Dart_kCanonicalizeUrl = 0;      // Canonicalize the URL. | 
 |  865 const _Dart_kScriptTag = 1;            // Load the root script. | 
 |  866 const _Dart_kSourceTag = 2;            // Load a part source. | 
 |  867 const _Dart_kImportTag = 3;            // Import a library. | 
 |  868  | 
 |  869 // Extra requests. Keep these in sync between loader.dart and builtin.dart. | 
 |  870 const _Dart_kInitLoader = 4;           // Initialize the loader. | 
 |  871 const _Dart_kResourceLoad = 5;         // Resource class support. | 
 |  872 const _Dart_kGetPackageRootUri = 6;    // Uri of the packages/ directory. | 
 |  873 const _Dart_kGetPackageConfigUri = 7;  // Uri of the .packages file. | 
 |  874 const _Dart_kResolvePackageUri = 8;    // Resolve a package: uri. | 
|  445  |  875  | 
|  446 // External entry point for loader requests. |  876 // External entry point for loader requests. | 
|  447 _processLoadRequest(request) { |  877 _processLoadRequest(request) { | 
|  448   SendPort sp = request[0]; |  878   assert(request is List); | 
|  449   assert(sp != null); |  879   assert(request.length > 4); | 
|  450   bool traceLoading = request[1]; |  880  | 
|  451   assert(traceLoading != null); |  881   // Should we trace loading? | 
|  452   int id = request[2]; |  882   bool traceLoading = request[0]; | 
|  453   assert(id != null); |  883  | 
|  454   String resource = request[3]; |  884   // This is the sending isolate's Dart_GetMainPortId(). | 
|  455   assert(resource != null); |  885   int isolateId = request[1]; | 
|  456   var uri = Uri.parse(resource); |  886  | 
|  457   if (id >= 0) { |  887   // The tag describing the operation. | 
|  458     _handleResourceRequest(sp, traceLoading, id, uri); |  888   int tag = request[2]; | 
|  459   } else { |  889  | 
|  460     _handlePackagesRequest(sp, traceLoading, id, uri); |  890   // The send port to send the response on. | 
 |  891   SendPort sp = request[3]; | 
 |  892  | 
 |  893   // Grab the loader state for the requesting isolate. | 
 |  894   IsolateLoaderState loaderState = isolateEmbedderData[isolateId]; | 
 |  895  | 
 |  896   // We are either about to initialize the loader, or, we already have. | 
 |  897   assert((tag == _Dart_kInitLoader) || (loaderState != null)); | 
 |  898  | 
 |  899   // Handle the request specified in the tag. | 
 |  900   switch (tag) { | 
 |  901     case _Dart_kScriptTag: { | 
 |  902       Uri uri = Uri.parse(request[4]); | 
 |  903       // Remember the root script. | 
 |  904       loaderState._rootScript = uri; | 
 |  905       _handleResourceRequest(loaderState, | 
 |  906                              sp, | 
 |  907                              traceLoading, | 
 |  908                              tag, | 
 |  909                              uri, | 
 |  910                              uri, | 
 |  911                              null); | 
 |  912     } | 
 |  913     break; | 
 |  914     case _Dart_kSourceTag: | 
 |  915     case _Dart_kImportTag: { | 
 |  916       // The url of the file being loaded. | 
 |  917       var uri = Uri.parse(request[4]); | 
 |  918       // The library that is importing/parting the file. | 
 |  919       String libraryUrl = request[5]; | 
 |  920       _handleResourceRequest(loaderState, | 
 |  921                              sp, | 
 |  922                              traceLoading, | 
 |  923                              tag, | 
 |  924                              uri, | 
 |  925                              uri, | 
 |  926                              libraryUrl); | 
 |  927     } | 
 |  928     break; | 
 |  929     case _Dart_kInitLoader: { | 
 |  930       String packageRoot = request[4]; | 
 |  931       String packagesFile = request[5]; | 
 |  932       String workingDirectory = request[6]; | 
 |  933       String rootScript = request[7]; | 
 |  934       if (loaderState == null) { | 
 |  935         loaderState = new IsolateLoaderState(isolateId); | 
 |  936         isolateEmbedderData[isolateId] = loaderState; | 
 |  937         loaderState.init(packageRoot, | 
 |  938                          packagesFile, | 
 |  939                          workingDirectory, | 
 |  940                          rootScript); | 
 |  941       } | 
 |  942       loaderState.sp = sp; | 
 |  943       assert(isolateEmbedderData[isolateId] == loaderState); | 
 |  944     } | 
 |  945     break; | 
 |  946     case _Dart_kResourceLoad: { | 
 |  947       Uri uri = Uri.parse(request[4]); | 
 |  948       _handleResourceRequest(loaderState, | 
 |  949                              sp, | 
 |  950                              traceLoading, | 
 |  951                              tag, | 
 |  952                              uri, | 
 |  953                              uri, | 
 |  954                              null); | 
 |  955     } | 
 |  956     break; | 
 |  957     case _Dart_kGetPackageRootUri: | 
 |  958       loaderState._triggerPackageResolution(() { | 
 |  959         // Respond with the package root (if any) after package resolution. | 
 |  960         sp.send(loaderState._packageRoot); | 
 |  961       }); | 
 |  962     break; | 
 |  963     case _Dart_kGetPackageConfigUri: | 
 |  964       loaderState._triggerPackageResolution(() { | 
 |  965         // Respond with the packages config (if any) after package resolution. | 
 |  966         sp.send(loaderState._packageConfig); | 
 |  967       }); | 
 |  968     break; | 
 |  969     case _Dart_kResolvePackageUri: | 
 |  970       Uri uri = Uri.parse(request[4]); | 
 |  971       loaderState._triggerPackageResolution(() { | 
 |  972         // Respond with the resolved package uri after package resolution. | 
 |  973         Uri resolvedUri; | 
 |  974         try { | 
 |  975           resolvedUri = loaderState._resolvePackageUri(uri); | 
 |  976         } catch (e, s) { | 
 |  977           if (traceLoading) { | 
 |  978             _log("Exception ($e) when resolving package URI: $uri"); | 
 |  979           } | 
 |  980           resolvedUri = null; | 
 |  981         } | 
 |  982         sp.send(resolvedUri); | 
 |  983       }); | 
 |  984     break; | 
 |  985     default: | 
 |  986       _log('Unknown loader request tag=$tag from $isolateId'); | 
|  461   } |  987   } | 
|  462 } |  988 } | 
| OLD | NEW |