diff options
Diffstat (limited to 'nixpkgs/pkgs/servers/http/nginx/nix-etag-1.15.4.patch')
-rw-r--r-- | nixpkgs/pkgs/servers/http/nginx/nix-etag-1.15.4.patch | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/nixpkgs/pkgs/servers/http/nginx/nix-etag-1.15.4.patch b/nixpkgs/pkgs/servers/http/nginx/nix-etag-1.15.4.patch new file mode 100644 index 000000000000..8c8c8ce74b21 --- /dev/null +++ b/nixpkgs/pkgs/servers/http/nginx/nix-etag-1.15.4.patch @@ -0,0 +1,106 @@ +This patch makes it possible to serve static content from Nix store paths, by +using the hash of the store path for the ETag header. + +diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c +index 97a91aee2..2d07d71e6 100644 +--- a/src/http/ngx_http_core_module.c ++++ b/src/http/ngx_http_core_module.c +@@ -1676,6 +1676,8 @@ 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; ++ ngx_err_t err; + + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + +@@ -1692,16 +1694,82 @@ ngx_http_set_etag(ngx_http_request_t *r) + etag->next = NULL; + 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; ++ // Upstream nginx uses file mod timestamp and content-length for Etag, but ++ // files in the Nix store have their timestamps reset, so that doesn't work. ++ // Instead, when serving from the Nix store, we use the hash from the store ++ // path and content-length. ++ // ++ // Every file in under the given store path will share the same store path ++ // hash. It is fine to serve different resources with the same Etag, but ++ // different representations of the same resource (eg the same file, but ++ // gzip-compressed) should have different Etags. Thus, we also append ++ // content-length, which should be different when the response is compressed ++ ++ err = ngx_errno; ++ real = ngx_realpath(clcf->root.data, NULL); ++ ngx_set_errno(err); ++ ++ #define NIX_STORE_DIR "@nixStoreDir@" ++ #define NIX_STORE_LEN @nixStoreDirLen@ ++ ++ if (r->headers_out.last_modified_time == 1 ++ && real != NULL ++ && !ngx_strncmp(real, NIX_STORE_DIR, NIX_STORE_LEN) ++ && real[NIX_STORE_LEN] == '/' ++ && real[NIX_STORE_LEN + 1] != '\0') ++ { ++ // extract the hash from a path formatted like ++ // /nix/store/hashhere1234-pname-1.0.0 ++ // +1 to skip the leading / ++ ptr1 = real + NIX_STORE_LEN + 1; ++ ++ ptr2 = (u_char *) ngx_strchr(ptr1, '-'); ++ ++ if (ptr2 == NULL) { ++ ngx_free(real); ++ etag->hash = 0; ++ return NGX_ERROR; ++ } ++ ++ *ptr2 = '\0'; ++ ++ // hash + content-length + quotes and hyphen. Note that the ++ // content-length part of the string can vary in length. ++ etag->value.data = ngx_pnalloc(r->pool, ngx_strlen(ptr1) + NGX_OFF_T_LEN + 3); ++ ++ if (etag->value.data == NULL) { ++ ngx_free(real); ++ etag->hash = 0; ++ return NGX_ERROR; ++ } ++ ++ ++ // set value.data content to "{hash}-{content-length}" (including quote ++ // marks), and set value.len to the length of the resulting string ++ etag->value.len = ngx_sprintf(etag->value.data, "\"\%s-%xO\"", ++ ptr1, ++ r->headers_out.content_length_n) ++ - etag->value.data; ++ ++ ngx_http_clear_last_modified(r); ++ } else { ++ // outside of Nix store, use the upstream Nginx logic for etags ++ ++ 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; + } + +- 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; ++ ngx_free(real); + + r->headers_out.etag = etag; |