source: bin/varnishd/cache/cache_esi_deliver.c @ 097e64

Revision 097e64, 13.1 KB checked in by Poul-Henning Kamp <phk@…>, 2 years ago (diff)

Move another 144 bytes from sess to req

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2011 Varnish Software AS
3 * All rights reserved.
4 *
5 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * VED - Varnish Esi Delivery
29 */
30
31#include "config.h"
32
33#include <stdio.h>
34#include <stdlib.h>
35
36#include "cache.h"
37
38#include "cache_esi.h"
39#include "vend.h"
40#include "vgz.h"
41
42/*--------------------------------------------------------------------*/
43
44static void
45ved_include(struct sess *sp, const char *src, const char *host)
46{
47        struct object *obj;
48        struct worker *w;
49        char *sp_ws_wm;
50        char *wrk_ws_wm;
51        unsigned sxid, res_mode;
52
53        w = sp->wrk;
54
55        if (sp->req->esi_level >= cache_param->max_esi_depth)
56                return;
57        sp->req->esi_level++;
58
59        (void)WRW_FlushRelease(w);
60
61        obj = sp->wrk->obj;
62        sp->wrk->obj = NULL;
63        res_mode = sp->wrk->res_mode;
64
65        /* Reset request to status before we started messing with it */
66        HTTP_Copy(sp->http, sp->http0);
67
68        /* Take a workspace snapshot */
69        sp_ws_wm = WS_Snapshot(sp->ws);
70        wrk_ws_wm = WS_Snapshot(w->ws);
71
72        http_SetH(sp->http, HTTP_HDR_URL, src);
73        if (host != NULL && *host != '\0')  {
74                http_Unset(sp->http, H_Host);
75                http_Unset(sp->http, H_If_Modified_Since);
76                http_SetHeader(w, sp->vsl_id, sp->http, host);
77        }
78        /*
79         * XXX: We should decide if we should cache the director
80         * XXX: or not (for session/backend coupling).  Until then
81         * XXX: make sure we don't trip up the check in vcl_recv.
82         */
83        sp->director = NULL;
84        sp->step = STP_RECV;
85        http_ForceGet(sp->http);
86
87        /* Don't do conditionals */
88        sp->http->conds = 0;
89        http_Unset(sp->http, H_If_Modified_Since);
90
91        /* Client content already taken care of */
92        http_Unset(sp->http, H_Content_Length);
93
94        sxid = sp->req->xid;
95        while (1) {
96                sp->wrk = w;
97                CNT_Session(sp);
98                if (sp->step == STP_DONE)
99                        break;
100                AZ(sp->wrk);
101                WSL_Flush(w, 0);
102                DSL(0x20, SLT_Debug, sp->vsl_id, "loop waiting for ESI");
103                (void)usleep(10000);
104        }
105        sp->req->xid = sxid;
106        AN(sp->wrk);
107        assert(sp->step == STP_DONE);
108        sp->req->esi_level--;
109        sp->wrk->obj = obj;
110        sp->wrk->res_mode = res_mode;
111
112        /* Reset the workspace */
113        WS_Reset(sp->ws, sp_ws_wm);
114        WS_Reset(w->ws, wrk_ws_wm);
115
116        WRW_Reserve(sp->wrk, &sp->fd);
117        if (sp->wrk->res_mode & RES_CHUNKED)
118                WRW_Chunked(sp->wrk);
119}
120
121/*--------------------------------------------------------------------*/
122
123
124//#define Debug(fmt, ...) printf(fmt, __VA_ARGS__)
125#define Debug(fmt, ...) /**/
126
127static ssize_t
128ved_decode_len(uint8_t **pp)
129{
130        uint8_t *p;
131        ssize_t l;
132
133        p = *pp;
134        switch (*p & 15) {
135        case 1:
136                l = p[1];
137                p += 2;
138                break;
139        case 2:
140                l = vbe16dec(p + 1);
141                p += 3;
142                break;
143        case 8:
144                l = vbe64dec(p + 1);
145                p += 9;
146                break;
147        default:
148                printf("Illegal Length %d %d\n", *p, (*p & 15));
149                INCOMPL();
150        }
151        *pp = p;
152        assert(l > 0);
153        return (l);
154}
155
156/*---------------------------------------------------------------------
157 * If a gzip'ed ESI object includes a ungzip'ed object, we need to make
158 * it looked like a gzip'ed data stream.  The official way to do so would
159 * be to fire up libvgz and gzip it, but we don't, we fake it.
160 *
161 * First, we cannot know if it is ungzip'ed on purpose, the admin may
162 * know something we don't.
163 *
164 * What do you mean "BS ?"
165 *
166 * All right then...
167 *
168 * The matter of the fact is that we simply will not fire up a gzip in
169 * the output path because it costs too much memory and CPU, so we simply
170 * wrap the data in very convenient "gzip copy-blocks" and send it down
171 * the stream with a bit more overhead.
172 */
173
174static void
175ved_pretend_gzip(const struct sess *sp, const uint8_t *p, ssize_t l)
176{
177        uint8_t buf1[5], buf2[5];
178        uint16_t lx;
179
180        lx = 65535;
181        buf1[0] = 0;
182        vle16enc(buf1 + 1, lx);
183        vle16enc(buf1 + 3, ~lx);
184
185        while (l > 0) {
186                if (l >= 65535) {
187                        lx = 65535;
188                        (void)WRW_Write(sp->wrk, buf1, sizeof buf1);
189                } else {
190                        lx = (uint16_t)l;
191                        buf2[0] = 0;
192                        vle16enc(buf2 + 1, lx);
193                        vle16enc(buf2 + 3, ~lx);
194                        (void)WRW_Write(sp->wrk, buf2, sizeof buf2);
195                }
196                (void)WRW_Write(sp->wrk, p, lx);
197                sp->wrk->crc = crc32(sp->wrk->crc, p, lx);
198                sp->wrk->l_crc += lx;
199                l -= lx;
200                p += lx;
201        }
202        /* buf2 is local, have to flush */
203        (void)WRW_Flush(sp->wrk);
204}
205
206/*---------------------------------------------------------------------
207 */
208
209static const uint8_t gzip_hdr[] = {
210        0x1f, 0x8b, 0x08,
211        0x00, 0x00, 0x00, 0x00,
212        0x00,
213        0x02, 0x03
214};
215
216void
217ESI_Deliver(struct sess *sp)
218{
219        struct storage *st;
220        uint8_t *p, *e, *q, *r;
221        unsigned off;
222        ssize_t l, l2, l_icrc = 0;
223        uint32_t icrc = 0;
224        uint8_t tailbuf[8 + 5];
225        int isgzip;
226        struct vgz *vgz = NULL;
227        char obuf[cache_param->gzip_stack_buffer];
228        ssize_t obufl = 0;
229        size_t dl;
230        const void *dp;
231        int i;
232
233        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
234        st = sp->wrk->obj->esidata;
235        AN(st);
236        assert(sizeof obuf >= 1024);
237
238        obuf[0] = 0;    /* For flexelint */
239
240        p = st->ptr;
241        e = st->ptr + st->len;
242
243        if (*p == VEC_GZ) {
244                isgzip = 1;
245                p++;
246        } else {
247                isgzip = 0;
248        }
249
250        if (sp->req->esi_level == 0) {
251                /*
252                 * Only the top level document gets to decide this.
253                 */
254                sp->wrk->gzip_resp = 0;
255                if (isgzip && !(sp->wrk->res_mode & RES_GUNZIP)) {
256                        assert(sizeof gzip_hdr == 10);
257                        /* Send out the gzip header */
258                        (void)WRW_Write(sp->wrk, gzip_hdr, 10);
259                        sp->wrk->l_crc = 0;
260                        sp->wrk->gzip_resp = 1;
261                        sp->wrk->crc = crc32(0L, Z_NULL, 0);
262                }
263        }
264
265        if (isgzip && !sp->wrk->gzip_resp) {
266                vgz = VGZ_NewUngzip(sp->wrk, "U D E");
267
268                /* Feed a gzip header to gunzip to make it happy */
269                VGZ_Ibuf(vgz, gzip_hdr, sizeof gzip_hdr);
270                VGZ_Obuf(vgz, obuf, sizeof obuf);
271                i = VGZ_Gunzip(vgz, &dp, &dl);
272                assert(i == VGZ_OK);
273                assert(VGZ_IbufEmpty(vgz));
274                assert(dl == 0);
275
276                obufl = 0;
277        }
278
279        st = VTAILQ_FIRST(&sp->wrk->obj->store);
280        off = 0;
281
282        while (p < e) {
283                switch (*p) {
284                case VEC_V1:
285                case VEC_V2:
286                case VEC_V8:
287                        l = ved_decode_len(&p);
288                        if (isgzip) {
289                                assert(*p == VEC_C1 || *p == VEC_C2 ||
290                                    *p == VEC_C8);
291                                l_icrc = ved_decode_len(&p);
292                                icrc = vbe32dec(p);
293                                p += 4;
294                                if (sp->wrk->gzip_resp) {
295                                        sp->wrk->crc = crc32_combine(
296                                            sp->wrk->crc, icrc, l_icrc);
297                                        sp->wrk->l_crc += l_icrc;
298                                }
299                        }
300                        /*
301                         * There is no guarantee that the 'l' bytes are all
302                         * in the same storage segment, so loop over storage
303                         * until we have processed them all.
304                         */
305                        while (l > 0) {
306                                l2 = l;
307                                if (l2 > st->len - off)
308                                        l2 = st->len - off;
309                                l -= l2;
310
311                                if (sp->wrk->gzip_resp && isgzip) {
312                                        /*
313                                         * We have a gzip'ed VEC and delivers
314                                         * a gzip'ed ESI response.
315                                         */
316                                        (void)WRW_Write(sp->wrk,
317                                            st->ptr + off, l2);
318                                } else if (sp->wrk->gzip_resp) {
319                                        /*
320                                         * A gzip'ed ESI response, but the VEC
321                                         * was not gzip'ed.
322                                         */
323                                        ved_pretend_gzip(sp, st->ptr + off, l2);
324                                } else if (isgzip) {
325                                        /*
326                                         * A gzip'ed VEC, but ungzip'ed ESI
327                                         * response
328                                         */
329                                        AN(vgz);
330                                        i = VGZ_WrwGunzip(sp->wrk, vgz,
331                                                st->ptr + off, l2,
332                                                obuf, sizeof obuf, &obufl);
333                                        if (WRW_Error(sp->wrk)) {
334                                                SES_Close(sp, "remote closed");
335                                                p = e;
336                                                break;
337                                        }
338                                        assert (i == VGZ_OK || i == VGZ_END);
339                                } else {
340                                        /*
341                                         * Ungzip'ed VEC, ungzip'ed ESI response
342                                         */
343                                        (void)WRW_Write(sp->wrk,
344                                            st->ptr + off, l2);
345                                }
346                                off += l2;
347                                if (off == st->len) {
348                                        st = VTAILQ_NEXT(st, list);
349                                        off = 0;
350                                }
351                        }
352                        break;
353                case VEC_S1:
354                case VEC_S2:
355                case VEC_S8:
356                        l = ved_decode_len(&p);
357                        Debug("SKIP1(%d)\n", (int)l);
358                        /*
359                         * There is no guarantee that the 'l' bytes are all
360                         * in the same storage segment, so loop over storage
361                         * until we have processed them all.
362                         */
363                        while (l > 0) {
364                                l2 = l;
365                                if (l2 > st->len - off)
366                                        l2 = st->len - off;
367                                l -= l2;
368                                off += l2;
369                                if (off == st->len) {
370                                        st = VTAILQ_NEXT(st, list);
371                                        off = 0;
372                                }
373                        }
374                        break;
375                case VEC_INCL:
376                        p++;
377                        q = (void*)strchr((const char*)p, '\0');
378                        AN(q);
379                        q++;
380                        r = (void*)strchr((const char*)q, '\0');
381                        AN(r);
382                        if (obufl > 0) {
383                                (void)WRW_Write(sp->wrk, obuf, obufl);
384                                obufl = 0;
385                        }
386                        if (WRW_Flush(sp->wrk)) {
387                                SES_Close(sp, "remote closed");
388                                p = e;
389                                break;
390                        }
391                        Debug("INCL [%s][%s] BEGIN\n", q, p);
392                        ved_include(sp, (const char*)q, (const char*)p);
393                        Debug("INCL [%s][%s] END\n", q, p);
394                        p = r + 1;
395                        break;
396                default:
397                        printf("XXXX 0x%02x [%s]\n", *p, p);
398                        INCOMPL();
399                }
400        }
401        if (vgz != NULL) {
402                if (obufl > 0)
403                        (void)WRW_Write(sp->wrk, obuf, obufl);
404                (void)VGZ_Destroy(&vgz, sp->vsl_id);
405        }
406        if (sp->wrk->gzip_resp && sp->req->esi_level == 0) {
407                /* Emit a gzip literal block with finish bit set */
408                tailbuf[0] = 0x01;
409                tailbuf[1] = 0x00;
410                tailbuf[2] = 0x00;
411                tailbuf[3] = 0xff;
412                tailbuf[4] = 0xff;
413
414                /* Emit CRC32 */
415                vle32enc(tailbuf + 5, sp->wrk->crc);
416
417                /* MOD(2^32) length */
418                vle32enc(tailbuf + 9, sp->wrk->l_crc);
419
420                (void)WRW_Write(sp->wrk, tailbuf, 13);
421        }
422        (void)WRW_Flush(sp->wrk);
423}
424
425/*---------------------------------------------------------------------
426 * Include an object in a gzip'ed ESI object delivery
427 */
428
429static uint8_t
430ved_deliver_byterange(const struct sess *sp, ssize_t low, ssize_t high)
431{
432        struct storage *st;
433        ssize_t l, lx;
434        u_char *p;
435
436//printf("BR %jd %jd\n", low, high);
437        lx = 0;
438        VTAILQ_FOREACH(st, &sp->wrk->obj->store, list) {
439                p = st->ptr;
440                l = st->len;
441//printf("[0-] %jd %jd\n", lx, lx + l);
442                if (lx + l < low) {
443                        lx += l;
444                        continue;
445                }
446                if (lx == high)
447                        return (p[0]);
448                assert(lx < high);
449                if (lx < low) {
450                        p += (low - lx);
451                        l -= (low - lx);
452                        lx = low;
453                }
454//printf("[1-] %jd %jd\n", lx, lx + l);
455                if (lx + l >= high)
456                        l = high - lx;
457//printf("[2-] %jd %jd\n", lx, lx + l);
458                assert(lx >= low && lx + l <= high);
459                if (l != 0)
460                        (void)WRW_Write(sp->wrk, p, l);
461                if (lx + st->len > high)
462                        return(p[l]);
463                lx += st->len;
464        }
465        INCOMPL();
466}
467
468void
469ESI_DeliverChild(const struct sess *sp)
470{
471        struct storage *st;
472        struct object *obj;
473        ssize_t start, last, stop, lpad;
474        u_char *p, cc;
475        uint32_t icrc;
476        uint32_t ilen;
477        uint8_t *dbits;
478
479        if (!sp->wrk->obj->gziped) {
480                VTAILQ_FOREACH(st, &sp->wrk->obj->store, list)
481                        ved_pretend_gzip(sp, st->ptr, st->len);
482                return;
483        }
484        /*
485         * This is the interesting case: Deliver all the deflate
486         * blocks, stripping the "LAST" bit of the last one and
487         * padding it, as necessary, to a byte boundary.
488         */
489
490        dbits = (void*)WS_Alloc(sp->wrk->ws, 8);
491        AN(dbits);
492        obj = sp->wrk->obj;
493        CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
494        start = obj->gzip_start;
495        last = obj->gzip_last;
496        stop = obj->gzip_stop;
497        assert(start > 0 && start < obj->len * 8);
498        assert(last > 0 && last < obj->len * 8);
499        assert(stop > 0 && stop < obj->len * 8);
500        assert(last >= start);
501        assert(last < stop);
502
503        /* The start bit must be byte aligned. */
504        AZ(start & 7);
505
506        /*
507         * XXX: optimize for the case where the 'last'
508         * XXX: bit is in a empty copy block
509         */
510        *dbits = ved_deliver_byterange(sp, start/8, last/8);
511        *dbits &= ~(1U << (last & 7));
512        (void)WRW_Write(sp->wrk, dbits, 1);
513        cc = ved_deliver_byterange(sp, 1 + last/8, stop/8);
514        switch((int)(stop & 7)) {
515        case 0: /* xxxxxxxx */
516                /* I think we have an off by one here, but that's OK */
517                lpad = 0;
518                break;
519        case 1: /* x000.... 00000000 00000000 11111111 11111111 */
520        case 3: /* xxx000.. 00000000 00000000 11111111 11111111 */
521        case 5: /* xxxxx000 00000000 00000000 11111111 11111111 */
522                dbits[1] = cc | 0x00;
523                dbits[2] = 0x00; dbits[3] = 0x00;
524                dbits[4] = 0xff; dbits[5] = 0xff;
525                lpad = 5;
526                break;
527        case 2: /* xx010000 00000100 00000001 00000000 */
528                dbits[1] = cc | 0x08;
529                dbits[2] = 0x20;
530                dbits[3] = 0x80;
531                dbits[4] = 0x00;
532                lpad = 4;
533                break;
534        case 4: /* xxxx0100 00000001 00000000 */
535                dbits[1] = cc | 0x20;
536                dbits[2] = 0x80;
537                dbits[3] = 0x00;
538                lpad = 3;
539                break;
540        case 6: /* xxxxxx01 00000000 */
541                dbits[1] = cc | 0x80;
542                dbits[2] = 0x00;
543                lpad = 2;
544                break;
545        case 7: /* xxxxxxx0 00...... 00000000 00000000 11111111 11111111 */
546                dbits[1] = cc | 0x00;
547                dbits[2] = 0x00;
548                dbits[3] = 0x00; dbits[4] = 0x00;
549                dbits[5] = 0xff; dbits[6] = 0xff;
550                lpad = 6;
551                break;
552        default:
553                INCOMPL();
554        }
555        if (lpad > 0)
556                (void)WRW_Write(sp->wrk, dbits + 1, lpad);
557        st = VTAILQ_LAST(&sp->wrk->obj->store, storagehead);
558        assert(st->len > 8);
559
560        p = st->ptr + st->len - 8;
561        icrc = vle32dec(p);
562        ilen = vle32dec(p + 4);
563        sp->wrk->crc = crc32_combine(sp->wrk->crc, icrc, ilen);
564        sp->wrk->l_crc += ilen;
565}
Note: See TracBrowser for help on using the repository browser.