Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| 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. | |
| 4 | |
| 5 part of dart._vmservice; | |
| 6 | |
| 7 String _encodeDevFSDisabledError(Message message) { | |
| 8 return encodeRpcError( | |
| 9 message, kFeatureDisabled, | |
| 10 details: "DevFS is not supported by this Dart implementation"); | |
| 11 } | |
| 12 | |
| 13 String _encodeFileSystemAlreadyExistsError(Message message, String fsName) { | |
| 14 return encodeRpcError( | |
| 15 message, kFileSystemAlreadyExists, | |
| 16 details: "${message.method}: file system '${fsName}' already exists"); | |
| 17 } | |
| 18 | |
| 19 String _encodeFileSystemDoesNotExistError(Message message, String fsName) { | |
| 20 return encodeRpcError( | |
| 21 message, kFileSystemDoesNotExist, | |
| 22 details: "${message.method}: file system '${fsName}' does not exist"); | |
| 23 } | |
| 24 | |
| 25 class _FileSystem { | |
| 26 _FileSystem(this.name, this.uri); | |
| 27 | |
| 28 final String name; | |
| 29 final Uri uri; | |
| 30 | |
| 31 Uri resolvePath(String path) { | |
| 32 if (path.startsWith('/')) { | |
| 33 path = path.substring(1); | |
| 34 } | |
| 35 if (path.isEmpty) { | |
| 36 return null; | |
| 37 } | |
| 38 Uri pathUri; | |
| 39 try { | |
| 40 pathUri = Uri.parse(path); | |
| 41 } on FormatException catch(e) { | |
| 42 return null; | |
| 43 } | |
| 44 Uri resolvedUri = uri.resolveUri(pathUri); | |
| 45 if (!resolvedUri.toString().startsWith(uri.toString())) { | |
| 46 // Resolved uri must be within the filesystem's base uri. | |
| 47 return null; | |
| 48 } | |
| 49 return resolvedUri; | |
| 50 } | |
| 51 | |
| 52 Map toMap() { | |
| 53 return { | |
| 54 'type': 'FileSystem', | |
| 55 'name': name, | |
| 56 'uri': uri.toString(), | |
| 57 }; | |
| 58 } | |
| 59 } | |
| 60 | |
| 61 class DevFS { | |
| 62 DevFS(); | |
| 63 | |
| 64 Map<String, _FileSystem> _fsMap = {}; | |
| 65 | |
| 66 final Set _rpcNames = new Set.from([ | |
| 67 '_listDevFS', | |
| 68 '_createDevFS', | |
| 69 '_deleteDevFS', | |
| 70 '_readDevFSFile', | |
| 71 '_writeDevFSFile', | |
| 72 '_writeDevFSFiles', | |
| 73 '_listDevFSFiles', | |
| 74 ]); | |
| 75 | |
| 76 void cleanup() { | |
| 77 var deleteDir = VMServiceEmbedderHooks.deleteDir; | |
| 78 if (deleteDir == null) { | |
| 79 return; | |
| 80 } | |
| 81 var deletions = []; | |
| 82 for (var fs in _fsMap.values) { | |
| 83 deletions.add(deleteDir(fs.uri)); | |
| 84 } | |
| 85 Future.wait(deletions); | |
| 86 _fsMap.clear(); | |
| 87 } | |
| 88 | |
| 89 bool shouldHandleMessage(Message message) { | |
| 90 return _rpcNames.contains(message.method); | |
| 91 } | |
| 92 | |
| 93 Future<String> handleMessage(Message message) async { | |
| 94 switch (message.method) { | |
| 95 case '_listDevFS': | |
| 96 return _listDevFS(message); | |
| 97 case '_createDevFS': | |
| 98 return _createDevFS(message); | |
| 99 case '_deleteDevFS': | |
| 100 return _deleteDevFS(message); | |
| 101 case '_readDevFSFile': | |
| 102 return _readDevFSFile(message); | |
| 103 case '_writeDevFSFile': | |
| 104 return _writeDevFSFile(message); | |
| 105 case '_writeDevFSFiles': | |
| 106 return _writeDevFSFiles(message); | |
| 107 case '_listDevFSFiles': | |
| 108 return _listDevFSFiles(message); | |
| 109 default: | |
| 110 return encodeRpcError( | |
| 111 message, kInternalError, | |
| 112 details: 'Unexpected rpc ${message.method}'); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 Future<String> _listDevFS(Message message) async { | |
| 117 var result = {}; | |
| 118 result['type'] = 'FileSystemList'; | |
| 119 result['fsNames'] = _fsMap.keys.toList(); | |
| 120 return encodeResult(message, result); | |
| 121 } | |
| 122 | |
| 123 Future<String> _createDevFS(Message message) async { | |
| 124 var createTempDir = VMServiceEmbedderHooks.createTempDir; | |
| 125 if (createTempDir == null) { | |
| 126 return _encodeDevFSDisabledError(message); | |
| 127 } | |
| 128 var fsName = message.params['fsName']; | |
| 129 if (fsName == null) { | |
| 130 return encodeMissingParamError(message, 'fsName'); | |
| 131 } | |
| 132 if (fsName is! String) { | |
| 133 return encodeInvalidParamError(message, 'fsName'); | |
| 134 } | |
| 135 var fs = _fsMap[fsName]; | |
| 136 if (fs != null) { | |
| 137 return _encodeFileSystemAlreadyExistsError(message, fsName); | |
| 138 } | |
| 139 var tempDir = await createTempDir(fsName); | |
| 140 fs = new _FileSystem(fsName, tempDir); | |
| 141 _fsMap[fsName] = fs; | |
| 142 return encodeResult(message, fs.toMap()); | |
| 143 } | |
| 144 | |
| 145 Future<String> _deleteDevFS(Message message) async { | |
| 146 var deleteDir = VMServiceEmbedderHooks.deleteDir; | |
| 147 if (deleteDir == null) { | |
| 148 return _encodeDevFSDisabledError(message); | |
| 149 } | |
| 150 var fsName = message.params['fsName']; | |
| 151 if (fsName == null) { | |
| 152 return encodeMissingParamError(message, 'fsName'); | |
| 153 } | |
| 154 if (fsName is! String) { | |
|
Cutch
2016/07/01 21:23:17
(here and elsewhere) the null check above is redun
| |
| 155 return encodeInvalidParamError(message, 'fsName'); | |
| 156 } | |
| 157 var fs = _fsMap.remove(fsName); | |
| 158 if (fs == null) { | |
| 159 return _encodeFileSystemDoesNotExistError(message, fsName); | |
| 160 } | |
| 161 await deleteDir(fs.uri); | |
| 162 return encodeSuccess(message); | |
| 163 } | |
| 164 | |
| 165 Future<String> _readDevFSFile(Message message) async { | |
| 166 var readFile = VMServiceEmbedderHooks.readFile; | |
| 167 if (readFile == null) { | |
| 168 return _encodeDevFSDisabledError(message); | |
| 169 } | |
| 170 var fsName = message.params['fsName']; | |
| 171 if (fsName == null) { | |
| 172 return encodeMissingParamError(message, 'fsName'); | |
| 173 } | |
| 174 if (fsName is! String) { | |
| 175 return encodeInvalidParamError(message, 'fsName'); | |
| 176 } | |
| 177 var fs = _fsMap[fsName]; | |
| 178 if (fs == null) { | |
| 179 return _encodeFileSystemDoesNotExistError(message, fsName); | |
| 180 } | |
| 181 var path = message.params['path']; | |
| 182 if (path == null) { | |
| 183 return encodeMissingParamError(message, 'path'); | |
| 184 } | |
| 185 if (path is! String) { | |
| 186 return encodeInvalidParamError(message, 'path'); | |
| 187 } | |
| 188 Uri uri = fs.resolvePath(path); | |
| 189 if (uri == null) { | |
| 190 return encodeInvalidParamError(message, 'path'); | |
| 191 } | |
| 192 | |
| 193 try { | |
| 194 List<int> bytes = await readFile(uri); | |
| 195 var result = { | |
| 196 'type': 'FSFile', | |
| 197 'fileContents': BASE64.encode(bytes) | |
| 198 }; | |
| 199 return encodeResult(message, result); | |
| 200 } catch (e) { | |
| 201 return encodeRpcError( | |
| 202 message, kFileDoesNotExist, | |
| 203 details: "_readDevFSFile: $e"); | |
| 204 } | |
| 205 } | |
| 206 | |
| 207 Future<String> _writeDevFSFile(Message message) async { | |
| 208 var writeFile = VMServiceEmbedderHooks.writeFile; | |
| 209 if (writeFile == null) { | |
| 210 return _encodeDevFSDisabledError(message); | |
| 211 } | |
| 212 var fsName = message.params['fsName']; | |
| 213 if (fsName == null) { | |
| 214 return encodeMissingParamError(message, 'fsName'); | |
| 215 } | |
| 216 if (fsName is! String) { | |
| 217 return encodeInvalidParamError(message, 'fsName'); | |
| 218 } | |
| 219 var fs = _fsMap[fsName]; | |
| 220 if (fs == null) { | |
| 221 return _encodeFileSystemDoesNotExistError(message, fsName); | |
| 222 } | |
| 223 var path = message.params['path']; | |
| 224 if (path == null) { | |
| 225 return encodeMissingParamError(message, 'path'); | |
| 226 } | |
| 227 if (path is! String) { | |
| 228 return encodeInvalidParamError(message, 'path'); | |
| 229 } | |
| 230 Uri uri = fs.resolvePath(path); | |
| 231 if (uri == null) { | |
| 232 return encodeInvalidParamError(message, 'path'); | |
| 233 } | |
| 234 var fileContents = message.params['fileContents']; | |
| 235 if (fileContents == null) { | |
| 236 return encodeMissingParamError(message, 'fileContents'); | |
| 237 } | |
| 238 if (fileContents is! String) { | |
| 239 return encodeInvalidParamError(message, 'fileContents'); | |
| 240 } | |
| 241 List<int> decodedFileContents = BASE64.decode(fileContents); | |
| 242 | |
| 243 await writeFile(uri, decodedFileContents); | |
| 244 return encodeSuccess(message); | |
| 245 } | |
| 246 | |
| 247 Future<String> _writeDevFSFiles(Message message) async { | |
| 248 var writeFile = VMServiceEmbedderHooks.writeFile; | |
| 249 if (writeFile == null) { | |
| 250 return _encodeDevFSDisabledError(message); | |
| 251 } | |
| 252 var fsName = message.params['fsName']; | |
| 253 if (fsName == null) { | |
| 254 return encodeMissingParamError(message, 'fsName'); | |
| 255 } | |
| 256 if (fsName is! String) { | |
| 257 return encodeInvalidParamError(message, 'fsName'); | |
| 258 } | |
| 259 var fs = _fsMap[fsName]; | |
| 260 if (fs == null) { | |
| 261 return _encodeFileSystemDoesNotExistError(message, fsName); | |
| 262 } | |
| 263 var files = message.params['files']; | |
| 264 if (files == null) { | |
| 265 return encodeMissingParamError(message, 'files'); | |
| 266 } | |
| 267 if (files is! List) { | |
| 268 return encodeInvalidParamError(message, 'files'); | |
| 269 } | |
| 270 var uris = []; | |
| 271 for (int i = 0; i < files.length; i++) { | |
| 272 var fileInfo = files[i]; | |
| 273 if (fileInfo is! List || | |
| 274 fileInfo.length != 2 || | |
| 275 fileInfo[0] is! String || fileInfo[1] is! String) { | |
| 276 return encodeRpcError( | |
| 277 message, kInvalidParams, | |
| 278 details: "${message.method}: invalid 'files' parameter " | |
| 279 "at index ${i}: ${fileInfo}"); | |
| 280 } | |
| 281 var uri = fs.resolvePath(fileInfo[0]); | |
| 282 if (uri == null) { | |
| 283 return encodeRpcError( | |
| 284 message, kInvalidParams, | |
| 285 details: "${message.method}: invalid 'files' parameter " | |
| 286 "at index ${i}: ${fileInfo}"); | |
| 287 } | |
| 288 uris.add(uri); | |
| 289 } | |
| 290 var pendingWrites = []; | |
| 291 for (int i = 0; i < uris.length; i++) { | |
| 292 List<int> decodedFileContents = BASE64.decode(files[i][1]); | |
| 293 pendingWrites.add(writeFile(uris[i], decodedFileContents)); | |
| 294 } | |
| 295 await Future.wait(pendingWrites); | |
| 296 return encodeSuccess(message); | |
| 297 } | |
| 298 | |
| 299 Future<String> _listDevFSFiles(Message message) async { | |
| 300 var listFiles = VMServiceEmbedderHooks.listFiles; | |
| 301 if (listFiles == null) { | |
| 302 return _encodeDevFSDisabledError(message); | |
| 303 } | |
| 304 var fsName = message.params['fsName']; | |
| 305 if (fsName == null) { | |
| 306 return encodeMissingParamError(message, 'fsName'); | |
| 307 } | |
| 308 if (fsName is! String) { | |
| 309 return encodeInvalidParamError(message, 'fsName'); | |
| 310 } | |
| 311 var fs = _fsMap[fsName]; | |
| 312 if (fs == null) { | |
| 313 return _encodeFileSystemDoesNotExistError(message, fsName); | |
| 314 } | |
| 315 var fileList = await listFiles(fs.uri); | |
| 316 var result = { 'type': 'FSFileList', 'files': fileList }; | |
| 317 return encodeResult(message, result); | |
| 318 } | |
| 319 } | |
| OLD | NEW |