vfp_gzip_end(struct busyobj *bo) { struct vgz *vg; size_t dl; const void *dp; int i; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); vg = bo->vgz_rx; CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); bo->vgz_rx = NULL; if (bo->state == BOS_FAILED) { (void)VGZ_Destroy(&vg); return(0); } do { VGZ_Ibuf(vg, "", 0); if (VGZ_ObufStorage(bo, vg)) return(-1); i = VGZ_Gzip(vg, &dp, &dl, VGZ_FINISH); VBO_extend(bo, dl); } while (i != Z_STREAM_END); VGZ_UpdateObj(vg, bo->fetch_obj); if (VGZ_Destroy(&vg) != VGZ_END) return(VFP_Error(bo, "Gzip error at the very end")); return (0); }
vfp_esi_end(struct sess *sp) { struct vsb *vsb; struct vef_priv *vef; ssize_t l; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); AN(sp->wrk->vep); vsb = VEP_Finish(sp); if (vsb != NULL) { l = VSB_len(vsb); assert(l > 0); /* XXX: This is a huge waste of storage... */ sp->obj->esidata = STV_alloc(sp, l); XXXAN(sp->obj->esidata); memcpy(sp->obj->esidata->ptr, VSB_data(vsb), l); sp->obj->esidata->len = l; VSB_delete(vsb); } if (sp->wrk->vgz_rx != NULL) VGZ_Destroy(&sp->wrk->vgz_rx); if (sp->wrk->vef_priv != NULL) { vef = sp->wrk->vef_priv; CHECK_OBJ_NOTNULL(vef, VEF_MAGIC); sp->wrk->vef_priv = NULL; VGZ_UpdateObj(vef->vgz, sp->obj); VGZ_Destroy(&vef->vgz); XXXAZ(vef->error); FREE_OBJ(vef); } return (0); }
vfp_esi_end(struct busyobj *bo) { struct vsb *vsb; struct vef_priv *vef; ssize_t l; int retval = 0; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AN(bo->vep); if (bo->state == BOS_FAILED) retval = -1; if (bo->vgz_rx != NULL && VGZ_Destroy(&bo->vgz_rx) != VGZ_END) retval = VFP_Error(bo, "Gunzip+ESI Failed at the very end"); vsb = VEP_Finish(bo); if (vsb != NULL) { if (!retval) { l = VSB_len(vsb); assert(l > 0); /* XXX: This is a huge waste of storage... */ bo->fetch_obj->esidata = STV_alloc(bo, l); if (bo->fetch_obj->esidata != NULL) { memcpy(bo->fetch_obj->esidata->ptr, VSB_data(vsb), l); bo->fetch_obj->esidata->len = l; } else { retval = VFP_Error(bo, "Could not allocate storage for esidata"); } } VSB_delete(vsb); } vef = bo->vef_priv; bo->vef_priv = NULL; CHECK_OBJ_NOTNULL(vef, VEF_MAGIC); if (vef->vgz != NULL) { VGZ_UpdateObj(vef->vgz, bo->fetch_obj); if (VGZ_Destroy(&vef->vgz) != VGZ_END) retval = VFP_Error(bo, "ESI+Gzip Failed at the very end"); } if (vef->ibuf != NULL) free(vef->ibuf); if (vef->ibuf2 != NULL) free(vef->ibuf2); FREE_OBJ(vef); return (retval); }
vfp_esi_end(struct worker *wrk) { struct vsb *vsb; struct vef_priv *vef; struct busyobj *bo; ssize_t l; int retval; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); bo = wrk->busyobj; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AN(bo->vep); retval = bo->fetch_failed; if (bo->vgz_rx != NULL && VGZ_Destroy(&bo->vgz_rx, -1) != VGZ_END) retval = FetchError(wrk, "Gunzip+ESI Failed at the very end"); vsb = VEP_Finish(wrk); if (vsb != NULL) { if (!retval) { l = VSB_len(vsb); assert(l > 0); /* XXX: This is a huge waste of storage... */ bo->fetch_obj->esidata = STV_alloc(wrk, l); if (bo->fetch_obj->esidata != NULL) { memcpy(bo->fetch_obj->esidata->ptr, VSB_data(vsb), l); bo->fetch_obj->esidata->len = l; } else { retval = FetchError(wrk, "Could not allocate storage for esidata"); } } VSB_delete(vsb); } vef = bo->vef_priv; if (vef != NULL) { CHECK_OBJ_NOTNULL(vef, VEF_MAGIC); bo->vef_priv = NULL; VGZ_UpdateObj(vef->vgz, bo->fetch_obj); if (VGZ_Destroy(&vef->vgz, -1) != VGZ_END) retval = FetchError(wrk, "ESI+Gzip Failed at the very end"); FREE_OBJ(vef); } return (retval); }
vfp_gunzip_end(struct busyobj *bo) { struct vgz *vg; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); vg = bo->vgz_rx; bo->vgz_rx = NULL; CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); if (bo->state == BOS_FAILED) { (void)VGZ_Destroy(&vg); return(0); } if (VGZ_Destroy(&vg) != VGZ_END) return(VFP_Error(bo, "Gunzip error at the very end")); return (0); }
vfp_testgzip_end(struct busyobj *bo) { struct vgz *vg; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); vg = bo->vgz_rx; bo->vgz_rx = NULL; CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC); if (bo->state == BOS_FAILED) { (void)VGZ_Destroy(&vg); return(0); } VGZ_UpdateObj(vg, bo->fetch_obj); if (VGZ_Destroy(&vg) != VGZ_END) return(FetchError(bo, "TestGunzip error at the very end")); return (0); }
vfp_gzip_fini(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 (vfe->priv1 != NULL) { CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); vfe->priv1 = NULL; (void)VGZ_Destroy(&vg); } }
vfp_gzip_fini(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->priv1 != NULL) { CAST_OBJ_NOTNULL(vg, vfe->priv1, VGZ_MAGIC); vfe->priv1 = NULL; (void)VGZ_Destroy(&vg); } }
static enum vfp_status vfp_esi_end(struct busyobj *bo, struct vef_priv *vef, enum vfp_status retval) { struct vsb *vsb; ssize_t l; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CHECK_OBJ_NOTNULL(vef, VEF_MAGIC); vsb = VEP_Finish(vef->vep, bo); if (vsb != NULL) { if (retval == VFP_END) { l = VSB_len(vsb); assert(l > 0); /* XXX: This is a huge waste of storage... */ bo->fetch_obj->esidata = STV_alloc(bo, l); if (bo->fetch_obj->esidata != NULL) { memcpy(bo->fetch_obj->esidata->ptr, VSB_data(vsb), l); bo->fetch_obj->esidata->len = l; } else { retval = VFP_Error(bo, "Could not allocate storage for esidata"); } } VSB_delete(vsb); } if (vef->vgz != NULL) { VGZ_UpdateObj(vef->vgz, bo->fetch_obj); if (VGZ_Destroy(&vef->vgz) != VGZ_END) retval = VFP_Error(bo, "ESI+Gzip Failed at the very end"); } if (vef->ibuf != NULL) free(vef->ibuf); FREE_OBJ(vef); return (retval); }
static enum vfp_status vfp_esi_end(struct vfp_ctx *vc, struct vef_priv *vef, enum vfp_status retval) { struct vsb *vsb; ssize_t l; void *p; CHECK_OBJ_NOTNULL(vc, VFP_CTX_MAGIC); CHECK_OBJ_NOTNULL(vef, VEF_MAGIC); vsb = VEP_Finish(vef->vep); if (vsb != NULL) { if (retval == VFP_END) { l = VSB_len(vsb); assert(l > 0); p = ObjSetattr(vc->wrk, vc->oc, OA_ESIDATA, l, VSB_data(vsb)); if (p == NULL) { retval = VFP_Error(vc, "Could not allocate storage for esidata"); } } VSB_delete(vsb); } if (vef->vgz != NULL) { VGZ_UpdateObj(vc, vef->vgz, VUA_END_GZIP); if (VGZ_Destroy(&vef->vgz) != VGZ_END) retval = VFP_Error(vc, "ESI+Gzip Failed at the very end"); } if (vef->ibuf != NULL) free(vef->ibuf); FREE_OBJ(vef); return (retval); }
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); }