| 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 builtin; | 5 library builtin; |
| 6 import 'dart:io'; | |
| 7 import 'dart:async'; | 6 import 'dart:async'; |
| 8 import 'dart:convert'; | 7 import 'dart:convert'; |
| 8 import 'dart:isolate'; |
| 9 |
| 10 |
| 11 ////////////////////// |
| 12 /* Support for loading within the isolate via dart:io */ |
| 13 import 'dart:io'; |
| 14 |
| 15 // Enable by setting the #define LOAD_VIA_SERVICE_ISOLATE (see dartutils.cc) |
| 16 bool _load_via_service_isolate = false; |
| 17 |
| 18 var _httpClient; |
| 19 void _httpGet(int tag, |
| 20 Uri uri, |
| 21 String libraryUri, |
| 22 loadCallback(List<int> data)) { |
| 23 if (_httpClient == null) { |
| 24 _httpClient = new HttpClient()..maxConnectionsPerHost = 6; |
| 25 } |
| 26 _httpClient.getUrl(uri) |
| 27 .then((HttpClientRequest request) => request.close()) |
| 28 .then((HttpClientResponse response) { |
| 29 var builder = new BytesBuilder(copy: false); |
| 30 response.listen( |
| 31 builder.add, |
| 32 onDone: () { |
| 33 if (response.statusCode != 200) { |
| 34 var msg = 'Failure getting $uri: ' |
| 35 '${response.statusCode} ${response.reasonPhrase}'; |
| 36 _asyncLoadError(tag, uri.toString(), libraryUri, msg); |
| 37 } |
| 38 loadCallback(builder.takeBytes()); |
| 39 }, |
| 40 onError: (error) { |
| 41 _asyncLoadError(tag, uri.toString(), libraryUri, error); |
| 42 }); |
| 43 }) |
| 44 .catchError((error) { |
| 45 _asyncLoadError(tag, uri.toString(), libraryUri, error); |
| 46 }); |
| 47 // TODO(floitsch): remove this line. It's just here to push an event on the |
| 48 // event loop so that we invoke the scheduled microtasks. Also remove the |
| 49 // import of dart:async when this line is not needed anymore. |
| 50 Timer.run(() {}); |
| 51 } |
| 52 |
| 53 |
| 54 void _cleanup() { |
| 55 if (_httpClient != null) { |
| 56 _httpClient.close(); |
| 57 _httpClient = null; |
| 58 } |
| 59 } |
| 60 |
| 61 _loadDataAsyncDartIO(int tag, |
| 62 String uri, |
| 63 String libraryUri, |
| 64 Uri resourceUri) { |
| 65 _startingOneLoadRequest(uri); |
| 66 if ((resourceUri.scheme == 'http') || (resourceUri.scheme == 'https')) { |
| 67 _httpGet(tag, resourceUri, libraryUri, (data) { |
| 68 _loadScript(tag, uri, libraryUri, data); |
| 69 }); |
| 70 } else { |
| 71 var sourceFile = new File(resourceUri.toFilePath()); |
| 72 sourceFile.readAsBytes().then((data) { |
| 73 _loadScript(tag, uri, libraryUri, data); |
| 74 }, |
| 75 onError: (e) { |
| 76 _asyncLoadError(tag, uri, libraryUri, e); |
| 77 }); |
| 78 } |
| 79 } |
| 80 |
| 81 ////////////////////// |
| 82 |
| 83 /* See Dart_LibraryTag in dart_api.h */ |
| 84 const Dart_kScriptTag = null; |
| 85 const Dart_kImportTag = 0; |
| 86 const Dart_kSourceTag = 1; |
| 87 const Dart_kCanonicalizeUrl = 2; |
| 88 |
| 89 // Dart native extension scheme. |
| 90 const _DART_EXT = 'dart-ext:'; |
| 91 |
| 9 // import 'root_library'; happens here from C Code | 92 // import 'root_library'; happens here from C Code |
| 10 | 93 |
| 11 // The root library (aka the script) is imported into this library. The | 94 // The root library (aka the script) is imported into this library. The |
| 12 // standalone embedder uses this to lookup the main entrypoint in the | 95 // standalone embedder uses this to lookup the main entrypoint in the |
| 13 // root library's namespace. | 96 // root library's namespace. |
| 14 Function _getMainClosure() => main; | 97 Function _getMainClosure() => main; |
| 15 | 98 |
| 99 // A port for communicating with the service isolate for I/O. |
| 100 SendPort _loadPort; |
| 101 |
| 102 const _logBuiltin = false; |
| 16 | 103 |
| 17 // Corelib 'print' implementation. | 104 // Corelib 'print' implementation. |
| 18 void _print(arg) { | 105 void _print(arg) { |
| 19 _Logger._printString(arg.toString()); | 106 _Logger._printString(arg.toString()); |
| 20 } | 107 } |
| 21 | 108 |
| 22 | |
| 23 class _Logger { | 109 class _Logger { |
| 24 static void _printString(String s) native "Logger_PrintString"; | 110 static void _printString(String s) native "Logger_PrintString"; |
| 25 } | 111 } |
| 26 | 112 |
| 27 | |
| 28 _getPrintClosure() => _print; | 113 _getPrintClosure() => _print; |
| 29 | 114 |
| 30 const _logBuiltin = false; | 115 _getCurrentDirectoryPath() native "Directory_Current"; |
| 31 | 116 |
| 32 // Corelib 'Uri.base' implementation. | 117 // Corelib 'Uri.base' implementation. |
| 33 Uri _uriBase() { | 118 Uri _uriBase() { |
| 34 return new Uri.file(Directory.current.path + "/"); | 119 return new Uri.file(_getCurrentDirectoryPath() + "/"); |
| 35 } | 120 } |
| 36 | 121 |
| 37 | |
| 38 _getUriBaseClosure() => _uriBase; | 122 _getUriBaseClosure() => _uriBase; |
| 39 | 123 |
| 40 | 124 |
| 41 // Are we running on Windows? | 125 // Are we running on Windows? |
| 42 var _isWindows = false; | 126 var _isWindows; |
| 43 var _workingWindowsDrivePrefix; | 127 var _workingWindowsDrivePrefix; |
| 44 // The current working directory | 128 // The current working directory |
| 45 var _workingDirectoryUri; | 129 var _workingDirectoryUri; |
| 46 // The URI that the entry point script was loaded from. Remembered so that | 130 // The URI that the entry point script was loaded from. Remembered so that |
| 47 // package imports can be resolved relative to it. | 131 // package imports can be resolved relative to it. |
| 48 var _entryPointScript; | 132 var _entryPointScript; |
| 49 // The directory to look in to resolve "package:" scheme URIs. | 133 // The directory to look in to resolve "package:" scheme URIs. |
| 50 var _packageRoot; | 134 var _packageRoot; |
| 51 | 135 |
| 52 | |
| 53 void _setWindows() { | |
| 54 _isWindows = true; | |
| 55 } | |
| 56 | |
| 57 | |
| 58 _sanitizeWindowsPath(path) { | 136 _sanitizeWindowsPath(path) { |
| 59 // For Windows we need to massage the paths a bit according to | 137 // For Windows we need to massage the paths a bit according to |
| 60 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx | 138 // http://blogs.msdn.com/b/ie/archive/2006/12/06/file-uris-in-windows.aspx |
| 61 // | 139 // |
| 62 // Convert | 140 // Convert |
| 63 // C:\one\two\three | 141 // C:\one\two\three |
| 64 // to | 142 // to |
| 65 // /C:/one/two/three | 143 // /C:/one/two/three |
| 66 | 144 |
| 67 if (_isWindows == false) { | 145 if (_isWindows == false) { |
| 68 // Do nothing when not running Windows. | 146 // Do nothing when not running Windows. |
| 69 return path; | 147 return path; |
| 70 } | 148 } |
| 71 | 149 |
| 72 var fixedPath = "${path.replaceAll('\\', '/')}"; | 150 var fixedPath = "${path.replaceAll('\\', '/')}"; |
| 73 | 151 |
| 74 if ((path.length > 2) && (path[1] == ':')) { | 152 if ((path.length > 2) && (path[1] == ':')) { |
| 75 // Path begins with a drive letter. | 153 // Path begins with a drive letter. |
| 76 return '/$fixedPath'; | 154 return '/$fixedPath'; |
| 77 } | 155 } |
| 78 | 156 |
| 79 return fixedPath; | 157 return fixedPath; |
| 80 } | 158 } |
| 81 | 159 |
| 160 _trimWindowsPath(path) { |
| 161 // Convert /X:/ to X:/. |
| 162 if (_isWindows == false) { |
| 163 // Do nothing when not running Windows. |
| 164 return path; |
| 165 } |
| 166 if (!path.startsWith('/') || (path.length < 3)) { |
| 167 return path; |
| 168 } |
| 169 // Match '/?:'. |
| 170 if ((path[0] == '/') && (path[2] == ':')) { |
| 171 // Remove leading '/'. |
| 172 return path.substring(1); |
| 173 } |
| 174 return path; |
| 175 } |
| 82 | 176 |
| 83 _enforceTrailingSlash(uri) { | 177 _enforceTrailingSlash(uri) { |
| 84 // Ensure we have a trailing slash character. | 178 // Ensure we have a trailing slash character. |
| 85 if (!uri.endsWith('/')) { | 179 if (!uri.endsWith('/')) { |
| 86 return '$uri/'; | 180 return '$uri/'; |
| 87 } | 181 } |
| 88 return uri; | 182 return uri; |
| 89 } | 183 } |
| 90 | 184 |
| 91 | 185 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 111 } | 205 } |
| 112 | 206 |
| 113 | 207 |
| 114 _setPackageRoot(String packageRoot) { | 208 _setPackageRoot(String packageRoot) { |
| 115 packageRoot = _enforceTrailingSlash(packageRoot); | 209 packageRoot = _enforceTrailingSlash(packageRoot); |
| 116 if (packageRoot.startsWith('file:') || | 210 if (packageRoot.startsWith('file:') || |
| 117 packageRoot.startsWith('http:') || | 211 packageRoot.startsWith('http:') || |
| 118 packageRoot.startsWith('https:')) { | 212 packageRoot.startsWith('https:')) { |
| 119 _packageRoot = _workingDirectoryUri.resolve(packageRoot); | 213 _packageRoot = _workingDirectoryUri.resolve(packageRoot); |
| 120 } else { | 214 } else { |
| 215 packageRoot = _sanitizeWindowsPath(packageRoot); |
| 216 packageRoot = _trimWindowsPath(packageRoot); |
| 121 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); | 217 _packageRoot = _workingDirectoryUri.resolveUri(new Uri.file(packageRoot)); |
| 122 } | 218 } |
| 123 if (_logBuiltin) { | 219 if (_logBuiltin) { |
| 124 _print('# Package root: $packageRoot -> $_packageRoot'); | 220 _print('# Package root: $packageRoot -> $_packageRoot'); |
| 125 } | 221 } |
| 126 } | 222 } |
| 127 | 223 |
| 128 | 224 |
| 225 // Given a uri with a 'package' scheme, return a Uri that is prefixed with |
| 226 // the package root. |
| 227 Uri _resolvePackageUri(Uri uri) { |
| 228 if (!uri.host.isEmpty) { |
| 229 var path = '${uri.host}${uri.path}'; |
| 230 var right = 'package:$path'; |
| 231 var wrong = 'package://$path'; |
| 232 |
| 233 throw "URIs using the 'package:' scheme should look like " |
| 234 "'$right', not '$wrong'."; |
| 235 } |
| 236 |
| 237 var packageRoot = _packageRoot == null ? |
| 238 _entryPointScript.resolve('packages/') : |
| 239 _packageRoot; |
| 240 return packageRoot.resolve(uri.path); |
| 241 } |
| 242 |
| 243 |
| 244 |
| 129 String _resolveScriptUri(String scriptName) { | 245 String _resolveScriptUri(String scriptName) { |
| 130 if (_workingDirectoryUri == null) { | 246 if (_workingDirectoryUri == null) { |
| 131 throw 'No current working directory set.'; | 247 throw 'No current working directory set.'; |
| 132 } | 248 } |
| 133 scriptName = _sanitizeWindowsPath(scriptName); | 249 scriptName = _sanitizeWindowsPath(scriptName); |
| 134 | 250 |
| 135 var scriptUri = Uri.parse(scriptName); | 251 var scriptUri = Uri.parse(scriptName); |
| 136 if (scriptUri.scheme != '') { | 252 if (scriptUri.scheme != '') { |
| 137 // Script has a scheme, assume that it is fully formed. | 253 // Script has a scheme, assume that it is fully formed. |
| 138 _entryPointScript = scriptUri; | 254 _entryPointScript = scriptUri; |
| 139 } else { | 255 } else { |
| 140 // Script does not have a scheme, assume that it is a path, | 256 // Script does not have a scheme, assume that it is a path, |
| 141 // resolve it against the working directory. | 257 // resolve it against the working directory. |
| 142 _entryPointScript = _workingDirectoryUri.resolve(scriptName); | 258 _entryPointScript = _workingDirectoryUri.resolve(scriptName); |
| 143 } | 259 } |
| 144 if (_logBuiltin) { | 260 if (_logBuiltin) { |
| 145 _print('# Resolved entry point to: $_entryPointScript'); | 261 _print('# Resolved entry point to: $_entryPointScript'); |
| 146 } | 262 } |
| 147 return _entryPointScript.toString(); | 263 return _entryPointScript.toString(); |
| 148 } | 264 } |
| 149 | 265 |
| 150 const _DART_EXT = 'dart-ext:'; | |
| 151 | 266 |
| 267 // Function called by standalone embedder to resolve uris. |
| 152 String _resolveUri(String base, String userString) { | 268 String _resolveUri(String base, String userString) { |
| 153 if (_logBuiltin) { | 269 if (_logBuiltin) { |
| 154 _print('# Resolving: $userString from $base'); | 270 _print('# Resolving: $userString from $base'); |
| 155 } | 271 } |
| 156 var baseUri = Uri.parse(base); | 272 var baseUri = Uri.parse(base); |
| 157 if (userString.startsWith(_DART_EXT)) { | 273 if (userString.startsWith(_DART_EXT)) { |
| 158 var uri = userString.substring(_DART_EXT.length); | 274 var uri = userString.substring(_DART_EXT.length); |
| 159 return '$_DART_EXT${baseUri.resolve(uri)}'; | 275 return '$_DART_EXT${baseUri.resolve(uri)}'; |
| 160 } else { | 276 } else { |
| 161 return baseUri.resolve(userString).toString(); | 277 return baseUri.resolve(userString).toString(); |
| 162 } | 278 } |
| 163 } | 279 } |
| 164 | 280 |
| 165 | 281 Uri _createUri(String userUri) { |
| 166 // Returns either a file path or a URI starting with http[s]:, as a String. | |
| 167 String _filePathFromUri(String userUri) { | |
| 168 var uri = Uri.parse(userUri); | 282 var uri = Uri.parse(userUri); |
| 169 if (_logBuiltin) { | |
| 170 _print('# Getting file path from: $uri'); | |
| 171 } | |
| 172 | |
| 173 var path; | |
| 174 switch (uri.scheme) { | 283 switch (uri.scheme) { |
| 175 case '': | 284 case '': |
| 176 case 'file': | 285 case 'file': |
| 177 return uri.toFilePath(); | |
| 178 case 'package': | |
| 179 return _filePathFromUri(_resolvePackageUri(uri).toString()); | |
| 180 case 'http': | 286 case 'http': |
| 181 case 'https': | 287 case 'https': |
| 182 return uri.toString(); | 288 return uri; |
| 289 case 'package': |
| 290 return _resolvePackageUri(uri); |
| 183 default: | 291 default: |
| 184 // Only handling file, http, and package URIs | 292 // Only handling file, http[s], and package URIs |
| 185 // in standalone binary. | 293 // in standalone binary. |
| 186 if (_logBuiltin) { | 294 if (_logBuiltin) { |
| 187 _print('# Unknown scheme (${uri.scheme}) in $uri.'); | 295 _print('# Unknown scheme (${uri.scheme}) in $uri.'); |
| 188 } | 296 } |
| 189 throw 'Not a known scheme: $uri'; | 297 throw 'Not a known scheme: $uri'; |
| 190 } | 298 } |
| 191 } | 299 } |
| 192 | 300 |
| 193 | |
| 194 Uri _resolvePackageUri(Uri uri) { | |
| 195 if (!uri.host.isEmpty) { | |
| 196 var path = '${uri.host}${uri.path}'; | |
| 197 var right = 'package:$path'; | |
| 198 var wrong = 'package://$path'; | |
| 199 | |
| 200 throw "URIs using the 'package:' scheme should look like " | |
| 201 "'$right', not '$wrong'."; | |
| 202 } | |
| 203 | |
| 204 var packageRoot = _packageRoot == null ? | |
| 205 _entryPointScript.resolve('packages/') : | |
| 206 _packageRoot; | |
| 207 return packageRoot.resolve(uri.path); | |
| 208 } | |
| 209 | |
| 210 | |
| 211 int _numOutstandingLoadRequests = 0; | 301 int _numOutstandingLoadRequests = 0; |
| 212 var _httpClient; | 302 void _finishedOneLoadRequest(String uri) { |
| 213 | |
| 214 void _httpGet(Uri uri, String libraryUri, loadCallback(List<int> data)) { | |
| 215 if (_httpClient == null) { | |
| 216 _httpClient = new HttpClient()..maxConnectionsPerHost = 6; | |
| 217 } | |
| 218 _httpClient.getUrl(uri) | |
| 219 .then((HttpClientRequest request) => request.close()) | |
| 220 .then((HttpClientResponse response) { | |
| 221 var builder = new BytesBuilder(copy: false); | |
| 222 response.listen( | |
| 223 builder.add, | |
| 224 onDone: () { | |
| 225 if (response.statusCode != 200) { | |
| 226 var msg = 'Failure getting $uri: ' | |
| 227 '${response.statusCode} ${response.reasonPhrase}'; | |
| 228 _asyncLoadError(uri.toString(), libraryUri, msg); | |
| 229 } | |
| 230 loadCallback(builder.takeBytes()); | |
| 231 }, | |
| 232 onError: (error) { | |
| 233 _asyncLoadError(uri.toString(), libraryUri, error); | |
| 234 }); | |
| 235 }) | |
| 236 .catchError((error) { | |
| 237 _asyncLoadError(uri.toString(), libraryUri, error); | |
| 238 }); | |
| 239 // TODO(floitsch): remove this line. It's just here to push an event on the | |
| 240 // event loop so that we invoke the scheduled microtasks. Also remove the | |
| 241 // import of dart:async when this line is not needed anymore. | |
| 242 Timer.run(() {}); | |
| 243 } | |
| 244 | |
| 245 | |
| 246 void _signalDoneLoading() native "Builtin_DoneLoading"; | |
| 247 | |
| 248 void _cleanup() { | |
| 249 if (_httpClient != null) { | |
| 250 _httpClient.close(); | |
| 251 _httpClient = null; | |
| 252 } | |
| 253 } | |
| 254 | |
| 255 void _loadScriptCallback(int tag, String uri, String libraryUri, List<int> data) | |
| 256 native "Builtin_LoadScript"; | |
| 257 | |
| 258 void _loadScript(int tag, String uri, String libraryUri, List<int> data) { | |
| 259 // TODO: Currently a compilation error while loading the script is | |
| 260 // fatal for the isolate. _loadScriptCallback() does not return and | |
| 261 // the _numOutstandingLoadRequests counter remains out of sync. | |
| 262 _loadScriptCallback(tag, uri, libraryUri, data); | |
| 263 assert(_numOutstandingLoadRequests > 0); | 303 assert(_numOutstandingLoadRequests > 0); |
| 264 _numOutstandingLoadRequests--; | 304 _numOutstandingLoadRequests--; |
| 265 if (_logBuiltin) { | 305 if (_logBuiltin) { |
| 266 _print("native Builtin_LoadScript($uri) completed, " | 306 _print("Loading of $uri finished, " |
| 267 "${_numOutstandingLoadRequests} requests remaining"); | 307 "${_numOutstandingLoadRequests} requests remaining"); |
| 268 } | 308 } |
| 269 if (_numOutstandingLoadRequests == 0) { | 309 if (_numOutstandingLoadRequests == 0) { |
| 270 _signalDoneLoading(); | 310 _signalDoneLoading(); |
| 271 _cleanup(); | 311 _cleanup(); |
| 272 } | 312 } |
| 273 } | 313 } |
| 274 | 314 |
| 315 void _startingOneLoadRequest(String uri) { |
| 316 assert(_numOutstandingLoadRequests >= 0); |
| 317 _numOutstandingLoadRequests++; |
| 318 if (_logBuiltin) { |
| 319 _print("Loading of $uri started, " |
| 320 "${_numOutstandingLoadRequests} requests outstanding"); |
| 321 } |
| 322 } |
| 275 | 323 |
| 324 class LoadError extends Error { |
| 325 final String message; |
| 326 LoadError(this.message); |
| 327 |
| 328 String toString() => 'Load Error: $message'; |
| 329 } |
| 330 |
| 331 void _signalDoneLoading() native "Builtin_DoneLoading"; |
| 332 void _loadScriptCallback(int tag, String uri, String libraryUri, List<int> data) |
| 333 native "Builtin_LoadScript"; |
| 276 void _asyncLoadErrorCallback(uri, libraryUri, error) | 334 void _asyncLoadErrorCallback(uri, libraryUri, error) |
| 277 native "Builtin_AsyncLoadError"; | 335 native "Builtin_AsyncLoadError"; |
| 278 | 336 |
| 279 void _asyncLoadError(uri, libraryUri, error) { | 337 void _loadScript(int tag, String uri, String libraryUri, List<int> data) { |
| 280 assert(_numOutstandingLoadRequests > 0); | 338 // TODO: Currently a compilation error while loading the script is |
| 339 // fatal for the isolate. _loadScriptCallback() does not return and |
| 340 // the _numOutstandingLoadRequests counter remains out of sync. |
| 341 _loadScriptCallback(tag, uri, libraryUri, data); |
| 342 _finishedOneLoadRequest(uri); |
| 343 } |
| 344 |
| 345 void _asyncLoadError(tag, uri, libraryUri, error) { |
| 281 if (_logBuiltin) { | 346 if (_logBuiltin) { |
| 282 _print("_asyncLoadError($uri), error: $error"); | 347 _print("_asyncLoadError($uri), error: $error"); |
| 283 } | 348 } |
| 284 _numOutstandingLoadRequests--; | 349 if (tag == Dart_kImportTag) { |
| 285 _asyncLoadErrorCallback(uri, libraryUri, error); | 350 // When importing a library, the libraryUri is the imported |
| 286 if (_numOutstandingLoadRequests == 0) { | 351 // uri. |
| 287 _signalDoneLoading(); | 352 libraryUri = uri; |
| 288 _cleanup(); | 353 } |
| 354 _asyncLoadErrorCallback(uri, libraryUri, new LoadError(error)); |
| 355 _finishedOneLoadRequest(uri); |
| 356 } |
| 357 |
| 358 |
| 359 _loadDataAsyncLoadPort(int tag, |
| 360 String uri, |
| 361 String libraryUri, |
| 362 Uri resourceUri) { |
| 363 var receivePort = new ReceivePort(); |
| 364 receivePort.first.then((dataOrError) { |
| 365 if (dataOrError is List<int>) { |
| 366 _loadScript(tag, uri, libraryUri, dataOrError); |
| 367 } else { |
| 368 _asyncLoadError(tag, uri, libraryUri, dataOrError); |
| 369 } |
| 370 }).catchError((e) { |
| 371 _asyncLoadError(tag, uri, libraryUri, e.toString()); |
| 372 }); |
| 373 |
| 374 try { |
| 375 var msg = [receivePort.sendPort, resourceUri.toString()]; |
| 376 _loadPort.send(msg); |
| 377 _startingOneLoadRequest(uri); |
| 378 } catch (e) { |
| 379 if (_logBuiltin) { |
| 380 _print("Exception when communicating with service isolate: $e"); |
| 381 } |
| 382 _asyncLoadError(tag, uri, libraryUri, e.toString()); |
| 383 receivePort.close(); |
| 289 } | 384 } |
| 290 } | 385 } |
| 291 | 386 |
| 387 // Asynchronously loads script data through a http[s] or file uri. |
| 388 _loadDataAsync(int tag, String uri, String libraryUri) { |
| 389 if (tag == Dart_kScriptTag) { |
| 390 uri = _resolveScriptUri(uri); |
| 391 } |
| 292 | 392 |
| 293 // Create a Uri of 'userUri'. If the input uri is a package uri, then the | 393 Uri resourceUri = _createUri(uri); |
| 294 // package uri is resolved. | 394 |
| 295 Uri _createUri(String userUri) { | 395 if (_load_via_service_isolate) { |
| 396 _loadDataAsyncLoadPort(tag, uri, libraryUri, resourceUri); |
| 397 } else { |
| 398 _loadDataAsyncDartIO(tag, uri, libraryUri, resourceUri); |
| 399 } |
| 400 |
| 401 } |
| 402 |
| 403 // Returns either a file path or a URI starting with http[s]:, as a String. |
| 404 String _filePathFromUri(String userUri) { |
| 296 var uri = Uri.parse(userUri); | 405 var uri = Uri.parse(userUri); |
| 297 if (_logBuiltin) { | 406 if (_logBuiltin) { |
| 298 _print('# Creating uri for: $uri'); | 407 _print('# Getting file path from: $uri'); |
| 299 } | 408 } |
| 300 | 409 |
| 410 var path; |
| 301 switch (uri.scheme) { | 411 switch (uri.scheme) { |
| 302 case '': | 412 case '': |
| 303 case 'file': | 413 case 'file': |
| 414 return uri.toFilePath(); |
| 415 case 'package': |
| 416 return _filePathFromUri(_resolvePackageUri(uri).toString()); |
| 304 case 'http': | 417 case 'http': |
| 305 case 'https': | 418 case 'https': |
| 306 return uri; | 419 return uri.toString(); |
| 307 case 'package': | |
| 308 return _resolvePackageUri(uri); | |
| 309 default: | 420 default: |
| 310 // Only handling file, http[s], and package URIs | 421 // Only handling file, http, and package URIs |
| 311 // in standalone binary. | 422 // in standalone binary. |
| 312 if (_logBuiltin) { | 423 if (_logBuiltin) { |
| 313 _print('# Unknown scheme (${uri.scheme}) in $uri.'); | 424 _print('# Unknown scheme (${uri.scheme}) in $uri.'); |
| 314 } | 425 } |
| 315 throw 'Not a known scheme: $uri'; | 426 throw 'Not a known scheme: $uri'; |
| 316 } | 427 } |
| 317 } | 428 } |
| 318 | 429 |
| 430 String _nativeLibraryExtension() native "Builtin_NativeLibraryExtension"; |
| 319 | 431 |
| 320 // Asynchronously loads script data through a http[s] or file uri. | 432 String _platformExtensionFileName(String name) { |
| 321 _loadDataAsync(int tag, String uri, String libraryUri) { | 433 var extension = _nativeLibraryExtension(); |
| 322 if (tag == null) { | 434 |
| 323 uri = _resolveScriptUri(uri); | 435 if (_isWindows) { |
| 324 } | 436 return '$name.$extension'; |
| 325 Uri resourceUri = _createUri(uri); | |
| 326 _numOutstandingLoadRequests++; | |
| 327 if (_logBuiltin) { | |
| 328 _print("_loadDataAsync($uri), " | |
| 329 "${_numOutstandingLoadRequests} requests outstanding"); | |
| 330 } | |
| 331 if ((resourceUri.scheme == 'http') || (resourceUri.scheme == 'https')) { | |
| 332 _httpGet(resourceUri, libraryUri, (data) { | |
| 333 _loadScript(tag, uri, libraryUri, data); | |
| 334 }); | |
| 335 } else { | 437 } else { |
| 336 var sourceFile = new File(resourceUri.toFilePath()); | 438 return 'lib$name.$extension'; |
| 337 sourceFile.readAsBytes().then((data) { | |
| 338 _loadScript(tag, uri, libraryUri, data); | |
| 339 }, | |
| 340 onError: (e) { | |
| 341 _asyncLoadError(uri, libraryUri, e); | |
| 342 }); | |
| 343 } | 439 } |
| 344 } | 440 } |
| 345 | 441 |
| 346 // Returns the directory part, the filename part, and the name | 442 // Returns the directory part, the filename part, and the name |
| 347 // of a native extension URL as a list [directory, filename, name]. | 443 // of a native extension URL as a list [directory, filename, name]. |
| 348 // The directory part is either a file system path or an HTTP(S) URL. | 444 // The directory part is either a file system path or an HTTP(S) URL. |
| 349 // The filename part is the extension name, with the platform-dependent | 445 // The filename part is the extension name, with the platform-dependent |
| 350 // prefixes and extensions added. | 446 // prefixes and extensions added. |
| 351 _extensionPathFromUri(String userUri) { | 447 _extensionPathFromUri(String userUri) { |
| 352 if (!userUri.startsWith(_DART_EXT)) { | 448 if (!userUri.startsWith(_DART_EXT)) { |
| 353 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:'; | 449 throw 'Unexpected internal error: Extension URI $userUri missing dart-ext:'; |
| 354 } | 450 } |
| 355 userUri = userUri.substring(_DART_EXT.length); | 451 userUri = userUri.substring(_DART_EXT.length); |
| 356 | 452 |
| 357 if (userUri.contains('\\')) { | 453 if (userUri.contains('\\')) { |
| 358 throw 'Unexpected internal error: Extension URI $userUri contains \\'; | 454 throw 'Unexpected internal error: Extension URI $userUri contains \\'; |
| 359 } | 455 } |
| 360 | 456 |
| 361 String filename; | 457 |
| 362 String name; | 458 String name; |
| 363 String path; // Will end in '/'. | 459 String path; // Will end in '/'. |
| 364 int index = userUri.lastIndexOf('/'); | 460 int index = userUri.lastIndexOf('/'); |
| 365 if (index == -1) { | 461 if (index == -1) { |
| 366 name = userUri; | 462 name = userUri; |
| 367 path = './'; | 463 path = './'; |
| 368 } else if (index == userUri.length - 1) { | 464 } else if (index == userUri.length - 1) { |
| 369 throw 'Extension name missing in $extensionUri'; | 465 throw 'Extension name missing in $extensionUri'; |
| 370 } else { | 466 } else { |
| 371 name = userUri.substring(index + 1); | 467 name = userUri.substring(index + 1); |
| 372 path = userUri.substring(0, index + 1); | 468 path = userUri.substring(0, index + 1); |
| 373 } | 469 } |
| 374 | 470 |
| 375 path = _filePathFromUri(path); | 471 path = _filePathFromUri(path); |
| 376 | 472 var filename = _platformExtensionFileName(name); |
| 377 if (Platform.isLinux || Platform.isAndroid) { | |
| 378 filename = 'lib$name.so'; | |
| 379 } else if (Platform.isMacOS) { | |
| 380 filename = 'lib$name.dylib'; | |
| 381 } else if (Platform.isWindows) { | |
| 382 filename = '$name.dll'; | |
| 383 } else { | |
| 384 if (_logBuiltin) { | |
| 385 _print('Native extensions not supported on ${Platform.operatingSystem}'); | |
| 386 } | |
| 387 throw 'Native extensions not supported on ${Platform.operatingSystem}'; | |
| 388 } | |
| 389 | 473 |
| 390 return [path, filename, name]; | 474 return [path, filename, name]; |
| 391 } | 475 } |
| OLD | NEW |