]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/commitdiff
server, ui : Add support for HTTP ETags in llama-server (#23701)
authorMarkus Tavenrath <redacted>
Thu, 28 May 2026 10:21:24 +0000 (20:21 +1000)
committerGitHub <redacted>
Thu, 28 May 2026 10:21:24 +0000 (12:21 +0200)
* allow caching of ui elements in llama-server

* use fnv_hash

* Update tools/server/server-http.cpp

etag has to be set always

Co-authored-by: Xuan-Son Nguyen <redacted>
---------

Co-authored-by: Xuan-Son Nguyen <redacted>
tools/server/server-http.cpp
tools/ui/embed.cpp

index c0a9af8f09246858e519ed31f40c0ffa1b96e645..00290b0782d4d24e7ca2795c92b2e890c1cc4d2f 100644 (file)
@@ -318,12 +318,19 @@ bool server_http_context::init(const common_params & params) {
         } else {
 #if defined(LLAMA_UI_HAS_ASSETS)
             auto serve_asset = [](const std::string & name, const char * mime, bool with_isolation_headers) {
-                return [name, mime, with_isolation_headers](const httplib::Request & /*req*/, httplib::Response & res) {
+                return [name, mime, with_isolation_headers](const httplib::Request & req, httplib::Response & res) {
                     const llama_ui_asset * a = llama_ui_find_asset(name.c_str());
                     if (!a) {
                         res.status = 404;
                         return false;
                     }
+                    res.set_header("ETag", a->etag);
+                    // Check If-None-Match for conditional GET (304 Not Modified)
+                    if (const std::string & inm = req.get_header_value("If-None-Match");
+                        !inm.empty() && inm == a->etag) {
+                        res.status = 304;
+                        return false;
+                    }
                     if (with_isolation_headers) {
                         // COEP and COOP headers, required by pyodide (python interpreter)
                         res.set_header("Cross-Origin-Embedder-Policy", "require-corp");
index 41227868e6bc38d400c519d20917c9fdd5f495fd..c88faefa1475b369749b9a4e8c58ee656a1338e4 100644 (file)
@@ -9,6 +9,19 @@
 #include <fstream>
 #include <string>
 #include <vector>
+#include <cstdint>
+
+// Computes FNV-1a hash of the data
+static uint64_t fnv_hash(const uint8_t * data, size_t len) {
+    const uint64_t fnv_prime = 0x100000001b3ULL;
+    uint64_t hash = 0xcbf29ce484222325ULL;
+
+    for (size_t i = 0; i < len; ++i) {
+        hash ^= data[i];
+        hash *= fnv_prime;
+    }
+    return hash;
+}
 
 static bool read_file(const std::string & path, std::vector<unsigned char> & out) {
     std::ifstream f(path, std::ios::binary | std::ios::ate);
@@ -95,6 +108,7 @@ int main(int argc, char ** argv) {
         "    const char *          name;\n"
         "    const unsigned char * data;\n"
         "    size_t                size;\n"
+        "    const char *          etag;\n"
         "};\n\n"
         "const llama_ui_asset * llama_ui_find_asset(const char * name);\n";
 
@@ -110,14 +124,18 @@ int main(int argc, char ** argv) {
             }
             cpp += fmt("static const unsigned char asset_%d_data[] = {", i);
             append_bytes_hex(cpp, bytes);
-            cpp += fmt("};\nstatic const size_t        asset_%d_size = %lu;\n\n",
+            const auto hash = fnv_hash(bytes.data(), bytes.size());
+
+            cpp += fmt("};\nstatic const size_t        asset_%d_size = %lu;\n",
                        i, static_cast<unsigned long>(bytes.size()));
+            cpp += fmt("static const char        asset_%d_etag[] = \"\\\"0x%016lx\\\"\";\n\n",
+                       i, static_cast<unsigned long>(hash));
         }
 
         cpp += "static const llama_ui_asset g_assets[] = {\n";
         for (int i = 0; i < n_assets; i++) {
-            const char * name = argv[3 + i * 2];
-            cpp += fmt("    { \"%s\", asset_%d_data, asset_%d_size },\n", name, i, i);
+            cpp += fmt("    { \"%s\", asset_%d_data, asset_%d_size, asset_%d_etag },\n",
+                       argv[3 + i * 2], i, i, i);
         }
         cpp += "};\n\n";