| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 http_server; | 5 part of http_server; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A [VirtualDirectory] can serve files and directory-listing from a root path, | 8 * A [VirtualDirectory] can serve files and directory-listing from a root path, |
| 9 * to [HttpRequest]s. | 9 * to [HttpRequest]s. |
| 10 * | 10 * |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 70 Function _errorCallback; | 70 Function _errorCallback; |
| 71 Function _dirCallback; | 71 Function _dirCallback; |
| 72 | 72 |
| 73 _VirtualDirectory(this.root); | 73 _VirtualDirectory(this.root); |
| 74 | 74 |
| 75 void serve(Stream<HttpRequest> requests) { | 75 void serve(Stream<HttpRequest> requests) { |
| 76 requests.listen(serveRequest); | 76 requests.listen(serveRequest); |
| 77 } | 77 } |
| 78 | 78 |
| 79 void serveRequest(HttpRequest request) { | 79 void serveRequest(HttpRequest request) { |
| 80 _locateResource(new Path('.'), request.uri.pathSegments.iterator..moveNext()
) | 80 _locateResource('.', request.uri.pathSegments.iterator..moveNext()) |
| 81 .then((entity) { | 81 .then((entity) { |
| 82 if (entity == null) { | 82 if (entity == null) { |
| 83 _serveErrorPage(HttpStatus.NOT_FOUND, request); | 83 _serveErrorPage(HttpStatus.NOT_FOUND, request); |
| 84 return; | 84 return; |
| 85 } | 85 } |
| 86 if (entity is File) { | 86 if (entity is File) { |
| 87 _serveFile(entity, request); | 87 _serveFile(entity, request); |
| 88 } else if (entity is Directory) { | 88 } else if (entity is Directory) { |
| 89 _serveDirectory(entity, request); | 89 _serveDirectory(entity, request); |
| 90 } else { | 90 } else { |
| 91 _serveErrorPage(HttpStatus.NOT_FOUND, request); | 91 _serveErrorPage(HttpStatus.NOT_FOUND, request); |
| 92 } | 92 } |
| 93 }); | 93 }); |
| 94 } | 94 } |
| 95 | 95 |
| 96 void setDirectoryHandler(void callback(Directory dir, HttpRequest request)) { | 96 void setDirectoryHandler(void callback(Directory dir, HttpRequest request)) { |
| 97 _dirCallback = callback; | 97 _dirCallback = callback; |
| 98 } | 98 } |
| 99 | 99 |
| 100 void setErrorPageHandler(void callback(HttpRequest request)) { | 100 void setErrorPageHandler(void callback(HttpRequest request)) { |
| 101 _errorCallback = callback; | 101 _errorCallback = callback; |
| 102 } | 102 } |
| 103 | 103 |
| 104 Future<FileSystemEntity> _locateResource(Path path, | 104 Future<FileSystemEntity> _locateResource(String path, |
| 105 Iterator<String> segments) { | 105 Iterator<String> segments) { |
| 106 path = path.canonicalize(); | 106 path = normalize(path); |
| 107 if (path.segments().first == "..") return new Future.value(null); | 107 if (split(path).first == "..") return new Future.value(null); |
| 108 Path fullPath() => new Path(root).join(path); | 108 String fullPath() => join(root, path); |
| 109 return FileSystemEntity.type(fullPath().toNativePath(), followLinks: false) | 109 return FileSystemEntity.type(fullPath(), followLinks: false) |
| 110 .then((type) { | 110 .then((type) { |
| 111 switch (type) { | 111 switch (type) { |
| 112 case FileSystemEntityType.FILE: | 112 case FileSystemEntityType.FILE: |
| 113 if (segments.current == null) { | 113 if (segments.current == null) { |
| 114 return new File.fromPath(fullPath()); | 114 return new File(fullPath()); |
| 115 } | 115 } |
| 116 break; | 116 break; |
| 117 | 117 |
| 118 case FileSystemEntityType.DIRECTORY: | 118 case FileSystemEntityType.DIRECTORY: |
| 119 if (segments.current == null) { | 119 if (segments.current == null) { |
| 120 if (allowDirectoryListing) { | 120 if (allowDirectoryListing) { |
| 121 return new Directory.fromPath(fullPath()); | 121 return new Directory(fullPath()); |
| 122 } | 122 } |
| 123 } else { | 123 } else { |
| 124 if (_invalidPathRegExp.hasMatch(segments.current)) break; | 124 if (_invalidPathRegExp.hasMatch(segments.current)) break; |
| 125 return _locateResource(path.append(segments.current), | 125 return _locateResource(join(path, segments.current), |
| 126 segments..moveNext()); | 126 segments..moveNext()); |
| 127 } | 127 } |
| 128 break; | 128 break; |
| 129 | 129 |
| 130 case FileSystemEntityType.LINK: | 130 case FileSystemEntityType.LINK: |
| 131 if (followLinks) { | 131 if (followLinks) { |
| 132 return new Link.fromPath(fullPath()).target() | 132 return new Link(fullPath()).target() |
| 133 .then((target) { | 133 .then((target) { |
| 134 var targetPath = new Path(target).canonicalize(); | 134 String targetPath = normalize(target); |
| 135 if (targetPath.isAbsolute) return null; | 135 if (isAbsolute(targetPath)) return null; |
| 136 targetPath = path.directoryPath.join(targetPath); | 136 targetPath = join(dirname(path), targetPath); |
| 137 return _locateResource(targetPath, segments); | 137 return _locateResource(targetPath, segments); |
| 138 }); | 138 }); |
| 139 } | 139 } |
| 140 break; | 140 break; |
| 141 } | 141 } |
| 142 // Return `null` on fall-through, to indicate NOT_FOUND. | 142 // Return `null` on fall-through, to indicate NOT_FOUND. |
| 143 return null; | 143 return null; |
| 144 }); | 144 }); |
| 145 } | 145 } |
| 146 | 146 |
| (...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 247 $server | 247 $server |
| 248 </body> | 248 </body> |
| 249 </html> | 249 </html> |
| 250 '''; | 250 '''; |
| 251 | 251 |
| 252 response.write(header); | 252 response.write(header); |
| 253 | 253 |
| 254 void add(String name, String modified, var size) { | 254 void add(String name, String modified, var size) { |
| 255 if (size == null) size = "-"; | 255 if (size == null) size = "-"; |
| 256 if (modified == null) modified = ""; | 256 if (modified == null) modified = ""; |
| 257 var p = new Path(path).append(name).canonicalize().toString(); | 257 var p = normalize(join(path, name)); |
| 258 var entry = | 258 var entry = |
| 259 ''' <tr> | 259 ''' <tr> |
| 260 <td><a href="$p">$name</a></td> | 260 <td><a href="$p">$name</a></td> |
| 261 <td>$modified</td> | 261 <td>$modified</td> |
| 262 <td style="text-align: right">$size</td> | 262 <td style="text-align: right">$size</td> |
| 263 </tr>'''; | 263 </tr>'''; |
| 264 response.write(entry); | 264 response.write(entry); |
| 265 } | 265 } |
| 266 | 266 |
| 267 if (path != '/') { | 267 if (path != '/') { |
| 268 add('../', null, null); | 268 add('../', null, null); |
| 269 } | 269 } |
| 270 | 270 |
| 271 dir.list(followLinks: true).listen((entity) { | 271 dir.list(followLinks: true).listen((entity) { |
| 272 // TODO(ajohnsen): Consider async dir listing. | 272 // TODO(ajohnsen): Consider async dir listing. |
| 273 if (entity is File) { | 273 if (entity is File) { |
| 274 var stat = entity.statSync(); | 274 var stat = entity.statSync(); |
| 275 add(new Path(entity.path).filename, | 275 add(basename(entity.path), |
| 276 stat.modified.toString(), | 276 stat.modified.toString(), |
| 277 stat.size); | 277 stat.size); |
| 278 } else if (entity is Directory) { | 278 } else if (entity is Directory) { |
| 279 add(new Path(entity.path).filename + '/', | 279 add(basename(entity.path) + '/', |
| 280 entity.statSync().modified.toString(), | 280 entity.statSync().modified.toString(), |
| 281 null); | 281 null); |
| 282 } | 282 } |
| 283 }, onError: (e) { | 283 }, onError: (e) { |
| 284 }, onDone: () { | 284 }, onDone: () { |
| 285 response.write(footer); | 285 response.write(footer); |
| 286 response.close(); | 286 response.close(); |
| 287 }); | 287 }); |
| 288 }, onError: (e) => response.close()); | 288 }, onError: (e) => response.close()); |
| 289 } | 289 } |
| (...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 | 366 |
| 367 Future close() => new Future.value(); | 367 Future close() => new Future.value(); |
| 368 | 368 |
| 369 void setMimeType(var bytes) { | 369 void setMimeType(var bytes) { |
| 370 var mimeType = lookupMimeType(path, headerBytes: bytes); | 370 var mimeType = lookupMimeType(path, headerBytes: bytes); |
| 371 if (mimeType != null) { | 371 if (mimeType != null) { |
| 372 response.headers.contentType = ContentType.parse(mimeType); | 372 response.headers.contentType = ContentType.parse(mimeType); |
| 373 } | 373 } |
| 374 } | 374 } |
| 375 } | 375 } |
| OLD | NEW |