[master] cd5ddaa64 Add gunzip for http2

Federico G. Schwindt fgsch at lodoss.net
Mon Aug 5 14:28:09 UTC 2019


commit cd5ddaa64e0d3f5c2bca2b7998922e73b9d878e7
Author: Federico G. Schwindt <fgsch at lodoss.net>
Date:   Mon Aug 5 13:24:42 2019 +0100

    Add gunzip for http2
    
    While here also implement -gziplen and -gzipbody.
    
    Fixes #3031.

diff --git a/bin/varnishtest/Makefile.am b/bin/varnishtest/Makefile.am
index b9c1def06..dc67a98c0 100644
--- a/bin/varnishtest/Makefile.am
+++ b/bin/varnishtest/Makefile.am
@@ -38,6 +38,7 @@ varnishtest_SOURCES = \
 		vtc.c \
 		vtc_barrier.c \
 		vtc_client.c \
+		vtc_gzip.c \
 		vtc_haproxy.c \
 		vtc_h2_dectbl.h \
 		vtc_h2_enctbl.h \
diff --git a/bin/varnishtest/tests/a02026.vtc b/bin/varnishtest/tests/a02026.vtc
new file mode 100644
index 000000000..71bcca94d
--- /dev/null
+++ b/bin/varnishtest/tests/a02026.vtc
@@ -0,0 +1,29 @@
+varnishtest "Test -gzipbody and -gziplen"
+
+server s1 {
+	stream 1 {
+		rxreq
+		txresp -gzipbody "foo"
+	} -run
+
+	stream 3 {
+		rxreq
+		txresp -gziplen 10
+	} -run
+} -start
+
+client c1 -connect ${s1_sock} {
+	stream 1 {
+		txreq
+		rxresp
+		gunzip
+		expect resp.body == "foo"
+	} -run
+
+	stream 3 {
+		txreq
+		rxresp
+		gunzip
+		expect resp.bodylen == 10
+	} -run
+} -run
diff --git a/bin/varnishtest/vtc.h b/bin/varnishtest/vtc.h
index 50f5e8f1a..61c8dcb2d 100644
--- a/bin/varnishtest/vtc.h
+++ b/bin/varnishtest/vtc.h
@@ -130,6 +130,10 @@ void start_h2(struct http *hp);
 void stop_h2(struct http *hp);
 void b64_settings(const struct http *hp, const char *s);
 
+/* vtc_gzip.c */
+void vtc_gzip(struct http *, const char *, char **, unsigned *);
+void vtc_gunzip(struct http *, char *, unsigned *);
+
 /* vtc_subr.c */
 struct vsb *vtc_hex_to_bin(struct vtclog *vl, const char *arg);
 void vtc_expect(struct vtclog *, const char *, const char *, const char *,
diff --git a/bin/varnishtest/vtc_gzip.c b/bin/varnishtest/vtc_gzip.c
new file mode 100644
index 000000000..9eeb67a51
--- /dev/null
+++ b/bin/varnishtest/vtc_gzip.c
@@ -0,0 +1,134 @@
+/*-
+ * Copyright (c) 2008-2019 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vtc.h"
+#include "vtc_http.h"
+#include "vgz.h"
+
+#define OVERHEAD 64L
+
+
+void
+vtc_gzip(struct http *hp, const char *input, char **body, unsigned *bodylen)
+{
+	unsigned l;
+	z_stream vz;
+#ifdef VGZ_EXTENSIONS
+	int i;
+#endif
+
+	memset(&vz, 0, sizeof vz);
+
+	l = strlen(input);
+	*body = calloc(1, l + OVERHEAD);
+	AN(*body);
+
+	vz.next_in = TRUST_ME(input);
+	vz.avail_in = l;
+
+	vz.next_out = TRUST_ME(*body);
+	vz.avail_out = l + OVERHEAD;
+
+	assert(Z_OK == deflateInit2(&vz,
+	    hp->gziplevel, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY));
+	assert(Z_STREAM_END == deflate(&vz, Z_FINISH));
+	*bodylen = vz.total_out;
+#ifdef VGZ_EXTENSIONS
+	i = vz.stop_bit & 7;
+	if (hp->gzipresidual >= 0 && hp->gzipresidual != i)
+		vtc_log(hp->vl, hp->fatal,
+		    "Wrong gzip residual got %d wanted %d",
+		    i, hp->gzipresidual);
+	vtc_log(hp->vl, 4, "startbit = %ju %ju/%ju",
+	    (uintmax_t)vz.start_bit,
+	    (uintmax_t)vz.start_bit >> 3, (uintmax_t)vz.start_bit & 7);
+	vtc_log(hp->vl, 4, "lastbit = %ju %ju/%ju",
+	    (uintmax_t)vz.last_bit,
+	    (uintmax_t)vz.last_bit >> 3, (uintmax_t)vz.last_bit & 7);
+	vtc_log(hp->vl, 4, "stopbit = %ju %ju/%ju",
+	    (uintmax_t)vz.stop_bit,
+	    (uintmax_t)vz.stop_bit >> 3, (uintmax_t)vz.stop_bit & 7);
+	assert(Z_OK == deflateEnd(&vz));
+#endif
+}
+
+void
+vtc_gunzip(struct http *hp, char *body, unsigned *bodylen)
+{
+	z_stream vz;
+	char *p;
+	unsigned l;
+	int i;
+
+	memset(&vz, 0, sizeof vz);
+
+	AN(body);
+	if (body[0] != (char)0x1f || body[1] != (char)0x8b)
+		vtc_log(hp->vl, hp->fatal,
+		    "Gunzip error: body lacks gzip magic");
+	vz.next_in = TRUST_ME(body);
+	vz.avail_in = *bodylen;
+
+	l = *bodylen * 10;
+	p = calloc(1, l);
+	AN(p);
+
+	vz.next_out = TRUST_ME(p);
+	vz.avail_out = l;
+
+	assert(Z_OK == inflateInit2(&vz, 31));
+	i = inflate(&vz, Z_FINISH);
+	assert(vz.total_out < l);
+	*bodylen = vz.total_out;
+	memcpy(body, p, *bodylen);
+	free(p);
+	vtc_log(hp->vl, 3, "new bodylen %u", *bodylen);
+	vtc_dump(hp->vl, 4, "body", body, *bodylen);
+	bprintf(hp->bodylen, "%u", *bodylen);
+#ifdef VGZ_EXTENSIONS
+	vtc_log(hp->vl, 4, "startbit = %ju %ju/%ju",
+	    (uintmax_t)vz.start_bit,
+	    (uintmax_t)vz.start_bit >> 3, (uintmax_t)vz.start_bit & 7);
+	vtc_log(hp->vl, 4, "lastbit = %ju %ju/%ju",
+	    (uintmax_t)vz.last_bit,
+	    (uintmax_t)vz.last_bit >> 3, (uintmax_t)vz.last_bit & 7);
+	vtc_log(hp->vl, 4, "stopbit = %ju %ju/%ju",
+	    (uintmax_t)vz.stop_bit,
+	    (uintmax_t)vz.stop_bit >> 3, (uintmax_t)vz.stop_bit & 7);
+#endif
+	if (i != Z_STREAM_END)
+		vtc_log(hp->vl, hp->fatal,
+		    "Gunzip error = %d (%s) in:%jd out:%jd",
+		    i, vz.msg, (intmax_t)vz.total_in, (intmax_t)vz.total_out);
+	assert(Z_OK == inflateEnd(&vz));
+	body[*bodylen] = '\0';
+}
diff --git a/bin/varnishtest/vtc_http.c b/bin/varnishtest/vtc_http.c
index e2f63d84c..8078ea645 100644
--- a/bin/varnishtest/vtc_http.c
+++ b/bin/varnishtest/vtc_http.c
@@ -749,12 +749,6 @@ cmd_http_rxresphdrs(CMD_ARGS)
 		    "Multiple Content-Length headers.\n");
 }
 
-/**********************************************************************
- * Ungzip rx'ed body
- */
-
-#define OVERHEAD 64L
-
 /* SECTION: client-server.spec.gunzip
  *
  * gunzip
@@ -763,107 +757,14 @@ cmd_http_rxresphdrs(CMD_ARGS)
 static void
 cmd_http_gunzip(CMD_ARGS)
 {
-	int i;
-	z_stream vz;
 	struct http *hp;
-	char *p;
-	unsigned l;
 
 	(void)av;
 	(void)cmd;
 	(void)vl;
-	CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
 
-	memset(&vz, 0, sizeof vz);
-
-	AN(hp->body);
-	if (hp->body[0] != (char)0x1f || hp->body[1] != (char)0x8b)
-		vtc_log(hp->vl, hp->fatal,
-		    "Gunzip error: Body lacks gzip magics");
-	vz.next_in = TRUST_ME(hp->body);
-	vz.avail_in = hp->bodyl;
-
-	l = hp->bodyl * 10;
-	p = calloc(1, l);
-	AN(p);
-
-	vz.next_out = TRUST_ME(p);
-	vz.avail_out = l;
-
-	assert(Z_OK == inflateInit2(&vz, 31));
-	i = inflate(&vz, Z_FINISH);
-	assert(vz.total_out < l);
-	hp->bodyl = vz.total_out;
-	memcpy(hp->body, p, hp->bodyl);
-	free(p);
-	vtc_log(hp->vl, 3, "new bodylen %u", hp->bodyl);
-	vtc_dump(hp->vl, 4, "body", hp->body, hp->bodyl);
-	bprintf(hp->bodylen, "%u", hp->bodyl);
-#ifdef VGZ_EXTENSIONS
-	vtc_log(hp->vl, 4, "startbit = %ju %ju/%ju",
-	    (uintmax_t)vz.start_bit,
-	    (uintmax_t)vz.start_bit >> 3, (uintmax_t)vz.start_bit & 7);
-	vtc_log(hp->vl, 4, "lastbit = %ju %ju/%ju",
-	    (uintmax_t)vz.last_bit,
-	    (uintmax_t)vz.last_bit >> 3, (uintmax_t)vz.last_bit & 7);
-	vtc_log(hp->vl, 4, "stopbit = %ju %ju/%ju",
-	    (uintmax_t)vz.stop_bit,
-	    (uintmax_t)vz.stop_bit >> 3, (uintmax_t)vz.stop_bit & 7);
-#endif
-	if (i != Z_STREAM_END)
-		vtc_log(hp->vl, hp->fatal,
-		    "Gunzip error = %d (%s) in:%jd out:%jd",
-		    i, vz.msg, (intmax_t)vz.total_in, (intmax_t)vz.total_out);
-	assert(Z_OK == inflateEnd(&vz));
-	hp->body[hp->bodyl] = '\0';
-}
-
-/**********************************************************************
- * Create a gzip'ed body
- */
-
-static void
-gzip_body(const struct http *hp, const char *txt, char **body, int *bodylen)
-{
-	int l;
-	z_stream vz;
-#ifdef VGZ_EXTENSIONS
-	int i;
-#endif
-
-	memset(&vz, 0, sizeof vz);
-
-	l = strlen(txt);
-	*body = calloc(1, l + OVERHEAD);
-	AN(*body);
-
-	vz.next_in = TRUST_ME(txt);
-	vz.avail_in = l;
-
-	vz.next_out = TRUST_ME(*body);
-	vz.avail_out = l + OVERHEAD;
-
-	assert(Z_OK == deflateInit2(&vz,
-	    hp->gziplevel, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY));
-	assert(Z_STREAM_END == deflate(&vz, Z_FINISH));
-	*bodylen = vz.total_out;
-#ifdef VGZ_EXTENSIONS
-	i = vz.stop_bit & 7;
-	if (hp->gzipresidual >= 0 && hp->gzipresidual != i)
-		vtc_log(hp->vl, hp->fatal,
-		    "Wrong gzip residual got %d wanted %d",
-		    i, hp->gzipresidual);
-	vtc_log(hp->vl, 4, "startbit = %ju %ju/%ju",
-	    (uintmax_t)vz.start_bit,
-	    (uintmax_t)vz.start_bit >> 3, (uintmax_t)vz.start_bit & 7);
-	vtc_log(hp->vl, 4, "lastbit = %ju %ju/%ju",
-	    (uintmax_t)vz.last_bit,
-	    (uintmax_t)vz.last_bit >> 3, (uintmax_t)vz.last_bit & 7);
-	vtc_log(hp->vl, 4, "stopbit = %ju %ju/%ju",
-	    (uintmax_t)vz.stop_bit,
-	    (uintmax_t)vz.stop_bit >> 3, (uintmax_t)vz.stop_bit & 7);
-	assert(Z_OK == deflateEnd(&vz));
-#endif
+	CAST_OBJ_NOTNULL(hp, priv, HTTP_MAGIC);
+	vtc_gunzip(hp, hp->body, (unsigned *)&hp->bodyl);
 }
 
 /**********************************************************************
@@ -947,7 +848,7 @@ http_tx_parse_args(char * const *av, struct vtclog *vl, struct http *hp,
 			assert(body == nullbody);
 			free(body);
 			b = synth_body(av[1], 1);
-			gzip_body(hp, b, &body, &bodylen);
+			vtc_gzip(hp, b, &body, (unsigned *)&bodylen);
 			free(b);
 			VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl);
 			// vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen);
@@ -955,7 +856,7 @@ http_tx_parse_args(char * const *av, struct vtclog *vl, struct http *hp,
 		} else if (!strcmp(*av, "-gzipbody")) {
 			assert(body == nullbody);
 			free(body);
-			gzip_body(hp, av[1], &body, &bodylen);
+			vtc_gzip(hp, av[1], &body, (unsigned *)&bodylen);
 			VSB_printf(hp->vsb, "Content-Encoding: gzip%s", nl);
 			// vtc_hexdump(hp->vl, 4, "gzip", (void*)body, bodylen);
 			av++;
diff --git a/bin/varnishtest/vtc_http2.c b/bin/varnishtest/vtc_http2.c
index 74cea13bb..d915b7e51 100644
--- a/bin/varnishtest/vtc_http2.c
+++ b/bin/varnishtest/vtc_http2.c
@@ -43,6 +43,7 @@
 #include "vtc_http.h"
 
 #include "vfil.h"
+#include "vgz.h"
 #include "hpack.h"
 #include "vend.h"
 
@@ -1334,6 +1335,13 @@ cmd_sendhex(CMD_ARGS)
  *	Do the same thing as ``-body`` but generate an string of INT length
  *	for you.
  *
+ * \-gzipbody STRING (txreq, txresp)
+ *      Gzip STRING and send it as body.
+ *
+ * \-gziplen NUMBER (txreq, txresp)
+ *      Combine -body and -gzipbody: create a body of length NUMBER,
+ *      gzip it and send as body.
+ *
  * \-nostrend (txreq, txresp)
  *	Don't set the END_STREAM flag automatically, making the peer expect
  *	a body after the headers.
@@ -1386,7 +1394,7 @@ cmd_tx11obj(CMD_ARGS)
 	/*XXX: do we need a better api? yes we do */
 	struct hpk_hdr hdr;
 	char *cmd_str = *av;
-	char *p;
+	char *b, *p;
 	(void)cmd;
 
 	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
@@ -1540,7 +1548,28 @@ cmd_tx11obj(CMD_ARGS)
 				bodylen = strlen(body);
 				f.flags &= ~END_STREAM;
 				av++;
-			}else if (AV_IS("-dep")) {
+			}
+			else if (!strcmp(*av, "-gzipbody")) {
+				AZ(body);
+				vtc_gzip(s->hp, av[1], &body,
+				    (unsigned *)&bodylen);
+				AN(body);
+				ENC(hdr, ":content-encoding", "gzip");
+				f.flags &= ~END_STREAM;
+				av++;
+			}
+			else if (!strcmp(*av, "-gziplen")) {
+				AZ(body);
+				b = synth_body(av[1], 1);
+				vtc_gzip(s->hp, b, &body,
+				    (unsigned *)&bodylen);
+				AN(body);
+				free(b);
+				ENC(hdr, ":content-encoding", "gzip");
+				f.flags &= ~END_STREAM;
+				av++;
+			}
+			else if (AV_IS("-dep")) {
 				STRTOU32_CHECK(stid, av, p, vl, "-dep", 0);
 				f.flags |= PRIORITY;
 			}
@@ -2438,6 +2467,27 @@ cmd_expect(CMD_ARGS)
 	AZ(pthread_mutex_unlock(&s->hp->mtx));
 }
 
+/* SECTION: stream.spec.gunzip gunzip
+ *
+ * Same as the ``gunzip`` command for HTTP/1.
+ */
+static void
+cmd_gunzip(CMD_ARGS)
+{
+	struct http *hp;
+	struct stream *s;
+
+	(void)av;
+	(void)cmd;
+	(void)vl;
+
+	CAST_OBJ_NOTNULL(s, priv, STREAM_MAGIC);
+	hp = s->hp;
+	CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
+
+	vtc_gunzip(s->hp, s->body, (unsigned *)&s->bodylen);
+}
+
 /* SECTION: stream.spec.write_body
  *
  * write_body STRING
@@ -2469,6 +2519,7 @@ static const struct cmds stream_cmds[] = {
 #define CMD_STREAM(n) { #n, cmd_##n },
 	/* spec */
 	CMD_STREAM(expect)
+	CMD_STREAM(gunzip)
 	CMD_STREAM(rxcont)
 	CMD_STREAM(rxdata)
 	CMD_STREAM(rxframe)


More information about the varnish-commit mailing list