From 745ee0fbd055f7539354837a3fcb3a8b2c87cbe7 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sat, 26 Nov 2016 20:30:49 +0100 Subject: [PATCH 1/3] fix #716 --- http/vibe/http/fileserver.d | 51 +++++++++++++++++++++++++++++++++---- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/http/vibe/http/fileserver.d b/http/vibe/http/fileserver.d index e3c4f4806c..5066c1979a 100644 --- a/http/vibe/http/fileserver.d +++ b/http/vibe/http/fileserver.d @@ -13,6 +13,7 @@ import vibe.http.server; import vibe.inet.message; import vibe.inet.mimetypes; import vibe.inet.url; +import vibe.stream.counting; import std.conv; import std.datetime; @@ -311,7 +312,41 @@ private void sendFileImpl(scope HTTPServerRequest req, scope HTTPServerResponse if ("Content-Encoding" in res.headers && isCompressedFormat(mimetype)) res.headers.remove("Content-Encoding"); res.headers["Content-Type"] = mimetype; - res.headers["Content-Length"] = to!string(dirent.size); + res.headers.addField("Accept-Ranges", "bytes"); + ulong rangeStart = 0; + ulong rangeEnd = 0; + auto prange = "Range" in req.headers; + + if (prange) { + auto range = (*prange).chompPrefix("bytes="); + auto s = range.split("-"); + // https://tools.ietf.org/html/rfc7233 + // Range can be in form "-\d", "\d-" or "\d-\d" + if (s[0].length) { + rangeStart = s[0].to!ulong; + rangeEnd = s[1].length ? s[1].to!ulong : dirent.size; + } else if (s[1].length) { + rangeEnd = dirent.size; + auto len = s[1].to!ulong; + if (len >= rangeEnd) + rangeStart = 0; + else + rangeStart = rangeEnd - len; + } else { + throw new HTTPStatusException(HTTPStatus.badRequest); + } + if (rangeEnd > dirent.size) + rangeEnd = dirent.size; + if (rangeStart > rangeEnd) + rangeStart = rangeEnd; + if (rangeEnd) + rangeEnd--; // End is inclusive, so one less than length + // potential integer overflow with rangeEnd - rangeStart == size_t.max is intended. This only happens with empty files, the + 1 will then put it back to 0 + res.headers["Content-Length"] = to!string(rangeEnd - rangeStart + 1); + res.headers["Content-Range"] = "bytes %s-%s/%s".format(rangeStart < rangeEnd ? rangeStart : rangeEnd, rangeEnd, dirent.size); + res.statusCode = HTTPStatus.partialContent; + } else + res.headers["Content-Length"] = dirent.size.to!string; // check for already encoded file if configured string encodedFilepath; @@ -366,8 +401,14 @@ private void sendFileImpl(scope HTTPServerRequest req, scope HTTPServerResponse } scope(exit) fil.close(); - if (pce && !encodedFilepath.length) - res.bodyWriter.write(fil); - else res.writeRawBody(fil); - logTrace("sent file %d, %s!", fil.size, res.headers["Content-Type"]); + if (prange) { + fil.seek(rangeStart); + res.bodyWriter.write(new LimitedInputStream(fil, rangeEnd - rangeStart + 1)); + logTrace("partially sent file %d-%d, %s!", rangeStart, rangeEnd, res.headers["Content-Type"]); + } else { + if (pce && !encodedFilepath.length) + res.bodyWriter.write(fil); + else res.writeRawBody(fil); + logTrace("sent file %d, %s!", fil.size, res.headers["Content-Type"]); + } } From d3971b8bc2b74a2fd97b3ace0f7d8b43a10c7d97 Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 27 Nov 2016 12:07:30 +0100 Subject: [PATCH 2/3] Using write overload instead of LimitedInputStream --- http/vibe/http/fileserver.d | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/http/vibe/http/fileserver.d b/http/vibe/http/fileserver.d index 5066c1979a..396f8d3233 100644 --- a/http/vibe/http/fileserver.d +++ b/http/vibe/http/fileserver.d @@ -13,7 +13,6 @@ import vibe.http.server; import vibe.inet.message; import vibe.inet.mimetypes; import vibe.inet.url; -import vibe.stream.counting; import std.conv; import std.datetime; @@ -403,7 +402,7 @@ private void sendFileImpl(scope HTTPServerRequest req, scope HTTPServerResponse if (prange) { fil.seek(rangeStart); - res.bodyWriter.write(new LimitedInputStream(fil, rangeEnd - rangeStart + 1)); + res.bodyWriter.write(fil, rangeEnd - rangeStart + 1); logTrace("partially sent file %d-%d, %s!", rangeStart, rangeEnd, res.headers["Content-Type"]); } else { if (pce && !encodedFilepath.length) From 85e6ea1cd2b6d09259893408673a0721631bf7ef Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Sun, 27 Nov 2016 14:49:58 +0100 Subject: [PATCH 3/3] Not implemented exception for multiple ranges --- http/vibe/http/fileserver.d | 3 +++ 1 file changed, 3 insertions(+) diff --git a/http/vibe/http/fileserver.d b/http/vibe/http/fileserver.d index 396f8d3233..3afe5ca479 100644 --- a/http/vibe/http/fileserver.d +++ b/http/vibe/http/fileserver.d @@ -18,6 +18,7 @@ import std.conv; import std.datetime; import std.digest.md; import std.string; +import std.algorithm; /** @@ -318,6 +319,8 @@ private void sendFileImpl(scope HTTPServerRequest req, scope HTTPServerResponse if (prange) { auto range = (*prange).chompPrefix("bytes="); + if (range.canFind(',')) + throw new HTTPStatusException(HTTPStatus.notImplemented); auto s = range.split("-"); // https://tools.ietf.org/html/rfc7233 // Range can be in form "-\d", "\d-" or "\d-\d"