varnish-cache/bin/varnishd/cache/cache_esi_deliver.c
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
 * VED - Varnish Esi Delivery
29
 */
30
31
#include "config.h"
32
33
#include "cache_varnishd.h"
34
35
#include <stdlib.h>
36
37
#include "cache_transport.h"
38
#include "cache_filter.h"
39
#include "cache_vgz.h"
40
41
#include "vtim.h"
42
#include "cache_esi.h"
43
#include "vend.h"
44
#include "vgz.h"
45
46
static vtr_deliver_f ved_deliver;
47
static vtr_reembark_f ved_reembark;
48
49
static const uint8_t gzip_hdr[] = {
50
        0x1f, 0x8b, 0x08,
51
        0x00, 0x00, 0x00, 0x00,
52
        0x00,
53
        0x02, 0x03
54
};
55
56
struct ecx {
57
        unsigned        magic;
58
#define ECX_MAGIC       0x0b0f9163
59
        const uint8_t   *p;
60
        const uint8_t   *e;
61
        int             state;
62
        ssize_t         l;
63
        int             isgzip;
64
        int             woken;
65
66
        struct req      *preq;
67
        ssize_t         l_crc;
68
        uint32_t        crc;
69
};
70
71
static const struct transport VED_transport = {
72
        .magic =        TRANSPORT_MAGIC,
73
        .name =         "ESI_INCLUDE",
74
        .deliver =      ved_deliver,
75
        .reembark =     ved_reembark,
76
};
77
78
/*--------------------------------------------------------------------*/
79
80
static void v_matchproto_(vtr_reembark_f)
81 2
ved_reembark(struct worker *wrk, struct req *req)
82
{
83
        struct ecx *ecx;
84
85
        (void)wrk;
86 2
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
87 2
        CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);
88 2
        Lck_Lock(&req->sp->mtx);
89 2
        ecx->woken = 1;
90 2
        AZ(pthread_cond_signal(&ecx->preq->wrk->cond));
91 2
        Lck_Unlock(&req->sp->mtx);
92 2
}
93
94
/*--------------------------------------------------------------------*/
95
96
static void
97 492
ved_include(struct req *preq, const char *src, const char *host,
98
    struct ecx *ecx)
99
{
100
        struct worker *wrk;
101
        struct sess *sp;
102
        struct req *req;
103
        enum req_fsm_nxt s;
104
105 492
        CHECK_OBJ_NOTNULL(preq, REQ_MAGIC);
106 492
        sp = preq->sp;
107 492
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
108 492
        CHECK_OBJ_NOTNULL(ecx, ECX_MAGIC);
109 492
        wrk = preq->wrk;
110
111 492
        if (preq->esi_level >= cache_param->max_esi_depth)
112 0
                return;
113
114 492
        req = Req_New(wrk, sp);
115 492
        SES_Ref(sp);
116 492
        req->req_body_status = REQ_BODY_NONE;
117 492
        AZ(req->vsl->wid);
118 492
        req->vsl->wid = VXID_Get(wrk, VSL_CLIENTMARKER);
119 492
        VSLb(req->vsl, SLT_Begin, "req %u esi", VXID(preq->vsl->wid));
120 492
        VSLb(preq->vsl, SLT_Link, "req %u esi", VXID(req->vsl->wid));
121 492
        req->esi_level = preq->esi_level + 1;
122
123 492
        if (preq->esi_level == 0)
124 464
                assert(preq->top == preq);
125
        else
126 28
                CHECK_OBJ_NOTNULL(preq->top, REQ_MAGIC);
127
128 492
        req->top = preq->top;
129
130 492
        HTTP_Copy(req->http0, preq->http0);
131
132 492
        req->http0->ws = req->ws;
133 492
        req->http0->vsl = req->vsl;
134 492
        req->http0->logtag = SLT_ReqMethod;
135 492
        req->http0->conds = 0;
136
137 492
        http_SetH(req->http0, HTTP_HDR_URL, src);
138 492
        if (host != NULL && *host != '\0')  {
139 4
                http_Unset(req->http0, H_Host);
140 4
                http_SetHeader(req->http0, host);
141
        }
142
143 492
        http_ForceField(req->http0, HTTP_HDR_METHOD, "GET");
144 492
        http_ForceField(req->http0, HTTP_HDR_PROTO, "HTTP/1.1");
145
146
        /* Don't allow conditionals, we can't use a 304 */
147 492
        http_Unset(req->http0, H_If_Modified_Since);
148 492
        http_Unset(req->http0, H_If_None_Match);
149
150
        /* Don't allow Range */
151 492
        http_Unset(req->http0, H_Range);
152
153
        /* Set Accept-Encoding according to what we want */
154 492
        http_Unset(req->http0, H_Accept_Encoding);
155 492
        if (ecx->isgzip)
156 86
                http_ForceHeader(req->http0, H_Accept_Encoding, "gzip");
157
158
        /* Client content already taken care of */
159 492
        http_Unset(req->http0, H_Content_Length);
160
161
        /* Reset request to status before we started messing with it */
162 492
        HTTP_Copy(req->http, req->http0);
163
164 492
        AZ(req->vcl);
165 492
        req->vcl = preq->vcl;
166 492
        preq->vcl = NULL;
167
168 492
        req->req_step = R_STP_RECV;
169 492
        req->t_req = preq->t_req;
170 492
        assert(isnan(req->t_first));
171 492
        assert(isnan(req->t_prev));
172
173 492
        req->transport = &VED_transport;
174 492
        req->transport_priv = ecx;
175
176 492
        THR_SetRequest(req);
177
178 492
        VSLb_ts_req(req, "Start", W_TIM_real(wrk));
179
180 492
        req->ws_req = WS_Snapshot(req->ws);
181
182
        while (1) {
183 496
                req->wrk = wrk;
184 494
                ecx->woken = 0;
185 494
                s = CNT_Request(wrk, req);
186 494
                if (s == REQ_FSM_DONE)
187 492
                        break;
188 2
                DSL(DBG_WAITINGLIST, req->vsl->wid,
189
                    "loop waiting for ESI (%d)", (int)s);
190 2
                assert(s == REQ_FSM_DISEMBARK);
191 2
                Lck_Lock(&sp->mtx);
192 2
                if (!ecx->woken)
193 4
                        (void)Lck_CondWait(
194 2
                            &ecx->preq->wrk->cond, &sp->mtx, 0);
195 2
                Lck_Unlock(&sp->mtx);
196 2
                ecx->woken = 0;
197 2
                AZ(req->wrk);
198
        }
199
200 492
        VRTPRIV_dynamic_kill(req->privs, (uintptr_t)req);
201
202 492
        AZ(preq->vcl);
203 492
        preq->vcl = req->vcl;
204 492
        req->vcl = NULL;
205
206 492
        req->wrk = NULL;
207 492
        THR_SetRequest(preq);
208
209 492
        Req_AcctLogCharge(wrk->stats, req);
210 492
        Req_Release(req);
211 492
        SES_Rel(sp);
212
}
213
214
/*--------------------------------------------------------------------*/
215
216
//#define Debug(fmt, ...) printf(fmt, __VA_ARGS__)
217
#define Debug(fmt, ...) /**/
218
219
static ssize_t
220 1506
ved_decode_len(struct req *req, const uint8_t **pp)
221
{
222
        const uint8_t *p;
223
        ssize_t l;
224
225 1506
        p = *pp;
226 1506
        switch (*p & 15) {
227
        case 1:
228 1498
                l = p[1];
229 1498
                p += 2;
230 1498
                break;
231
        case 2:
232 4
                l = vbe16dec(p + 1);
233 4
                p += 3;
234 4
                break;
235
        case 8:
236 4
                l = vbe64dec(p + 1);
237 4
                p += 9;
238 4
                break;
239
        default:
240 0
                VSLb(req->vsl, SLT_Error,
241 0
                    "ESI-corruption: Illegal Length %d %d\n", *p, (*p & 15));
242 0
                WRONG("ESI-codes: illegal length");
243
        }
244 1506
        *pp = p;
245 1506
        assert(l > 0);
246 1506
        return (l);
247
}
248
249
/*---------------------------------------------------------------------
250
 */
251
252
static int v_matchproto_(vdp_bytes)
253 720
ved_vdp(struct req *req, enum vdp_action act, void **priv,
254
    const void *ptr, ssize_t len)
255
{
256
        uint8_t *q, *r;
257 720
        ssize_t l = 0;
258 720
        uint32_t icrc = 0;
259
        uint8_t tailbuf[8 + 5];
260
        const uint8_t *pp;
261 720
        struct ecx *ecx, *pecx = NULL;
262 720
        int retval = 0;
263
264 720
        if (act == VDP_INIT) {
265 206
                AZ(*priv);
266 206
                ALLOC_OBJ(ecx, ECX_MAGIC);
267 206
                AN(ecx);
268
                assert(sizeof gzip_hdr == 10);
269 206
                ecx->preq = req;
270 206
                *priv = ecx;
271 206
                RFC2616_Weaken_Etag(req->resp);
272 206
                req->res_mode |= RES_ESI;
273 206
                if (req->resp_len != 0)
274 206
                        req->resp_len = -1;
275 206
                return (0);
276
        }
277 514
        CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC);
278 514
        if (act == VDP_FINI) {
279 206
                FREE_OBJ(ecx);
280 206
                *priv = NULL;
281 206
                return (0);
282
        }
283 308
        pp = ptr;
284
285 308
        if (req->esi_level > 0) {
286 52
                assert(req->transport == &VED_transport);
287 52
                CAST_OBJ_NOTNULL(pecx, req->transport_priv, ECX_MAGIC);
288 52
                if (!pecx->isgzip)
289 40
                        pecx = NULL;
290
        }
291
292
        while (1) {
293 7656
                switch (ecx->state) {
294
                case 0:
295 204
                        ecx->p = ObjGetAttr(req->wrk, req->objcore,
296
                            OA_ESIDATA, &l);
297 204
                        AN(ecx->p);
298 204
                        assert(l > 0);
299 204
                        ecx->e = ecx->p + l;
300
301 204
                        if (*ecx->p == VEC_GZ) {
302 56
                                if (pecx == NULL)
303 52
                                        retval = VDP_bytes(req, VDP_NULL,
304
                                            gzip_hdr, 10);
305 56
                                ecx->l_crc = 0;
306 56
                                ecx->crc = crc32(0L, Z_NULL, 0);
307 56
                                ecx->isgzip = 1;
308 56
                                ecx->p++;
309
                        }
310 204
                        ecx->state = 1;
311 204
                        break;
312
                case 1:
313 2084
                        if (ecx->p >= ecx->e) {
314 200
                                ecx->state = 2;
315 200
                                break;
316
                        }
317 1884
                        switch (*ecx->p) {
318
                        case VEC_V1:
319
                        case VEC_V2:
320
                        case VEC_V8:
321 608
                                ecx->l = ved_decode_len(req, &ecx->p);
322 608
                                if (ecx->l < 0)
323 0
                                        return (-1);
324 608
                                if (ecx->isgzip) {
325 116
                                        assert(*ecx->p == VEC_C1 ||
326
                                            *ecx->p == VEC_C2 ||
327
                                            *ecx->p == VEC_C8);
328 116
                                        l = ved_decode_len(req, &ecx->p);
329 116
                                        if (l < 0)
330 0
                                                return (-1);
331 116
                                        icrc = vbe32dec(ecx->p);
332 116
                                        ecx->p += 4;
333 232
                                        ecx->crc = crc32_combine(
334 116
                                            ecx->crc, icrc, l);
335 116
                                        ecx->l_crc += l;
336
                                }
337 608
                                ecx->state = 3;
338 608
                                break;
339
                        case VEC_S1:
340
                        case VEC_S2:
341
                        case VEC_S8:
342 782
                                ecx->l = ved_decode_len(req, &ecx->p);
343 782
                                if (ecx->l < 0)
344 0
                                        return (-1);
345
                                Debug("SKIP1(%d)\n", (int)ecx->l);
346 782
                                ecx->state = 4;
347 782
                                break;
348
                        case VEC_INCL:
349 494
                                ecx->p++;
350 494
                                q = (void*)strchr((const char*)ecx->p, '\0');
351 494
                                AN(q);
352 494
                                q++;
353 494
                                r = (void*)strchr((const char*)q, '\0');
354 494
                                AN(r);
355 494
                                if (VDP_bytes(req, VDP_FLUSH, NULL, 0)) {
356 2
                                        ecx->p = ecx->e;
357 2
                                        break;
358
                                }
359
                                Debug("INCL [%s][%s] BEGIN\n", q, ecx->p);
360 492
                                ved_include(req,
361 492
                                    (const char*)q, (const char*)ecx->p, ecx);
362
                                Debug("INCL [%s][%s] END\n", q, ecx->p);
363 492
                                ecx->p = r + 1;
364 492
                                break;
365
                        default:
366 0
                                VSLb(req->vsl, SLT_Error,
367
                                    "ESI corruption line %d 0x%02x [%s]\n",
368 0
                                    __LINE__, *ecx->p, ecx->p);
369 0
                                WRONG("ESI-codes: Illegal code");
370
                        }
371 1884
                        break;
372
                case 2:
373 200
                        if (ecx->isgzip && pecx == NULL) {
374
                                /*
375
                                 * We are bytealigned here, so simply emit
376
                                 * a gzip literal block with finish bit set.
377
                                 */
378 52
                                tailbuf[0] = 0x01;
379 52
                                tailbuf[1] = 0x00;
380 52
                                tailbuf[2] = 0x00;
381 52
                                tailbuf[3] = 0xff;
382 52
                                tailbuf[4] = 0xff;
383
384
                                /* Emit CRC32 */
385 52
                                vle32enc(tailbuf + 5, ecx->crc);
386
387
                                /* MOD(2^32) length */
388 52
                                vle32enc(tailbuf + 9, ecx->l_crc);
389
390 52
                                (void)VDP_bytes(req, VDP_NULL, tailbuf, 13);
391 148
                        } else if (pecx != NULL) {
392 8
                                pecx->crc = crc32_combine(pecx->crc,
393 4
                                    ecx->crc, ecx->l_crc);
394 4
                                pecx->l_crc += ecx->l_crc;
395
                        }
396 200
                        retval = VDP_bytes(req, VDP_FLUSH, NULL, 0);
397 200
                        ecx->state = 99;
398 200
                        return (retval);
399
                case 3:
400
                case 4:
401
                        /*
402
                         * There is no guarantee that the 'l' bytes are all
403
                         * in the same storage segment, so loop over storage
404
                         * until we have processed them all.
405
                         */
406 1464
                        if (ecx->l <= len) {
407 1390
                                if (ecx->state == 3)
408 608
                                        retval = VDP_bytes(req, act,
409
                                            pp, ecx->l);
410 1390
                                len -= ecx->l;
411 1390
                                pp += ecx->l;
412 1390
                                ecx->state = 1;
413 1390
                                break;
414
                        }
415 74
                        if (ecx->state == 3 && len > 0)
416 30
                                retval = VDP_bytes(req, act, pp, len);
417 74
                        ecx->l -= len;
418 74
                        return (retval);
419
                case 99:
420
                        /*
421
                         * VEP does not account for the PAD+CRC+LEN
422
                         * so we can see up to approx 15 bytes here.
423
                         */
424 30
                        return (retval);
425
                default:
426 0
                        WRONG("FOO");
427
                        break;
428
                }
429 3678
                if (retval)
430 4
                        return (retval);
431
        }
432
}
433
434
const struct vdp VDP_esi = {
435
        .name =         "esi",
436
        .func =         ved_vdp,
437
};
438
439
/*
440
 * Account body bytes on req
441
 * Push bytes to preq
442
 */
443
static inline int
444 1148
ved_bytes(struct req *req, struct req *preq, enum vdp_action act,
445
    const void *ptr, ssize_t len)
446
{
447 1148
        req->acct.resp_bodybytes += len;
448 1148
        return (VDP_bytes(preq, act, ptr, len));
449
}
450
451
/*---------------------------------------------------------------------
452
 * If a gzip'ed ESI object includes a ungzip'ed object, we need to make
453
 * it looked like a gzip'ed data stream.  The official way to do so would
454
 * be to fire up libvgz and gzip it, but we don't, we fake it.
455
 *
456
 * First, we cannot know if it is ungzip'ed on purpose, the admin may
457
 * know something we don't.
458
 *
459
 * What do you mean "BS ?"
460
 *
461
 * All right then...
462
 *
463
 * The matter of the fact is that we simply will not fire up a gzip in
464
 * the output path because it costs too much memory and CPU, so we simply
465
 * wrap the data in very convenient "gzip copy-blocks" and send it down
466
 * the stream with a bit more overhead.
467
 */
468
469
static int v_matchproto_(vdp_bytes)
470 72
ved_pretend_gzip(struct req *req, enum vdp_action act, void **priv,
471
    const void *pv, ssize_t l)
472
{
473
        uint8_t buf1[5], buf2[5];
474
        const uint8_t *p;
475
        uint16_t lx;
476
        struct ecx *ecx;
477
        struct req *preq;
478
479 72
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
480 72
        CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC);
481 72
        preq = ecx->preq;
482
483
        (void)priv;
484 72
        if (act == VDP_INIT)
485 18
                return (0);
486 54
        if (act == VDP_FINI) {
487 18
                *priv = NULL;
488 18
                return (0);
489
        }
490 36
        if (l == 0)
491 18
                return (ved_bytes(req, ecx->preq, act, pv, l));
492
493 18
        p = pv;
494
495 18
        AN (ecx->isgzip);
496 18
        ecx->crc = crc32(ecx->crc, p, l);
497 18
        ecx->l_crc += l;
498
499 18
        lx = 65535;
500 18
        buf1[0] = 0;
501 18
        vle16enc(buf1 + 1, lx);
502 18
        vle16enc(buf1 + 3, ~lx);
503
504 54
        while (l > 0) {
505 18
                if (l >= 65535) {
506 0
                        lx = 65535;
507 0
                        if (ved_bytes(req, preq, VDP_NULL, buf1, sizeof buf1))
508 0
                                return (-1);
509
                } else {
510 18
                        lx = (uint16_t)l;
511 18
                        buf2[0] = 0;
512 18
                        vle16enc(buf2 + 1, lx);
513 18
                        vle16enc(buf2 + 3, ~lx);
514 18
                        if (ved_bytes(req, preq, VDP_NULL, buf2, sizeof buf2))
515 0
                                return (-1);
516
                }
517 18
                if (ved_bytes(req, preq, VDP_NULL, p, lx))
518 0
                        return (-1);
519 18
                l -= lx;
520 18
                p += lx;
521
        }
522
        /* buf2 is local, have to flush */
523 18
        return (ved_bytes(req, preq, VDP_FLUSH, NULL, 0));
524
}
525
526
static const struct vdp ved_vdp_pgz = {
527
        .name =         "PGZ",
528
        .func =         ved_pretend_gzip,
529
};
530
531
/*---------------------------------------------------------------------
532
 * Include an object in a gzip'ed ESI object delivery
533
 *
534
 * This is not written as a VDP (yet) because it relies on the
535
 * OA_GZIPBITS which only becomes available when the input side
536
 * has fully digested the object and located the magic bit positions.
537
 *
538
 * We can improve this two ways.
539
 *
540
 * One is to run a gunzip instance here, to find the stopbit ourselves,
541
 * but that would be double work, in particular when passing a gziped
542
 * object, where we would have two null-gunzips.
543
 *
544
 * The other is to have the input side guarantee that OA_GZIPBITS::stopbit
545
 * always is committed before the chunk of data containing it.  We would
546
 * be required to poll OA_GZIPBITS on every chunk presented, but that is
547
 * much cheaper than running a gunzip instance.
548
 */
549
550
struct ved_foo {
551
        unsigned                magic;
552
#define VED_FOO_MAGIC           0x6a5a262d
553
        struct req              *req;
554
        struct req              *preq;
555
        ssize_t start, last, stop, lpad;
556
        ssize_t ll;
557
        uint64_t olen;
558
        uint8_t *dbits;
559
        uint8_t tailbuf[8];
560
};
561
562
static int
563 72
ved_objiterate(void *priv, int flush, const void *ptr, ssize_t len)
564
{
565
        struct ved_foo *foo;
566
        const uint8_t *pp;
567
        ssize_t dl;
568
        ssize_t l;
569
570 72
        CAST_OBJ_NOTNULL(foo, priv, VED_FOO_MAGIC);
571
        (void)flush;
572 72
        pp = ptr;
573 72
        if (len > 0) {
574
                /* Skip over the GZIP header */
575 72
                dl = foo->start / 8 - foo->ll;
576 72
                if (dl > 0) {
577
                        /* Before foo.start, skip */
578 62
                        if (dl > len)
579 6
                                dl = len;
580 62
                        foo->ll += dl;
581 62
                        len -= dl;
582 62
                        pp += dl;
583
                }
584
        }
585 72
        if (len > 0) {
586
                /* The main body of the object */
587 66
                dl = foo->last / 8 - foo->ll;
588 66
                if (dl > 0) {
589 10
                        if (dl > len)
590 0
                                dl = len;
591 10
                        if (ved_bytes(foo->req, foo->preq, VDP_NULL, pp, dl))
592 0
                                return(-1);
593 10
                        foo->ll += dl;
594 10
                        len -= dl;
595 10
                        pp += dl;
596
                }
597
        }
598 72
        if (len > 0 && foo->ll == foo->last / 8) {
599
                /* Remove the "LAST" bit */
600 56
                foo->dbits[0] = *pp;
601 56
                foo->dbits[0] &= ~(1U << (foo->last & 7));
602 56
                if (ved_bytes(foo->req, foo->preq, VDP_NULL, foo->dbits, 1))
603 0
                        return (-1);
604 56
                foo->ll++;
605 56
                len--;
606 56
                pp++;
607
        }
608 72
        if (len > 0) {
609
                /* Last block */
610 66
                dl = foo->stop / 8 - foo->ll;
611 66
                if (dl > 0) {
612 50
                        if (dl > len)
613 4
                                dl = len;
614 50
                        if (ved_bytes(foo->req, foo->preq, VDP_NULL, pp, dl))
615 0
                                return (-1);
616 50
                        foo->ll += dl;
617 50
                        len -= dl;
618 50
                        pp += dl;
619
                }
620
        }
621 72
        if (len > 0 && (foo->stop & 7) && foo->ll == foo->stop / 8) {
622
                /* Add alignment to byte boundary */
623 40
                foo->dbits[1] = *pp;
624 40
                foo->ll++;
625 40
                len--;
626 40
                pp++;
627 40
                switch ((int)(foo->stop & 7)) {
628
                case 1: /*
629
                         * x000....
630
                         * 00000000 00000000 11111111 11111111
631
                         */
632
                case 3: /*
633
                         * xxx000..
634
                         * 00000000 00000000 11111111 11111111
635
                         */
636
                case 5: /*
637
                         * xxxxx000
638
                         * 00000000 00000000 11111111 11111111
639
                         */
640 12
                        foo->dbits[2] = 0x00; foo->dbits[3] = 0x00;
641 12
                        foo->dbits[4] = 0xff; foo->dbits[5] = 0xff;
642 12
                        foo->lpad = 5;
643 12
                        break;
644
                case 2: /* xx010000 00000100 00000001 00000000 */
645 16
                        foo->dbits[1] |= 0x08;
646 16
                        foo->dbits[2] = 0x20;
647 16
                        foo->dbits[3] = 0x80;
648 16
                        foo->dbits[4] = 0x00;
649 16
                        foo->lpad = 4;
650 16
                        break;
651
                case 4: /* xxxx0100 00000001 00000000 */
652 4
                        foo->dbits[1] |= 0x20;
653 4
                        foo->dbits[2] = 0x80;
654 4
                        foo->dbits[3] = 0x00;
655 4
                        foo->lpad = 3;
656 4
                        break;
657
                case 6: /* xxxxxx01 00000000 */
658 4
                        foo->dbits[1] |= 0x80;
659 4
                        foo->dbits[2] = 0x00;
660 4
                        foo->lpad = 2;
661 4
                        break;
662
                case 7: /*
663
                         * xxxxxxx0
664
                         * 00......
665
                         * 00000000 00000000 11111111 11111111
666
                         */
667 4
                        foo->dbits[2] = 0x00;
668 4
                        foo->dbits[3] = 0x00; foo->dbits[4] = 0x00;
669 4
                        foo->dbits[5] = 0xff; foo->dbits[6] = 0xff;
670 4
                        foo->lpad = 6;
671 4
                        break;
672
                case 0: /* xxxxxxxx */
673
                default:
674 0
                        WRONG("compiler must be broken");
675
                }
676 80
                if (ved_bytes(foo->req, foo->preq,
677 40
                    VDP_NULL, foo->dbits + 1, foo->lpad))
678 0
                        return (-1);
679
        }
680 72
        if (len > 0) {
681
                /* Recover GZIP tail */
682 60
                dl = foo->olen - foo->ll;
683 60
                assert(dl >= 0);
684 60
                if (dl > len)
685 4
                        dl = len;
686 60
                if (dl > 0) {
687 60
                        assert(dl <= 8);
688 60
                        l = foo->ll - (foo->olen - 8);
689 60
                        assert(l >= 0);
690 60
                        assert(l <= 8);
691 60
                        assert(l + dl <= 8);
692 60
                        memcpy(foo->tailbuf + l, pp, dl);
693 60
                        foo->ll += dl;
694 60
                        len -= dl;
695
                }
696
        }
697 72
        assert(len == 0);
698 72
        return (0);
699
}
700
701
static void
702 58
ved_stripgzip(struct req *req, const struct boc *boc)
703
{
704
        ssize_t l;
705
        const char *p;
706
        uint32_t icrc;
707
        uint32_t ilen;
708
        uint8_t *dbits;
709
        struct ecx *ecx;
710
        struct ved_foo foo;
711
712 58
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
713 58
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
714 58
        CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);
715
716 58
        INIT_OBJ(&foo, VED_FOO_MAGIC);
717 58
        foo.req = req;
718 58
        foo.preq = ecx->preq;
719 58
        memset(foo.tailbuf, 0xdd, sizeof foo.tailbuf);
720
721
        /* OA_GZIPBITS is not valid until BOS_FINISHED */
722 58
        if (boc != NULL)
723 24
                ObjWaitState(req->objcore, BOS_FINISHED);
724 58
        if (req->objcore->flags & OC_F_FAILED) {
725
                /* No way of signalling errors in the middle of
726
                   the ESI body. Omit this ESI fragment. */
727 2
                return;
728
        }
729
730 56
        AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED));
731
732
        /*
733
         * This is the interesting case: Deliver all the deflate
734
         * blocks, stripping the "LAST" bit of the last one and
735
         * padding it, as necessary, to a byte boundary.
736
         */
737
738 56
        p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &l);
739 56
        AN(p);
740 56
        assert(l == 32);
741 56
        foo.start = vbe64dec(p);
742 56
        foo.last = vbe64dec(p + 8);
743 56
        foo.stop = vbe64dec(p + 16);
744 56
        foo.olen = ObjGetLen(req->wrk, req->objcore);
745 56
        assert(foo.start > 0 && foo.start < foo.olen * 8);
746 56
        assert(foo.last > 0 && foo.last < foo.olen * 8);
747 56
        assert(foo.stop > 0 && foo.stop < foo.olen * 8);
748 56
        assert(foo.last >= foo.start);
749 56
        assert(foo.last < foo.stop);
750
751
        /* The start bit must be byte aligned. */
752 56
        AZ(foo.start & 7);
753
754 56
        dbits = WS_Alloc(req->ws, 8);
755 56
        AN(dbits);
756 56
        foo.dbits = dbits;
757 56
        (void)ObjIterate(req->wrk, req->objcore, &foo, ved_objiterate, 0);
758
        /* XXX: error check ?? */
759 56
        (void)ved_bytes(req, foo.preq, VDP_FLUSH, NULL, 0);
760
761 56
        icrc = vle32dec(foo.tailbuf);
762 56
        ilen = vle32dec(foo.tailbuf + 4);
763
764 56
        ecx->crc = crc32_combine(ecx->crc, icrc, ilen);
765 56
        ecx->l_crc += ilen;
766
}
767
768
/*--------------------------------------------------------------------*/
769
770
static int v_matchproto_(vdp_bytes)
771 1652
ved_vdp_bytes(struct req *req, enum vdp_action act, void **priv,
772
    const void *ptr, ssize_t len)
773
{
774
        struct req *preq;
775
776 1652
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
777 1652
        if (act == VDP_INIT)
778 394
                return (0);
779 1258
        if (act == VDP_FINI) {
780 394
                *priv = NULL;
781 394
                return (0);
782
        }
783 864
        CAST_OBJ_NOTNULL(preq, *priv, REQ_MAGIC);
784 864
        return (ved_bytes(req, preq, act, ptr, len));
785
}
786
787
static const struct vdp ved_ved = {
788
        .name =         "VED",
789
        .func =         ved_vdp_bytes,
790
};
791
792
/*--------------------------------------------------------------------*/
793
794
static void v_matchproto_(vtr_deliver_f)
795 492
ved_deliver(struct req *req, struct boc *boc, int wantbody)
796
{
797
        int i;
798
        struct ecx *ecx;
799
800 492
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
801 492
        CHECK_OBJ_ORNULL(boc, BOC_MAGIC);
802 492
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
803
804 492
        CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);
805
806 492
        if (wantbody == 0)
807 4
                return;
808
809 488
        if (boc == NULL && ObjGetLen(req->wrk, req->objcore) == 0)
810 18
                return;
811
812 470
        req->res_mode |= RES_ESI_CHILD;
813 470
        i = ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED);
814 470
        if (ecx->isgzip && i && !(req->res_mode & RES_ESI)) {
815 58
                ved_stripgzip(req, boc);
816
        } else {
817 412
                if (ecx->isgzip && !i)
818 18
                        (void)VDP_push(req, &ved_vdp_pgz, ecx, 1);
819
                else
820 394
                        (void)VDP_push(req, &ved_ved, ecx->preq, 1);
821 412
                (void)VDP_DeliverObj(req);
822 412
                (void)VDP_bytes(req, VDP_FLUSH, NULL, 0);
823
        }
824 470
        VDP_close(req);
825
}