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 1
ved_reembark(struct worker *wrk, struct req *req)
82
{
83
        struct ecx *ecx;
84
85
        (void)wrk;
86 1
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
87 1
        CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);
88 1
        Lck_Lock(&req->sp->mtx);
89 1
        ecx->woken = 1;
90 1
        AZ(pthread_cond_signal(&ecx->preq->wrk->cond));
91 1
        Lck_Unlock(&req->sp->mtx);
92 1
}
93
94
/*--------------------------------------------------------------------*/
95
96
static void
97 244
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 244
        CHECK_OBJ_NOTNULL(preq, REQ_MAGIC);
106 244
        sp = preq->sp;
107 244
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
108 244
        CHECK_OBJ_NOTNULL(ecx, ECX_MAGIC);
109 244
        wrk = preq->wrk;
110
111 244
        if (preq->esi_level >= cache_param->max_esi_depth)
112 244
                return;
113
114 244
        req = Req_New(wrk, sp);
115 244
        SES_Ref(sp);
116 244
        req->req_body_status = REQ_BODY_NONE;
117 244
        AZ(req->vsl->wid);
118 244
        req->vsl->wid = VXID_Get(wrk, VSL_CLIENTMARKER);
119 244
        VSLb(req->vsl, SLT_Begin, "req %u esi", VXID(preq->vsl->wid));
120 244
        VSLb(preq->vsl, SLT_Link, "req %u esi", VXID(req->vsl->wid));
121 244
        req->esi_level = preq->esi_level + 1;
122
123 244
        if (preq->esi_level == 0)
124 230
                assert(preq->top == preq);
125
        else
126 14
                CHECK_OBJ_NOTNULL(preq->top, REQ_MAGIC);
127
128 244
        req->top = preq->top;
129
130 244
        HTTP_Copy(req->http0, preq->http0);
131
132 244
        req->http0->ws = req->ws;
133 244
        req->http0->vsl = req->vsl;
134 244
        req->http0->logtag = SLT_ReqMethod;
135 244
        req->http0->conds = 0;
136
137 244
        http_SetH(req->http0, HTTP_HDR_URL, src);
138 244
        if (host != NULL && *host != '\0')  {
139 2
                http_Unset(req->http0, H_Host);
140 2
                http_SetHeader(req->http0, host);
141
        }
142
143 244
        http_ForceField(req->http0, HTTP_HDR_METHOD, "GET");
144 244
        http_ForceField(req->http0, HTTP_HDR_PROTO, "HTTP/1.1");
145
146
        /* Don't allow conditionals, we can't use a 304 */
147 244
        http_Unset(req->http0, H_If_Modified_Since);
148 244
        http_Unset(req->http0, H_If_None_Match);
149
150
        /* Don't allow Range */
151 244
        http_Unset(req->http0, H_Range);
152
153
        /* Set Accept-Encoding according to what we want */
154 244
        http_Unset(req->http0, H_Accept_Encoding);
155 244
        if (ecx->isgzip)
156 42
                http_ForceHeader(req->http0, H_Accept_Encoding, "gzip");
157
158
        /* Client content already taken care of */
159 244
        http_Unset(req->http0, H_Content_Length);
160
161
        /* Reset request to status before we started messing with it */
162 244
        HTTP_Copy(req->http, req->http0);
163
164 244
        AZ(req->vcl);
165 244
        req->vcl = preq->vcl;
166 244
        preq->vcl = NULL;
167
168 244
        req->req_step = R_STP_RECV;
169 244
        req->t_req = preq->t_req;
170 244
        assert(isnan(req->t_first));
171 244
        assert(isnan(req->t_prev));
172
173 244
        req->transport = &VED_transport;
174 244
        req->transport_priv = ecx;
175
176 244
        THR_SetRequest(req);
177
178 244
        VSLb_ts_req(req, "Start", W_TIM_real(wrk));
179
180 244
        req->ws_req = WS_Snapshot(req->ws);
181
182
        while (1) {
183 245
                req->wrk = wrk;
184 245
                ecx->woken = 0;
185 245
                s = CNT_Request(wrk, req);
186 245
                if (s == REQ_FSM_DONE)
187 244
                        break;
188 1
                DSL(DBG_WAITINGLIST, req->vsl->wid,
189
                    "loop waiting for ESI (%d)", (int)s);
190 1
                assert(s == REQ_FSM_DISEMBARK);
191 1
                Lck_Lock(&sp->mtx);
192 1
                if (!ecx->woken)
193 2
                        (void)Lck_CondWait(
194 1
                            &ecx->preq->wrk->cond, &sp->mtx, 0);
195 1
                Lck_Unlock(&sp->mtx);
196 1
                ecx->woken = 0;
197 1
                AZ(req->wrk);
198 1
        }
199
200 244
        VRTPRIV_dynamic_kill(req->privs, (uintptr_t)req);
201
202 244
        AZ(preq->vcl);
203 244
        preq->vcl = req->vcl;
204 244
        req->vcl = NULL;
205
206 244
        req->wrk = NULL;
207 244
        THR_SetRequest(preq);
208
209 244
        Req_AcctLogCharge(wrk->stats, req);
210 244
        Req_Release(req);
211 244
        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 742
ved_decode_len(struct req *req, const uint8_t **pp)
221
{
222
        const uint8_t *p;
223
        ssize_t l;
224
225 742
        p = *pp;
226 742
        switch (*p & 15) {
227
        case 1:
228 738
                l = p[1];
229 738
                p += 2;
230 738
                break;
231
        case 2:
232 2
                l = vbe16dec(p + 1);
233 2
                p += 3;
234 2
                break;
235
        case 8:
236 2
                l = vbe64dec(p + 1);
237 2
                p += 9;
238 2
                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 742
        *pp = p;
245 742
        assert(l > 0);
246 742
        return (l);
247
}
248
249
/*---------------------------------------------------------------------
250
 */
251
252
static int v_matchproto_(vdp_bytes)
253 349
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 349
        ssize_t l = 0;
258 349
        uint32_t icrc = 0;
259
        uint8_t tailbuf[8 + 5];
260
        const uint8_t *pp;
261 349
        struct ecx *ecx, *pecx = NULL;
262 349
        int retval = 0;
263
264 349
        if (act == VDP_INIT) {
265 100
                AZ(*priv);
266 100
                ALLOC_OBJ(ecx, ECX_MAGIC);
267 100
                AN(ecx);
268
                assert(sizeof gzip_hdr == 10);
269 100
                ecx->preq = req;
270 100
                *priv = ecx;
271 100
                RFC2616_Weaken_Etag(req->resp);
272 100
                req->res_mode |= RES_ESI;
273 100
                if (req->resp_len != 0)
274 100
                        req->resp_len = -1;
275 100
                return (0);
276
        }
277 249
        CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC);
278 249
        if (act == VDP_FINI) {
279 100
                FREE_OBJ(ecx);
280 100
                *priv = NULL;
281 100
                return (0);
282
        }
283 149
        pp = ptr;
284
285 149
        if (req->esi_level > 0) {
286 26
                assert(req->transport == &VED_transport);
287 26
                CAST_OBJ_NOTNULL(pecx, req->transport_priv, ECX_MAGIC);
288 26
                if (!pecx->isgzip)
289 20
                        pecx = NULL;
290
        }
291
292
        while (1) {
293 1958
                switch (ecx->state) {
294
                case 0:
295 99
                        ecx->p = ObjGetAttr(req->wrk, req->objcore,
296
                            OA_ESIDATA, &l);
297 99
                        AN(ecx->p);
298 99
                        assert(l > 0);
299 99
                        ecx->e = ecx->p + l;
300
301 99
                        if (*ecx->p == VEC_GZ) {
302 26
                                if (pecx == NULL)
303 24
                                        retval = VDP_bytes(req, VDP_NULL,
304
                                            gzip_hdr, 10);
305 26
                                ecx->l_crc = 0;
306 26
                                ecx->crc = crc32(0L, Z_NULL, 0);
307 26
                                ecx->isgzip = 1;
308 26
                                ecx->p++;
309
                        }
310 99
                        ecx->state = 1;
311 99
                        break;
312
                case 1:
313 1027
                        if (ecx->p >= ecx->e) {
314 97
                                ecx->state = 2;
315 97
                                break;
316
                        }
317 930
                        switch (*ecx->p) {
318
                        case VEC_V1:
319
                        case VEC_V2:
320
                        case VEC_V8:
321 300
                                ecx->l = ved_decode_len(req, &ecx->p);
322 300
                                if (ecx->l < 0)
323 0
                                        return (-1);
324 300
                                if (ecx->isgzip) {
325 57
                                        assert(*ecx->p == VEC_C1 ||
326
                                            *ecx->p == VEC_C2 ||
327
                                            *ecx->p == VEC_C8);
328 57
                                        l = ved_decode_len(req, &ecx->p);
329 57
                                        if (l < 0)
330 0
                                                return (-1);
331 57
                                        icrc = vbe32dec(ecx->p);
332 57
                                        ecx->p += 4;
333 114
                                        ecx->crc = crc32_combine(
334 57
                                            ecx->crc, icrc, l);
335 57
                                        ecx->l_crc += l;
336
                                }
337 300
                                ecx->state = 3;
338 300
                                break;
339
                        case VEC_S1:
340
                        case VEC_S2:
341
                        case VEC_S8:
342 385
                                ecx->l = ved_decode_len(req, &ecx->p);
343 385
                                if (ecx->l < 0)
344 0
                                        return (-1);
345
                                Debug("SKIP1(%d)\n", (int)ecx->l);
346 385
                                ecx->state = 4;
347 385
                                break;
348
                        case VEC_INCL:
349 245
                                ecx->p++;
350 245
                                q = (void*)strchr((const char*)ecx->p, '\0');
351 245
                                AN(q);
352 245
                                q++;
353 245
                                r = (void*)strchr((const char*)q, '\0');
354 245
                                AN(r);
355 245
                                if (VDP_bytes(req, VDP_FLUSH, NULL, 0)) {
356 1
                                        ecx->p = ecx->e;
357 1
                                        break;
358
                                }
359
                                Debug("INCL [%s][%s] BEGIN\n", q, ecx->p);
360 244
                                ved_include(req,
361 244
                                    (const char*)q, (const char*)ecx->p, ecx);
362
                                Debug("INCL [%s][%s] END\n", q, ecx->p);
363 244
                                ecx->p = r + 1;
364 244
                                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 930
                        break;
372
                case 2:
373 97
                        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 24
                                tailbuf[0] = 0x01;
379 24
                                tailbuf[1] = 0x00;
380 24
                                tailbuf[2] = 0x00;
381 24
                                tailbuf[3] = 0xff;
382 24
                                tailbuf[4] = 0xff;
383
384
                                /* Emit CRC32 */
385 24
                                vle32enc(tailbuf + 5, ecx->crc);
386
387
                                /* MOD(2^32) length */
388 24
                                vle32enc(tailbuf + 9, ecx->l_crc);
389
390 24
                                (void)VDP_bytes(req, VDP_NULL, tailbuf, 13);
391 73
                        } else if (pecx != NULL) {
392 4
                                pecx->crc = crc32_combine(pecx->crc,
393 2
                                    ecx->crc, ecx->l_crc);
394 2
                                pecx->l_crc += ecx->l_crc;
395
                        }
396 97
                        retval = VDP_bytes(req, VDP_FLUSH, NULL, 0);
397 97
                        ecx->state = 99;
398 97
                        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 721
                        if (ecx->l <= len) {
407 685
                                if (ecx->state == 3)
408 300
                                        retval = VDP_bytes(req, act,
409
                                            pp, ecx->l);
410 685
                                len -= ecx->l;
411 685
                                pp += ecx->l;
412 685
                                ecx->state = 1;
413 685
                                break;
414
                        }
415 36
                        if (ecx->state == 3 && len > 0)
416 15
                                retval = VDP_bytes(req, act, pp, len);
417 36
                        ecx->l -= len;
418 36
                        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 14
                        return (retval);
425
                default:
426 0
                        WRONG("FOO");
427
                        break;
428
                }
429 1811
                if (retval)
430 2
                        return (retval);
431 1809
        }
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 568
ved_bytes(struct req *req, struct req *preq, enum vdp_action act,
445
    const void *ptr, ssize_t len)
446
{
447 568
        req->acct.resp_bodybytes += len;
448 568
        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 36
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 36
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
480 36
        CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC);
481 36
        preq = ecx->preq;
482
483
        (void)priv;
484 36
        if (act == VDP_INIT)
485 9
                return (0);
486 27
        if (act == VDP_FINI) {
487 9
                *priv = NULL;
488 9
                return (0);
489
        }
490 18
        if (l == 0)
491 9
                return (ved_bytes(req, ecx->preq, act, pv, l));
492
493 9
        p = pv;
494
495 9
        AN (ecx->isgzip);
496 9
        ecx->crc = crc32(ecx->crc, p, l);
497 9
        ecx->l_crc += l;
498
499 9
        lx = 65535;
500 9
        buf1[0] = 0;
501 9
        vle16enc(buf1 + 1, lx);
502 9
        vle16enc(buf1 + 3, ~lx);
503
504 27
        while (l > 0) {
505 9
                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 9
                        lx = (uint16_t)l;
511 9
                        buf2[0] = 0;
512 9
                        vle16enc(buf2 + 1, lx);
513 9
                        vle16enc(buf2 + 3, ~lx);
514 9
                        if (ved_bytes(req, preq, VDP_NULL, buf2, sizeof buf2))
515 0
                                return (-1);
516
                }
517 9
                if (ved_bytes(req, preq, VDP_NULL, p, lx))
518 0
                        return (-1);
519 9
                l -= lx;
520 9
                p += lx;
521
        }
522
        /* buf2 is local, have to flush */
523 9
        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 34
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 34
        CAST_OBJ_NOTNULL(foo, priv, VED_FOO_MAGIC);
571
        (void)flush;
572 34
        pp = ptr;
573 34
        if (len > 0) {
574
                /* Skip over the GZIP header */
575 34
                dl = foo->start / 8 - foo->ll;
576 34
                if (dl > 0) {
577
                        /* Before foo.start, skip */
578 30
                        if (dl > len)
579 3
                                dl = len;
580 30
                        foo->ll += dl;
581 30
                        len -= dl;
582 30
                        pp += dl;
583
                }
584
        }
585 34
        if (len > 0) {
586
                /* The main body of the object */
587 31
                dl = foo->last / 8 - foo->ll;
588 31
                if (dl > 0) {
589 4
                        if (dl > len)
590 0
                                dl = len;
591 4
                        if (ved_bytes(foo->req, foo->preq, VDP_NULL, pp, dl))
592 0
                                return(-1);
593 4
                        foo->ll += dl;
594 4
                        len -= dl;
595 4
                        pp += dl;
596
                }
597
        }
598 34
        if (len > 0 && foo->ll == foo->last / 8) {
599
                /* Remove the "LAST" bit */
600 27
                foo->dbits[0] = *pp;
601 27
                foo->dbits[0] &= ~(1U << (foo->last & 7));
602 27
                if (ved_bytes(foo->req, foo->preq, VDP_NULL, foo->dbits, 1))
603 0
                        return (-1);
604 27
                foo->ll++;
605 27
                len--;
606 27
                pp++;
607
        }
608 34
        if (len > 0) {
609
                /* Last block */
610 31
                dl = foo->stop / 8 - foo->ll;
611 31
                if (dl > 0) {
612 25
                        if (dl > len)
613 2
                                dl = len;
614 25
                        if (ved_bytes(foo->req, foo->preq, VDP_NULL, pp, dl))
615 0
                                return (-1);
616 25
                        foo->ll += dl;
617 25
                        len -= dl;
618 25
                        pp += dl;
619
                }
620
        }
621 34
        if (len > 0 && (foo->stop & 7) && foo->ll == foo->stop / 8) {
622
                /* Add alignment to byte boundary */
623 19
                foo->dbits[1] = *pp;
624 19
                foo->ll++;
625 19
                len--;
626 19
                pp++;
627 19
                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 6
                        foo->dbits[2] = 0x00; foo->dbits[3] = 0x00;
641 6
                        foo->dbits[4] = 0xff; foo->dbits[5] = 0xff;
642 6
                        foo->lpad = 5;
643 6
                        break;
644
                case 2: /* xx010000 00000100 00000001 00000000 */
645 7
                        foo->dbits[1] |= 0x08;
646 7
                        foo->dbits[2] = 0x20;
647 7
                        foo->dbits[3] = 0x80;
648 7
                        foo->dbits[4] = 0x00;
649 7
                        foo->lpad = 4;
650 7
                        break;
651
                case 4: /* xxxx0100 00000001 00000000 */
652 2
                        foo->dbits[1] |= 0x20;
653 2
                        foo->dbits[2] = 0x80;
654 2
                        foo->dbits[3] = 0x00;
655 2
                        foo->lpad = 3;
656 2
                        break;
657
                case 6: /* xxxxxx01 00000000 */
658 2
                        foo->dbits[1] |= 0x80;
659 2
                        foo->dbits[2] = 0x00;
660 2
                        foo->lpad = 2;
661 2
                        break;
662
                case 7: /*
663
                         * xxxxxxx0
664
                         * 00......
665
                         * 00000000 00000000 11111111 11111111
666
                         */
667 2
                        foo->dbits[2] = 0x00;
668 2
                        foo->dbits[3] = 0x00; foo->dbits[4] = 0x00;
669 2
                        foo->dbits[5] = 0xff; foo->dbits[6] = 0xff;
670 2
                        foo->lpad = 6;
671 2
                        break;
672
                case 0: /* xxxxxxxx */
673
                default:
674 0
                        WRONG("compiler must be broken");
675
                }
676 38
                if (ved_bytes(foo->req, foo->preq,
677 19
                    VDP_NULL, foo->dbits + 1, foo->lpad))
678 0
                        return (-1);
679
        }
680 34
        if (len > 0) {
681
                /* Recover GZIP tail */
682 29
                dl = foo->olen - foo->ll;
683 29
                assert(dl >= 0);
684 29
                if (dl > len)
685 2
                        dl = len;
686 29
                if (dl > 0) {
687 29
                        assert(dl <= 8);
688 29
                        l = foo->ll - (foo->olen - 8);
689 29
                        assert(l >= 0);
690 29
                        assert(l <= 8);
691 29
                        assert(l + dl <= 8);
692 29
                        memcpy(foo->tailbuf + l, pp, dl);
693 29
                        foo->ll += dl;
694 29
                        len -= dl;
695
                }
696
        }
697 34
        assert(len == 0);
698 34
        return (0);
699
}
700
701
static void
702 28
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 28
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
713 28
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
714 28
        CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);
715
716 28
        INIT_OBJ(&foo, VED_FOO_MAGIC);
717 28
        foo.req = req;
718 28
        foo.preq = ecx->preq;
719 28
        memset(foo.tailbuf, 0xdd, sizeof foo.tailbuf);
720
721
        /* OA_GZIPBITS is not valid until BOS_FINISHED */
722 28
        if (boc != NULL)
723 12
                ObjWaitState(req->objcore, BOS_FINISHED);
724 28
        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 29
                return;
728
        }
729
730 27
        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 27
        p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &l);
739 27
        AN(p);
740 27
        assert(l == 32);
741 27
        foo.start = vbe64dec(p);
742 27
        foo.last = vbe64dec(p + 8);
743 27
        foo.stop = vbe64dec(p + 16);
744 27
        foo.olen = ObjGetLen(req->wrk, req->objcore);
745 27
        assert(foo.start > 0 && foo.start < foo.olen * 8);
746 27
        assert(foo.last > 0 && foo.last < foo.olen * 8);
747 27
        assert(foo.stop > 0 && foo.stop < foo.olen * 8);
748 27
        assert(foo.last >= foo.start);
749 27
        assert(foo.last < foo.stop);
750
751
        /* The start bit must be byte aligned. */
752 27
        AZ(foo.start & 7);
753
754 27
        dbits = WS_Alloc(req->ws, 8);
755 27
        AN(dbits);
756 27
        foo.dbits = dbits;
757 27
        (void)ObjIterate(req->wrk, req->objcore, &foo, ved_objiterate, 0);
758
        /* XXX: error check ?? */
759 27
        (void)ved_bytes(req, foo.preq, VDP_FLUSH, NULL, 0);
760
761 27
        icrc = vle32dec(foo.tailbuf);
762 27
        ilen = vle32dec(foo.tailbuf + 4);
763
764 27
        ecx->crc = crc32_combine(ecx->crc, icrc, ilen);
765 27
        ecx->l_crc += ilen;
766
}
767
768
/*--------------------------------------------------------------------*/
769
770
static int v_matchproto_(vdp_bytes)
771 822
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 822
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
777 822
        if (act == VDP_INIT)
778 196
                return (0);
779 626
        if (act == VDP_FINI) {
780 196
                *priv = NULL;
781 196
                return (0);
782
        }
783 430
        CAST_OBJ_NOTNULL(preq, *priv, REQ_MAGIC);
784 430
        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 244
ved_deliver(struct req *req, struct boc *boc, int wantbody)
796
{
797
        int i;
798
        struct ecx *ecx;
799
800 244
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
801 244
        CHECK_OBJ_ORNULL(boc, BOC_MAGIC);
802 244
        CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
803
804 244
        CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);
805
806 244
        if (wantbody == 0)
807 2
                return;
808
809 242
        if (boc == NULL && ObjGetLen(req->wrk, req->objcore) == 0)
810 9
                return;
811
812 233
        req->res_mode |= RES_ESI_CHILD;
813 233
        i = ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED);
814 233
        if (ecx->isgzip && i && !(req->res_mode & RES_ESI)) {
815 28
                ved_stripgzip(req, boc);
816
        } else {
817 205
                if (ecx->isgzip && !i)
818 9
                        VDP_push(req, &ved_vdp_pgz, ecx, 1);
819
                else
820 196
                        VDP_push(req, &ved_ved, ecx->preq, 1);
821 205
                (void)VDP_DeliverObj(req);
822 205
                (void)VDP_bytes(req, VDP_FLUSH, NULL, 0);
823
        }
824 233
        VDP_close(req);
825
}