VDP_gunzip(struct req *req, enum vdp_action act, void **priv, const void *ptr, ssize_t len) { enum vgzret_e vr; ssize_t dl; const void *dp; struct worker *wrk; struct vgz *vg; const char *p; uint64_t u; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); if (act == VDP_INIT) { vg = VGZ_NewUngzip(req->vsl, "U D -"); AN(vg); if (vgz_getmbuf(vg)) { (void)VGZ_Destroy(&vg); return (-1); } req->res_mode |= RES_GUNZIP; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); *priv = vg; http_Unset(req->resp, H_Content_Encoding); req->resp_len = -1; if (req->objcore->boc != NULL) return (0); /* No idea about length (yet) */ p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &dl); if (p == NULL || dl != 32) return (0); /* No OA_GZIPBITS yet */ u = vbe64dec(p + 24); /* * If the size is non-zero AND we are the top * VDP (ie: no ESI), we know what size the output will be. */ if (u != 0 && VTAILQ_FIRST(&req->vdp)->func == VDP_gunzip) req->resp_len = u; return (0); } CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC); AN(vg->m_buf); if (act == VDP_FINI) { /* NB: Gunzip'ing may or may not have completed successfully. */ AZ(len); (void)VGZ_Destroy(&vg); *priv = NULL; return (0); } if (len == 0) return (0); VGZ_Ibuf(vg, ptr, len); do { vr = VGZ_Gunzip(vg, &dp, &dl); vg->m_len += dl; if (vr < VGZ_OK) return (-1); if (vg->m_len == vg->m_sz || vr != VGZ_OK) { if (VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len)) return (req->vdp_retval); vg->m_len = 0; VGZ_Obuf(vg, vg->m_buf, vg->m_sz); } } while (!VGZ_IbufEmpty(vg)); assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END); return (0); }
static void ved_stripgzip(struct req *req, const struct boc *boc) { ssize_t l; char *p; uint32_t icrc; uint32_t ilen; uint8_t *dbits; struct ecx *ecx; struct ved_foo foo; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); INIT_OBJ(&foo, VED_FOO_MAGIC); foo.req = req; foo.preq = ecx->preq; memset(foo.tailbuf, 0xdd, sizeof foo.tailbuf); /* OA_GZIPBITS is not valid until BOS_FINISHED */ if (boc != NULL) ObjWaitState(req->objcore, BOS_FINISHED); AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED)); /* * This is the interesting case: Deliver all the deflate * blocks, stripping the "LAST" bit of the last one and * padding it, as necessary, to a byte boundary. */ p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &l); AN(p); assert(l == 32); foo.start = vbe64dec(p); foo.last = vbe64dec(p + 8); foo.stop = vbe64dec(p + 16); foo.olen = ObjGetLen(req->wrk, req->objcore); assert(foo.start > 0 && foo.start < foo.olen * 8); assert(foo.last > 0 && foo.last < foo.olen * 8); assert(foo.stop > 0 && foo.stop < foo.olen * 8); assert(foo.last >= foo.start); assert(foo.last < foo.stop); /* The start bit must be byte aligned. */ AZ(foo.start & 7); dbits = WS_Alloc(req->ws, 8); AN(dbits); foo.dbits = dbits; (void)ObjIterate(req->wrk, req->objcore, &foo, ved_objiterate); /* XXX: error check ?? */ (void)ved_bytes(req, foo.preq, VDP_FLUSH, NULL, 0); icrc = vle32dec(foo.tailbuf); ilen = vle32dec(foo.tailbuf + 4); ecx->crc = crc32_combine(ecx->crc, icrc, ilen); ecx->l_crc += ilen; }
static enum req_fsm_nxt cnt_deliver(struct worker *wrk, struct req *req) { CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CHECK_OBJ_NOTNULL(req->objcore->objhead, OBJHEAD_MAGIC); AN(req->vcl); assert(req->objcore->refcnt > 0); ObjTouch(req->wrk, req->objcore, req->t_prev); HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod); if (HTTP_Decode(req->resp, ObjGetAttr(req->wrk, req->objcore, OA_HEADERS, NULL))) { req->err_code = 500; req->req_step = R_STP_SYNTH; return (REQ_FSM_MORE); } http_ForceField(req->resp, HTTP_HDR_PROTO, "HTTP/1.1"); if (req->is_hit) http_PrintfHeader(req->resp, "X-Varnish: %u %u", VXID(req->vsl->wid), ObjGetXID(wrk, req->objcore)); else http_PrintfHeader(req->resp, "X-Varnish: %u", VXID(req->vsl->wid)); /* * We base Age calculation upon the last timestamp taken during * client request processing. This gives some inaccuracy, but * since Age is only full second resolution that shouldn't * matter. (Last request timestamp could be a Start timestamp * taken before the object entered into cache leading to negative * age. Truncate to zero in that case). */ http_PrintfHeader(req->resp, "Age: %.0f", fmax(0., req->t_prev - req->objcore->t_origin)); http_SetHeader(req->resp, "Via: 1.1 varnish-v4"); if (cache_param->http_gzip_support && ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) && !RFC2616_Req_Gzip(req->http)) RFC2616_Weaken_Etag(req->resp); VCL_deliver_method(req->vcl, wrk, req, NULL, NULL); VSLb_ts_req(req, "Process", W_TIM_real(wrk)); /* Stop the insanity before it turns "Hotel California" on us */ if (req->restarts >= cache_param->max_restarts) wrk->handling = VCL_RET_DELIVER; if (wrk->handling != VCL_RET_DELIVER) { (void)HSH_DerefObjCore(wrk, &req->objcore); http_Teardown(req->resp); switch (wrk->handling) { case VCL_RET_RESTART: req->req_step = R_STP_RESTART; break; case VCL_RET_SYNTH: req->req_step = R_STP_SYNTH; break; default: WRONG("Illegal return from vcl_deliver{}"); } return (REQ_FSM_MORE); } assert(wrk->handling == VCL_RET_DELIVER); if (!(req->objcore->flags & OC_F_PASS) && req->esi_level == 0 && http_IsStatus(req->resp, 200) && req->http->conds && RFC2616_Do_Cond(req)) http_PutResponse(req->resp, "HTTP/1.1", 304, NULL); req->req_step = R_STP_TRANSMIT; return (REQ_FSM_MORE); }
VDP_ESI(struct req *req, enum vdp_action act, void **priv, const void *ptr, ssize_t len) { uint8_t *q, *r; ssize_t l = 0; uint32_t icrc = 0; uint8_t tailbuf[8 + 5]; const uint8_t *pp; struct ecx *ecx, *pecx; int retval = 0; if (act == VDP_INIT) { AZ(*priv); ALLOC_OBJ(ecx, ECX_MAGIC); AN(ecx); ecx->preq = req; *priv = ecx; RFC2616_Weaken_Etag(req->resp); req->res_mode |= RES_ESI; if (req->resp_len != 0) req->resp_len = -1; return (0); } CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC); if (act == VDP_FINI) { FREE_OBJ(ecx); *priv = NULL; return (0); } pp = ptr; while (1) { switch (ecx->state) { case 0: ecx->p = ObjGetAttr(req->wrk, req->objcore, OA_ESIDATA, &l); AN(ecx->p); assert(l > 0); ecx->e = ecx->p + l; if (*ecx->p == VEC_GZ) { ecx->isgzip = 1; ecx->p++; } if (req->esi_level == 0) { /* * Only the top level document gets to * decide this. */ if (ecx->isgzip) { assert(sizeof gzip_hdr == 10); /* Send out the gzip header */ retval = VDP_bytes(req, VDP_NULL, gzip_hdr, 10); ecx->l_crc = 0; ecx->crc = crc32(0L, Z_NULL, 0); } } ecx->state = 1; break; case 1: if (ecx->p >= ecx->e) { ecx->state = 2; break; } switch (*ecx->p) { case VEC_V1: case VEC_V2: case VEC_V8: ecx->l = ved_decode_len(req, &ecx->p); if (ecx->l < 0) return (-1); if (ecx->isgzip) { assert(*ecx->p == VEC_C1 || *ecx->p == VEC_C2 || *ecx->p == VEC_C8); l = ved_decode_len(req, &ecx->p); if (l < 0) return (-1); icrc = vbe32dec(ecx->p); ecx->p += 4; if (ecx->isgzip) { ecx->crc = crc32_combine( ecx->crc, icrc, l); ecx->l_crc += l; } } ecx->state = 3; break; case VEC_S1: case VEC_S2: case VEC_S8: ecx->l = ved_decode_len(req, &ecx->p); if (ecx->l < 0) return (-1); Debug("SKIP1(%d)\n", (int)ecx->l); ecx->state = 4; break; case VEC_INCL: ecx->p++; q = (void*)strchr((const char*)ecx->p, '\0'); AN(q); q++; r = (void*)strchr((const char*)q, '\0'); AN(r); if (VDP_bytes(req, VDP_FLUSH, NULL, 0)) { ecx->p = ecx->e; break; } Debug("INCL [%s][%s] BEGIN\n", q, ecx->p); ved_include(req, (const char*)q, (const char*)ecx->p, ecx); Debug("INCL [%s][%s] END\n", q, ecx->p); ecx->p = r + 1; break; default: VSLb(req->vsl, SLT_Error, "ESI corruption line %d 0x%02x [%s]\n", __LINE__, *ecx->p, ecx->p); WRONG("ESI-codes: Illegal code"); } break; case 2: if (ecx->isgzip && req->esi_level == 0) { /* * We are bytealigned here, so simply emit * a gzip literal block with finish bit set. */ tailbuf[0] = 0x01; tailbuf[1] = 0x00; tailbuf[2] = 0x00; tailbuf[3] = 0xff; tailbuf[4] = 0xff; /* Emit CRC32 */ vle32enc(tailbuf + 5, ecx->crc); /* MOD(2^32) length */ vle32enc(tailbuf + 9, ecx->l_crc); (void)VDP_bytes(req, VDP_NULL, tailbuf, 13); } if (req->transport->deliver == VED_Deliver) { CAST_OBJ_NOTNULL(pecx, req->transport_priv, ECX_MAGIC); pecx->crc = crc32_combine(pecx->crc, ecx->crc, ecx->l_crc); pecx->l_crc += ecx->l_crc; } retval = VDP_bytes(req, VDP_FLUSH, NULL, 0); ecx->state = 99; return (retval); case 3: case 4: /* * There is no guarantee that the 'l' bytes are all * in the same storage segment, so loop over storage * until we have processed them all. */ if (ecx->l <= len) { if (ecx->state == 3) retval = VDP_bytes(req, act, pp, ecx->l); len -= ecx->l; pp += ecx->l; ecx->state = 1; break; } if (ecx->state == 3 && len > 0) retval = VDP_bytes(req, act, pp, len); ecx->l -= len; return (retval); case 99: /* * VEP does not account for the PAD+CRC+LEN * so we can see up to approx 15 bytes here. */ return (retval); default: WRONG("FOO"); break; } if (retval) return (retval); } }