nginx: if root is in Nix store, use path's hash as ETag

Resolves #25485. Usage example:

$ realpath /var/www
/nix/store/wnrhnnpdj3x50j5xz38zp1qxs1ygwccw-site
$ curl --head localhost
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 28 Sep 2018 06:09:25 GMT
Content-Type: text/html
Content-Length: 50
Last-Modified: Thu, 01 Jan 1970 00:00:01 GMT
Connection: keep-alive
ETag: "wnrhnnpdj3x50j5xz38zp1qxs1ygwccw"
Accept-Ranges: bytes
This commit is contained in:
Yegor Timoshenko 2018-10-13 21:45:25 +00:00 committed by aszlig
parent b050097edf
commit 135d54f535
No known key found for this signature in database
GPG key ID: 684089CE67EBB691
2 changed files with 90 additions and 1 deletions

View file

@ -75,7 +75,9 @@ stdenv.mkDerivation {
preConfigure = (concatMapStringsSep "\n" (mod: mod.preConfigure or "") modules);
patches = stdenv.lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
patches = [
./nix-etag-1.15.4.patch
] ++ stdenv.lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) [
(fetchpatch {
url = "https://raw.githubusercontent.com/openwrt/packages/master/net/nginx/patches/102-sizeof_test_fix.patch";
sha256 = "0i2k30ac8d7inj9l6bl0684kjglam2f68z8lf3xggcc2i5wzhh8a";

View file

@ -0,0 +1,87 @@
From 3ed81ef9e973247d0c95bf240b3bd2e640f2605a Mon Sep 17 00:00:00 2001
From: Yegor Timoshenko <yegortimoshenko@riseup.net>
Date: Fri, 28 Sep 2018 03:27:04 +0000
Subject: [PATCH] If root is in Nix store, set ETag to its path hash
---
src/http/ngx_http_core_module.c | 56 +++++++++++++++++++++++++++------
1 file changed, 47 insertions(+), 9 deletions(-)
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index c57ec00c..d996d7e3 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -1583,6 +1583,7 @@ ngx_http_set_etag(ngx_http_request_t *r)
{
ngx_table_elt_t *etag;
ngx_http_core_loc_conf_t *clcf;
+ u_char *real, *ptr1, *ptr2;
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
@@ -1598,16 +1599,53 @@ ngx_http_set_etag(ngx_http_request_t *r)
etag->hash = 1;
ngx_str_set(&etag->key, "ETag");
- etag->value.data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN + NGX_TIME_T_LEN + 3);
- if (etag->value.data == NULL) {
- etag->hash = 0;
- return NGX_ERROR;
- }
+ real = ngx_realpath(clcf->root.data, NULL);
+
+ #define NIX_STORE_DIR "/nix/store"
+ #define NIX_STORE_LEN ngx_strlen(NIX_STORE_DIR)
+
+ if (!ngx_strncmp(real, NIX_STORE_DIR, NIX_STORE_LEN)
+ && real[NIX_STORE_LEN] == '/'
+ && real[NIX_STORE_LEN + 1] != '\0')
+ {
+ ptr1 = real + NIX_STORE_LEN;
+ *ptr1 = '"';
+
+ ptr2 = (u_char *) ngx_strchr(ptr1, '-');
+
+ if (ptr2 == NULL) {
+ ngx_free(real);
+ etag->hash = 0;
+ return NGX_ERROR;
+ }
+
+ *ptr2++ = '"';
+ *ptr2 = '\0';
- etag->value.len = ngx_sprintf(etag->value.data, "\"%xT-%xO\"",
- r->headers_out.last_modified_time,
- r->headers_out.content_length_n)
- - etag->value.data;
+ etag->value.len = ngx_strlen(ptr1);
+ etag->value.data = ngx_pnalloc(r->pool, etag->value.len);
+
+ if (etag->value.data == NULL) {
+ ngx_free(real);
+ etag->hash = 0;
+ return NGX_ERROR;
+ }
+
+ ngx_memcpy(etag->value.data, ptr1, etag->value.len);
+ } else {
+ etag->value.data = ngx_pnalloc(r->pool, NGX_OFF_T_LEN + NGX_TIME_T_LEN + 3);
+
+ if (etag->value.data == NULL) {
+ ngx_free(real);
+ etag->hash = 0;
+ return NGX_ERROR;
+ }
+
+ etag->value.len = ngx_sprintf(etag->value.data, "\"%xT-%xO\"",
+ r->headers_out.last_modified_time,
+ r->headers_out.content_length_n)
+ - etag->value.data;
+ }
r->headers_out.etag = etag;
--
2.18.0