vfp_testgzip_begin(struct busyobj *bo, size_t estimate) { CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); (void)estimate; bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "u F -"); CHECK_OBJ_NOTNULL(bo->vgz_rx, VGZ_MAGIC); XXXAZ(vgz_getmbuf(bo->vgz_rx)); }
vfp_esi_begin(struct busyobj *bo, size_t estimate) { struct vef_priv *vef; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); (void)estimate; ALLOC_OBJ(vef, VEF_MAGIC); XXXAN(vef); AZ(bo->vef_priv); bo->vef_priv = vef; AZ(bo->vgz_rx); if (bo->is_gzip && bo->do_gunzip) { bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "U F E"); VEP_Init(bo, NULL); vef->ibuf_sz = cache_param->gzip_buffer; } else if (bo->is_gunzip && bo->do_gzip) { vef->vgz = VGZ_NewGzip(bo->vsl, "G F E"); VEP_Init(bo, vfp_vep_callback); vef->ibuf_sz = cache_param->gzip_buffer; } else if (bo->is_gzip) { bo->vgz_rx = VGZ_NewUngzip(bo->vsl, "U F E"); vef->vgz = VGZ_NewGzip(bo->vsl, "G F E"); VEP_Init(bo, vfp_vep_callback); vef->ibuf_sz = cache_param->gzip_buffer; vef->ibuf2_sz = cache_param->gzip_buffer; } else { VEP_Init(bo, NULL); } if (vef->ibuf_sz > 0) { vef->ibuf = calloc(1L, vef->ibuf_sz); XXXAN(vef->ibuf); vef->ibuf_i = vef->ibuf; vef->ibuf_o = vef->ibuf; } if (vef->ibuf2_sz > 0) { vef->ibuf2 = calloc(1L, vef->ibuf2_sz); XXXAN(vef->ibuf2); } AN(bo->vep); }
vfp_esi_begin(struct sess *sp, size_t estimate) { struct vef_priv *vef; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); /* XXX: snapshot WS's ? We'll need the space */ AZ(sp->wrk->vgz_rx); if (sp->wrk->is_gzip && sp->wrk->do_gunzip) { sp->wrk->vgz_rx = VGZ_NewUngzip(sp, "U F E"); VEP_Init(sp, NULL); } else if (sp->wrk->is_gunzip && sp->wrk->do_gzip) { ALLOC_OBJ(vef, VEF_MAGIC); AN(vef); //vef = (void*)WS_Alloc(sp->ws, sizeof *vef); //memset(vef, 0, sizeof *vef); //vef->magic = VEF_MAGIC; vef->vgz = VGZ_NewGzip(sp, "G F E"); AZ(sp->wrk->vef_priv); sp->wrk->vef_priv = vef; VEP_Init(sp, vfp_vep_callback); } else if (sp->wrk->is_gzip) { sp->wrk->vgz_rx = VGZ_NewUngzip(sp, "U F E"); ALLOC_OBJ(vef, VEF_MAGIC); AN(vef); //vef = (void*)WS_Alloc(sp->ws, sizeof *vef); //memset(vef, 0, sizeof *vef); //vef->magic = VEF_MAGIC; vef->vgz = VGZ_NewGzip(sp, "G F E"); AZ(sp->wrk->vef_priv); sp->wrk->vef_priv = vef; VEP_Init(sp, vfp_vep_callback); } else { AZ(sp->wrk->vef_priv); VEP_Init(sp, NULL); } (void)estimate; AN(sp->wrk->vep); }
vfp_esi_begin(struct worker *wrk, size_t estimate) { struct busyobj *bo; struct vef_priv *vef; (void)estimate; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); bo = wrk->busyobj; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AZ(bo->vgz_rx); if (bo->is_gzip && bo->do_gunzip) { bo->vgz_rx = VGZ_NewUngzip(wrk, "U F E"); VEP_Init(wrk, NULL); } else if (bo->is_gunzip && bo->do_gzip) { ALLOC_OBJ(vef, VEF_MAGIC); AN(vef); vef->vgz = VGZ_NewGzip(wrk, "G F E"); AZ(bo->vef_priv); bo->vef_priv = vef; VEP_Init(wrk, vfp_vep_callback); } else if (bo->is_gzip) { bo->vgz_rx = VGZ_NewUngzip(wrk, "U F E"); ALLOC_OBJ(vef, VEF_MAGIC); AN(vef); vef->vgz = VGZ_NewGzip(wrk, "G F E"); AZ(bo->vef_priv); bo->vef_priv = vef; VEP_Init(wrk, vfp_vep_callback); } else { AZ(bo->vef_priv); VEP_Init(wrk, NULL); } AN(bo->vep); }
vfp_gzip_init(struct vfp_ctx *vc, struct vfp_entry *vfe) { struct vgz *vg; CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); if (http_HdrIs(vc->http, H_Content_Length, "0")) { http_Unset(vc->http, H_Content_Encoding); return (VFP_NULL); } if (vfe->vfp->priv2 == VFP_GZIP) { if (http_GetHdr(vc->http, H_Content_Encoding, NULL)) return (VFP_NULL); vg = VGZ_NewGzip(vc->wrk->vsl, vfe->vfp->priv1); } else { if (!http_HdrIs(vc->http, H_Content_Encoding, "gzip")) return (VFP_NULL); vg = VGZ_NewUngzip(vc->wrk->vsl, vfe->vfp->priv1); } if (vg == NULL) return (VFP_ERROR); vfe->priv1 = vg; if (vgz_getmbuf(vg)) return (VFP_ERROR); VGZ_Ibuf(vg, vg->m_buf, 0); AZ(vg->m_len); if (vfe->vfp->priv2 == VFP_GUNZIP || vfe->vfp->priv2 == VFP_GZIP) { http_Unset(vc->http, H_Content_Encoding); http_Unset(vc->http, H_Content_Length); RFC2616_Weaken_Etag(vc->http); } if (vfe->vfp->priv2 == VFP_GZIP) http_SetHeader(vc->http, "Content-Encoding: gzip"); if (vfe->vfp->priv2 == VFP_GZIP || vfe->vfp->priv2 == VFP_TESTGUNZIP) RFC2616_Vary_AE(vc->http); return (VFP_OK); }
vfp_gzip_init(struct busyobj *bo, struct vfp_entry *vfe) { struct vgz *vg; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CHECK_OBJ_NOTNULL(vfe, VFP_ENTRY_MAGIC); if (vfe->vfp->priv2) vg = VGZ_NewGzip(bo->vsl, vfe->vfp->priv1); else vg = VGZ_NewUngzip(bo->vsl, vfe->vfp->priv1); if (vg == NULL) return (VFP_ERROR); if (vgz_getmbuf(vg)) return (VFP_ERROR); vfe->priv1 = vg; VGZ_Ibuf(vg, vg->m_buf, 0); AZ(vg->m_len); return (VFP_OK); }
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); }
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; 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); } VGZ_Obuf(vg, vg->m_buf, vg->m_sz); *priv = vg; http_Unset(req->resp, H_Content_Length); p = ObjGetattr(req->wrk, req->objcore, OA_GZIPBITS, &dl); if (p != NULL && dl == 32) { u = vbe64dec(p + 24); /* XXX: Zero is suspect: OA_GZIPBITS wasn't set */ if (u != 0) http_PrintfHeader(req->resp, "Content-Length: %ju", (uintmax_t)u); } http_Unset(req->resp, H_Content_Encoding); 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 (-1); 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); }
void V1D_Deliver(struct req *req) { char *r; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC); CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC); req->res_mode = 0; if (!req->disable_esi && req->obj->esidata != NULL) { /* In ESI mode, we can't know the aggregate length */ req->res_mode &= ~RES_LEN; req->res_mode |= RES_ESI; } else if (req->resp->status == 304) { req->res_mode &= ~RES_LEN; http_Unset(req->resp, H_Content_Length); req->wantbody = 0; } else if (req->obj->objcore->busyobj == NULL) { /* XXX: Not happy with this convoluted test */ req->res_mode |= RES_LEN; if (!(req->obj->objcore->flags & OC_F_PASS) || req->obj->len != 0) { http_Unset(req->resp, H_Content_Length); http_PrintfHeader(req->resp, "Content-Length: %zd", req->obj->len); } } if (req->esi_level > 0) { /* Included ESI object, always CHUNKED or EOF */ req->res_mode &= ~RES_LEN; req->res_mode |= RES_ESI_CHILD; } if (cache_param->http_gzip_support && req->obj->gziped && !RFC2616_Req_Gzip(req->http)) { /* * We don't know what it uncompresses to * XXX: we could cache that, but would still deliver * XXX: with multiple writes because of the gunzip buffer */ req->res_mode &= ~RES_LEN; req->res_mode |= RES_GUNZIP; } if (!(req->res_mode & (RES_LEN|RES_CHUNKED|RES_EOF))) { /* We havn't chosen yet, do so */ if (!req->wantbody) { /* Nothing */ } else if (req->http->protover >= 11) { req->res_mode |= RES_CHUNKED; } else { req->res_mode |= RES_EOF; req->doclose = SC_TX_EOF; } } VSLb(req->vsl, SLT_Debug, "RES_MODE %x", req->res_mode); if (!(req->res_mode & RES_LEN)) http_Unset(req->resp, H_Content_Length); if (req->res_mode & RES_GUNZIP) http_Unset(req->resp, H_Content_Encoding); if (req->res_mode & RES_CHUNKED) http_SetHeader(req->resp, "Transfer-Encoding: chunked"); http_SetHeader(req->resp, req->doclose ? "Connection: close" : "Connection: keep-alive"); req->vdps[0] = v1d_bytes; req->vdp_nxt = 0; if ( req->wantbody && !(req->res_mode & (RES_ESI|RES_ESI_CHILD)) && cache_param->http_range_support && req->obj->response == 200) { http_SetHeader(req->resp, "Accept-Ranges: bytes"); if (http_GetHdr(req->http, H_Range, &r)) v1d_dorange(req, r); } if (req->res_mode & RES_ESI) RFC2616_Weaken_Etag(req->resp); WRW_Reserve(req->wrk, &req->sp->fd, req->vsl, req->t_resp); /* * Send HTTP protocol header, unless interior ESI object */ if (!(req->res_mode & RES_ESI_CHILD)) req->acct_req.hdrbytes += HTTP1_Write(req->wrk, req->resp, 1); if (req->res_mode & RES_CHUNKED) WRW_Chunked(req->wrk); if (!req->wantbody) { /* This was a HEAD or conditional request */ } else if (req->res_mode & RES_ESI) { AZ(req->obj->objcore->busyobj); ESI_Deliver(req); } else if (req->res_mode & RES_ESI_CHILD && req->gzip_resp) { while (req->obj->objcore->busyobj) (void)usleep(10000); ESI_DeliverChild(req); } else if (req->res_mode & RES_GUNZIP || (req->res_mode & RES_ESI_CHILD && !req->gzip_resp && req->obj->gziped)) { VDP_push(req, VDP_gunzip); req->vgz = VGZ_NewUngzip(req->vsl, "U D -"); AZ(VGZ_WrwInit(req->vgz)); v1d_WriteDirObj(req); (void)VGZ_Destroy(&req->vgz); VDP_pop(req, VDP_gunzip); } else { v1d_WriteDirObj(req); } if (req->res_mode & RES_CHUNKED && !(req->res_mode & RES_ESI_CHILD)) WRW_EndChunk(req->wrk); if (WRW_FlushRelease(req->wrk) && req->sp->fd >= 0) SES_Close(req->sp, SC_REM_CLOSE); }
static int cnt_streambody(struct sess *sp) { int i; struct stream_ctx sctx; uint8_t obuf[sp->wrk->res_mode & RES_GUNZIP ? cache_param->gzip_stack_buffer : 1]; struct worker *wrk; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); wrk = sp->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC); memset(&sctx, 0, sizeof sctx); sctx.magic = STREAM_CTX_MAGIC; AZ(wrk->sctx); wrk->sctx = &sctx; if (wrk->res_mode & RES_GUNZIP) { sctx.vgz = VGZ_NewUngzip(wrk, "U S -"); sctx.obuf = obuf; sctx.obuf_len = sizeof (obuf); } RES_StreamStart(sp); AssertObjCorePassOrBusy(wrk->obj->objcore); i = FetchBody(wrk, wrk->obj); http_Setup(wrk->busyobj->bereq, NULL); http_Setup(wrk->busyobj->beresp, NULL); wrk->busyobj->vfp = NULL; AZ(wrk->busyobj->vbc); AN(sp->director); if (!i && wrk->obj->objcore != NULL) { EXP_Insert(wrk->obj); AN(wrk->obj->objcore); AN(wrk->obj->objcore->ban); HSH_Unbusy(wrk); } else { sp->doclose = "Stream error"; } wrk->acct_tmp.fetch++; sp->director = NULL; sp->restarts = 0; RES_StreamEnd(sp); if (wrk->res_mode & RES_GUNZIP) (void)VGZ_Destroy(&sctx.vgz, sp->vsl_id); wrk->sctx = NULL; assert(WRW_IsReleased(wrk)); assert(wrk->wrw.ciov == wrk->wrw.siov); (void)HSH_Deref(wrk, NULL, &wrk->obj); VBO_DerefBusyObj(wrk, &wrk->busyobj); http_Setup(wrk->resp, NULL); sp->step = STP_DONE; return (0); }