Squashed 'src/deps/src/zstd-nginx-module/' content from commit f4ba115e0b

git-subtree-dir: src/deps/src/zstd-nginx-module
git-subtree-split: f4ba115e0b0eaecde545e5f37db6aa18917d8f4b
This commit is contained in:
Théophile Diot 2025-01-16 14:35:41 +01:00
commit 978165a4fd
14 changed files with 4383 additions and 0 deletions

1
.gitattributes vendored Normal file
View file

@ -0,0 +1 @@
*.t linguist-language=Text

54
.gitignore vendored Normal file
View file

@ -0,0 +1,54 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
t/servroot/*

25
LICENSE Normal file
View file

@ -0,0 +1,25 @@
BSD 2-Clause License
Copyright (c) 2018, Alex Zhang
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

155
README.md Normal file
View file

@ -0,0 +1,155 @@
# Name
zstd-nginx-module - Nginx module for the [Zstandard compression](https://facebook.github.io/zstd/).
# Table of Content
* [Name](#name)
* [Status](#status)
* [Synopsis](#synopsis)
* [Installation](#installation)
* [Directives](#directives)
* [ngx_http_zstd_filter_module](#ngx_http_zstd_filter_module)
* [zstd_dict_file](#zstd_dict_file)
* [zstd](#zstd)
* [zstd_comp_level](#zstd_comp_level)
* [zstd_min_length](#zstd_min_length)
* [zstd_types](#zstd_types)
* [zstd_buffers](#zstd_buffers)
* [ngx_http_zstd_static_module](#ngx_http_zstd_static_module)
* [zstd_static](#zstd_static)
* [Variables](#variables)
* [ngx_http_zstd_filter_module](#ngx_http_zstd_filter_module)
* [$zstd_ratio](#$zstd_ratio)
* [Author](#author)
# Status
This Nginx module is currently considered experimental. Issues and PRs are welcome if you encounter any problems.
# Synopsis
```nginx
# specify the dictionary
zstd_dict_file /path/to/dict;
server {
listen 127.0.0.1:8080;
server_name localhost;
location / {
# enable zstd compression
zstd on;
zstd_min_length 256; # no less than 256 bytes
zstd_comp_level 3; # set the level to 3
proxy_pass http://foo.com;
}
}
server {
listen 127.0.0.1:8081;
server_name localhost;
location / {
zstd_static on;
root html;
}
}
```
# Installation
To use theses modules, configure your nginx branch with `--add-module=/path/to/zstd-nginx-module`. Several points should be taken care.
* You can set environment variables `ZSTD_INC` and `ZSTD_LIB` to specify the path to `zstd.h` and the path to zstd shared library represently.
* static library will be tried prior to dynamic library, since this Nginx module uses some **advanced APIs** where static linking is recommended.
* System's zstd bundle will be linked if `ZSTD_INC` and `ZSTD_LIB` are not specified.
* Both `ngx_http_zstd_static_module` and `ngx_http_zstd_filter_module` will be configured.
# Directives
## ngx_http_zstd_filter_module
The `ngx_http_zstd_filter_module` module is a filter that compresses responses using the "zstd" method. This often helps to reduce the size of transmitted data by half or even more.
### zstd_dict_file
**Syntax:** *zstd_dict_file /path/to/dict;*
**Default:** *-*
**Context:** *http*
Specifies the external dictionary.
**WARNING:** Be careful! The content-coding registration only specifies a means to signal the use of the zstd format, and does not additionally specify any mechanism for advertising/negotiating/synchronizing the use of a specific dictionary between client and server. Use the `zstd_dict_file` only if you can insure that both ends (server and client) are capable of using the same dictionary (e.g. advertise with a HTTP header). See https://github.com/tokers/zstd-nginx-module/issues/2 for the details.
### zstd
**Syntax:** *zstd on | off;*
**Default:** *zstd off;*
**Context:** *http, server, location, if in location*
Enables or disables zstd compression for response.
### zstd_comp_level
**Syntax:** *zstd_comp_level level;*
**Default:** *zstd_comp_level 1;*
**Context:** *http, server, location*
Sets a zstd compression level of a response. Acceptable values are in the range from 1 to `ZSTD_maxCLevel()`.
### zstd_min_length
**Syntax:** *zstd_min_length length;*
**Default:** *zstd_min_length 20;*
**Context:** *http, server, location*
Sets the minimum length of a response that will be compressed by zstd. The length is determined only from the "Content-Length" response header field.
### zstd_types
**Syntax:** *zstd_types mime-type ...;*
**Default:** *zstd_types text/html;*
**Context:** *http, server, location*
Enables ztd of responses for the specified MIME types in addition to "text/html". The special value "*" matches any MIME type.
### zstd_buffers
**Syntax:** *zstd_buffers number size;*
**Default:** *zstd_buffers 32 4k | 16 8k;*
**Context:** *http, server, location*
Sets the number and size of buffers used to compress a response. By default, the buffer size is equal to one memory page. This is either 4K or 8K, depending on a platform.
## ngx_http_zstd_static_module
The `ngx_http_zstd_static_module` module allows sending precompressed files with the ".zst" filename extension instead of regular files.
### zstd_static
**Syntax:** *zstd_static on | off | always;*
**Default:** *zstd_static off;*
**Context:** *http, server, location*
Enables ("on") or disables ("off") checking the existence of precompressed files. The following directives are also taken into account: gzip_vary.
With the "always" value, "zsted" file is used in all cases, without checking if the client supports it.
# Variables
## ngx_http_zstd_filter_module
### $zstd_ratio
Achieved compression ratio, computed as the ratio between the original and compressed response sizes.
# Author
Alex Zhang (张超) zchao1995@gmail, UPYUN Inc.
# License
This Nginx module is licensed under [BSD 2-Clause License](LICENSE).

11
config Normal file
View file

@ -0,0 +1,11 @@
# Make sure the module knows it is a submodule.
ngx_addon_name=ngx_zstd
. $ngx_addon_dir/filter/config
# Make sure the module knows it is a submodule.
ngx_addon_name=ngx_zstd
. $ngx_addon_dir/static/config
# The final name for reporting.
ngx_addon_name=ngx_zstd

144
filter/config Normal file
View file

@ -0,0 +1,144 @@
ngx_feature_incs="#include <zstd.h>"
ngx_feature_test="(void) ZSTD_createCCtx();"
ngx_feature_libs=
ngx_feature_run=yes
ngx_zstd_opt_I=
ngx_zstd_opt_L=
if [ -n "$ZSTD_INC" -o -n "$ZSTD_LIB" ]; then
ngx_feature="ZStandard static library in $ZSTD_INC and $ZSTD_LIB"
ngx_feature_path=$ZSTD_INC
# we try the static shared library firstly
ngx_zstd_opt_I="-I$ZSTD_INC -DZSTD_STATIC_LINKING_ONLY"
ngx_zstd_opt_L="$ZSTD_LIB/libzstd.a"
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
if [ $ngx_found = no ]; then
# then try the dynamic shared library
ngx_feature="ZStandard dynamic library in $ZSTD_INC and $ZSTD_LIB"
ngx_zstd_opt_L="-L$ZSTD_LIB -lzstd -Wl,-rpath, $ZSTD_LIB"
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
if [ $ngx_found = no ]; then
cat << END
$0: error: ngx_http_zstd_filter_module requires the ZStandard library, please be sure that "\$ZSTD_INC" and "\$ZSTD_LIB" are set correctly.
END
exit 1
fi
fi
else
# auto-discovery
ngx_feature="ZStandard static library"
ngx_zstd_opt_I="-DZSTD_STATIC_LINKING_ONLY"
ngx_zstd_opt_L="-l:libzstd.a"
# still we consider the static library firstly
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
if [ $ngx_found = no ]; then
ngx_feature="ZStandard dynamic library"
ngx_zstd_opt_L="-lzstd"
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
if [ $ngx_found = no ]; then
cat << END
$0: error: ngx_http_zstd_filter_module requires the ZStandard library.
END
exit 1
fi
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
cat << END
$0: warning: ngx_http_zstd_filter_module uses advanced ZStandard APIs (which are still considered experimental) while you are trying to link the dynamic shared library.
END
fi
# TODO we need more tries for the different OS port.
fi
NGX_LD_OPT="$ngx_zstd_opt_L $NGX_LD_OPT"
HTTP_ZSTD_SRCS="$ngx_addon_dir/filter/ngx_http_zstd_filter_module.c"
ngx_addon_name=ngx_http_zstd_filter_module
ngx_module_type=HTTP_FILTER
ngx_module_name=ngx_http_zstd_filter_module
ngx_module_incs="$ngx_zstd_opt_I"
ngx_module_srcs=$HTTP_ZSTD_SRCS
ngx_module_libs=$NGX_LD_OPT
ngx_module_order="$ngx_module_name \
ngx_pagespeed \
ngx_http_postpone_filter_module \
ngx_http_ssi_filter_module \
ngx_http_charset_filter_module \
ngx_http_xslt_filter_module \
ngx_http_image_filter_module \
ngx_http_sub_filter_module \
ngx_http_addition_filter_module \
ngx_http_gunzip_filter_module \
ngx_http_userid_filter_module \
ngx_http_headers_filter_module \
ngx_http_copy_filter_module \
ngx_http_range_body_filter_module \
ngx_http_not_modified_filter_module \
ngx_http_slice_filter_module"
. auto/module
if [ "$ngx_module_link" != DYNAMIC ]; then
# ngx_module_order doesn't work with static modules,
# so we must re-order filters here.
if [ "$HTTP_GZIP" = YES ]; then
next=ngx_http_gzip_filter_module
elif echo $HTTP_FILTER_MODULES | grep pagespeed_etag_filter >/dev/null; then
next=ngx_pagespeed_etag_filter
else
next=ngx_http_range_header_filter_module
fi
HTTP_FILTER_MODULES=`echo $HTTP_FILTER_MODULES \
| sed "s/$ngx_module_name//" \
| sed "s/$next/$next $ngx_module_name/"`
fi

File diff suppressed because it is too large Load diff

111
static/config Normal file
View file

@ -0,0 +1,111 @@
ngx_feature_incs="#include <zstd.h>"
ngx_feature_test="(void) ZSTD_createCCtx();"
ngx_feature_libs=
ngx_feature_run=yes
ngx_zstd_opt_I=
ngx_zstd_opt_L=
if [ -n "$ZSTD_INC" -o -n "$ZSTD_LIB" ]; then
ngx_feature="ZStandard static library in $ZSTD_INC and $ZSTD_LIB"
ngx_feature_path=$ZSTD_INC
# we try the static shared library firstly
ngx_zstd_opt_I="-I$ZSTD_INC -DZSTD_STATIC_LINKING_ONLY"
ngx_zstd_opt_L="$ZSTD_LIB/libzstd.a"
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
if [ $ngx_found = no ]; then
# then try the dynamic shared library
ngx_feature="ZStandard dynamic library in $ZSTD_INC and $ZSTD_LIB"
ngx_zstd_opt_L="-L$ZSTD_LIB -lzstd -Wl,-rpath, $ZSTD_LIB"
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
if [ $ngx_found = no ]; then
cat << END
$0: error: ngx_http_zstd_filter_module requires the ZStandard library, please be sure that "\$ZSTD_INC" and "\$ZSTD_LIB" are set correctly.
END
exit 1
fi
fi
else
# auto-discovery
ngx_feature="ZStandard static library"
ngx_zstd_opt_I="-DZSTD_STATIC_LINKING_ONLY"
ngx_zstd_opt_L="-l:libzstd.a"
# still we consider the static library firstly
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
if [ $ngx_found = no ]; then
ngx_feature="ZStandard dynamic library"
ngx_zstd_opt_L="-lzstd"
SAVED_CC_TAST_FLAGS=$CC_TEST_FLAGS
CC_TEST_FLAGS="$ngx_zstd_opt_I $CC_TEST_FLAGS"
SAVED_NGX_TEST_LD_OPT=$NGX_TEST_LD_OPT
NGX_TEST_LD_OPT="$ngx_zstd_opt_L $NGX_TEST_LD_OPT"
. auto/feature
if [ $ngx_found = no ]; then
cat << END
$0: error: ngx_http_zstd_filter_module requires the ZStandard library.
END
exit 1
fi
# restore
CC_TEST_FLAGS=$SAVED_CC_TAST_FLAGS
NGX_TEST_LD_OPT=$SAVED_NGX_TEST_LD_OPT
cat << END
$0: warning: ngx_http_zstd_filter_module uses advanced ZStandard APIs (which are still considered experimental) while you are trying to link the dynamic shared library.
END
fi
# TODO we need more tries for the different OS port.
fi
CFLAGS="$ngx_zstd_opt_I $CFLAGS"
NGX_LD_OPT="$ngx_zstd_opt_L $NGX_LD_OPT"
# build the ngx_http_zstd_static_module
HTTP_ZSTD_SRCS="$ngx_addon_dir/static/ngx_http_zstd_static_module.c"
ngx_addon_name=ngx_http_zstd_static_module
ngx_module_type=HTTP
ngx_module_name=ngx_http_zstd_static_module
ngx_module_incs="$ngx_zstd_opt_I"
ngx_module_srcs=$HTTP_ZSTD_SRCS
. auto/module

View file

@ -0,0 +1,383 @@
/*
* Copyright (C) Alex Zhang
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
#define NGX_HTTP_ZSTD_STATIC_OFF 0
#define NGX_HTTP_ZSTD_STATIC_ON 1
#define NGX_HTTP_ZSTD_STATIC_ALWAYS 2
typedef struct {
ngx_uint_t enable;
} ngx_http_zstd_static_conf_t;
static ngx_conf_enum_t ngx_http_zstd_static[] = {
{ ngx_string("off"), NGX_HTTP_ZSTD_STATIC_OFF },
{ ngx_string("on"), NGX_HTTP_ZSTD_STATIC_ON },
{ ngx_string("always"), NGX_HTTP_ZSTD_STATIC_ALWAYS },
};
static ngx_command_t ngx_http_zstd_static_commands[] = {
{ ngx_string("zstd_static"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_enum_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_zstd_static_conf_t, enable),
&ngx_http_zstd_static },
ngx_null_command
};
static ngx_int_t ngx_http_zstd_static_handler(ngx_http_request_t *r);
static ngx_int_t ngx_http_zstd_accept_encoding(ngx_str_t *ae);
static ngx_int_t ngx_http_zstd_ok(ngx_http_request_t *r);
static void * ngx_http_zstd_static_create_loc_conf(ngx_conf_t *cf);
static char * ngx_http_zstd_static_merge_loc_conf(ngx_conf_t *cf, void *parent,
void *child);
static ngx_int_t ngx_http_zstd_static_init(ngx_conf_t *cf);
static ngx_http_module_t ngx_http_zstd_static_module_ctx = {
NULL, /* preconfiguration */
ngx_http_zstd_static_init, /* postconfiguration */
NULL, /* create main configuration */
NULL, /* init main configuration */
NULL, /* create server configuration */
NULL, /* merge server configuration */
ngx_http_zstd_static_create_loc_conf, /* create location configuration */
ngx_http_zstd_static_merge_loc_conf, /* merge location configuration */
};
ngx_module_t ngx_http_zstd_static_module = {
NGX_MODULE_V1,
&ngx_http_zstd_static_module_ctx, /* module context */
ngx_http_zstd_static_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_int_t
ngx_http_zstd_static_handler(ngx_http_request_t *r)
{
u_char *p;
ngx_int_t rc;
ngx_uint_t level;
size_t root;
ngx_str_t path;
ngx_buf_t *b;
ngx_log_t *log;
ngx_table_elt_t *h;
ngx_chain_t out;
ngx_open_file_info_t of;
ngx_http_core_loc_conf_t *clcf;
ngx_http_zstd_static_conf_t *zscf;
if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
return NGX_DECLINED;
}
if (r->uri.data[r->uri.len - 1] == '/') {
return NGX_DECLINED;
}
zscf = ngx_http_get_module_loc_conf(r, ngx_http_zstd_static_module);
if (zscf->enable == NGX_HTTP_ZSTD_STATIC_OFF) {
return NGX_DECLINED;
}
if (zscf->enable == NGX_HTTP_ZSTD_STATIC_ON) {
rc = ngx_http_zstd_ok(r);
} else {
rc = NGX_OK;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (!clcf->gzip_vary && rc != NGX_OK) {
return NGX_DECLINED;
}
log = r->connection->log;
p = ngx_http_map_uri_to_path(r, &path, &root, sizeof(".zst") - 1);
if (p == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
*p++ = '.';
*p++ = 'z';
*p++ = 's';
*p++ = 't';
*p = '\0';
path.len = p - path.data;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
"http filename: \"%s\"", path.data);
ngx_memzero(&of, sizeof(ngx_open_file_info_t));
of.read_ahead = clcf->read_ahead;
of.directio = clcf->directio;
of.valid = clcf->open_file_cache_valid;
of.min_uses = clcf->open_file_cache_min_uses;
of.errors = clcf->open_file_cache_errors;
of.events = clcf->open_file_cache_events;
if (ngx_http_set_disable_symlinks(r, clcf, &path, &of) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
!= NGX_OK)
{
switch (of.err) {
case 0:
return NGX_HTTP_INTERNAL_SERVER_ERROR;
case NGX_ENOENT:
case NGX_ENOTDIR:
case NGX_ENAMETOOLONG:
return NGX_DECLINED;
case NGX_EACCES:
#if (NGX_HAVE_OPENAT)
case NGX_EMLINK:
case NGX_ELOOP:
#endif
level = NGX_LOG_ERR;
break;
default:
level = NGX_LOG_CRIT;
break;
}
ngx_log_error(level, log, of.err,
"%s \"%s\" failed", of.failed, path.data);
return NGX_DECLINED;
}
if (zscf->enable == NGX_HTTP_ZSTD_STATIC_ON) {
r->gzip_vary = 1;
if (rc != NGX_OK) {
return NGX_DECLINED;
}
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
if (of.is_dir) {
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, log, 0, "http dir");
return NGX_DECLINED;
}
#if !(NGX_WIN32) /* the not regular files are probably Unix specific */
if (!of.is_file) {
ngx_log_error(NGX_LOG_CRIT, log, 0,
"\"%s\" is not a regular file", path.data);
return NGX_HTTP_NOT_FOUND;
}
#endif
r->root_tested = !r->error_page;
rc = ngx_http_discard_request_body(r);
if (rc != NGX_OK) {
return rc;
}
log->action = "sending response to client";
r->headers_out.status = NGX_HTTP_OK;
r->headers_out.content_length_n = of.size;
r->headers_out.last_modified_time = of.mtime;
if (ngx_http_set_etag(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
if (ngx_http_set_content_type(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
h = ngx_list_push(&r->headers_out.headers);
if (h == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
h->hash = 1;
ngx_str_set(&h->key, "Content-Encoding");
ngx_str_set(&h->value, "zstd");
r->headers_out.content_encoding = h;
b = ngx_calloc_buf(r->pool);
if (b == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
if (b->file == NULL) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}
rc = ngx_http_send_header(r);
if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
return rc;
}
b->file_pos = 0;
b->file_last = of.size;
b->in_file = b->file_last ? 1 : 0;
b->last_buf = (r == r->main) ? 1 : 0;
b->last_in_chain = 1;
b->file->fd = of.fd;
b->file->name = path;
b->file->log = log;
b->file->directio = of.is_directio;
out.buf = b;
out.next = NULL;
return ngx_http_output_filter(r, &out);
}
static ngx_int_t
ngx_http_zstd_ok(ngx_http_request_t *r)
{
ngx_table_elt_t *ae;
if (r != r->main) {
return NGX_DECLINED;
}
ae = r->headers_in.accept_encoding;
if (ae == NULL) {
return NGX_DECLINED;
}
if (ae->value.len < sizeof("zstd") - 1) {
return NGX_DECLINED;
}
if (ngx_memcmp(ae->value.data, "zstd", 4) != 0
&& ngx_http_zstd_accept_encoding(&ae->value) != NGX_OK)
{
return NGX_DECLINED;
}
r->gzip_tested = 1;
r->gzip_ok = 0;
return NGX_OK;
}
static ngx_int_t
ngx_http_zstd_accept_encoding(ngx_str_t *ae)
{
u_char *p;
p = ngx_strcasestrn(ae->data, "zstd", sizeof("zstd") - 1);
if (p == NULL) {
return NGX_DECLINED;
}
if (p == ae->data || (*(p - 1) == ',' || *(p - 1) == ' ')) {
p += sizeof("zstd") - 1;
if (p == ae->data + ae->len || *p == ',' || *p == ' ' || *p == ';') {
return NGX_OK;
}
}
return NGX_DECLINED;
}
static void *
ngx_http_zstd_static_create_loc_conf(ngx_conf_t *cf)
{
ngx_http_zstd_static_conf_t *conf;
conf = ngx_palloc(cf->pool, sizeof(ngx_http_zstd_static_conf_t));
if (conf == NULL) {
return NULL;
}
conf->enable = NGX_CONF_UNSET_UINT;
return conf;
}
static char *
ngx_http_zstd_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
{
ngx_http_zstd_static_conf_t *prev = parent;
ngx_http_zstd_static_conf_t *conf = child;
ngx_conf_merge_uint_value(conf->enable, prev->enable,
NGX_HTTP_ZSTD_STATIC_OFF);
return NGX_CONF_OK;
}
static ngx_int_t
ngx_http_zstd_static_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers);
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_zstd_static_handler;
return NGX_OK;
}

8
t/00-filter.t Normal file
View file

@ -0,0 +1,8 @@
use Test::Nginx::Socket::Lua;
no_long_string();
run_tests();
__DATA__

198
t/01-static.t Normal file
View file

@ -0,0 +1,198 @@
use Test::Nginx::Socket;
use lib 'lib';
no_long_string();
log_level 'debug';
repeat_each(3);
plan tests => repeat_each() * ((blocks() - 3) * 5 + 3);
run_tests();
__DATA__
=== TEST 1: zstd_static off
--- config
location /test {
zstd_static off;
root ../../t/suite;
}
--- request
GET /test
--- response_headers
Content-Length: 59738
ETag: "5be17d33-e95a"
!Content-Encoding
--- no_error_log
[error]
=== TEST 2: zstd_static off (with accept-encoding header)
--- config
location /test {
zstd_static off;
root ../../t/suite;
}
--- request
GET /test
Accept-Encoding: gzip,zstd
--- response_headers
Content-Length: 59738
ETag: "5be17d33-e95a"
!Content-Encoding
--- no_error_log
[error]
=== TEST 3: zstd_static on
--- config
location /test {
zstd_static on;
root ../../t/suite;
}
--- request
GET /test
--- more_headers
Accept-Encoding: gzip, zstd
--- response_headers
Content-Length: 20706
ETag: "5be17d33-50e2"
!Content-Encoding
Content-Encoding: zstd
--- no_error_log
[error]
=== TEST 4: zstd_static on (without accept-encoding header)
--- config
location /test {
zstd_static on;
root ../../t/suite;
}
--- request
GET /test
--- response_headers
Content-Length: 59738
ETag: "5be17d33-e95a"
Content-Encoding: zstd
!Content-Encoding
--- no_error_log
[error]
=== TEST 5: zstd_static on (without zstd component in accept-encoding header)
--- config
location /test {
zstd_static on;
root ../../t/suite;
}
--- request
GET /test
--- more_headers
Accept-Encoding: gzip, br
--- response_headers
Content-Length: 59738
ETag: "5be17d33-e95a"
!Content-Encoding
--- no_error_log
[error]
=== TEST 6: zstd_static always
--- config
location /test {
zstd_static always;
root ../../t/suite;
}
--- request
GET /test
--- more_headers
Accept-Encoding: gzip, br
--- response_headers
Content-Length: 20706
ETag: "5be17d33-50e2"
Content-Encoding: zstd
--- no_error_log
[error]
=== TEST 6: zstd_static always (without accept-encoding header)
--- config
location /test {
zstd_static always;
root ../../t/suite;
}
--- request
GET /test
--- response_headers
Content-Length: 20706
ETag: "5be17d33-50e2"
Content-Encoding: zstd
--- no_error_log
[error]
=== TEST 7: zstd_static always (without zstd component in accept-encoding header)
--- config
location /test {
zstd_static always;
root ../../t/suite;
}
--- request
GET /test
--- more_headers
Accept-Encoding: gzip, br
--- response_headers
Content-Length: 20706
ETag: "5be17d33-50e2"
Content-Encoding: zstd
--- no_error_log
[error]
=== TEST 8: zstd_static always (file does not exist)
--- config
location /test2 {
zstd_static always;
root ../../t/suite;
}
--- request
GET /test2
--- more_headers
Accept-Encoding: gzip, br
--- error_code: 404
=== TEST 9: zstd_static on (file does not exist)
--- config
location /test2 {
zstd_static on;
root ../../t/suite;
}
--- request
GET /test2
--- more_headers
Accept-Encoding: gzip, br
--- error_code: 404
=== TEST 10: zstd_static off (file does not exist)
--- config
location /test2 {
zstd_static off;
root ../../t/suite;
}
--- request
GET /test2
--- more_headers
Accept-Encoding: gzip, br
--- error_code: 404

2040
t/suite/test Normal file

File diff suppressed because it is too large Load diff

BIN
t/suite/test.zst Normal file

Binary file not shown.

218
valgrind.suppress Normal file
View file

@ -0,0 +1,218 @@
{
<insert_a_suppression_name_here>
Memcheck:Addr1
fun:ngx_init_cycle
fun:ngx_master_process_cycle
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Addr4
fun:ngx_init_cycle
fun:ngx_master_process_cycle
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:ngx_vslprintf
fun:ngx_snprintf
fun:ngx_sock_ntop
fun:ngx_event_accept
fun:ngx_epoll_process_events
fun:ngx_process_events_and_timers
}
{
<insert_a_suppression_name_here>
Memcheck:Addr1
fun:ngx_vslprintf
fun:ngx_snprintf
fun:ngx_sock_ntop
fun:ngx_event_accept
}
{
<insert_a_suppression_name_here>
exp-sgcheck:SorG
fun:ngx_http_lua_ndk_set_var_get
}
{
<insert_a_suppression_name_here>
exp-sgcheck:SorG
fun:ngx_http_variables_init_vars
fun:ngx_http_block
}
{
<insert_a_suppression_name_here>
exp-sgcheck:SorG
fun:ngx_conf_parse
}
{
<insert_a_suppression_name_here>
exp-sgcheck:SorG
fun:ngx_vslprintf
fun:ngx_log_error_core
}
{
<insert_a_suppression_name_here>
Memcheck:Param
epoll_ctl(event)
fun:epoll_ctl
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:ngx_conf_flush_files
fun:ngx_single_process_cycle
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:memcpy
fun:ngx_vslprintf
fun:ngx_log_error_core
fun:ngx_http_charset_header_filter
}
{
<insert_a_suppression_name_here>
Memcheck:Param
socketcall.setsockopt(optval)
fun:setsockopt
fun:drizzle_state_connect
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:ngx_conf_flush_files
fun:ngx_single_process_cycle
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
fun:malloc
fun:ngx_alloc
fun:ngx_event_process_init
}
{
<insert_a_suppression_name_here>
Memcheck:Param
sendmsg(mmsg[0].msg_hdr)
fun:sendmmsg
fun:__libc_res_nsend
}
{
<insert_a_suppression_name_here>
Memcheck:Param
sendmsg(msg.msg_iov[0])
fun:__sendmsg_nocancel
fun:ngx_write_channel
fun:ngx_pass_open_channel
fun:ngx_start_cache_manager_processes
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:ngx_init_cycle
fun:ngx_master_process_cycle
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
fun:index
fun:expand_dynamic_string_token
fun:_dl_map_object
fun:map_doit
fun:_dl_catch_error
fun:do_preload
fun:dl_main
fun:_dl_sysdep_start
fun:_dl_start
}
{
<insert_a_suppression_name_here>
Memcheck:Param
sendmsg(mmsg[0].msg_hdr)
fun:sendmmsg
fun:__libc_res_nsend
fun:__libc_res_nquery
fun:__libc_res_nquerydomain
fun:__libc_res_nsearch
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:ngx_alloc
fun:ngx_set_environment
fun:ngx_single_process_cycle
}
{
<insert_a_suppression_name_here>
Memcheck:Cond
obj:*
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:ngx_alloc
fun:ngx_set_environment
fun:ngx_worker_process_init
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: definite
fun:malloc
fun:ngx_alloc
fun:ngx_create_pool
fun:main
}
{
<insert_a_suppression_name_here>
Memcheck:Param
epoll_pwait(sigmask)
fun:epoll_pwait
fun:epoll_wait
fun:ngx_epoll_process_events
fun:ngx_process_events_and_timers
}
{
<insert_a_suppression_name_here>
Memcheck:Param
epoll_pwait(sigmask)
fun:epoll_pwait
fun:epoll_wait
fun:ngx_epoll_test_rdhup
fun:ngx_epoll_init
fun:ngx_event_process_init
}
{
<insert_a_suppression_name_here>
Memcheck:Param
epoll_pwait(sigmask)
fun:epoll_pwait
fun:ngx_epoll_process_events
fun:ngx_process_events_and_timers
}
{
<insert_a_suppression_name_here>
Memcheck:Param
epoll_pwait(sigmask)
fun:epoll_pwait
fun:ngx_epoll_test_rdhup
fun:ngx_epoll_init
fun:ngx_event_process_init
}
{
<insert_a_suppression_name_here>
Memcheck:Leak
match-leak-kinds: possible
fun:malloc
fun:ngx_alloc
fun:ngx_crc32_table_init
fun:main
}