Skip to content

Commit

Permalink
Merge pull request #1 from fholzer/variable-compression-level
Browse files Browse the repository at this point in the history
Variable compression level
  • Loading branch information
dvershinin authored Jul 1, 2021
2 parents 25f86f0 + f078bdb commit 718918f
Show file tree
Hide file tree
Showing 5 changed files with 173 additions and 19 deletions.
2 changes: 1 addition & 1 deletion deps/brotli
Submodule brotli updated 135 files
144 changes: 133 additions & 11 deletions filter/ngx_http_brotli_filter_module.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@
IIUC, buffered == some data passed to filter has not been pushed further. */
#define NGX_HTTP_BROTLI_BUFFERED NGX_HTTP_GZIP_BUFFERED

typedef struct {
ngx_int_t value;
ngx_http_complex_value_t *cv;
} ngx_http_brotli_quality_t;

/* Module configuration. */
typedef struct {
ngx_flag_t enable;
Expand All @@ -34,7 +39,7 @@ typedef struct {
ngx_bufs_t deprecated_unused_bufs;

/* Brotli encoder parameter: quality */
ngx_int_t quality;
ngx_http_brotli_quality_t *quality;

/* Brotli encoder parameter: (max) lg_win */
size_t lg_win;
Expand Down Expand Up @@ -111,10 +116,11 @@ static ngx_int_t ngx_http_brotli_filter_init(ngx_conf_t* cf);
static char* ngx_http_brotli_parse_wbits(ngx_conf_t* cf, void* post,
void* data);

/* Configuration literals. */
static char* ngx_http_brotli_comp_level_set_slot(ngx_conf_t *cf,
ngx_command_t *cmd,
void *conf);

static ngx_conf_num_bounds_t ngx_http_brotli_comp_level_bounds = {
ngx_conf_check_num_bounds, BROTLI_MIN_QUALITY, BROTLI_MAX_QUALITY};
/* Configuration literals. */

static ngx_conf_post_handler_pt ngx_http_brotli_parse_wbits_p =
ngx_http_brotli_parse_wbits;
Expand Down Expand Up @@ -143,9 +149,9 @@ static ngx_command_t ngx_http_brotli_filter_commands[] = {
{ngx_string("brotli_comp_level"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
NGX_CONF_TAKE1,
ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET,
ngx_http_brotli_comp_level_set_slot, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_brotli_conf_t, quality),
&ngx_http_brotli_comp_level_bounds},
NULL},

{ngx_string("brotli_window"),
NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF |
Expand Down Expand Up @@ -524,11 +530,121 @@ static ngx_int_t ngx_http_brotli_body_filter(ngx_http_request_t* r,
return NGX_ERROR;
}

static ngx_int_t
ngx_http_brotli_parse_quality(ngx_http_complex_value_t *cv, ngx_http_request_t *r) {
ngx_str_t quality_str;
ngx_int_t quality;

ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "brotli parsing compression level");

if (ngx_http_complex_value(r, cv, &quality_str) != NGX_OK) {
return NGX_CONF_UNSET;
}

quality = ngx_atoi(quality_str.data, quality_str.len);
if (quality == NGX_ERROR) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"brotli_comp_level value \"%V\" is not a valid number",
&quality_str);
return NGX_CONF_UNSET;
}

if (quality < BROTLI_MIN_QUALITY || quality > BROTLI_MAX_QUALITY) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"brotli_comp_level value %uD must be between 0 and 11",
(uint32_t) quality);
return NGX_CONF_UNSET;
}

return quality;
}

static ngx_int_t
ngx_http_brotli_get_quality(ngx_http_brotli_conf_t *conf, ngx_http_request_t *r) {

if (conf->quality == NGX_CONF_UNSET_PTR) {
return 6;
}

if (conf->quality->cv == NULL) {
return conf->quality->value;
}

return ngx_http_brotli_parse_quality(conf->quality->cv, r);
}

static char *
ngx_http_brotli_comp_level_set_slot(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf)
{
ngx_http_brotli_conf_t *p = conf;

ngx_str_t *value;
ngx_http_complex_value_t cv;
ngx_http_brotli_quality_t **pquality, *quality;
ngx_http_compile_complex_value_t ccv;

pquality = &p->quality;

if (*pquality != NGX_CONF_UNSET_PTR) {
return "is duplicate";
}

value = cf->args->elts;

ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));

ccv.cf = cf;
ccv.value = &value[1];
ccv.complex_value = &cv;

if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
return NGX_CONF_ERROR;
}

quality = ngx_pcalloc(cf->pool, sizeof(ngx_http_brotli_quality_t));
if (quality == NULL) {
return NGX_CONF_ERROR;
}

*pquality = quality;

if (cv.lengths) {
quality->cv = ngx_palloc(cf->pool, sizeof(ngx_http_complex_value_t));
if (quality->cv == NULL) {
return NGX_CONF_ERROR;
}

*quality->cv = cv;

} else {
quality->value = ngx_atoi(value[1].data, value[1].len);
if (quality->value == NGX_ERROR) {
ngx_conf_log_error(NGX_LOG_ALERT, cf, 0,
"brotli_comp_level value \"%V\" is not a valid number",
&value[1]);
return NGX_CONF_ERROR;
}

if (quality->value < BROTLI_MIN_QUALITY || quality->value > BROTLI_MAX_QUALITY) {
ngx_conf_log_error(NGX_LOG_ALERT, cf, 0,
"brotli_comp_level value %uD must be between 0 and 11",
(uint32_t) quality->value);
return NGX_CONF_ERROR;
}

quality->cv = NULL;
}

return NGX_CONF_OK;
}

static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized(
ngx_http_request_t* r, ngx_http_brotli_ctx_t* ctx) {
ngx_http_brotli_conf_t* conf;
BROTLI_BOOL ok;
size_t wbits;
ngx_int_t quality;

if (ctx->initialized) {
return NGX_OK;
Expand All @@ -537,6 +653,11 @@ static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized(

conf = ngx_http_get_module_loc_conf(r, ngx_http_brotli_filter_module);

quality = ngx_http_brotli_get_quality(conf, r);
if (quality == NGX_CONF_UNSET) {
return NGX_ERROR;
}

/* Tune lg_win, if size is known. */
if (ctx->content_length > 0) {
wbits = BROTLI_MIN_WINDOW_BITS;
Expand All @@ -556,11 +677,11 @@ static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized(
}

ok = BrotliEncoderSetParameter(ctx->encoder, BROTLI_PARAM_QUALITY,
(uint32_t)conf->quality);
(uint32_t)quality);
if (!ok) {
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"BrotliEncoderSetParameter(QUALITY, %uD) failed",
(uint32_t)conf->quality);
(uint32_t)quality);
return NGX_ERROR;
}

Expand All @@ -587,7 +708,7 @@ static ngx_int_t ngx_http_brotli_filter_ensure_stream_initialized(
ctx->out_chain->next = NULL;

ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"brotli encoder initialized: lvl:%i win:%d", conf->quality,
"brotli encoder initialized: lvl:%i win:%d", quality,
(1 << wbits));

return NGX_OK;
Expand Down Expand Up @@ -710,9 +831,9 @@ static void* ngx_http_brotli_create_conf(ngx_conf_t* cf) {

conf->enable = NGX_CONF_UNSET;

conf->quality = NGX_CONF_UNSET;
conf->lg_win = NGX_CONF_UNSET_SIZE;
conf->min_length = NGX_CONF_UNSET;
conf->quality = NGX_CONF_UNSET_PTR;

return conf;
}
Expand All @@ -725,7 +846,8 @@ static char* ngx_http_brotli_merge_conf(ngx_conf_t* cf, void* parent,

ngx_conf_merge_value(conf->enable, prev->enable, 0);

ngx_conf_merge_value(conf->quality, prev->quality, 6);
ngx_conf_merge_ptr_value(conf->quality,
prev->quality, NULL);
ngx_conf_merge_size_value(conf->lg_win, prev->lg_win, 19);
ngx_conf_merge_value(conf->min_length, prev->min_length, 20);

Expand Down
18 changes: 11 additions & 7 deletions script/.travis-compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,22 @@ fi

# Build nginx + filter module.
cd $ROOT/nginx
# Pro memoria: --with-debug
./auto/configure \
--prefix=$ROOT/script/test \
--with-http_v2_module \
--add-module=$ROOT
if [ ! -f "Makefile" ]; then
# Pro memoria: --with-debug
./auto/configure \
--prefix=$ROOT/script/test \
--with-http_v2_module \
--add-module=$ROOT
fi
make -j 16

# Build brotli CLI.
cd $ROOT/deps/brotli
mkdir out
mkdir -p out
cd out
cmake ..
if [ ! -f "Makefile" ]; then
cmake ..
fi
make -j 16 brotli

# Restore status-quo.
Expand Down
24 changes: 24 additions & 0 deletions script/.travis-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ expect_br_equal() {
fi
}

expect_smaller_and_larger_file() {
smaller_file=$1
larger_file=$2
smaller_size=$(get_size $smaller_file)
larger_size=$(get_size $larger_file)
if [ $smaller_size -lt $larger_size ]; then
add_result "OK"
else
add_result "FAIL (file size)"
fi
}

get_size() {
stat --printf="%s" $1
}

################################################################################

# Start default server.
Expand Down Expand Up @@ -120,6 +136,14 @@ echo "Test: A-E: 'b'"
$CURL -H 'Accept-encoding: b' -o tmp/ae-13.txt $SERVER/small.html
expect_equal $FILES/small.html tmp/ae-13.txt

echo "Test: dynamic compression"
$CURL -H 'Accept-encoding: br' -o tmp/war-and-peace5.br $SERVER/level-test/war-and-peace.txt?level=5
$CURL -H 'Accept-encoding: br' -o tmp/war-and-peace11.br $SERVER/level-test/war-and-peace.txt?level=11
expect_br_equal $FILES/war-and-peace.txt tmp/war-and-peace5
expect_br_equal $FILES/war-and-peace.txt tmp/war-and-peace11
expect_smaller_and_larger_file tmp/war-and-peace5.br tmp/war-and-peace.br
expect_smaller_and_larger_file tmp/war-and-peace11.br tmp/war-and-peace5.br

echo $HR
echo "Stopping default NGINX"
# Stop server.
Expand Down
4 changes: 4 additions & 0 deletions script/test.conf
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,9 @@ http {
location / {
try_files $uri $uri/ =404;
}
location /level-test/ {
alias ./;
brotli_comp_level $arg_level;
}
}
}

0 comments on commit 718918f

Please sign in to comment.