On Sat, May 01, 2021 at 09:26:39PM +0000, alloca wrote:
> This patch adds a serve_gzip option. When enabled, If the client requests 
> path, then serve path.gz if it exists and the client accepts 
> Content-Encoding: gzip.
>
>


man style


> diff -up httpd.orig/config.c httpd/config.c
> --- httpd.orig/config.c Sat May  1 15:03:11 2021
> +++ httpd/config.c Sat May  1 15:45:43 2021
> @@ -568,12 +568,12 @@ config_getserver_config(struct httpd *env, struct serv
>     &parent->default_type, sizeof(struct media_type));
> }
>
> - f = SRVFLAG_PATH_REWRITE|SRVFLAG_NO_PATH_REWRITE;
> +/* f = SRVFLAG_PATH_REWRITE|SRVFLAG_NO_PATH_REWRITE;
> if ((srv_conf->flags & f) == 0) {
> srv_conf->flags |= parent->flags & f;
> (void)strlcpy(srv_conf->path, parent->path,
>     sizeof(srv_conf->path));
> - }
> + } */
>
> f = SRVFLAG_SERVER_HSTS;
> srv_conf->flags |= parent->flags & f;
> diff -up httpd.orig/httpd.conf.5 httpd/httpd.conf.5
> --- httpd.orig/httpd.conf.5 Sat May  1 15:03:11 2021
> +++ httpd/httpd.conf.5 Sat May  1 16:02:44 2021
> @@ -397,6 +397,13 @@ a browser's preload list.
> Signal to the receiving user agent that this host and all sub domains
> of the host's domain should be considered HSTS hosts.
> .El
> +.It Ic serve_gzip
> +If the client requests
> +.Nm path ,
> +then serve
> +.Nm path.gz
> +if it exists and the client accepts
> +.Nm Content-Encoding: gzip .
> .It Ic listen on Ar address Oo Ic tls Oc Ic port Ar number
> Set the listen address and port.
> This statement can be specified multiple times.
> diff -up httpd.orig/httpd.h httpd/httpd.h
> --- httpd.orig/httpd.h Sat May  1 15:03:11 2021
> +++ httpd/httpd.h Sat May  1 15:41:58 2021
> @@ -390,17 +390,17 @@ SPLAY_HEAD(client_tree, client);
> #define SRVFLAG_SERVER_MATCH 0x00200000
> #define SRVFLAG_SERVER_HSTS 0x00400000
> #define SRVFLAG_DEFAULT_TYPE 0x00800000
> -#define SRVFLAG_PATH_REWRITE 0x01000000
> -#define SRVFLAG_NO_PATH_REWRITE 0x02000000
> +/* #define SRVFLAG_PATH_REWRITE 0x01000000
> +#define SRVFLAG_NO_PATH_REWRITE 0x02000000 */
> #define SRVFLAG_LOCATION_FOUND 0x40000000
> #define SRVFLAG_LOCATION_NOT_FOUND 0x80000000
> -
> +#define SRVFLAG_SERVER_GZIP 0x01000000
> #define SRVFLAG_BITS \
> "\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX" \
> "\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG" \
> "\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG" \
> "\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH" \
> - "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31PATH\32NO_PATH" \
> + "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31SERVER_GZIP" \
> "\37LOCATION_FOUND\40LOCATION_NOT_FOUND"
>
> #define TCPFLAG_NODELAY 0x01
> @@ -684,7 +684,7 @@ int server_headers(struct client *, void *,
>     int (*)(struct client *, struct kv *, void *), void *);
> int server_writeresponse_http(struct client *);
> int server_response_http(struct client *, unsigned int,
> -     struct media_type *, off_t, time_t);
> +     struct media_type *, off_t, time_t, int);
> void server_reset_http(struct client *);
> void server_close_http(struct client *);
> int server_response(struct httpd *, struct client *);
> diff -up httpd.orig/parse.y httpd/parse.y
> --- httpd.orig/parse.y Sat May  1 15:03:11 2021
> +++ httpd/parse.y Sat May  1 15:48:31 2021
> @@ -138,7 +138,7 @@ typedef struct {
> %token COMBINED CONNECTION DHE DIRECTORY ECDHE ERR FCGI INDEX IP KEY LIFETIME
> %token LISTEN LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON PORT 
> PREFORK
> %token PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG TCP 
> TICKET
> -%token TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD REQUEST
> +%token TIMEOUT TLS TYPE TYPES HSTS SERVE_GZIP 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 <v.string> STRING
> @@ -644,6 +644,9 @@ serveroptsl : LISTEN ON STRING opttls port {
> }
> srv->srv_conf.flags |= SRVFLAG_SERVER_HSTS;
> }
> + | SERVE_GZIP {
> + srv->srv_conf.flags |= SRVFLAG_SERVER_GZIP;
> + }
> ;
>
> optfound : /* empty */ { $$ = 0; }
> @@ -925,23 +928,7 @@ requestflags_l : requestflags optcommanl requestflags_
> | requestflags optnl
> ;
>
> -requestflags : REWRITE STRING {
> - if (strlcpy(srv->srv_conf.path, $2,
> -     sizeof(srv->srv_conf.path)) >=
> -     sizeof(srv->srv_conf.path)) {
> - yyerror("request path too long");
> - free($2);
> - YYERROR;
> - }
> - free($2);
> - srv->srv_conf.flags |= SRVFLAG_PATH_REWRITE;
> - srv->srv_conf.flags &= ~SRVFLAG_NO_PATH_REWRITE;
> - }
> - | NO REWRITE {
> - srv->srv_conf.flags |= SRVFLAG_NO_PATH_REWRITE;
> - srv->srv_conf.flags &= ~SRVFLAG_PATH_REWRITE;
> - }
> - | STRIP NUMBER {
> +requestflags :  STRIP NUMBER {
> if ($2 < 0 || $2 > INT_MAX) {
> yyerror("invalid strip number");
> YYERROR;
> @@ -1431,6 +1418,7 @@ lookup(char *s)
> { "rewrite", REWRITE },
> { "root", ROOT },
> { "sack", SACK },
> + { "serve_gzip", SERVE_GZIP },
> { "server", SERVER },
> { "socket", SOCKET },
> { "strip", STRIP },
> diff -up httpd.orig/server_file.c httpd/server_file.c
> --- httpd.orig/server_file.c Sat May  1 15:03:11 2021
> +++ httpd/server_file.c Sat May  1 15:40:14 2021
> @@ -50,7 +50,7 @@ int server_file_modified_since(struct http_descripto
> int server_file_method(struct client *);
> int parse_range_spec(char *, size_t, struct range *);
> int parse_ranges(struct client *, char *, size_t);
> -
> +int accepts_gzip(struct http_descriptor *);
> int
> server_file_access(struct httpd *env, struct client *clt,
>      char *path, size_t len)
> @@ -221,30 +221,48 @@ server_file_request(struct httpd *env, struct client *
> struct server_config *srv_conf = clt->clt_srv_conf;
> struct media_type *media;
> const char *errstr = NULL;
> - int fd = -1, ret, code = 500;
> size_t bufsiz;
> -
> + char gzip_path[PATH_MAX];
> + int fd = -1, ret, code = 500, len = 0, gzip = 0;
> if ((ret = server_file_method(clt)) != 0) {
> code = ret;
> goto abort;
> }
>
> if ((ret = server_file_modified_since(clt->clt_descreq, st)) != -1) {
> - /* send the header without a body */
> + /* 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)
> +     MINIMUM(time(NULL), st->st_mtim.tv_sec), 0)) == -1)
> goto fail;
> goto done;
> - }
> + }
>
> - /* Now open the file, should be readable or we have another problem */
> - if ((fd = open(path, O_RDONLY)) == -1)
> - goto abort;
> +/* If the client accepts gzip, try to find a .gz file */
> + if (srv_conf->flags & SRVFLAG_SERVER_GZIP &&
> +     (gzip = accepts_gzip(clt->clt_descreq))) {
> + len = snprintf(gzip_path, sizeof(gzip_path), "%s.gz", path);
> + if (len > 0 && len < PATH_MAX) {
> + fd = open(gzip_path, O_RDONLY);
> + }
>
> + if (fd == -1)
> + gzip = 0;
> + else {
> + if (fstat(fd, st) == -1)
> + goto abort;
> + }
> + }
> +
> + /* Otherwise, open the file, should be readable or we have
> + * another problem */
> + if (fd == -1) {
> + 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));
> +     MINIMUM(time(NULL), st->st_mtim.tv_sec), gzip);
> switch (ret) {
> case -1:
> goto fail;
> @@ -379,7 +397,7 @@ server_partial_file_request(struct httpd *env, struct
> r->range_toread = TOREAD_HTTP_RANGE;
>
> ret = server_response_http(clt, 206, media, content_length,
> -     MINIMUM(time(NULL), st->st_mtim.tv_sec));
> +     MINIMUM(time(NULL), st->st_mtim.tv_sec), 0);
> switch (ret) {
> case -1:
> goto fail;
> @@ -555,7 +573,7 @@ server_file_index(struct httpd *env, struct client *cl
>
> media = media_find_config(env, srv_conf, "index.html");
> ret = server_response_http(clt, 200, media, EVBUFFER_LENGTH(evb),
> -     dir_mtime);
> +     dir_mtime, 0);
> switch (ret) {
> case -1:
> goto fail;
> @@ -765,4 +783,34 @@ parse_range_spec(char *str, size_t size, struct range
> return (0);
>
> return (1);
> +}
> +
> +int
> +accepts_gzip(struct http_descriptor *desc) {
> + struct kv key, *encodings;
> + char *cursor;
> + char *element;
> +
> + key.kv_key = "Accept-Encoding";
> + encodings = kv_find(&desc->http_headers, &key);
> + if (encodings == NULL)
> + return (0);
> +
> + if (encodings->kv_value == NULL)
> + return (0);
> +
> + cursor = encodings->kv_value;
> + while ((element = strsep(&cursor, ",")) != NULL) {
> + if (strstr(element, "gzip") == NULL)
> + continue;
> +
> + /* For simplicity, assume that if a qvalue is given, we
> +    cannot provide gzip */
> + if (strchr(element, ';') != NULL)
> + return (0);
> +
> + return (1);
> + }
> +
> + return (0);
> }
> diff -up httpd.orig/server_http.c httpd/server_http.c
> --- httpd.orig/server_http.c Sat May  1 15:03:11 2021
> +++ httpd/server_http.c Sat May  1 15:44:46 2021
> @@ -1325,18 +1325,18 @@ server_response(struct httpd *httpd, struct client *cl
> return (-1);
> }
>
> - /* Optional rewrite */
> + /* Optional rewrite *
> if (srv_conf->flags & SRVFLAG_PATH_REWRITE) {
> - /* Expand macros */
> + * Expand macros *
> if (server_expand_http(clt, srv_conf->path,
>     path, sizeof(path)) == NULL)
> goto fail;
>
> - /*
> + *
> * Reset and update the query.  The updated query must already
> * be URL encoded - either specified by the user or by using the
> * original $QUERY_STRING.
> - */
> + *
> free(desc->http_query_alias);
> desc->http_query_alias = NULL;
> if ((query = strchr(path, '?')) != NULL) {
> @@ -1345,7 +1345,7 @@ server_response(struct httpd *httpd, struct client *cl
> goto fail;
> }
>
> - /* Canonicalize the updated request path */
> + * Canonicalize the updated request path *
> if (canonicalize_path(path,
>     path, sizeof(path)) == NULL)
> goto fail;
> @@ -1358,14 +1358,14 @@ server_response(struct httpd *httpd, struct client *cl
> if ((desc->http_path_alias = strdup(path)) == NULL)
> goto fail;
>
> - /* Now search for the updated location */
> + * Now search for the updated location *
> if ((srv_conf = server_getlocation(clt,
>     desc->http_path_alias)) == NULL) {
> server_abort_http(clt, 500, desc->http_path_alias);
> return (-1);
> }
> }
> -
> +*/
> if (clt->clt_toread > 0 && (size_t)clt->clt_toread >
>     srv_conf->maxrequestbody) {
> server_abort_http(clt, 413, NULL);
> @@ -1468,7 +1468,7 @@ server_locationaccesstest(struct server_config *srv_co
>
> int
> server_response_http(struct client *clt, unsigned int code,
> -    struct media_type *media, off_t size, time_t mtime)
> +    struct media_type *media, off_t size, time_t mtime, int compressed)
> {
> struct server_config *srv_conf = clt->clt_srv_conf;
> struct http_descriptor *desc = clt->clt_descreq;
> @@ -1516,7 +1516,15 @@ server_response_http(struct client *clt, unsigned int
> if (server_http_time(mtime, tmbuf, sizeof(tmbuf)) <= 0 ||
>     kv_add(&resp->http_headers, "Last-Modified", tmbuf) == NULL)
> return (-1);
> +/* Prevent caches from serving incorrectly encoded content */
> + if (kv_add(&resp->http_headers, "Vary", "Accept-Encoding") == NULL)
> + return (-1);
>
> + /* Set encoding type */
> + if (compressed) {
> + if (kv_add(&resp->http_headers, "Content-Encoding", "gzip") == NULL)
> + return (-1);
> + }
> /* HSTS header */
> if (srv_conf->flags & SRVFLAG_SERVER_HSTS &&
>     srv_conf->flags & SRVFLAG_TLS) {
>

Reply via email to