[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