On Fri, Feb 25, 2022 at 11:00:22AM +0100, prx wrote:
> After a few months, I reupload the patch to enable httpd static 
> compression using "location {}" instructions.
> 
> I use it without any issue on my own website and to serve 
> https://webzine.pufy.cafe.
> Anyone else tried it?

I just added it to bluhm.genua.de.  There I deliver large html
tables.  For http://bluhm.genua.de/regress/results/regress.html it
reduces bandwith by factor 20.

> +.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.

Mention for what this is useful.

> +#define SERVER_DEFAULT_GZIP_STATIC 0

A define for a default 0 is overkill.

> +     int                      gzip_static;

Better use a flag than an int for a boolean.

> +             { "gzip_static",        GZIPSTATIC },

We do not have keywords with _ but one with -

> +     /* 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;

Outside of a block you must not use pointer to variables that are
defined inside a block.

> +                                     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;

With all that fixed, diff looks like this and works fine in my setup.

ok?

bluhm

Index: httpd.conf.5
===================================================================
RCS file: /data/mirror/openbsd/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        25 Feb 2022 18:41:42 -0000
@@ -425,6 +425,12 @@ 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 to save bandwith.
+.Pp
+If gzip encoding is accepted and if the requested file exists with
+an additional .gz suffix, use the compressed file instead and deliver
+it with content encoding gzip.
 .It Ic hsts Oo Ar option Oc
 Enable HTTP Strict Transport Security.
 Valid options are:
Index: httpd.h
===================================================================
RCS file: /data/mirror/openbsd/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     25 Feb 2022 18:40:58 -0000
@@ -396,6 +396,7 @@ SPLAY_HEAD(client_tree, client);
 #define SRVFLAG_DEFAULT_TYPE   0x00800000
 #define SRVFLAG_PATH_REWRITE   0x01000000
 #define SRVFLAG_NO_PATH_REWRITE        0x02000000
+#define SRVFLAG_GZIP_STATIC    0x04000000
 #define SRVFLAG_LOCATION_FOUND 0x40000000
 #define SRVFLAG_LOCATION_NOT_FOUND 0x80000000
 
Index: parse.y
===================================================================
RCS file: /data/mirror/openbsd/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     25 Feb 2022 18:24:30 -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
@@ -553,6 +553,7 @@ serveroptsl : LISTEN ON STRING opttls po
                | logformat
                | fastcgi
                | authenticate
+               | gzip_static
                | filter
                | LOCATION optfound optmatch STRING     {
                        struct server           *s;
@@ -1217,6 +1218,14 @@ fcgiport : NUMBER                {
                }
                ;
 
+gzip_static    : NO GZIPSTATIC         {
+                       srv->srv_conf.flags &= ~SRVFLAG_GZIP_STATIC;
+               }
+               | GZIPSTATIC            {
+                       srv->srv_conf.flags |= SRVFLAG_GZIP_STATIC;
+               }
+               ;
+
 tcpip          : TCP '{' optnl tcpflags_l '}'
                | TCP tcpflags
                ;
@@ -1441,6 +1450,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: /data/mirror/openbsd/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       25 Feb 2022 18:26:11 -0000
@@ -223,26 +223,53 @@ server_file_request(struct httpd *env, s
        const char              *errstr = NULL;
        int                      fd = -1, ret, code = 500;
        size_t                   bufsiz;
+       struct stat              gzst;
+       char                     gzpath[PATH_MAX];
 
        if ((ret = server_file_method(clt)) != 0) {
                code = ret;
                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->flags & SRVFLAG_GZIP_STATIC) {
+               struct http_descriptor  *req = clt->clt_descreq;
+               struct http_descriptor  *resp = clt->clt_descresp;
+               struct kv               *r, key;
+
+               /* check Accept-Encoding header */
+               key.kv_key = "Accept-Encoding";
+               r = kv_find(&req->http_headers, &key);
+
+               if (r != NULL && 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) {

Reply via email to