source: bin/varnishd/cache_gzip.c @ 09e0e8

Revision 09e0e8, 13.0 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Continuation of #861 fix: The vef structure cannot be on the
workspace either.

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2011 Varnish Software AS
3 * All rights reserved.
4 *
5 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * Interaction with the linvgz (zlib) library.
29 *
30 * The zlib library pollutes namespace a LOT when you include the "vgz.h"
31 * (aka (zlib.h") file so we contain the damage by vectoring all access
32 * to libz through this source file.
33 *
34 * The API defined by this file, will also insulate the rest of the code,
35 * should we find a better gzip library at a later date.
36 *
37 * The absolutely worst case gzip processing path, once we have pipe-lining,
38 * will be the following, so we need to be a bit careful with the scratch
39 * space we use:
40 *
41 *      Backend         Tmp     Input   Output
42 *         |            ----------------------
43 *         v
44 *       gunzip         wrk     stack   ?
45 *         |
46 *         v
47 *        esi
48 *         |
49 *         v
50 *        gzip          wrk     ?       storage
51 *         |
52 *         v
53 *        cache
54 *         |
55 *         v
56 *       gunzip         wrk     storage stack
57 *         |
58 *         v
59 *       client
60 *
61 * XXXX: The two '?' are obviously the same memory, but I have yet to decide
62 * where it goes.   As usual we try to avoid the session->ws if we can but
63 * I may have to use that.
64 *
65 */
66
67#include "config.h"
68#include <stdio.h>
69#include <stdlib.h>
70
71#include "svnid.h"
72SVNID("$Id$")
73
74#include "vsl.h"
75#include "cache.h"
76#include "stevedore.h"
77
78#include "vgz.h"
79
80struct vgz {
81        unsigned                magic;
82#define VGZ_MAGIC               0x162df0cb
83        struct sess             *sess;
84        const char              *id;
85        struct ws               *tmp;
86        char                    *tmp_snapshot;
87
88        struct storage          *obuf;
89
90        z_stream                vz;
91};
92
93/*--------------------------------------------------------------------*/
94
95static voidpf
96vgz_alloc(voidpf opaque, uInt items, uInt size)
97{
98        struct vgz *vg;
99
100        CAST_OBJ_NOTNULL(vg, opaque, VGZ_MAGIC);
101
102        return (WS_Alloc(vg->tmp, items * size));
103}
104
105static void
106vgz_free(voidpf opaque, voidpf address)
107{
108        struct vgz *vg;
109
110        CAST_OBJ_NOTNULL(vg, opaque, VGZ_MAGIC);
111        (void)address;
112}
113
114/*--------------------------------------------------------------------
115 * Set up a gunzip instance
116 */
117
118static struct vgz *
119vgz_alloc_vgz(struct sess *sp, const char *id)
120{
121        struct vgz *vg;
122        struct ws *ws = sp->wrk->ws;
123
124        WS_Assert(ws);
125        // XXX: we restore workspace in esi:include
126        // vg = (void*)WS_Alloc(ws, sizeof *vg);
127        ALLOC_OBJ(vg, VGZ_MAGIC);
128        AN(vg);
129        memset(vg, 0, sizeof *vg);
130        vg->magic = VGZ_MAGIC;
131        vg->sess = sp;
132        vg->id = id;
133
134        switch (params->gzip_tmp_space) {
135        case 0:
136                /* malloc, the default */
137                break;
138        case 1:
139                vg->tmp = sp->ws;
140                vg->tmp_snapshot = WS_Snapshot(vg->tmp);
141                vg->vz.zalloc = vgz_alloc;
142                vg->vz.zfree = vgz_free;
143                vg->vz.opaque = vg;
144                break;
145        case 2:
146                vg->tmp = sp->wrk->ws;
147                vg->tmp_snapshot = WS_Snapshot(vg->tmp);
148                vg->vz.zalloc = vgz_alloc;
149                vg->vz.zfree = vgz_free;
150                vg->vz.opaque = vg;
151                break;
152        default:
153                assert(0 == __LINE__);
154        }
155        return (vg);
156}
157
158struct vgz *
159VGZ_NewUngzip(struct sess *sp, const char *id)
160{
161        struct vgz *vg;
162
163        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
164        vg = vgz_alloc_vgz(sp, id);
165        VSC_main->n_gunzip++;
166
167        /*
168         * Max memory usage according to zonf.h:
169         *      mem_needed = "a few kb" + (1 << (windowBits))
170         * Since we don't control windowBits, we have to assume
171         * it is 15, so 34-35KB or so.
172         */
173        assert(Z_OK == inflateInit2(&vg->vz, 31));
174        return (vg);
175}
176
177struct vgz *
178VGZ_NewGzip(struct sess *sp, const char *id)
179{
180        struct vgz *vg;
181        int i;
182
183        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
184        vg = vgz_alloc_vgz(sp, id);
185        VSC_main->n_gzip++;
186
187        /*
188         * From zconf.h:
189         *
190         *      mem_needed = "a few kb"
191         *              + (1 << (windowBits+2))
192         *              +  (1 << (memLevel+9))
193         *
194         * windowBits [8..15] (-> 1K..128K)
195         * memLevel [1..9] (-> 1K->256K)
196         *
197         * XXX: They probably needs to be params...
198         *
199         * XXX: It may be more efficent to malloc them, rather than have
200         * XXX: too many worker threads grow the stacks.
201         */
202        i = deflateInit2(&vg->vz,
203            params->gzip_level,         /* Level */
204            Z_DEFLATED,                 /* Method */
205            16 + 8,                     /* Window bits (16=gzip + 15) */
206            1,                          /* memLevel */
207            Z_DEFAULT_STRATEGY);
208        if (i != Z_OK)
209                printf("deflateInit2() = %d\n", i);
210        assert(Z_OK == i);
211        return (vg);
212}
213
214/*--------------------------------------------------------------------*/
215
216void
217VGZ_Ibuf(struct vgz *vg, const void *ptr, ssize_t len)
218{
219
220        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
221
222        AZ(vg->vz.avail_in);
223        vg->vz.next_in = TRUST_ME(ptr);
224        vg->vz.avail_in = len;
225}
226
227int
228VGZ_IbufEmpty(const struct vgz *vg)
229{
230
231        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
232        return (vg->vz.avail_in == 0);
233}
234
235/*--------------------------------------------------------------------*/
236
237void
238VGZ_Obuf(struct vgz *vg, const void *ptr, ssize_t len)
239{
240
241        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
242
243        vg->vz.next_out = TRUST_ME(ptr);
244        vg->vz.avail_out = len;
245}
246
247int
248VGZ_ObufFull(const struct vgz *vg)
249{
250
251        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
252        return (vg->vz.avail_out == 0);
253}
254
255/*--------------------------------------------------------------------
256 * Keep the outbuffer supplied with storage and file it under the
257 * sp->obj as it fills.
258 */
259
260int
261VGZ_ObufStorage(const struct sess *sp, struct vgz *vg)
262{
263        struct storage *st;
264
265        st = FetchStorage(sp, 0);
266        if (st == NULL)
267                return (-1);
268
269        vg->obuf = st;
270        VGZ_Obuf(vg, st->ptr + st->len, st->space - st->len);
271
272        return (0);
273}
274
275/*--------------------------------------------------------------------*/
276
277int
278VGZ_Gunzip(struct vgz *vg, const void **pptr, size_t *plen)
279{
280        int i;
281        ssize_t l;
282        const uint8_t *before;
283
284        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
285
286        *pptr = NULL;
287        *plen = 0;
288        AN(vg->vz.next_out);
289        AN(vg->vz.avail_out);
290        before = vg->vz.next_out;
291        i = inflate(&vg->vz, 0);
292        if (i == Z_OK || i == Z_STREAM_END) {
293                *pptr = before;
294                l = (const uint8_t *)vg->vz.next_out - before;
295                *plen = l;
296                if (vg->obuf != NULL)
297                        vg->obuf->len += l;
298        }
299        if (i == Z_OK)
300                return (0);
301        if (i == Z_STREAM_END)
302                return (1);
303        if (i == Z_BUF_ERROR)
304                return (2);
305printf("INFLATE=%d\n", i);
306        return (-1);
307}
308
309/*--------------------------------------------------------------------*/
310
311int
312VGZ_Gzip(struct vgz *vg, const void **pptr, size_t *plen, enum vgz_flag flags)
313{
314        int i;
315        int zflg;
316        ssize_t l;
317        const uint8_t *before;
318
319        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
320
321        *pptr = NULL;
322        *plen = 0;
323        AN(vg->vz.next_out);
324        AN(vg->vz.avail_out);
325        before = vg->vz.next_out;
326        switch(flags) {
327        case VGZ_NORMAL:        zflg = Z_NO_FLUSH; break;
328        case VGZ_ALIGN:         zflg = Z_SYNC_FLUSH; break;
329        case VGZ_RESET:         zflg = Z_FULL_FLUSH; break;
330        case VGZ_FINISH:        zflg = Z_FINISH; break;
331        default:                INCOMPL();
332        }
333        i = deflate(&vg->vz, zflg);
334        if (i == Z_OK || i == Z_STREAM_END) {
335                *pptr = before;
336                l = (const uint8_t *)vg->vz.next_out - before;
337                *plen = l;
338                if (vg->obuf != NULL)
339                        vg->obuf->len += l;
340        }
341        if (i == Z_OK)
342                return (0);
343        if (i == Z_STREAM_END)
344                return (1);
345        if (i == Z_BUF_ERROR)
346                return (2);
347        return (-1);
348}
349
350/*--------------------------------------------------------------------*/
351
352void
353VGZ_UpdateObj(const struct vgz *vg, struct object *obj)
354{
355
356        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
357        CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
358        obj->gzip_start = vg->vz.start_bit;
359        obj->gzip_last  = vg->vz.last_bit;
360        obj->gzip_stop  = vg->vz.stop_bit;
361}
362
363/*--------------------------------------------------------------------*/
364
365void
366VGZ_Destroy(struct vgz **vgp)
367{
368        struct vgz *vg;
369
370        vg = *vgp;
371        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
372        *vgp = NULL;
373
374        WSP(vg->sess, SLT_Gzip, "%s %jd %jd %jd %jd %jd",
375            vg->id,
376            (intmax_t)vg->vz.total_in,
377            (intmax_t)vg->vz.total_out,
378            (intmax_t)vg->vz.start_bit,
379            (intmax_t)vg->vz.last_bit,
380            (intmax_t)vg->vz.stop_bit);
381        if (vg->tmp != NULL)
382                WS_Reset(vg->tmp, vg->tmp_snapshot);
383        FREE_OBJ(vg);
384}
385
386/*--------------------------------------------------------------------
387 * VFP_GUNZIP
388 *
389 * A VFP for gunzip'ing an object as we receive it from the backend
390 */
391
392static void __match_proto__()
393vfp_gunzip_begin(struct sess *sp, size_t estimate)
394{
395        (void)estimate;
396        sp->wrk->vgz_rx = VGZ_NewUngzip(sp, "U F -");
397}
398
399static int __match_proto__()
400vfp_gunzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
401{
402        struct vgz *vg;
403        ssize_t l, w;
404        int i = -100;
405        uint8_t ibuf[params->gzip_stack_buffer];
406        size_t dl;
407        const void *dp;
408
409        vg = sp->wrk->vgz_rx;
410        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
411        AZ(vg->vz.avail_in);
412        while (bytes > 0 || vg->vz.avail_in > 0) {
413                if (vg->vz.avail_in == 0 && bytes > 0) {
414                        l = sizeof ibuf;
415                        if (l > bytes)
416                                l = bytes;
417                        w = HTC_Read(htc, ibuf, l);
418                        if (w <= 0)
419                                return (w);
420                        VGZ_Ibuf(vg, ibuf, w);
421                        bytes -= w;
422                }
423
424                if (VGZ_ObufStorage(sp, vg))
425                        return (-1);
426                i = VGZ_Gunzip(vg, &dp, &dl);
427                assert(i == Z_OK || i == Z_STREAM_END);
428                sp->obj->len += dl;
429        }
430        if (i == Z_STREAM_END)
431                return (1);
432        return (-1);
433}
434
435static int __match_proto__()
436vfp_gunzip_end(struct sess *sp)
437{
438        struct vgz *vg;
439
440        vg = sp->wrk->vgz_rx;
441        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
442        VGZ_Destroy(&vg);
443        sp->obj->gziped = 0;
444        return (0);
445}
446
447struct vfp vfp_gunzip = {
448        .begin  =       vfp_gunzip_begin,
449        .bytes  =       vfp_gunzip_bytes,
450        .end    =       vfp_gunzip_end,
451};
452
453
454/*--------------------------------------------------------------------
455 * VFP_GZIP
456 *
457 * A VFP for gzip'ing an object as we receive it from the backend
458 */
459
460static void __match_proto__()
461vfp_gzip_begin(struct sess *sp, size_t estimate)
462{
463        (void)estimate;
464
465        sp->wrk->vgz_rx = VGZ_NewGzip(sp, "G F -");
466}
467
468static int __match_proto__()
469vfp_gzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
470{
471        struct vgz *vg;
472        ssize_t l, w;
473        int i = -100;
474        uint8_t ibuf[params->gzip_stack_buffer];
475        size_t dl;
476        const void *dp;
477
478        vg = sp->wrk->vgz_rx;
479        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
480        AZ(vg->vz.avail_in);
481        while (bytes > 0 || !VGZ_IbufEmpty(vg)) {
482                if (VGZ_IbufEmpty(vg) && bytes > 0) {
483                        l = sizeof ibuf;
484                        if (l > bytes)
485                                l = bytes;
486                        w = HTC_Read(htc, ibuf, l);
487                        if (w <= 0)
488                                return (w);
489                        VGZ_Ibuf(vg, ibuf, w);
490                        bytes -= w;
491                }
492                if (VGZ_ObufStorage(sp, vg))
493                        return (-1);
494                i = VGZ_Gzip(vg, &dp, &dl, VGZ_NORMAL);
495                assert(i == Z_OK);
496                sp->obj->len += dl;
497        }
498        return (1);
499}
500
501static int __match_proto__()
502vfp_gzip_end(struct sess *sp)
503{
504        struct vgz *vg;
505        size_t dl;
506        const void *dp;
507        int i;
508
509        vg = sp->wrk->vgz_rx;
510        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
511        do {
512                VGZ_Ibuf(vg, "", 0);
513                if (VGZ_ObufStorage(sp, vg))
514                        return (-1);
515                i = VGZ_Gzip(vg, &dp, &dl, VGZ_FINISH);
516                sp->obj->len += dl;
517        } while (i != Z_STREAM_END);
518        VGZ_UpdateObj(vg, sp->obj);
519        VGZ_Destroy(&vg);
520        sp->obj->gziped = 1;
521        return (0);
522}
523
524struct vfp vfp_gzip = {
525        .begin  =       vfp_gzip_begin,
526        .bytes  =       vfp_gzip_bytes,
527        .end    =       vfp_gzip_end,
528};
529
530/*--------------------------------------------------------------------
531 * VFP_TESTGZIP
532 *
533 * A VFP for testing that received gzip data is valid, and for
534 * collecting the magic bits while we're at it.
535 */
536
537static void __match_proto__()
538vfp_testgzip_begin(struct sess *sp, size_t estimate)
539{
540        (void)estimate;
541        sp->wrk->vgz_rx = VGZ_NewUngzip(sp, "u F -");
542}
543
544static int __match_proto__()
545vfp_testgzip_bytes(struct sess *sp, struct http_conn *htc, ssize_t bytes)
546{
547        struct vgz *vg;
548        ssize_t l, w;
549        int i = -100;
550        uint8_t ibuf[params->gzip_stack_buffer];
551        size_t dl;
552        const void *dp;
553        struct storage *st;
554
555        vg = sp->wrk->vgz_rx;
556        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
557        AZ(vg->vz.avail_in);
558        while (bytes > 0) {
559                st = FetchStorage(sp, 0);
560                if (st == NULL)
561                        return (-1);
562                l = st->space - st->len;
563                if (l > bytes)
564                        l = bytes;
565                w = HTC_Read(htc, st->ptr + st->len, l);
566                if (w <= 0)
567                        return (w);
568                bytes -= w;
569                VGZ_Ibuf(vg, st->ptr + st->len, w);
570                st->len += w;
571                sp->obj->len += w;
572
573                while (!VGZ_IbufEmpty(vg)) {
574                        VGZ_Obuf(vg, ibuf, sizeof ibuf);
575                        i = VGZ_Gunzip(vg, &dp, &dl);
576                        assert(i == Z_OK || i == Z_STREAM_END);
577                }
578        }
579        if (i == Z_STREAM_END)
580                return (1);
581        return (-1);
582}
583
584static int __match_proto__()
585vfp_testgzip_end(struct sess *sp)
586{
587        struct vgz *vg;
588
589        vg = sp->wrk->vgz_rx;
590        CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
591        VGZ_UpdateObj(vg, sp->obj);
592        VGZ_Destroy(&vg);
593        sp->obj->gziped = 1;
594        return (0);
595}
596
597struct vfp vfp_testgzip = {
598        .begin  =       vfp_testgzip_begin,
599        .bytes  =       vfp_testgzip_bytes,
600        .end    =       vfp_testgzip_end,
601};
602
603
Note: See TracBrowser for help on using the repository browser.