Chromium Code Reviews| Index: pkg/http_server/lib/src/virtual_directory.dart |
| diff --git a/pkg/http_server/lib/src/virtual_directory.dart b/pkg/http_server/lib/src/virtual_directory.dart |
| index 680781e1c501eef310b210944639686fd49e596f..7a4cd422267f9c2646d2750843b522b8f9ea70f9 100644 |
| --- a/pkg/http_server/lib/src/virtual_directory.dart |
| +++ b/pkg/http_server/lib/src/virtual_directory.dart |
| @@ -78,7 +78,7 @@ class _VirtualDirectory implements VirtualDirectory { |
| return; |
| } |
| if (entity is File) { |
| - entity.openRead().pipe(request.response).catchError((_) {}); |
| + _serveFile(entity, request); |
| } else { |
| _serveErrorPage(HttpStatus.NOT_FOUND, request); |
| } |
| @@ -114,6 +114,64 @@ class _VirtualDirectory implements VirtualDirectory { |
| }); |
| } |
| + void _serveFile(File file, HttpRequest request) { |
| + file.lastModified().then((lastModified) { |
| + var response = request.response; |
| + |
| + if (request.headers.ifModifiedSince != null && |
| + !lastModified.isAfter(request.headers.ifModifiedSince)) { |
| + response.statusCode = HttpStatus.NOT_MODIFIED; |
| + response.close(); |
| + return; |
| + } |
| + |
| + response.headers.set(HttpHeaders.LAST_MODIFIED, lastModified); |
| + response.headers.set(HttpHeaders.ACCEPT_RANGES, "bytes"); |
| + |
| + if (request.method == 'HEAD') { |
| + response.close(); |
| + return; |
| + } |
| + |
| + file.length().then((length) { |
| + String range = request.headers.value("range"); |
| + if (range != null) { |
| + // We only support one range, where the standard support several. |
| + Match matches = new RegExp(r"^bytes=(\d*)\-(\d*)$").firstMatch(range); |
| + // If the range header have the right format, handle it. |
| + if (matches != null) { |
| + // Serve sub-range. |
| + int start; |
| + int end; |
| + if (matches[1].isEmpty) { |
| + start = matches[2].isEmpty ? |
| + length : |
| + length - int.parse(matches[2]); |
| + end = length; |
| + } else { |
| + start = int.parse(matches[1]); |
| + end = matches[2].isEmpty ? length : int.parse(matches[2]) + 1; |
| + } |
| + |
| + // Override Content-Length with the actual bytes sent. |
| + response.headers.set(HttpHeaders.CONTENT_LENGTH, end - start); |
| + |
| + // Set 'Partial Content' status code. |
| + response.statusCode = HttpStatus.PARTIAL_CONTENT; |
| + response.headers.set(HttpHeaders.CONTENT_RANGE, |
| + "bytes $start-${end - 1}/$length"); |
| + |
| + // Pipe the 'range' of the file. |
| + file.openRead(start, end).pipe(response).catchError((_) {}); |
| + return; |
| + } |
| + } |
| + |
| + 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
|
| + }, onError: (_) {}); |
| + }, onError: (_) {}); |
| + } |
| + |
| void _serveErrorPage(int error, HttpRequest request) { |
| request.response.statusCode = error; |
| request.response.close(); |