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