varnish-cache/bin/varnishd/cache/cache_gzip.c
0
/*-
1
 * Copyright (c) 2013-2015 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
 * Interaction with the libvgz (zlib) library.
30
 *
31
 * The zlib library pollutes namespace a LOT when you include the "vgz.h"
32
 * (aka "zlib.h") file so we contain the damage by vectoring all access
33
 * to libz through this source file.
34
 *
35
 * The API defined by this file, will also insulate the rest of the code,
36
 * should we find a better gzip library at a later date.
37
 *
38
 */
39
40
#include "config.h"
41
42
#include <stdlib.h>
43
44
#include "cache_varnishd.h"
45
#include "cache_filter.h"
46
#include "cache_objhead.h"
47
#include "cache_vgz.h"
48
49
#include "storage/storage.h"
50
51
#include "vend.h"
52
53
#include "vgz.h"
54
55
struct vgz {
56
        unsigned                magic;
57
#define VGZ_MAGIC               0x162df0cb
58
        enum {VGZ_GZ,VGZ_UN}    dir;
59
        struct vsl_log          *vsl;
60
        const char              *id;
61
        int                     last_i;
62
        enum vgz_flag           flag;
63
64
        struct stv_buffer       *stvbuf;
65
        char                    *m_buf;
66
        ssize_t                 m_sz;
67
        ssize_t                 m_len;
68
69
        intmax_t                bits;
70
71
        z_stream                vz;
72
};
73
74
static const char *
75 240
vgz_msg(const struct vgz *vg)
76
{
77 240
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
78 240
        return (vg->vz.msg ? vg->vz.msg : "(null)");
79
}
80
81
/*--------------------------------------------------------------------
82
 * Set up a gunzip instance
83
 */
84
85
static struct vgz *
86 10240
vgz_gunzip(struct vsl_log *vsl, const char *id)
87
{
88
        struct vgz *vg;
89
90 10240
        ALLOC_OBJ(vg, VGZ_MAGIC);
91 10240
        AN(vg);
92 10240
        vg->vsl = vsl;
93 10240
        vg->id = id;
94 10240
        vg->dir = VGZ_UN;
95
96
        /*
97
         * Max memory usage according to zonf.h:
98
         *      mem_needed = "a few kb" + (1 << (windowBits))
99
         * Since we don't control windowBits, we have to assume
100
         * it is 15, so 34-35KB or so.
101
         */
102 10240
        assert(Z_OK == inflateInit2(&vg->vz, 31));
103 10240
        return (vg);
104
}
105
106
static struct vgz *
107 9000
VGZ_NewGunzip(struct vsl_log *vsl, const char *id)
108
{
109 9000
        VSC_C_main->n_gunzip++;
110 9000
        return (vgz_gunzip(vsl, id));
111
}
112
113
static struct vgz *
114 1240
VGZ_NewTestGunzip(struct vsl_log *vsl, const char *id)
115
{
116 1240
        VSC_C_main->n_test_gunzip++;
117 1240
        return (vgz_gunzip(vsl, id));
118
}
119
120
struct vgz *
121 3680
VGZ_NewGzip(struct vsl_log *vsl, const char *id)
122
{
123
        struct vgz *vg;
124
        int i;
125
126 3680
        VSC_C_main->n_gzip++;
127 3680
        ALLOC_OBJ(vg, VGZ_MAGIC);
128 3680
        AN(vg);
129 3680
        vg->vsl = vsl;
130 3680
        vg->id = id;
131 3680
        vg->dir = VGZ_GZ;
132
133
        /*
134
         * From zconf.h:
135
         *
136
         *      mem_needed = "a few kb"
137
         *              + (1 << (windowBits+2))
138
         *              +  (1 << (memLevel+9))
139
         *
140
         * windowBits [8..15] (-> 1K..128K)
141
         * memLevel [1..9] (-> 1K->256K)
142
         */
143 3680
        i = deflateInit2(&vg->vz,
144
            cache_param->gzip_level,            /* Level */
145
            Z_DEFLATED,                         /* Method */
146
            16 + 15,                            /* Window bits (16=gzip) */
147
            cache_param->gzip_memlevel,         /* memLevel */
148
            Z_DEFAULT_STRATEGY);
149 3680
        assert(Z_OK == i);
150 3680
        return (vg);
151
}
152
153
/*--------------------------------------------------------------------
154
 */
155
156
static int
157 10880
vgz_getmbuf(struct worker *wrk, struct vgz *vg)
158
{
159
        size_t sz;
160
161 10880
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
162 10880
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
163 10880
        AZ(vg->m_sz);
164 10880
        AZ(vg->m_len);
165 10880
        AZ(vg->m_buf);
166 10880
        AZ(vg->stvbuf);
167
168 10880
        vg->stvbuf = STV_AllocBuf(wrk, stv_transient, cache_param->gzip_buffer);
169 10880
        if (vg->stvbuf == NULL)
170 0
                return (-1);
171 10880
        vg->m_buf = STV_GetBufPtr(vg->stvbuf, &sz);
172 10880
        vg->m_sz = sz;
173 10880
        AN(vg->m_buf);
174 10880
        assert(vg->m_sz > 0);
175 10880
        return (0);
176 10880
}
177
178
/*--------------------------------------------------------------------*/
179
180
void
181 67351
VGZ_Ibuf(struct vgz *vg, const void *ptr, ssize_t len)
182
{
183
184 67351
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
185 67351
        AZ(vg->vz.avail_in);
186 67351
        assert(len >= 0);
187 67351
        if (len > 0)
188 45271
                AN(ptr);
189
190 67351
        vg->vz.next_in = TRUST_ME(ptr);
191 67351
        vg->vz.avail_in = len;
192 67351
}
193
194
int
195 151293
VGZ_IbufEmpty(const struct vgz *vg)
196
{
197
198 151293
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
199 151293
        return (vg->vz.avail_in == 0);
200
}
201
202
/*--------------------------------------------------------------------*/
203
204
void
205 72229
VGZ_Obuf(struct vgz *vg, void *ptr, ssize_t len)
206
{
207
208 72229
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
209 72229
        AN(ptr);
210 72229
        assert(len > 0);
211
212 72229
        vg->vz.next_out = ptr;
213 72229
        vg->vz.avail_out = len;
214 72229
}
215
216
int
217 42748
VGZ_ObufFull(const struct vgz *vg)
218
{
219
220 42748
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
221 42748
        return (vg->vz.avail_out == 0);
222
}
223
224
/*--------------------------------------------------------------------*/
225
226
static enum vgzret_e
227 33001
VGZ_Gunzip(struct vgz *vg, const void **pptr, ssize_t *plen)
228
{
229
        int i;
230
        ssize_t l;
231
        const uint8_t *before;
232
233 33001
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
234
235 33001
        *pptr = NULL;
236 33001
        *plen = 0;
237 33001
        AN(vg->vz.next_out);
238 33001
        AN(vg->vz.avail_out);
239 33001
        before = vg->vz.next_out;
240 33001
        i = inflate(&vg->vz, 0);
241 33001
        if (i == Z_OK || i == Z_STREAM_END) {
242 32839
                *pptr = before;
243 32839
                l = (const uint8_t *)vg->vz.next_out - before;
244 32839
                *plen = l;
245 32839
        }
246 33001
        vg->last_i = i;
247 33001
        if (i == Z_OK)
248 22561
                return (VGZ_OK);
249 10440
        if (i == Z_STREAM_END)
250 10280
                return (VGZ_END);
251 160
        if (i == Z_BUF_ERROR)
252 80
                return (VGZ_STUCK);
253 80
        VSLb(vg->vsl, SLT_Gzip, "Gunzip error: %d (%s)", i, vgz_msg(vg));
254 80
        return (VGZ_ERROR);
255 33001
}
256
257
/* set vz pointers for in and out iovecs */
258
static inline void
259 640
vgz_iovec_update(struct vgz *vg, const struct iovec *in, const struct iovec *buf)
260
{
261
        /* in: either fully consumed or the same */
262 640
        assert(vg->vz.avail_in == 0 || vg->vz.next_in == TRUST_ME(in->iov_base));
263 640
        vg->vz.next_in = TRUST_ME(in->iov_base);
264 640
        vg->vz.avail_in = in->iov_len;
265 640
        vg->vz.next_out = TRUST_ME(buf->iov_base);
266 640
        vg->vz.avail_out = buf->iov_len;
267 640
}
268
269
static enum vgzret_e
270 640
vgz_gunzip_iovec(struct vgz *vg, struct iovec *in, struct iovec *buf, struct iovec *out)
271
{
272
        int i;
273
274 640
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
275 640
        AN(in && buf && out);
276 640
        vgz_iovec_update(vg, in, buf);
277
278 640
        i = inflate(&vg->vz, 0);
279 640
        if (i == Z_OK || i == Z_STREAM_END) {
280 640
                iovec_collect(buf, out, pdiff(buf->iov_base, vg->vz.next_out));
281 640
                in->iov_base = TRUST_ME(vg->vz.next_in);
282 640
                in->iov_len = vg->vz.avail_in;
283 640
        }
284 640
        vg->last_i = i;
285 640
        if (i == Z_OK)
286 0
                return (VGZ_OK);
287 640
        if (i == Z_STREAM_END)
288 640
                return (VGZ_END);
289 0
        if (i == Z_BUF_ERROR)
290 0
                return (VGZ_STUCK);
291 0
        VSLb(vg->vsl, SLT_Gzip, "Gunzip error: %d (%s)", i, vgz_msg(vg));
292 0
        return (VGZ_ERROR);
293 640
}
294
295
/*--------------------------------------------------------------------*/
296
297
enum vgzret_e
298 45428
VGZ_Gzip(struct vgz *vg, const void **pptr, ssize_t *plen, enum vgz_flag flags)
299
{
300
        int i;
301
        int zflg;
302
        ssize_t l;
303
        const uint8_t *before;
304
305 45428
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
306
307 45428
        *pptr = NULL;
308 45428
        *plen = 0;
309 45428
        AN(vg->vz.next_out);
310 45428
        AN(vg->vz.avail_out);
311 45428
        before = vg->vz.next_out;
312 45428
        switch (flags) {
313 29908
        case VGZ_NORMAL:        zflg = Z_NO_FLUSH; break;
314 5000
        case VGZ_ALIGN:         zflg = Z_SYNC_FLUSH; break;
315 5040
        case VGZ_RESET:         zflg = Z_FULL_FLUSH; break;
316 5480
        case VGZ_FINISH:        zflg = Z_FINISH; break;
317 0
        default:                WRONG("Invalid VGZ flag");
318 0
        }
319 45428
        i = deflate(&vg->vz, zflg);
320 45428
        if (i == Z_OK || i == Z_STREAM_END) {
321 45428
                *pptr = before;
322 45428
                l = (const uint8_t *)vg->vz.next_out - before;
323 45428
                *plen = l;
324 45428
        }
325 45428
        vg->last_i = i;
326 45428
        if (i == Z_OK)
327 41948
                return (VGZ_OK);
328 3480
        if (i == Z_STREAM_END)
329 3480
                return (VGZ_END);
330 0
        if (i == Z_BUF_ERROR)
331 0
                return (VGZ_STUCK);
332 0
        VSLb(vg->vsl, SLT_Gzip, "Gzip error: %d (%s)", i, vgz_msg(vg));
333 0
        return (VGZ_ERROR);
334 45428
}
335
336
/*--------------------------------------------------------------------
337
 * VDP for gunzip'ing
338
 */
339
340
// common for traditional interface and vdpio
341
static int vdp_gunzip_init_common(struct vdp_ctx *vdc);
342
343
static int v_matchproto_(vdp_init_f)
344 4000
vdp_gunzip_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
345
{
346
        struct vgz *vg;
347
348 4000
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
349 4000
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
350 4000
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
351 4000
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
352 4000
        AN(vdc->clen);
353 4000
        AN(priv);
354
355 4000
        vg = VGZ_NewGunzip(vdc->vsl, "U D -");
356 4000
        AN(vg);
357 4000
        if (vgz_getmbuf(vdc->wrk, vg)) {
358 0
                (void)VGZ_Destroy(vdc->wrk, &vg);
359 0
                return (-1);
360
        }
361
362 4000
        VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
363 4000
        *priv = vg;
364 4000
        return (vdp_gunzip_init_common(vdc));
365 4000
}
366
367
static int
368 4000
vdp_gunzip_init_common(struct vdp_ctx *vdc)
369
{
370
        struct boc *boc;
371
        enum boc_state_e bos;
372
        const char *p;
373
        ssize_t dl;
374
        uint64_t u;
375 4000
        http_Unset(vdc->hp, H_Content_Encoding);
376
377 4000
        *vdc->clen = -1;
378
379 4000
        if (vdc->oc == NULL)
380 680
                return (0);
381
382 3320
        boc = HSH_RefBoc(vdc->oc);
383 3320
        if (boc != NULL) {
384 520
                CHECK_OBJ(boc, BOC_MAGIC);
385 520
                bos = boc->state;
386 520
                HSH_DerefBoc(vdc->wrk, vdc->oc);
387 520
                if (bos < BOS_FINISHED)
388 520
                        return (0); /* OA_GZIPBITS is not stable yet */
389 0
        }
390
391 2800
        p = ObjGetAttr(vdc->wrk, vdc->oc, OA_GZIPBITS, &dl);
392 2800
        if (p != NULL && dl == 32) {
393 2800
                u = vbe64dec(p + 24);
394 2800
                if (u != 0)
395 2760
                        *vdc->clen = u;
396 2800
        }
397 2800
        return (0);
398 4000
}
399
400
static int v_matchproto_(vdp_fini_f)
401 3360
vdp_gunzip_fini(struct vdp_ctx *vdc, void **priv)
402
{
403
        struct vgz *vg;
404
405 3360
        (void)vdc;
406 3360
        TAKE_OBJ_NOTNULL(vg, priv, VGZ_MAGIC);
407 3360
        AN(vg->m_buf);
408 3360
        (void)VGZ_Destroy(vdc->wrk, &vg);
409 3360
        return (0);
410
}
411
412
static int v_matchproto_(vdp_bytes_f)
413 17716
vdp_gunzip_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
414
    const void *ptr, ssize_t len)
415
{
416
        enum vgzret_e vr;
417
        ssize_t dl;
418
        const void *dp;
419
        struct vgz *vg;
420
421 17716
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
422 17716
        CHECK_OBJ_NOTNULL(vdc->wrk, WORKER_MAGIC);
423 17716
        (void)act;
424
425 17716
        CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC);
426 17716
        AN(vg->m_buf);
427
428 17716
        if (len == 0)
429 4676
                return (0);
430
431 13040
        VGZ_Ibuf(vg, ptr, len);
432 13040
        do {
433 13040
                vr = VGZ_Gunzip(vg, &dp, &dl);
434 13040
                if (vr == VGZ_END && !VGZ_IbufEmpty(vg)) {
435 80
                        VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)",
436 40
                             vr, "junk after VGZ_END");
437 40
                        return (-1);
438
                }
439 13000
                vg->m_len += dl;
440 13000
                if (vr < VGZ_OK)
441 0
                        return (-1);
442
                // END or STUCK
443 13000
                if (vg->m_len == vg->m_sz || vr != VGZ_OK) {
444 6480
                        if (VDP_bytes(vdc, vr == VGZ_END ? VDP_END : VDP_FLUSH,
445 3240
                            vg->m_buf, vg->m_len))
446 160
                                return (vdc->retval);
447 3080
                        vg->m_len = 0;
448 3080
                        VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
449 3080
                }
450 12840
        } while (!VGZ_IbufEmpty(vg));
451 12840
        assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END);
452 12840
        return (0);
453 17716
}
454
455
#ifdef LATER
456
/*
457
 * XXX does it make sense to work on more than one buffer?
458
 */
459
static int v_matchproto_(vdpio_init_f)
460
vdpio_gunzip_init(VRT_CTX, struct vdp_ctx *vdc, void **priv, int capacity)
461
{
462
        struct vgz *vg;
463
        struct vscarab *in;
464
465
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
466
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
467
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
468
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
469
        AN(vdc->clen);
470
        AN(priv);
471
        assert(capacity >= 1);
472
473
        if (capacity < 4)
474
                capacity = 4;
475
476
        in = WS_Alloc(ctx->ws, VSCARAB_SIZE(capacity));
477
        if (in == NULL)
478
                return (-1);
479
480
        vg = VGZ_NewGunzip(vdc->vsl, "U D -");
481
        if (vg == NULL)
482
                return (-1);
483
484
        AZ(vg->m_buf);
485
        vg->m_buf = (void *)in;
486
487
        *priv = vg;
488
        AZ(vdp_gunzip_init_common(vdc));
489
        return (1);
490
}
491
#endif
492
493
static int v_matchproto_(vdpio_init_f)
494 640
vdpio_gunzip_upgrade(VRT_CTX, struct vdp_ctx *vdc, void **priv, int capacity)
495
{
496
        struct vgz *vg;
497
        struct vscarab *in;
498
499 640
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
500 640
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
501 640
        AN(priv);
502 640
        assert(capacity >= 1);
503
504 640
        if (capacity < 4)
505 640
                capacity = 4;
506
507
        /* done in vdp_gunzip_init */
508 640
        CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC);
509
510 640
        in = WS_Alloc(ctx->ws, VSCARAB_SIZE(capacity));
511 640
        if (in == NULL)
512 0
                return (-1);
513 640
        VSCARAB_INIT(in, capacity);
514
515
        // XXX duplicate work - remove when completing transition to VAI
516 640
        AN(vg->m_buf);
517 640
        AN(vg->stvbuf);
518 640
        STV_FreeBuf(vdc->wrk, &vg->stvbuf);
519 640
        vg->stvbuf = NULL;
520 640
        vg->m_buf = (void *)in;
521
522 640
        return (1);
523 640
}
524
525
static int v_matchproto_(vdpio_lease_f)
526 1440
vdpio_gunzip_lease(struct vdp_ctx *vdc, struct vdp_entry *this, struct vscarab *out)
527
{
528
        struct vscarab *in;
529
        enum vgzret_e vr;
530
        struct vgz *vg;
531
        struct viov *v, *b, *o;
532
        int r;
533
534 1440
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
535 1440
        CHECK_OBJ_NOTNULL(this, VDP_ENTRY_MAGIC);
536 1440
        CAST_OBJ_NOTNULL(vg, this->priv, VGZ_MAGIC);
537 1440
        CAST_OBJ_NOTNULL(in, (void*)vg->m_buf, VSCARAB_MAGIC);
538
539 1440
        this->calls++;
540
541 1440
        if (out->used == out->capacity)
542 640
                return (0);
543
544 800
        if (in->used < in->capacity && (in->flags & VSCARAB_F_END) == 0)
545 800
                r = vdpio_pull(vdc, this, in);
546
        else
547 0
                r = 0;
548
549 800
        if (in->used == 0) {
550 160
                out->flags = in->flags & VSCARAB_F_END;
551 160
                return (r);
552
        }
553
554
        // XXX more than one buffer?
555 640
        VSCARAB_LOCAL(buf, 1);
556 640
        b = VSCARAB_GET(buf);
557 640
        AN(b);
558 640
        b->iov.iov_len = cache_param->gzip_buffer;
559 640
        r = ObjVAIbuffer(vdc->wrk, vdc->vai_hdl, buf);
560 640
        if (r < 0)
561 0
                return (out->used ? 0 : r);
562
563 640
        o = VSCARAB_GET(out);
564 640
        AN(o);
565 640
        r = 0;
566
567 640
        VSCARAB_FOREACH(v, in) {
568 640
                this->bytes_in += v->iov.iov_len;
569 640
                vr = vgz_gunzip_iovec(vg, &v->iov, &b->iov, &o->iov);
570 640
                if (vr == VGZ_END && v->iov.iov_len > 0) {
571 0
                        VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)",
572 0
                             vr, "junk after VGZ_END");
573 0
                        r = -EMSGSIZE;
574 0
                        break;
575
                }
576 640
                if (vr < VGZ_OK)
577 0
                        break;
578
579 640
                if (b->iov.iov_len == 0 || vr != VGZ_OK) {
580 640
                        r = 1;
581 640
                        break;
582
                }
583 0
        }
584
585 640
        if (r <= 0) {
586 0
                o->iov.iov_base = NULL;
587 0
                o->iov.iov_len = 0;
588 0
                vdpio_return_lease(vdc, b->lease);
589 0
                return (r);
590
        }
591
592 640
        o->lease = b->lease;
593 640
        b->lease = 0;
594
595 640
        vdpio_consolidate_vscarab(vdc, in);
596 640
        if (in->used == 0)
597 640
                out->flags = in->flags & VSCARAB_F_END;
598
599 640
        return (r);
600 1440
}
601
602
static void v_matchproto_(vdpio_fini_f)
603 640
vdpio_gunzip_fini(struct vdp_ctx *vdc, void **priv)
604
{
605
        struct vscarab *in;
606
        struct vgz *vg;
607
608 640
        (void)vdc;
609 640
        TAKE_OBJ_NOTNULL(vg, priv, VGZ_MAGIC);
610 640
        CAST_OBJ_NOTNULL(in, (void *)vg->m_buf, VSCARAB_MAGIC);
611 640
        vg->m_buf = NULL;
612
613 640
        (void)VGZ_Destroy(vdc->wrk, &vg);
614 640
}
615
616
const struct vdp VDP_gunzip = {
617
        .name =         "gunzip",
618
        .init =         vdp_gunzip_init,
619
        .bytes =        vdp_gunzip_bytes,
620
        .fini =         vdp_gunzip_fini,
621
622
#ifdef LATER
623
        .io_init =      vdpio_gunzip_init,
624
#endif
625
        .io_upgrade =   vdpio_gunzip_upgrade,
626
        .io_lease =     vdpio_gunzip_lease,
627
        .io_fini =      vdpio_gunzip_fini,
628
};
629
630
/*--------------------------------------------------------------------*/
631
632
void
633 50152
VGZ_UpdateObj(const struct vfp_ctx *vc, struct vgz *vg, enum vgzret_e e)
634
{
635
        char *p;
636
        intmax_t ii;
637
638 50152
        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
639 50152
        if (e < VGZ_OK)
640 0
                return;
641 50152
        ii = vg->vz.start_bit + vg->vz.last_bit + vg->vz.stop_bit;
642 50152
        if (e != VGZ_END && ii == vg->bits)
643 36828
                return;
644 13324
        vg->bits = ii;
645 13324
        p = ObjSetAttr(vc->wrk, vc->oc, OA_GZIPBITS, 32, NULL);
646 13324
        AN(p);
647 13324
        vbe64enc(p, vg->vz.start_bit);
648 13324
        vbe64enc(p + 8, vg->vz.last_bit);
649 13324
        vbe64enc(p + 16, vg->vz.stop_bit);
650 13324
        if (e != VGZ_END)
651 5084
                return;
652 8240
        if (vg->dir == VGZ_GZ)
653 6960
                vbe64enc(p + 24, vg->vz.total_in);
654 8240
        if (vg->dir == VGZ_UN)
655 1280
                vbe64enc(p + 24, vg->vz.total_out);
656 50152
}
657
658
/*--------------------------------------------------------------------
659
 */
660
661
enum vgzret_e
662 13920
VGZ_Destroy(struct worker *wrk, struct vgz **vgp)
663
{
664
        struct vgz *vg;
665
        enum vgzret_e vr;
666
        int i;
667
668 13920
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
669 13920
        TAKE_OBJ_NOTNULL(vg, vgp, VGZ_MAGIC);
670 13920
        AN(vg->id);
671 27840
        VSLb(vg->vsl, SLT_Gzip, "%s %jd %jd %jd %jd %jd",
672 13920
            vg->id,
673 13920
            (intmax_t)vg->vz.total_in,
674 13920
            (intmax_t)vg->vz.total_out,
675 13920
            (intmax_t)vg->vz.start_bit,
676 13920
            (intmax_t)vg->vz.last_bit,
677 13920
            (intmax_t)vg->vz.stop_bit);
678 13920
        if (vg->dir == VGZ_GZ)
679 3680
                i = deflateEnd(&vg->vz);
680
        else
681 10240
                i = inflateEnd(&vg->vz);
682 13920
        if (vg->last_i == Z_STREAM_END && i == Z_OK)
683 11320
                i = Z_STREAM_END;
684 13920
        if (vg->m_buf != NULL) {
685 10240
                AN(vg->stvbuf);
686 10240
                STV_FreeBuf(wrk, &vg->stvbuf);
687 10240
        }
688 13920
        AZ(vg->stvbuf);
689 13920
        if (i == Z_OK)
690 2520
                vr = VGZ_OK;
691 11400
        else if (i == Z_STREAM_END)
692 11320
                vr = VGZ_END;
693 80
        else if (i == Z_BUF_ERROR)
694 0
                vr = VGZ_STUCK;
695
        else {
696 160
                VSLb(vg->vsl, SLT_Gzip, "G(un)zip error: %d (%s)",
697 80
                    i, vgz_msg(vg));
698 80
                vr = VGZ_ERROR;
699
        }
700 13920
        FREE_OBJ(vg);
701 13920
        return (vr);
702
}
703
704
/*--------------------------------------------------------------------*/
705
706
static enum vfp_status v_matchproto_(vfp_init_f)
707 7040
vfp_gzip_init(VRT_CTX, struct vfp_ctx *vc, struct vfp_entry *vfe)
708
{
709
        struct vgz *vg;
710
711 7040
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
712 7040
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
713 7040
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
714
715
        /*
716
         * G(un)zip makes no sence on partial responses, but since
717
         * it is an pure 1:1 transform, we can just ignore it.
718
         */
719 7040
        if (http_GetStatus(vc->resp) == 206)
720 160
                return (VFP_NULL);
721
722 6880
        if (vfe->vfp == &VFP_gzip) {
723 640
                if (http_GetHdr(vc->resp, H_Content_Encoding, NULL))
724 0
                        return (VFP_NULL);
725 640
                vg = VGZ_NewGzip(vc->wrk->vsl, vfe->vfp->priv1);
726 640
                vc->obj_flags |= OF_GZIPED | OF_CHGCE;
727 640
        } else {
728 6240
                if (!http_HdrIs(vc->resp, H_Content_Encoding, "gzip"))
729 0
                        return (VFP_NULL);
730 6240
                if (vfe->vfp == &VFP_gunzip) {
731 5000
                        vg = VGZ_NewGunzip(vc->wrk->vsl, vfe->vfp->priv1);
732 5000
                        vc->obj_flags &= ~OF_GZIPED;
733 5000
                        vc->obj_flags |= OF_CHGCE;
734 5000
                } else {
735 1240
                        vg = VGZ_NewTestGunzip(vc->wrk->vsl, vfe->vfp->priv1);
736 1240
                        vc->obj_flags |= OF_GZIPED;
737
                }
738
        }
739 6880
        AN(vg);
740 6880
        vfe->priv1 = vg;
741 6880
        if (vgz_getmbuf(vc->wrk, vg))
742 0
                return (VFP_ERROR);
743 6880
        VGZ_Ibuf(vg, vg->m_buf, 0);
744 6880
        AZ(vg->m_len);
745
746 6880
        if (vfe->vfp == &VFP_gunzip || vfe->vfp == &VFP_gzip) {
747 5640
                http_Unset(vc->resp, H_Content_Encoding);
748 5640
                http_Unset(vc->resp, H_Content_Length);
749 5640
                RFC2616_Weaken_Etag(vc->resp);
750 5640
        }
751
752 6880
        if (vfe->vfp == &VFP_gzip)
753 640
                http_SetHeader(vc->resp, "Content-Encoding: gzip");
754
755 6880
        if (vfe->vfp == &VFP_gzip || vfe->vfp == &VFP_testgunzip)
756 1880
                RFC2616_Vary_AE(vc->resp);
757
758 6880
        return (VFP_OK);
759 7040
}
760
761
/*--------------------------------------------------------------------
762
 * VFP_GUNZIP
763
 *
764
 * A VFP for gunzip'ing an object as we receive it from the backend
765
 */
766
767
static enum vfp_status v_matchproto_(vfp_pull_f)
768 18357
vfp_gunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
769
    ssize_t *lp)
770
{
771
        ssize_t l;
772
        struct vgz *vg;
773 18357
        enum vgzret_e vr = VGZ_ERROR;
774
        const void *dp;
775
        ssize_t dl;
776 18357
        enum vfp_status vp = VFP_OK;
777
778 18357
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
779 18357
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
780 18357
        CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC);
781 18357
        AN(p);
782 18357
        AN(lp);
783 18357
        l = *lp;
784 18357
        *lp = 0;
785 18357
        VGZ_Obuf(vg, p, l);
786 18357
        do {
787 18437
                if (VGZ_IbufEmpty(vg)) {
788 5800
                        l = vg->m_sz;
789 5800
                        vp = VFP_Suck(vc, vg->m_buf, &l);
790 5800
                        if (vp == VFP_ERROR)
791 0
                                return (vp);
792 5800
                        VGZ_Ibuf(vg, vg->m_buf, l);
793 5800
                }
794 18437
                if (!VGZ_IbufEmpty(vg) || vp == VFP_END) {
795 18437
                        vr = VGZ_Gunzip(vg, &dp, &dl);
796 18437
                        if (vr == VGZ_END && !VGZ_IbufEmpty(vg))
797 40
                                return (VFP_Error(vc, "Junk after gzip data"));
798 18397
                        if (vr < VGZ_OK)
799 160
                                return (VFP_Error(vc,
800 80
                                    "Invalid Gzip data: %s", vgz_msg(vg)));
801 18317
                        if (dl > 0) {
802 15437
                                *lp = dl;
803 15437
                                assert(dp == p);
804 15437
                                return (VFP_OK);
805
                        }
806 2880
                }
807 2880
                AN(VGZ_IbufEmpty(vg));
808 2880
        } while (vp == VFP_OK);
809 2800
        if (vr != VGZ_END)
810 40
                return (VFP_Error(vc, "Gunzip error at the very end"));
811 2760
        return (vp);
812 18357
}
813
814
815
/*--------------------------------------------------------------------
816
 * VFP_GZIP
817
 *
818
 * A VFP for gzip'ing an object as we receive it from the backend
819
 */
820
821
static enum vfp_status v_matchproto_(vfp_pull_f)
822 2520
vfp_gzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
823
    ssize_t *lp)
824
{
825
        ssize_t l;
826
        struct vgz *vg;
827 2520
        enum vgzret_e vr = VGZ_ERROR;
828
        const void *dp;
829
        ssize_t dl;
830 2520
        enum vfp_status vp = VFP_ERROR;
831
832 2520
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
833 2520
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
834 2520
        CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC);
835 2520
        AN(p);
836 2520
        AN(lp);
837 2520
        l = *lp;
838 2520
        *lp = 0;
839 2520
        VGZ_Obuf(vg, p, l);
840 2520
        do {
841 2680
                if (VGZ_IbufEmpty(vg)) {
842 2520
                        l = vg->m_sz;
843 2520
                        vp = VFP_Suck(vc, vg->m_buf, &l);
844 2520
                        if (vp == VFP_ERROR)
845 0
                                break;
846 2520
                        if (vp == VFP_END)
847 880
                                vg->flag = VGZ_FINISH;
848 2520
                        VGZ_Ibuf(vg, vg->m_buf, l);
849 2520
                }
850 2680
                if (!VGZ_IbufEmpty(vg) || vg->flag == VGZ_FINISH) {
851 2680
                        vr = VGZ_Gzip(vg, &dp, &dl, vg->flag);
852 2680
                        if (vr < VGZ_OK)
853 0
                                return (VFP_Error(vc, "Gzip failed"));
854 2680
                        if (dl > 0) {
855 2520
                                VGZ_UpdateObj(vc, vg, vr);
856 2520
                                *lp = dl;
857 2520
                                assert(dp == p);
858 2520
                                if (vr != VGZ_END || !VGZ_IbufEmpty(vg))
859 1920
                                        return (VFP_OK);
860 600
                        }
861 760
                }
862 760
                AN(VGZ_IbufEmpty(vg));
863 760
        } while (vg->flag != VGZ_FINISH);
864
865 600
        if (vr != VGZ_END)
866 0
                return (VFP_Error(vc, "Gzip failed"));
867 600
        VGZ_UpdateObj(vc, vg, VGZ_END);
868 600
        return (VFP_END);
869 2520
}
870
871
/*--------------------------------------------------------------------
872
 * VFP_TESTGZIP
873
 *
874
 * A VFP for testing that received gzip data is valid, and for
875
 * collecting the magic bits while we're at it.
876
 */
877
878
static enum vfp_status v_matchproto_(vfp_pull_f)
879 1604
vfp_testgunzip_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
880
    ssize_t *lp)
881
{
882
        struct vgz *vg;
883 1604
        enum vgzret_e vr = VGZ_ERROR;
884
        const void *dp;
885
        ssize_t dl;
886
        enum vfp_status vp;
887
888 1604
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
889 1604
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
890 1604
        CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC);
891 1604
        AN(p);
892 1604
        AN(lp);
893 1604
        vp = VFP_Suck(vc, p, lp);
894 1604
        if (vp == VFP_ERROR)
895 80
                return (vp);
896 1524
        if (*lp > 0 || vp == VFP_END) {
897 1524
                VGZ_Ibuf(vg, p, *lp);
898 1524
                do {
899 1524
                        VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
900 1524
                        vr = VGZ_Gunzip(vg, &dp, &dl);
901 1524
                        if (vr == VGZ_END && !VGZ_IbufEmpty(vg))
902 120
                                return (VFP_Error(vc, "Junk after gzip data"));
903 1404
                        if (vr < VGZ_OK)
904 0
                                return (VFP_Error(vc,
905 0
                                    "Invalid Gzip data: %s", vgz_msg(vg)));
906 1404
                } while (!VGZ_IbufEmpty(vg));
907 1404
        }
908 1404
        VGZ_UpdateObj(vc, vg, vr);
909 1404
        if (vp == VFP_END && vr != VGZ_END)
910 40
                return (VFP_Error(vc, "tGunzip failed"));
911 1364
        return (vp);
912 1604
}
913
914
/*--------------------------------------------------------------------*/
915
916
static void v_matchproto_(vfp_fini_f)
917 7480
vfp_gzip_fini(struct vfp_ctx *vc, struct vfp_entry *vfe)
918
{
919
        struct vgz *vg;
920
921 7480
        CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC);
922 7480
        CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC);
923
924 7480
        if (vfe->priv1 != NULL) {
925 6880
                TAKE_OBJ_NOTNULL(vg, &vfe->priv1, VGZ_MAGIC);
926 6880
                (void)VGZ_Destroy(vc->wrk, &vg);
927 6880
        }
928 7480
}
929
930
/*--------------------------------------------------------------------*/
931
932
const struct vfp VFP_gunzip = {
933
        .name = "gunzip",
934
        .init = vfp_gzip_init,
935
        .pull = vfp_gunzip_pull,
936
        .fini = vfp_gzip_fini,
937
        .priv1 = "U F -",
938
};
939
940
const struct vfp VFP_gzip = {
941
        .name = "gzip",
942
        .init = vfp_gzip_init,
943
        .pull = vfp_gzip_pull,
944
        .fini = vfp_gzip_fini,
945
        .priv1 = "G F -",
946
};
947
948
const struct vfp VFP_testgunzip = {
949
        .name = "testgunzip",
950
        .init = vfp_gzip_init,
951
        .pull = vfp_testgunzip_pull,
952
        .fini = vfp_gzip_fini,
953
        .priv1 = "u F -",
954
};