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