* Theo de Raadt <dera...@openbsd.org> le [04-11-2021 08:27:47 -0600]:
> prx <p...@si3t.ch> wrote:
> 
> > * Stuart Henderson <s...@spacehopper.org> le [04-11-2021 14:09:39 +0000]:
> > > On 2021/11/04 14:21, prx wrote:
> > > > 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
> > > 
> > > btw this was rejected before,
> > > 
> > > https://github.com/reyk/httpd/issues/21
> > > 
> > 
> > This diff doesn't compress "on the fly".
> > It's up to the webmaster to compress files **before** serving them.
> 
> Does any other program work this way?
> 
> Where you request one filename, and it gives you another?
> 
> I have a difficult time understanding why gzip has to sneak it's way
> into everything.
> 
> I always prefer software that does precisely what I expect it to do.
> 

I think this remark should be placed into perspective.

When a file is requested, its gzipped version is send if : 
* The client ask for it with appropriate header.
* The server admin configured httpd to do so **and** compressed files.

In this situation, the client does get the expected file.

Of course, the admin has the responsibility to give the same content in "file" 
and "file.gz".

The cost for the server is negligible but reduce bandwidth usage (for
both client and server).

According to previous comments, find below a modified patch to enable
static gzip compression on a location match. ie : 

server "foo" {
    #[... snip ... ]
    location "/*.html" { gzip_static }
    location "/*.css" { gzip_static }
}

Regards.


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        5 Nov 2021 14:04:22 -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     5 Nov 2021 14:04:22 -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     5 Nov 2021 14:04:22 -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.gzip_static = SERVER_DEFAULT_GZIP_STATIC;
+               }
+               | GZIPSTATIC {
+                       srv->srv_conf.gzip_static = 1;
+               }
+               ;
+
 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: /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       5 Nov 2021 14:04:22 -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) {

Reply via email to