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 |