vinyl-cache/bin/vinyltest/vtest2/src/vtc_gzip.c
0
/*-
1
 * Copyright (c) 2008-2019 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <stdio.h>
33
#include <stdlib.h>
34
#include <string.h>
35
36
#include "vtc.h"
37
#include "vtc_http.h"
38
#if defined(WITH_ZLIB)
39
#include <zlib.h>
40
#else
41
#include "vgz.h"
42
#endif
43
44
#ifdef VGZ_EXTENSIONS
45
static void
46 1045
vtc_report_gz_bits(struct vtclog *vl, const z_stream *vz)
47
{
48 2090
        vtc_log(vl, 4, "startbit = %ju %ju/%ju",
49 1045
            (uintmax_t)vz->start_bit,
50 1045
            (uintmax_t)vz->start_bit >> 3, (uintmax_t)vz->start_bit & 7);
51 2090
        vtc_log(vl, 4, "lastbit = %ju %ju/%ju",
52 1045
            (uintmax_t)vz->last_bit,
53 1045
            (uintmax_t)vz->last_bit >> 3, (uintmax_t)vz->last_bit & 7);
54 2090
        vtc_log(vl, 4, "stopbit = %ju %ju/%ju",
55 1045
            (uintmax_t)vz->stop_bit,
56 1045
            (uintmax_t)vz->stop_bit >> 3, (uintmax_t)vz->stop_bit & 7);
57 1045
}
58
#endif
59
60
static size_t
61 4270
APOS(ssize_t sz)
62
{
63 4270
        assert(sz >= 0);
64 4270
        return (sz);
65
}
66
67
/**********************************************************************
68
 * GUNZIPery
69
 */
70
71
static struct vsb *
72 205
vtc_gunzip_vsb(struct vtclog *vl, int fatal, const struct vsb *vin)
73
{
74
        z_stream vz;
75
        struct vsb *vout;
76
        int i;
77
        char buf[BUFSIZ];
78
79 205
        memset(&vz, 0, sizeof vz);
80 205
        vout = VSB_new_auto();
81 205
        AN(vout);
82
83 205
        vz.next_in = (void*)VSB_data(vin);
84 205
        vz.avail_in = APOS(VSB_len(vin));
85
86 205
        assert(Z_OK == inflateInit2(&vz, 31));
87
88 205
        do {
89 255
                vz.next_out = (void*)buf;
90 255
                vz.avail_out = sizeof buf;
91 255
                i = inflate(&vz, Z_FINISH);
92 255
                if (vz.avail_out != sizeof buf)
93 255
                        VSB_bcat(vout, buf, sizeof buf - vz.avail_out);
94 255
        } while (i == Z_OK || i == Z_BUF_ERROR);
95 205
        if (i != Z_STREAM_END)
96 0
                vtc_log(vl, fatal,
97
                    "Gunzip error = %d (%s) in:%jd out:%jd len:%zd",
98 0
                    i, vz.msg, (intmax_t)vz.total_in, (intmax_t)vz.total_out,
99 0
                    VSB_len(vin));
100 205
        AZ(VSB_finish(vout));
101
#ifdef VGZ_EXTENSIONS
102 205
        vtc_report_gz_bits(vl, &vz);
103
#endif
104 205
        assert(Z_OK == inflateEnd(&vz));
105 205
        return (vout);
106
}
107
108
void
109 205
vtc_gunzip(struct http *hp, char *body, long *bodylen)
110
{
111
        struct vsb *vin, *vout;
112
113 205
        AN(body);
114 205
        if (body[0] != (char)0x1f || body[1] != (char)0x8b)
115 0
                vtc_log(hp->vl, hp->fatal,
116
                    "Gunzip error: body lacks gzip magic");
117
118 205
        vin = VSB_new_auto();
119 205
        AN(vin);
120 205
        VSB_bcat(vin, body, *bodylen);
121 205
        AZ(VSB_finish(vin));
122 205
        vout = vtc_gunzip_vsb(hp->vl, hp->fatal, vin);
123 205
        VSB_destroy(&vin);
124
125 205
        memcpy(body, VSB_data(vout), APOS(VSB_len(vout) + 1));
126 205
        *bodylen = APOS(VSB_len(vout));
127 205
        VSB_destroy(&vout);
128 205
        vtc_log(hp->vl, 3, "new bodylen %ld", *bodylen);
129 205
        vtc_dump(hp->vl, 4, "body", body, *bodylen);
130 205
        bprintf(hp->bodylen, "%ld", *bodylen);
131 205
}
132
133
/**********************************************************************
134
 * GZIPery
135
 */
136
137
static int
138 1135
vtc_gzip_chunk(z_stream *vz, struct vsb *vout, const char *in, size_t inlen, int flush)
139
{
140
        int i;
141
        char buf[BUFSIZ];
142
143 1135
        vz->next_in = TRUST_ME(in);
144 1135
        vz->avail_in = APOS(inlen);
145 1135
        do {
146 1475
                vz->next_out = (void*)buf;
147 1475
                vz->avail_out = sizeof buf;
148 1475
                i = deflate(vz, flush);
149 1475
                if (vz->avail_out != sizeof buf)
150 1180
                        VSB_bcat(vout, buf, sizeof buf - vz->avail_out);
151 1475
        } while (i == Z_OK || vz->avail_in > 0);
152 1135
        vz->next_out = NULL;
153 1135
        vz->avail_out = 0;
154 1135
        vz->next_in = NULL;
155 1135
        AZ(vz->avail_in);
156 1135
        vz->avail_in = 0;
157 1135
        return (i);
158
}
159
160
static void
161 840
vtc_gzip(struct http *hp, const char *input, char **body, long *bodylen, int fragment)
162
{
163
        struct vsb *vout;
164
        int i, res;
165 840
        size_t inlen = strlen(input);
166
        z_stream vz;
167
168 840
        memset(&vz, 0, sizeof vz);
169 840
        vout = VSB_new_auto();
170 840
        AN(vout);
171
172 840
        assert(Z_OK == deflateInit2(&vz,
173
            hp->gziplevel, Z_DEFLATED, 31, 9, Z_DEFAULT_STRATEGY));
174
175 1135
        while (fragment && inlen > 3) {
176 295
                res = inlen / 3;
177 295
                i = vtc_gzip_chunk(&vz, vout, input, res, Z_BLOCK);
178 295
                if (i != Z_OK && i != Z_BUF_ERROR) {
179 0
                        vtc_log(hp->vl, hp->fatal,
180
                            "Gzip error = %d (%s) in:%jd out:%jd len:%zd",
181 0
                            i, vz.msg, (intmax_t)vz.total_in,
182 0
                            (intmax_t)vz.total_out, strlen(input));
183 0
                }
184 295
                input += res;
185 295
                inlen -= res;
186
        }
187
188 840
        i = vtc_gzip_chunk(&vz, vout, input, inlen, Z_FINISH);
189 840
        if (i != Z_STREAM_END) {
190 0
                vtc_log(hp->vl, hp->fatal,
191
                    "Gzip error = %d (%s) in:%jd out:%jd len:%zd",
192 0
                    i, vz.msg, (intmax_t)vz.total_in, (intmax_t)vz.total_out,
193 0
                    strlen(input));
194 0
        }
195 840
        AZ(VSB_finish(vout));
196
#ifdef VGZ_EXTENSIONS
197 840
        res = vz.stop_bit & 7;
198 840
        vtc_report_gz_bits(hp->vl, &vz);
199
#else
200
        res = 0;
201
#endif
202 840
        assert(Z_OK == deflateEnd(&vz));
203
204
#ifdef VGZ_EXTENSIONS
205 840
        if (hp->gzipresidual >= 0 && hp->gzipresidual != res)
206 0
                vtc_log(hp->vl, hp->fatal,
207
                    "Wrong gzip residual got %d wanted %d",
208 0
                    res, hp->gzipresidual);
209
#endif
210 840
        *body = malloc(APOS(VSB_len(vout) + 1));
211 840
        AN(*body);
212 840
        memcpy(*body, VSB_data(vout), APOS(VSB_len(vout) + 1));
213 840
        *bodylen = APOS(VSB_len(vout));
214 840
        VSB_destroy(&vout);
215 840
        vtc_log(hp->vl, 3, "new bodylen %ld", *bodylen);
216 840
        vtc_dump(hp->vl, 4, "body", *body, *bodylen);
217 840
        bprintf(hp->bodylen, "%ld", *bodylen);
218 840
}
219
220
int
221 930
vtc_gzip_cmd(struct http *hp, char * const *av, char **body, long *bodylen)
222
{
223
        char *b;
224
225 930
        AN(hp);
226 930
        AN(av);
227 930
        AN(body);
228 930
        AN(bodylen);
229
230 930
        if (!strcmp(*av, "-gzipresidual")) {
231 40
                hp->gzipresidual = strtoul(av[1], NULL, 0);
232 40
                return (1);
233
        }
234 890
        if (!strcmp(*av, "-gziplevel")) {
235 50
                hp->gziplevel = strtoul(av[1], NULL, 0);
236 50
                return (1);
237
        }
238 840
        if (!strcmp(*av, "-gzipbody")) {
239 815
                if (*body != NULL)
240 800
                        free(*body);
241 815
                *body = NULL;
242 815
                vtc_gzip(hp, av[1], body, bodylen, 0);
243 815
                AN(*body);
244 815
                return (2);
245
        }
246 25
        if (!strcmp(*av, "-gziplen")) {
247 25
                if (*body != NULL)
248 20
                        free(*body);
249 25
                *body = NULL;
250 25
                b = synth_body(av[1], 1);
251 25
                vtc_gzip(hp, b, body, bodylen, 1);
252 25
                AN(*body);
253 25
                free(b);
254 25
                return (2);
255
        }
256 0
        return (0);
257 930
}