static void v1d_WriteDirObj(struct req *req) { enum objiter_status ois; ssize_t len; struct objiter *oi; void *ptr; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); oi = ObjIterBegin(req->wrk, req->obj); XXXAN(oi); do { ois = ObjIter(oi, &ptr, &len); switch(ois) { case OIS_DONE: AZ(len); break; case OIS_ERROR: break; case OIS_DATA: case OIS_STREAM: if (VDP_bytes(req, ois == OIS_DATA ? VDP_NULL : VDP_FLUSH, ptr, len)) ois = OIS_ERROR; break; default: WRONG("Wrong OIS value"); } } while (ois == OIS_DATA || ois == OIS_STREAM); (void)VDP_bytes(req, VDP_FINISH, NULL, 0); ObjIterEnd(&oi); }
enum objiter_status VDP_DeliverObj(struct req *req) { enum objiter_status ois; ssize_t len; void *oi; void *ptr; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); if (req->res_mode & RES_ESI) { ESI_Deliver(req); return (OIS_DONE); } oi = ObjIterBegin(req->wrk, req->objcore); XXXAN(oi); AZ(req->synth_body); do { ois = ObjIter(req->objcore, oi, &ptr, &len); switch(ois) { case OIS_DONE: AZ(len); break; case OIS_ERROR: break; case OIS_DATA: case OIS_STREAM: if (VDP_bytes(req, ois == OIS_DATA ? VDP_NULL : VDP_FLUSH, ptr, len)) ois = OIS_ERROR; break; default: WRONG("Wrong OIS value"); } } while (ois == OIS_DATA || ois == OIS_STREAM); ObjIterEnd(req->objcore, &oi); return (ois); }
static void ved_stripgzip(struct req *req, struct busyobj *bo) { ssize_t start, last, stop, lpad; ssize_t l; char *p; uint32_t icrc; uint32_t ilen; uint64_t olen; uint8_t *dbits; uint8_t *pp; uint8_t tailbuf[8]; enum objiter_status ois; void *oi; void *sp; ssize_t sl, ll, dl; struct ecx *ecx; struct req *preq; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC); preq = ecx->preq; if (bo != NULL) VBO_waitstate(bo, 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); start = vbe64dec(p); last = vbe64dec(p + 8); stop = vbe64dec(p + 16); olen = ObjGetLen(req->wrk, req->objcore); assert(start > 0 && start < olen * 8); assert(last > 0 && last < olen * 8); assert(stop > 0 && stop < olen * 8); assert(last >= start); assert(last < stop); /* The start bit must be byte aligned. */ AZ(start & 7); /* * XXX: optimize for the case where the 'last' * XXX: bit is in a empty copy block */ memset(tailbuf, 0xdd, sizeof tailbuf); dbits = WS_Alloc(req->ws, 8); AN(dbits); ll = 0; oi = ObjIterBegin(req->wrk, req->objcore); do { ois = ObjIter(req->objcore, oi, &sp, &sl); pp = sp; if (sl > 0) { /* Skip over the GZIP header */ dl = start / 8 - ll; if (dl > 0) { /* Before start, skip */ if (dl > sl) dl = sl; ll += dl; sl -= dl; pp += dl; } } if (sl > 0) { /* The main body of the object */ dl = last / 8 - ll; if (dl > 0) { if (dl > sl) dl = sl; if (ved_bytes(req, preq, VDP_NULL, pp, dl)) break; ll += dl; sl -= dl; pp += dl; } } if (sl > 0 && ll == last / 8) { /* Remove the "LAST" bit */ dbits[0] = *pp; dbits[0] &= ~(1U << (last & 7)); if (ved_bytes(req, preq, VDP_NULL, dbits, 1)) break; ll++; sl--; pp++; } if (sl > 0) { /* Last block */ dl = stop / 8 - ll; if (dl > 0) { if (dl > sl) dl = sl; if (ved_bytes(req, preq, VDP_NULL, pp, dl)) break; ll += dl; sl -= dl; pp += dl; } } if (sl > 0 && (stop & 7) && ll == stop / 8) { /* Add alignment to byte boundary */ dbits[1] = *pp; ll++; sl--; pp++; switch((int)(stop & 7)) { case 1: /* * x000.... * 00000000 00000000 11111111 11111111 */ case 3: /* * xxx000.. * 00000000 00000000 11111111 11111111 */ case 5: /* * xxxxx000 * 00000000 00000000 11111111 11111111 */ dbits[2] = 0x00; dbits[3] = 0x00; dbits[4] = 0xff; dbits[5] = 0xff; lpad = 5; break; case 2: /* xx010000 00000100 00000001 00000000 */ dbits[1] |= 0x08; dbits[2] = 0x20; dbits[3] = 0x80; dbits[4] = 0x00; lpad = 4; break; case 4: /* xxxx0100 00000001 00000000 */ dbits[1] |= 0x20; dbits[2] = 0x80; dbits[3] = 0x00; lpad = 3; break; case 6: /* xxxxxx01 00000000 */ dbits[1] |= 0x80; dbits[2] = 0x00; lpad = 2; break; case 7: /* * xxxxxxx0 * 00...... * 00000000 00000000 11111111 11111111 */ dbits[2] = 0x00; dbits[3] = 0x00; dbits[4] = 0x00; dbits[5] = 0xff; dbits[6] = 0xff; lpad = 6; break; case 0: /* xxxxxxxx */ default: WRONG("compiler must be broken"); } if (ved_bytes(req, preq, VDP_NULL, dbits + 1, lpad)) break; } if (sl > 0) { /* Recover GZIP tail */ dl = olen - ll; assert(dl >= 0); if (dl > sl) dl = sl; if (dl > 0) { assert(dl <= 8); l = ll - (olen - 8); assert(l >= 0); assert(l <= 8); assert(l + dl <= 8); memcpy(tailbuf + l, pp, dl); ll += dl; sl -= dl; pp += dl; } } } while (ois == OIS_DATA || ois == OIS_STREAM); ObjIterEnd(req->objcore, &oi); (void)ved_bytes(req, preq, VDP_FLUSH, NULL, 0); icrc = vle32dec(tailbuf); ilen = vle32dec(tailbuf + 4); ecx->crc = crc32_combine(ecx->crc, icrc, ilen); ecx->l_crc += ilen; }
static enum fetch_step vbf_stp_condfetch(struct worker *wrk, struct busyobj *bo) { void *oi; void *sp; ssize_t sl, al, l; uint8_t *ptr; enum objiter_status ois; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AZ(vbf_beresp2obj(bo)); if (ObjGetattr(bo->wrk, bo->stale_oc, OA_ESIDATA, NULL) != NULL) AZ(ObjCopyAttr(bo->wrk, bo->fetch_objcore, bo->stale_oc, OA_ESIDATA)); AZ(ObjCopyAttr(bo->wrk, bo->fetch_objcore, bo->stale_oc, OA_FLAGS)); AZ(ObjCopyAttr(bo->wrk, bo->fetch_objcore, bo->stale_oc, OA_GZIPBITS)); if (bo->do_stream) { HSH_Unbusy(wrk, bo->fetch_objcore); VBO_setstate(bo, BOS_STREAM); } al = 0; oi = ObjIterBegin(wrk, bo->stale_oc); do { ois = ObjIter(bo->stale_oc, oi, &sp, &sl); if (ois == OIS_ERROR) (void)VFP_Error(bo->vfc, "Template object failed"); while (sl > 0) { l = ObjGetLen(bo->wrk, bo->stale_oc) - al; assert(l > 0); if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK) break; if (sl < l) l = sl; memcpy(ptr, sp, l); VBO_extend(bo, l); al += l; sp = (char *)sp + l; sl -= l; } } while (!bo->vfc->failed && (ois == OIS_DATA || ois == OIS_STREAM)); ObjIterEnd(bo->stale_oc, &oi); if (bo->stale_oc->flags & OC_F_FAILED) (void)VFP_Error(bo->vfc, "Template object failed"); if (bo->vfc->failed) { VDI_Finish(bo->wrk, bo); return (F_STP_FAIL); } if (!bo->do_stream) HSH_Unbusy(wrk, bo->fetch_objcore); assert(ObjGetLen(bo->wrk, bo->fetch_objcore) == al); EXP_Rearm(bo->stale_oc, bo->stale_oc->exp.t_origin, 0, 0, 0); /* Recycle the backend connection before setting BOS_FINISHED to give predictable backend reuse behavior for varnishtest */ VDI_Finish(bo->wrk, bo); VBO_setstate(bo, BOS_FINISHED); VSLb_ts_busyobj(bo, "BerespBody", W_TIM_real(wrk)); return (F_STP_DONE); }
static enum fetch_step vbf_stp_condfetch(struct worker *wrk, struct busyobj *bo) { unsigned l; uint16_t nhttp; struct object *obj; struct objiter *oi; void *sp; ssize_t sl, al, tl, vl; struct storage *st; enum objiter_status ois; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); l = 0; if (bo->ims_obj->vary != NULL) { vl = VRY_Validate(bo->ims_obj->vary); l += vl; } else vl = 0; l += http_EstimateWS(bo->ims_obj->http, 0, &nhttp); bo->stats = &wrk->stats; obj = STV_NewObject(bo, bo->storage_hint, l, nhttp); if (obj == NULL) { (void)VFP_Error(bo, "Could not get storage"); VDI_CloseFd(&bo->vbc); return (F_STP_DONE); } AZ(bo->fetch_obj); bo->fetch_obj = obj; obj->gziped = bo->ims_obj->gziped; obj->gzip_start = bo->ims_obj->gzip_start; obj->gzip_last = bo->ims_obj->gzip_last; obj->gzip_stop = bo->ims_obj->gzip_stop; /* XXX: ESI */ if (bo->ims_obj->vary != NULL) { obj->vary = (void *)WS_Copy(obj->http->ws, bo->ims_obj->vary, vl); assert(vl == VRY_Validate(obj->vary)); } obj->vxid = bo->vsl->wid; obj->http->logtag = HTTP_Obj; /* XXX: we should have our own HTTP_A_CONDFETCH */ http_FilterResp(bo->ims_obj->http, obj->http, HTTPH_A_INS); http_CopyHome(obj->http); AZ(WS_Overflowed(bo->ws_o)); VBO_setstate(bo, BOS_FETCHING); HSH_Unbusy(&wrk->stats, obj->objcore); if (!(obj->objcore->flags & OC_F_PRIVATE)) { EXP_Insert(obj->objcore); AN(obj->objcore->ban); } st = NULL; al = 0; oi = ObjIterBegin(wrk, bo->ims_obj); do { ois = ObjIter(oi, &sp, &sl); while (sl > 0) { if (st == NULL) { st = VFP_GetStorage(bo, bo->ims_obj->len - al); XXXAN(st); } tl = sl; if (tl > st->space - st->len) tl = st->space - st->len; memcpy(st->ptr + st->len, sp, tl); al += tl; sp = (char *)sp + tl; sl -= tl; VBO_extend(bo, al); if (st->len == st->space) st = NULL; } } while (ois == OIS_DATA || ois == OIS_STREAM); ObjIterEnd(&oi); bo->stats = NULL; assert(al == bo->ims_obj->len); assert(obj->len == al); if (bo->state != BOS_FAILED) VBO_setstate(bo, BOS_FINISHED); HSH_Complete(obj->objcore); return (F_STP_DONE); }
static enum fetch_step vbf_stp_condfetch(struct worker *wrk, struct busyobj *bo) { struct object *obj; struct objiter *oi; void *sp; ssize_t sl, al, tl; struct storage *st; enum objiter_status ois; char *p; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); if (bo->ims_obj->changed_gzip) { /* * If we modified the gzip status of the IMS object, that * must control the C-E header, if any. */ http_Unset(bo->beresp, H_Content_Encoding); if (http_GetHdr(bo->ims_obj->http, H_Content_Encoding, &p)) http_PrintfHeader(bo->beresp, "Content-Encoding: %s", p); } AZ(vbf_beresp2obj(bo)); obj = bo->fetch_obj; bo->vfc->body = obj->body; if (bo->ims_obj->esidata != NULL) { sl = bo->ims_obj->esidata->len; obj->esidata = STV_alloc(bo->vfc, sl); if (obj->esidata == NULL || obj->esidata->space < sl) { VSLb(bo->vsl, SLT_Error, "No space for %zd bytes of ESI data", sl); return (F_STP_FAIL); } memcpy(obj->esidata->ptr, bo->ims_obj->esidata->ptr, sl); obj->esidata->len = sl; } obj->gziped = bo->ims_obj->gziped; obj->gzip_start = bo->ims_obj->gzip_start; obj->gzip_last = bo->ims_obj->gzip_last; obj->gzip_stop = bo->ims_obj->gzip_stop; AZ(WS_Overflowed(bo->ws_o)); if (bo->do_stream) { HSH_Unbusy(&wrk->stats, obj->objcore); VBO_setstate(bo, BOS_STREAM); } st = NULL; al = 0; oi = ObjIterBegin(wrk, bo->ims_obj); do { ois = ObjIter(oi, &sp, &sl); while (sl > 0) { if (st == NULL) st = VFP_GetStorage(bo->vfc, bo->ims_obj->len - al); if (st == NULL) break; tl = sl; if (tl > st->space - st->len) tl = st->space - st->len; memcpy(st->ptr + st->len, sp, tl); al += tl; sp = (char *)sp + tl; sl -= tl; VBO_extend(bo, tl); if (st->len == st->space) st = NULL; } } while (!bo->vfc->failed && (ois == OIS_DATA || ois == OIS_STREAM)); ObjIterEnd(&oi); if (bo->vfc->failed) return (F_STP_FAIL); if (!bo->do_stream) HSH_Unbusy(&wrk->stats, obj->objcore); assert(al == bo->ims_obj->len); assert(obj->len == al); EXP_Rearm(bo->ims_obj->objcore, bo->ims_obj->objcore->exp.t_origin, 0, 0, 0); /* Recycle the backend connection before setting BOS_FINISHED to give predictable backend reuse behavior for varnishtest */ if (bo->vbc != NULL && bo->doclose == SC_NULL) { VDI_RecycleFd(&bo->vbc, &bo->acct); AZ(bo->vbc); } VBO_setstate(bo, BOS_FINISHED); VSLb_ts_busyobj(bo, "BerespBody", W_TIM_real(wrk)); return (F_STP_DONE); }
ssize_t VRB_Iterate(struct req *req, req_body_iter_f *func, void *priv) { char buf[8192]; ssize_t l, ll = 0; void *p; int i; struct vfp_ctx *vfc; enum vfp_status vfps = VFP_ERROR; void *oi; enum objiter_status ois; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); AN(func); switch(req->req_body_status) { case REQ_BODY_CACHED: oi = ObjIterBegin(req->wrk, req->body_oc); AN(oi); do { ois = ObjIter(req->body_oc, oi, &p, &l); ll += l; if (l > 0 && func(req, priv, p, l)) break; } while (ois == OIS_DATA); ObjIterEnd(req->body_oc, &oi); return (ois == OIS_DONE ? ll : -1); case REQ_BODY_NONE: return (0); case REQ_BODY_WITH_LEN: case REQ_BODY_WITHOUT_LEN: break; case REQ_BODY_TAKEN: VSLb(req->vsl, SLT_VCL_Error, "Uncached req.body can only be consumed once."); return (-1); case REQ_BODY_FAIL: VSLb(req->vsl, SLT_FetchError, "Had failed reading req.body before."); return (-1); default: WRONG("Wrong req_body_status in VRB_IterateReqBody()"); } Lck_Lock(&req->sp->mtx); if (req->req_body_status == REQ_BODY_WITH_LEN || req->req_body_status == REQ_BODY_WITHOUT_LEN) { req->req_body_status = REQ_BODY_TAKEN; i = 0; } else i = -1; Lck_Unlock(&req->sp->mtx); if (i) { VSLb(req->vsl, SLT_VCL_Error, "Multiple attempts to access non-cached req.body"); return (i); } CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC); vfc = req->htc->vfc; VFP_Setup(vfc); vfc->http = req->http; vfc->wrk = req->wrk; V1F_Setup_Fetch(vfc, req->htc); if (VFP_Open(vfc) < 0) { VSLb(req->vsl, SLT_FetchError, "Could not open Fetch Pipeline"); return (-1); } do { l = sizeof buf; vfps = VFP_Suck(vfc, buf, &l); if (vfps == VFP_ERROR) { req->req_body_status = REQ_BODY_FAIL; ll = -1; break; } else if (l > 0) { req->req_bodybytes += l; req->acct.req_bodybytes += l; ll += l; l = func(req, priv, buf, l); if (l) { req->req_body_status = REQ_BODY_FAIL; ll = -1; break; } } } while (vfps == VFP_OK); VFP_Close(vfc); VSLb_ts_req(req, "ReqBody", VTIM_real()); return (ll); }