Properly support gzipped assets.

This reverts my previous approach and applies a better approach.

My previous approach expected URLs to change to have ".gz" extensions. The new approach keeps the URLs the same but checks if a file exists on-disk that has the same name with the ".gz" extension.
This commit is contained in:
Kenton Varda 2016-11-26 17:13:03 -08:00
parent bb89ca0b83
commit 6d934dbd6b
2 changed files with 42 additions and 35 deletions

View file

@ -291,59 +291,62 @@ private:
}
}
struct ContentType {
kj::StringPtr type;
kj::StringPtr encoding;
ContentType(kj::StringPtr type): type(type), encoding(nullptr) {}
ContentType(const char* type): type(type), encoding(nullptr) {}
ContentType() = default;
};
ContentType inferContentType(kj::StringPtr filename) {
ContentType result;
kj::String scratch;
if (filename.endsWith(".gz")) {
result.encoding = "gzip";
scratch = kj::str(filename.slice(0, filename.size() - 3));
filename = scratch;
}
kj::StringPtr inferContentType(kj::StringPtr filename) {
if (filename.endsWith(".html")) {
result.type = "text/html; charset=UTF-8";
return "text/html; charset=UTF-8";
} else if (filename.endsWith(".js")) {
result.type = "text/javascript; charset=UTF-8";
return "text/javascript; charset=UTF-8";
} else if (filename.endsWith(".css")) {
result.type = "text/css; charset=UTF-8";
return "text/css; charset=UTF-8";
} else if (filename.endsWith(".png")) {
result.type = "image/png";
return "image/png";
} else if (filename.endsWith(".gif")) {
result.type = "image/gif";
return "image/gif";
} else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) {
result.type = "image/jpeg";
return "image/jpeg";
} else if (filename.endsWith(".svg")) {
result.type = "image/svg+xml; charset=UTF-8";
return "image/svg+xml; charset=UTF-8";
} else if (filename.endsWith(".txt")) {
result.type = "text/plain; charset=UTF-8";
return "text/plain; charset=UTF-8";
} else {
result.type = "application/octet-stream";
return "application/octet-stream";
}
return result;
}
kj::Promise<void> readFile(
kj::StringPtr filename, GetContext context, ContentType contentType) {
KJ_IF_MAYBE(fd, tryOpen(filename, O_RDONLY)) {
kj::StringPtr filename, GetContext context, kj::StringPtr contentType) {
// Do we support compression?
bool canGzip = false;
for (auto accept: context.getParams().getContext().getAcceptEncoding()) {
if (accept.getContentCoding() == "gzip") {
canGzip = true;
break;
}
}
// If compression is supported, look for file with .gz extension.
kj::Maybe<kj::AutoCloseFd> maybeFd;
bool isGzipped = false;
if (canGzip) {
maybeFd = tryOpen(kj::str(filename, ".gz"), O_RDONLY);
isGzipped = maybeFd != nullptr;
}
// If we haven't found a suitable file yet, look for the uncompressed version.
if (maybeFd == nullptr) {
maybeFd = tryOpen(filename, O_RDONLY);
}
// Serve it.
KJ_IF_MAYBE(fd, kj::mv(maybeFd)) {
auto size = getFileSize(*fd, filename);
kj::FdInputStream stream(kj::mv(*fd));
auto response = context.getResults(capnp::MessageSize { size / sizeof(capnp::word) + 32, 0 });
auto content = response.initContent();
content.setStatusCode(sandstorm::WebSession::Response::SuccessCode::OK);
content.setMimeType(contentType.type);
if (contentType.encoding != nullptr) {
content.setEncoding(contentType.encoding);
content.setMimeType(contentType);
if (isGzipped) {
content.setEncoding("gzip");
}
stream.read(content.getBody().initBytes(size).begin(), size);
return kj::READY_NOW;

View file

@ -40,6 +40,10 @@ mkdir -p build/.sandstorm/client/styles
cp -rf ../../war/styles/* build/.sandstorm/client/styles/
mkdir -p build/.sandstorm/client/templates
cp -rf ../../war/templates/* build/.sandstorm/client/templates/
echo "Compressing assets"
gfind build/.sandstorm/client -name '*.html' -o -name '*.css' -o -name '*.js' -o -name '*.txt' -o -name '*.xml' | xargs gzip -k
echo "Creating file list"
cd build/.sandstorm
gfind ./client -type f -printf "%p\n" | cut -c 3- > sandstorm-files.list