Hello,
The attached patch add support for static gzip compression.
In other words, if a client support gzip compression, when "file" is
requested, httpd will check if "file.gz" is avaiable to serve.
Regards.
prx
Index: httpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v
retrieving revision 1.119
diff -u -p -r1.119 httpd.conf.5
--- httpd.conf.5 24 Oct 2021 16:01:04 -0000 1.119
+++ httpd.conf.5 4 Nov 2021 13:13:58 -0000
@@ -425,6 +425,10 @@ A variable that is set to a comma separa
features in use
.Pq omitted when TLS client verification is not in use .
.El
+.It Ic gzip_static
+Enable static gzip compression.
+.Pp
+When a file is requested, serves the file with .gz added to its path if it
exists.
.It Ic hsts Oo Ar option Oc
Enable HTTP Strict Transport Security.
Valid options are:
Index: httpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
retrieving revision 1.158
diff -u -p -r1.158 httpd.h
--- httpd.h 24 Oct 2021 16:01:04 -0000 1.158
+++ httpd.h 4 Nov 2021 13:13:58 -0000
@@ -87,6 +87,7 @@
#define SERVER_DEF_TLS_LIFETIME (2 * 3600)
#define SERVER_MIN_TLS_LIFETIME (60)
#define SERVER_MAX_TLS_LIFETIME (24 * 3600)
+#define SERVER_DEFAULT_GZIP_STATIC 0
#define MEDIATYPE_NAMEMAX 128 /* file name extension */
#define MEDIATYPE_TYPEMAX 64 /* length of type/subtype */
@@ -546,6 +547,7 @@ struct server_config {
struct server_fcgiparams fcgiparams;
int fcgistrip;
char errdocroot[HTTPD_ERRDOCROOT_MAX];
+ int gzip_static;
TAILQ_ENTRY(server_config) entry;
};
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
retrieving revision 1.127
diff -u -p -r1.127 parse.y
--- parse.y 24 Oct 2021 16:01:04 -0000 1.127
+++ parse.y 4 Nov 2021 13:13:58 -0000
@@ -141,7 +141,7 @@ typedef struct {
%token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
%token ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
%token CA CLIENT CRL OPTIONAL PARAM FORWARDED FOUND NOT
-%token ERRDOCS
+%token ERRDOCS GZIPSTATIC
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.port> port
@@ -306,6 +306,8 @@ server : SERVER optmatch STRING {
if (conf->sc_custom_errdocs)
s->srv_conf.flags |= SRVFLAG_ERRDOCS;
+ s->srv_conf.gzip_static = SERVER_DEFAULT_GZIP_STATIC;
+
if (last_server_id == INT_MAX) {
yyerror("too many servers defined");
free(s);
@@ -1180,6 +1182,9 @@ filter : block RETURN NUMBER optstring
srv_conf->flags &= ~SRVFLAG_BLOCK;
srv_conf->flags |= SRVFLAG_NO_BLOCK;
}
+ | GZIPSTATIC {
+ srv_conf->gzip_static = 1;
+ }
;
block : BLOCK {
@@ -1441,6 +1446,7 @@ lookup(char *s)
{ "fastcgi", FCGI },
{ "forwarded", FORWARDED },
{ "found", FOUND },
+ { "gzip_static", GZIPSTATIC },
{ "hsts", HSTS },
{ "include", INCLUDE },
{ "index", INDEX },
Index: server_file.c
===================================================================
RCS file: /cvs/src/usr.sbin/httpd/server_file.c,v
retrieving revision 1.70
diff -u -p -r1.70 server_file.c
--- server_file.c 29 Apr 2021 18:23:07 -0000 1.70
+++ server_file.c 4 Nov 2021 13:13:58 -0000
@@ -229,20 +229,49 @@ server_file_request(struct httpd *env, s
goto abort;
}
+ media = media_find_config(env, srv_conf, path);
+
if ((ret = server_file_modified_since(clt->clt_descreq, st)) != -1) {
/* send the header without a body */
- media = media_find_config(env, srv_conf, path);
if ((ret = server_response_http(clt, ret, media, -1,
MINIMUM(time(NULL), st->st_mtim.tv_sec))) == -1)
goto fail;
goto done;
}
+ /* change path to path.gz if necessary. */
+ if (srv_conf->gzip_static) {
+ struct http_descriptor *req = clt->clt_descreq;
+ struct http_descriptor *resp = clt->clt_descresp;
+ struct stat gzst;
+ struct kv *r, key;
+ char gzpath[PATH_MAX];
+
+ /* check Accept-Encoding header */
+ key.kv_key = "Accept-Encoding";
+ r = kv_find(&req->http_headers, &key);
+
+ if (r != NULL) {
+ if (strstr(r->kv_value, "gzip") != NULL) {
+ /* append ".gz" to path and check existence */
+ strlcpy(gzpath, path, sizeof(gzpath));
+ strlcat(gzpath, ".gz", sizeof(gzpath));
+
+ if ((access(gzpath, R_OK) == 0) &&
+ (stat(gzpath, &gzst) == 0)) {
+ path = gzpath;
+ st = &gzst;
+ kv_add(&resp->http_headers,
+ "Content-Encoding", "gzip");
+ }
+ }
+ }
+ }
+
/* Now open the file, should be readable or we have another problem */
if ((fd = open(path, O_RDONLY)) == -1)
goto abort;
- media = media_find_config(env, srv_conf, path);
ret = server_response_http(clt, 200, media, st->st_size,
MINIMUM(time(NULL), st->st_mtim.tv_sec));
switch (ret) {