| 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 6dfec5d9124d7644a9e4479edcf331e0833a7754..d82fd992c6e30e6bc287f83b15920e3a49e3646e 100644
|
| --- a/pkg/http_server/lib/src/virtual_directory.dart
|
| +++ b/pkg/http_server/lib/src/virtual_directory.dart
|
| @@ -209,54 +209,73 @@ class VirtualDirectory {
|
| response.headers.set(HttpHeaders.LAST_MODIFIED, lastModified);
|
| response.headers.set(HttpHeaders.ACCEPT_RANGES, "bytes");
|
|
|
| - if (request.method == 'HEAD') {
|
| - response.close();
|
| - return null;
|
| - }
|
| -
|
| return file.length().then((length) {
|
| - String range = request.headers.value("range");
|
| + String range = request.headers.value(HttpHeaders.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) {
|
| + if (matches != null &&
|
| + (matches[1].isNotEmpty || matches[2].isNotEmpty)) {
|
| // Serve sub-range.
|
| - int start;
|
| - int end;
|
| + int start; // First byte position - inclusive.
|
| + int end; // Last byte position - inclusive.
|
| if (matches[1].isEmpty) {
|
| - start = matches[2].isEmpty ?
|
| - length :
|
| - length - int.parse(matches[2]);
|
| - end = length;
|
| + start = length - int.parse(matches[2]);
|
| + if (start < 0) start = 0;
|
| + end = length - 1;
|
| } else {
|
| start = int.parse(matches[1]);
|
| - end = matches[2].isEmpty ? length : int.parse(matches[2]) + 1;
|
| + end = matches[2].isEmpty ? length - 1: int.parse(matches[2]);
|
| }
|
| + // If the range is syntactically invalid the Range header
|
| + // MUST be ignored (RFC 2616 section 14.35.1).
|
| + if (start <= end) {
|
| + if (end >= length) {
|
| + end = length - 1;
|
| + }
|
|
|
| - // Override Content-Length with the actual bytes sent.
|
| - response.headers.set(HttpHeaders.CONTENT_LENGTH, end - start);
|
| + if (start >= length) {
|
| + response
|
| + ..statusCode = HttpStatus.REQUESTED_RANGE_NOT_SATISFIABLE
|
| + ..close();
|
| + return;
|
| + }
|
|
|
| - // Set 'Partial Content' status code.
|
| - response.statusCode = HttpStatus.PARTIAL_CONTENT;
|
| - response.headers.set(HttpHeaders.CONTENT_RANGE,
|
| - "bytes $start-${end - 1}/$length");
|
| + // Override Content-Length with the actual bytes sent.
|
| + response.headers.set(HttpHeaders.CONTENT_LENGTH, end - start + 1);
|
|
|
| - // Pipe the 'range' of the file.
|
| - file.openRead(start, end)
|
| - .pipe(new _VirtualDirectoryFileStream(response, file.path))
|
| - .catchError((_) {
|
| - // TODO(kevmoo): log errors
|
| - });
|
| - return;
|
| + // Set 'Partial Content' status code.
|
| + response
|
| + ..statusCode = HttpStatus.PARTIAL_CONTENT
|
| + ..headers.set(HttpHeaders.CONTENT_RANGE,
|
| + 'bytes $start-$end/$length');
|
| +
|
| + // Pipe the 'range' of the file.
|
| + if (request.method == 'HEAD') {
|
| + response.close();
|
| + } else {
|
| + file.openRead(start, end + 1)
|
| + .pipe(new _VirtualDirectoryFileStream(response, file.path))
|
| + .catchError((_) {
|
| + // TODO(kevmoo): log errors
|
| + });
|
| + }
|
| + return;
|
| + }
|
| }
|
| }
|
|
|
| - file.openRead()
|
| - .pipe(new _VirtualDirectoryFileStream(response, file.path))
|
| - .catchError((_) {
|
| - // TODO(kevmoo): log errors
|
| - });
|
| + response.headers.set(HttpHeaders.CONTENT_LENGTH, length);
|
| + if (request.method == 'HEAD') {
|
| + response.close();
|
| + } else {
|
| + file.openRead()
|
| + .pipe(new _VirtualDirectoryFileStream(response, file.path))
|
| + .catchError((_) {
|
| + // TODO(kevmoo): log errors
|
| + });
|
| + }
|
| });
|
| }).catchError((_) {
|
| response.statusCode = HttpStatus.NOT_FOUND;
|
|
|