Chromium Code Reviews| 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 return _serveErrorPage(HttpStatus.NOT_FOUND, request); | 71 return _serveErrorPage(HttpStatus.NOT_FOUND, request); |
| 72 } | 72 } |
| 73 | 73 |
| 74 _locateResource(new Path(root), path.segments()) | 74 _locateResource(new Path(root), path.segments()) |
| 75 .then((entity) { | 75 .then((entity) { |
| 76 if (entity == null) { | 76 if (entity == null) { |
| 77 _serveErrorPage(HttpStatus.NOT_FOUND, request); | 77 _serveErrorPage(HttpStatus.NOT_FOUND, request); |
| 78 return; | 78 return; |
| 79 } | 79 } |
| 80 if (entity is File) { | 80 if (entity is File) { |
| 81 entity.openRead().pipe(request.response).catchError((_) {}); | 81 _serveFile(entity, request); |
| 82 } else { | 82 } else { |
| 83 _serveErrorPage(HttpStatus.NOT_FOUND, request); | 83 _serveErrorPage(HttpStatus.NOT_FOUND, request); |
| 84 } | 84 } |
| 85 }); | 85 }); |
| 86 } | 86 } |
| 87 | 87 |
| 88 Future<FileSystemEntity> _locateResource(Path path, | 88 Future<FileSystemEntity> _locateResource(Path path, |
| 89 Iterable<String> segments) { | 89 Iterable<String> segments) { |
| 90 return FileSystemEntity.type(path.toNativePath(), followLinks: false) | 90 return FileSystemEntity.type(path.toNativePath(), followLinks: false) |
| 91 .then((type) { | 91 .then((type) { |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 107 if (followLinks) { | 107 if (followLinks) { |
| 108 // TODO | 108 // TODO |
| 109 } | 109 } |
| 110 break; | 110 break; |
| 111 } | 111 } |
| 112 // Return `null` on fall-through, to indicate NOT_FOUND. | 112 // Return `null` on fall-through, to indicate NOT_FOUND. |
| 113 return null; | 113 return null; |
| 114 }); | 114 }); |
| 115 } | 115 } |
| 116 | 116 |
| 117 void _serveFile(File file, HttpRequest request) { | |
| 118 file.lastModified().then((lastModified) { | |
| 119 var response = request.response; | |
| 120 | |
| 121 if (request.headers.ifModifiedSince != null && | |
| 122 !lastModified.isAfter(request.headers.ifModifiedSince)) { | |
| 123 response.statusCode = HttpStatus.NOT_MODIFIED; | |
| 124 response.close(); | |
| 125 return; | |
| 126 } | |
| 127 | |
| 128 response.headers.set(HttpHeaders.LAST_MODIFIED, lastModified); | |
| 129 response.headers.set(HttpHeaders.ACCEPT_RANGES, "bytes"); | |
| 130 | |
| 131 if (request.method == 'HEAD') { | |
| 132 response.close(); | |
| 133 return; | |
| 134 } | |
| 135 | |
| 136 file.length().then((length) { | |
| 137 String range = request.headers.value("range"); | |
| 138 if (range != null) { | |
| 139 // We only support one range, where the standard support several. | |
| 140 Match matches = new RegExp(r"^bytes=(\d*)\-(\d*)$").firstMatch(range); | |
| 141 // If the range header have the right format, handle it. | |
| 142 if (matches != null) { | |
| 143 // Serve sub-range. | |
| 144 int start; | |
| 145 int end; | |
| 146 if (matches[1].isEmpty) { | |
| 147 start = matches[2].isEmpty ? | |
| 148 length : | |
| 149 length - int.parse(matches[2]); | |
| 150 end = length; | |
| 151 } else { | |
| 152 start = int.parse(matches[1]); | |
| 153 end = matches[2].isEmpty ? length : int.parse(matches[2]) + 1; | |
| 154 } | |
| 155 | |
| 156 // Override Content-Length with the actual bytes sent. | |
| 157 response.headers.set(HttpHeaders.CONTENT_LENGTH, end - start); | |
| 158 | |
| 159 // Set 'Partial Content' status code. | |
| 160 response.statusCode = HttpStatus.PARTIAL_CONTENT; | |
| 161 response.headers.set(HttpHeaders.CONTENT_RANGE, | |
| 162 "bytes $start-${end - 1}/$length"); | |
| 163 | |
| 164 // Pipe the 'range' of the file. | |
| 165 file.openRead(start, end).pipe(response).catchError((_) {}); | |
| 166 return; | |
| 167 } | |
| 168 } | |
| 169 | |
| 170 file.openRead().pipe(response).catchError((_) {}); | |
|
Søren Gjesse
2013/06/24 08:17:24
I don't think we should just swallow all errors. W
| |
| 171 }, onError: (_) {}); | |
| 172 }, onError: (_) {}); | |
| 173 } | |
| 174 | |
| 117 void _serveErrorPage(int error, HttpRequest request) { | 175 void _serveErrorPage(int error, HttpRequest request) { |
| 118 request.response.statusCode = error; | 176 request.response.statusCode = error; |
| 119 request.response.close(); | 177 request.response.close(); |
| 120 } | 178 } |
| 121 } | 179 } |
| OLD | NEW |