From 4ee772b0507ba4755738990963f9625864f7380b Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Fri, 19 Apr 2019 12:10:21 +0200 Subject: [PATCH] adjust to review --- http/vibe/http/fileserver.d | 63 ++++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/http/vibe/http/fileserver.d b/http/vibe/http/fileserver.d index 66ed8e0868..25b7c68177 100644 --- a/http/vibe/http/fileserver.d +++ b/http/vibe/http/fileserver.d @@ -16,12 +16,13 @@ import vibe.inet.mimetypes; import vibe.inet.url; import vibe.internal.interfaceproxy; +import std.algorithm; import std.conv; import std.datetime; import std.digest.md; import std.exception; +import std.range : popFront, empty, drop; import std.string; -import std.algorithm; @safe: @@ -502,7 +503,7 @@ bool handleCache(scope HTTPServerRequest req, scope HTTPServerResponse res, ETag res.headers["Cache-Control"] = cache_control; } } else if (max_age > Duration.zero) { - res.headers["Cache-Control"] = "max-age=" ~ to!string(max_age.total!"seconds"); + res.headers["Cache-Control"] = text("max-age=", max_age.total!"seconds"); } // https://tools.ietf.org/html/rfc7232#section-3.1 @@ -532,8 +533,8 @@ bool handleCache(scope HTTPServerRequest req, scope HTTPServerResponse res, ETag // https://tools.ietf.org/html/rfc7232#section-3.3 string ifModifiedSince = req.headers.get("If-Modified-Since"); if (ifModifiedSince.length) { - const check = lastModifiedString == ifModifiedSince - || last_modified <= parseRFC822DateTimeString(ifModifiedSince); + const check = lastModifiedString == ifModifiedSince || + last_modified <= parseRFC822DateTimeString(ifModifiedSince); if (check) { res.statusCode = HTTPStatus.notModified; res.writeVoidBody(); @@ -572,9 +573,7 @@ struct ETag enforce!ConvException(s.endsWith('"')); if (s.startsWith(`W/"`)) { - ETag ret; - ret.weak = true; - ret.tag = s[3 .. $ - 1]; + ETag ret = { weak: true, tag: s[3 .. $ - 1] }; return ret; } else if (s.startsWith('"')) { ETag ret; @@ -602,30 +601,56 @@ bool cacheMatch(string match, ETag etag, bool allow_weak) return true; } - if (etag.weak && !allow_weak) { + if ((etag.weak && !allow_weak) || !match.length) { return false; } - size_t i = match.indexOf('"'); - while (i != -1) { - size_t end = match.indexOf('"', i + 1); - if (end == -1) { - end = match.length; - } + auto allBytes = match.representation; + + for (auto range = allBytes; !range.empty; range.popFront) + { + auto start = range = range.find('"').drop(1); + range = range.find('"'); + if (range.empty) + break; - const check = match[i + 1 .. end]; - const checkWeak = match[0 .. i].endsWith("W/"); + const check = start[0 .. &range[0] - &start[0]]; + const checkWeak = match[0 .. &start[0] - &allBytes[0]].endsWith(`W/"`); if (allow_weak || !checkWeak) { - if (match[i + 1 .. end] == etag.tag) { + if (check == etag.tag) { return true; } } - if (!match[end + 1 .. $].stripLeft.startsWith(",")) + if (!(cast(string) range).stripLeft.startsWith(",")) break; - i = match.indexOf('"', end + 1); } return false; } + +unittest +{ + // from RFC 7232 Section 2.3.2 + // +--------+--------+-------------------+-----------------+ + // | ETag 1 | ETag 2 | Strong Comparison | Weak Comparison | + // +--------+--------+-------------------+-----------------+ + // | W/"1" | W/"1" | no match | match | + // | W/"1" | W/"2" | no match | no match | + // | W/"1" | "1" | no match | match | + // | "1" | "1" | match | match | + // +--------+--------+-------------------+-----------------+ + + assert(!cacheMatch(`W/"1"`, ETag(true, "1"), false)); + assert( cacheMatch(`W/"1"`, ETag(true, "1"), true)); + + assert(!cacheMatch(`W/"1"`, ETag(true, "2"), false)); + assert(!cacheMatch(`W/"1"`, ETag(true, "2"), true)); + + assert(!cacheMatch(`W/"1"`, ETag(false, "1"), false)); + assert( cacheMatch(`W/"1"`, ETag(false, "1"), true)); + + assert(cacheMatch(`"1"`, ETag(false, "1"), false)); + assert(cacheMatch(`"1"`, ETag(false, "1"), true)); +}