فهرست منبع

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.
Kenton Varda 8 سال پیش
والد
کامیت
6d934dbd6b
2فایلهای تغییر یافته به همراه42 افزوده شده و 35 حذف شده
  1. 38 35
      etc/sandstorm/server.c++
  2. 4 0
      etc/sandstorm/stage.sh

+ 38 - 35
etc/sandstorm/server.c++

@@ -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;

+ 4 - 0
etc/sandstorm/stage.sh

@@ -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