From 8dd33a72dd487b8fec0c544ab85d58c7528c0731 Mon Sep 17 00:00:00 2001 From: Glenn Strauss Date: Mon, 20 Jul 2020 03:40:50 -0400 Subject: [PATCH] [mod_deflate] mod_deflate subsumes mod_compress translate config server.modules "mod_compress" to "mod_deflate" accept compress.* directives, but issue DEPRECATED warning trace mod_deflate differences from mod_compress: - mod_compress compress.filetype was exact match; deflate.mimetypes is prefix match (behavior change might compress longer mimetype matches, which are likely of similar type and compressability) - mod_compress always sent entire (compressed) file for Range request mod_deflate will stream compress range result (not stored in cache) - mod_compress would short-circuit request with 403 Forbidden error if request file did not exist (stat() failed) (This behavior was unfriendly to other handlers) - mod_compress compress.cache-dir layout differs from deflate.cache-dir layout; file cache should be cleared (or renamed) when migrating from mod_compress to mod_deflate - mod_deflate does not issue Vary: Accept-Encoding if request does not contain Accept-Encoding. The identity response can be cache by proxies and served to clients. Historically, some proxies disabled caching if any Vary: response was seen. If the Vary header is desirable, mod_deflate code which checks for Accept-Encoding and compression type can be moved down a few lines to be below the setting of the Vary response header. --- src/configfile.c | 53 ++++++++++++++++++++++++++++ src/http-header-glue.c | 2 -- src/mod_deflate.c | 76 ++++++++++++++++++++++++++++++++++++++++- src/response.c | 3 -- tests/lighttpd.conf | 2 +- tests/mod-compress.conf | 8 ++--- tests/mod-compress.t | 2 +- 7 files changed, 134 insertions(+), 12 deletions(-) diff --git a/src/configfile.c b/src/configfile.c index 99baa79d..09129e93 100644 --- a/src/configfile.c +++ b/src/configfile.c @@ -388,6 +388,57 @@ static void config_compat_module_load (server *srv) { } } +static void config_deprecate_module_compress (server *srv) { + int mod_compress_idx = -1; + int mod_deflate_idx = -1; + for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { + buffer *m = &((data_string *)srv->srvconf.modules->data[i])->value; + if (buffer_eq_slen(m, CONST_STR_LEN("mod_compress"))) + mod_compress_idx = (int)i; + else if (buffer_eq_slen(m, CONST_STR_LEN("mod_deflate"))) + mod_deflate_idx = (int)i; + } + if (mod_compress_idx < 0) return; + + int has_compress_directive = 0; + for (uint32_t i = 0; i < srv->config_context->used; ++i) { + const data_config *config = + (data_config const *)srv->config_context->data[i]; + for (uint32_t j = 0; j < config->value->used; ++j) { + buffer *k = &config->value->data[j]->key; + if (0 == strncmp(k->ptr, "compress.", sizeof("compress.")-1)) { + has_compress_directive = 1; + break; + } + } + if (has_compress_directive) { + log_error(srv->errh, __FILE__, __LINE__, + "Warning: \"mod_compress\" is DEPRECATED and has been replaced " + "with \"mod_deflate\". A future release of lighttpd 1.4.x will " + "not contain mod_compress and lighttpd may fail to start up"); + break; + } + } + + if (mod_deflate_idx >= 0 || !has_compress_directive) { + /* create new modules value list without mod_compress */ + array *a = array_init(srv->srvconf.modules->used-1); + for (uint32_t i = 0; i < srv->srvconf.modules->used; ++i) { + buffer *m = &((data_string *)srv->srvconf.modules->data[i])->value; + if (buffer_eq_slen(m, CONST_STR_LEN("mod_compress"))) + continue; + array_insert_value(a, CONST_BUF_LEN(m)); + } + array_free(srv->srvconf.modules); + srv->srvconf.modules = a; + } + else { + /* replace "mod_compress" value with "mod_deflate" value */ + buffer *m = &((data_string *)srv->srvconf.modules->data[mod_compress_idx])->value; + buffer_copy_string_len(m, CONST_STR_LEN("mod_deflate")); + } +} + static int config_http_parseopts (server *srv, const array *a) { unsigned short int opts = srv->srvconf.http_url_normalize; unsigned short int decode_2f = 1; @@ -740,6 +791,8 @@ static int config_insert_srvconf(server *srv) { if (srv->srvconf.compat_module_load) config_compat_module_load(srv); + config_deprecate_module_compress(srv); + if (srv->srvconf.http_url_normalize && !config_burl_normalize_cond(srv)) rc = HANDLER_ERROR; diff --git a/src/http-header-glue.c b/src/http-header-glue.c index c11f555e..b74534fc 100644 --- a/src/http-header-glue.c +++ b/src/http-header-glue.c @@ -491,8 +491,6 @@ void http_response_send_file (request_st * const r, buffer * const path) { return; } - /* mod_compress might set several data directly, don't overwrite them */ - /* set response content-type, if not set already */ if (NULL == http_header_response_get(r, HTTP_HEADER_CONTENT_TYPE, CONST_STR_LEN("Content-Type"))) { diff --git a/src/mod_deflate.c b/src/mod_deflate.c index ce61a226..f6988b76 100644 --- a/src/mod_deflate.c +++ b/src/mod_deflate.c @@ -85,7 +85,6 @@ * - might add deflate.mimetypes-exclude = ( ... ) for list of mimetypes * to avoid compressing, even if a broader deflate.mimetypes matched, * e.g. to compress all "text/" except "text/special". - * - mod_compress and mod_deflate might merge overlapping feature sets * * Implementation notes: * - http_chunk_append_mem() used instead of http_chunk_append_buffer() @@ -351,6 +350,21 @@ static void mod_deflate_merge_config_cpv(plugin_config * const pconf, const conf case 8: /* deflate.cache-dir */ pconf->cache_dir = cpv->v.b; break; + case 9: /* compress.filetype */ + pconf->mimetypes = cpv->v.a; + break; + case 10:/* compress.allowed-encodings */ + pconf->allowed_encodings = (short)cpv->v.shrt; + break; + case 11:/* compress.cache-dir */ + pconf->cache_dir = cpv->v.b; + break; + case 12:/* compress.max-filesize */ + pconf->max_compress_size = cpv->v.u; + break; + case 13:/* compress.max-loadavg */ + pconf->max_loadavg = cpv->v.d; + break; default:/* should not happen */ return; } @@ -450,6 +464,21 @@ SETDEFAULTS_FUNC(mod_deflate_set_defaults) { ,{ CONST_STR_LEN("deflate.cache-dir"), T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("compress.filetype"), + T_CONFIG_ARRAY_VLIST, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("compress.allowed-encodings"), + T_CONFIG_ARRAY_VLIST, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("compress.cache-dir"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("compress.max-filesize"), + T_CONFIG_INT, + T_CONFIG_SCOPE_CONNECTION } + ,{ CONST_STR_LEN("compress.max-loadavg"), + T_CONFIG_STRING, + T_CONFIG_SCOPE_CONNECTION } ,{ NULL, 0, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET } @@ -517,6 +546,50 @@ SETDEFAULTS_FUNC(mod_deflate_set_defaults) { } } break; + case 9: /* compress.filetype */ + log_error(srv->errh, __FILE__, __LINE__, + "DEPRECATED: %s replaced with deflate.mimetypes", + cpk[cpv->k_id].k); + break; + case 10:/* compress.allowed-encodings */ + log_error(srv->errh, __FILE__, __LINE__, + "DEPRECATED: %s replaced with deflate.allowed-encodings", + cpk[cpv->k_id].k); + cpv->v.shrt = (unsigned short) + mod_deflate_encodings_to_flags(cpv->v.a); + cpv->vtype = T_CONFIG_SHORT; + break; + case 11:/* compress.cache-dir */ + log_error(srv->errh, __FILE__, __LINE__, + "DEPRECATED: %s replaced with deflate.cache-dir", + cpk[cpv->k_id].k); + if (!buffer_string_is_empty(cpv->v.b)) { + buffer *b; + *(const buffer **)&b = cpv->v.b; + const uint32_t len = buffer_string_length(b); + if (len > 0 && '/' == b->ptr[len-1]) + buffer_string_set_length(b, len-1); /*remove end slash*/ + struct stat st; + if (0 != stat(b->ptr,&st) && 0 != mkdir_recursive(b->ptr)) { + log_perror(srv->errh, __FILE__, __LINE__, + "can't stat %s %s", cpk[cpv->k_id].k, b->ptr); + return HANDLER_ERROR; + } + } + break; + case 12:/* compress.max-filesize */ + log_error(srv->errh, __FILE__, __LINE__, + "DEPRECATED: %s replaced with deflate.max-compress-size", + cpk[cpv->k_id].k); + break; + case 13:/* compress.max-loadavg */ + log_error(srv->errh, __FILE__, __LINE__, + "DEPRECATED: %s replaced with deflate.max-loadavg", + cpk[cpv->k_id].k); + cpv->v.d = (!buffer_string_is_empty(cpv->v.b)) + ? strtod(cpv->v.b->ptr, NULL) + : 0.0; + break; default:/* should not happen */ break; } @@ -1197,6 +1270,7 @@ static int mod_deflate_choose_encoding (const char *value, plugin_data *p, const int accept_encoding = 0; #if !defined(USE_ZLIB) && !defined(USE_BZ2LIB) && !defined(USE_BROTLI) UNUSED(value); + UNUSED(label); #else for (; *value; ++value) { const char *v; diff --git a/src/response.c b/src/response.c index 4033af15..f5631df6 100644 --- a/src/response.c +++ b/src/response.c @@ -349,9 +349,6 @@ handler_t http_response_prepare(request_st * const r) { * * fastcgi-auth might lead to a COMEBACK too * fastcgi again dead server too - * - * mod_compress might add headers twice too - * */ if (r->conf.log_request_handling) { diff --git a/tests/lighttpd.conf b/tests/lighttpd.conf index 7ac8a121..31515899 100644 --- a/tests/lighttpd.conf +++ b/tests/lighttpd.conf @@ -170,5 +170,5 @@ $HTTP["host"] =~ "allow\.example\.org$" { $HTTP["host"] == "etag.example.org" { static-file.etags = "disable" - compress.filetype = () + deflate.filetype = () } diff --git a/tests/mod-compress.conf b/tests/mod-compress.conf index 684bec90..8303e750 100644 --- a/tests/mod-compress.conf +++ b/tests/mod-compress.conf @@ -15,7 +15,7 @@ server.breakagelog = env.SRCDIR + "/tmp/lighttpd/logs/lighttpd.breakage. server.name = "www.example.org" server.modules = ( - "mod_compress", + "mod_deflate", ) mimetype.assign = ( @@ -24,15 +24,15 @@ mimetype.assign = ( ) $HTTP["host"] == "cache.example.org" { - compress.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/" + deflate.cache-dir = env.SRCDIR + "/tmp/lighttpd/cache/compress/" } -compress.filetype = ( +deflate.mimetypes = ( "text/plain", "text/html", ) -compress.allowed-encodings = ( +deflate.allowed-encodings = ( "gzip", "deflate", ) diff --git a/tests/mod-compress.t b/tests/mod-compress.t index 966f6130..bbcabfee 100755 --- a/tests/mod-compress.t +++ b/tests/mod-compress.t @@ -87,7 +87,7 @@ User-Agent: MYOB/6.66 (AN/ON) Connection: close EOF ); -$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '+Vary' => '', 'Content-Type' => "text/plain; charset=utf-8" } ]; +$t->{RESPONSE} = [ { 'HTTP-Protocol' => 'HTTP/1.0', 'HTTP-Status' => 200, '-Content-Encoding' => '', 'Content-Type' => "text/plain; charset=utf-8" } ]; ok($tf->handle_http($t) == 0, 'Empty Accept-Encoding'); $t->{REQUEST} = ( <