vfp_nop_end(struct worker *wrk) { struct storage *st; st = VTAILQ_LAST(&wrk->busyobj->fetch_obj->store, storagehead); if (st == NULL) return (0); if (st->len == 0) { VTAILQ_REMOVE(&wrk->busyobj->fetch_obj->store, st, list); STV_free(st); return (0); } if (st->len < st->space) STV_trim(st, st->len); return (0); }
vfp_nop_end(struct sess *sp) { struct storage *st; st = VTAILQ_LAST(&sp->obj->store, storagehead); if (st == NULL) return (0); if (st->len == 0) { VTAILQ_REMOVE(&sp->obj->store, st, list); STV_free(st); return (0); } if (st->len < st->space) STV_trim(st, st->len); return (0); }
void V1F_fetch_body(struct worker *wrk, struct busyobj *bo) { int cls; struct storage *st; ssize_t cl; struct http_conn *htc; struct object *obj; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); htc = &bo->htc; CHECK_OBJ_ORNULL(bo->vbc, VBC_MAGIC); obj = bo->fetch_obj; CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC); CHECK_OBJ_NOTNULL(obj->http, HTTP_MAGIC); assert(bo->state == BOS_FETCHING); /* * XXX: The busyobj needs a dstat, but it is not obvious which one * XXX: it should be (own/borrowed). For now borrow the wrk's. */ AZ(bo->stats); bo->stats = &wrk->stats; AN(bo->vfp); AZ(bo->vgz_rx); assert(VTAILQ_EMPTY(&obj->store)); /* XXX: pick up estimate from objdr ? */ cl = 0; cls = bo->should_close; switch (htc->body_status) { case BS_NONE: break; case BS_ZERO: break; case BS_LENGTH: cl = vbf_fetch_number(bo->h_content_length, 10); bo->vfp->begin(bo, cl); if (bo->state == BOS_FETCHING && cl > 0) cls |= vbf_fetch_straight(bo, htc, cl); if (bo->vfp->end(bo)) assert(bo->state == BOS_FAILED); break; case BS_CHUNKED: bo->vfp->begin(bo, cl > 0 ? cl : 0); if (bo->state == BOS_FETCHING) cls |= vbf_fetch_chunked(bo, htc); if (bo->vfp->end(bo)) assert(bo->state == BOS_FAILED); break; case BS_EOF: bo->vfp->begin(bo, cl > 0 ? cl : 0); if (bo->state == BOS_FETCHING) vbf_fetch_eof(bo, htc); cls = 1; if (bo->vfp->end(bo)) assert(bo->state == BOS_FAILED); break; case BS_ERROR: cls |= VFP_Error(bo, "error incompatible Transfer-Encoding"); break; default: INCOMPL(); } bo->t_body = VTIM_mono(); AZ(bo->vgz_rx); /* * Trim or delete the last segment, if any */ st = VTAILQ_LAST(&bo->fetch_obj->store, storagehead); /* XXX: Temporary: Only trim if we are not streaming */ if (st != NULL && !bo->do_stream) { /* XXX: is any of this safe under streaming ? */ if (st->len == 0) { VTAILQ_REMOVE(&bo->fetch_obj->store, st, list); STV_free(st); } else if (st->len < st->space) { STV_trim(st, st->len, 1); } } bo->vfp = NULL; VSLb(bo->vsl, SLT_Fetch_Body, "%u(%s) cls %d", htc->body_status, body_status_2str(htc->body_status), cls); http_Teardown(bo->bereq); http_Teardown(bo->beresp); if (bo->vbc != NULL) { if (cls) VDI_CloseFd(&bo->vbc); else VDI_RecycleFd(&bo->vbc); } AZ(bo->vbc); if (bo->state == BOS_FAILED) { wrk->stats.fetch_failed++; } else { assert(bo->state == BOS_FETCHING); VSLb(bo->vsl, SLT_Length, "%zd", obj->len); { /* Sanity check fetch methods accounting */ ssize_t uu; uu = 0; VTAILQ_FOREACH(st, &obj->store, list) uu += st->len; if (bo->do_stream) /* Streaming might have started freeing stuff */ assert(uu <= obj->len); else assert(uu == obj->len); } } bo->stats = NULL; }
void VFP_Fetch_Body(struct busyobj *bo, ssize_t est) { ssize_t l; enum vfp_status vfps = VFP_ERROR; struct storage *st = NULL; CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); AN(bo->vfp_nxt); if (est < 0) est = 0; if (vfp_suck_init(bo) != VFP_OK) { (void)VFP_Error(bo, "Fetch Pipeline failed to initialize"); bo->should_close = 1; return; } do { if (bo->abandon) { /* * A pass object and delivery was terminted * We don't fail the fetch, in order for hit-for-pass * objects to be created. */ AN(bo->fetch_objcore->flags & OC_F_PASS); VSLb(bo->vsl, SLT_FetchError, "Pass delivery abandoned"); vfps = VFP_END; bo->should_close = 1; break; } AZ(bo->failed); if (st == NULL) { st = VFP_GetStorage(bo, est); est = 0; } if (st == NULL) { bo->should_close = 1; (void)VFP_Error(bo, "Out of storage"); break; } CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC); assert(st == VTAILQ_LAST(&bo->fetch_obj->store, storagehead)); l = st->space - st->len; AZ(bo->failed); vfps = VFP_Suck(bo, st->ptr + st->len, &l); if (l > 0 && vfps != VFP_ERROR) { AZ(VTAILQ_EMPTY(&bo->fetch_obj->store)); VBO_extend(bo, l); } if (st->len == st->space) st = NULL; } while (vfps == VFP_OK); if (vfps == VFP_ERROR) { AN(bo->failed); (void)VFP_Error(bo, "Fetch Pipeline failed to process"); bo->should_close = 1; } vfp_suck_fini(bo); /* * Trim or delete the last segment, if any */ st = VTAILQ_LAST(&bo->fetch_obj->store, storagehead); /* XXX: Temporary: Only trim if we are not streaming */ if (st != NULL && !bo->do_stream) { /* None of this this is safe under streaming */ if (st->len == 0) { VTAILQ_REMOVE(&bo->fetch_obj->store, st, list); STV_free(st); } else if (st->len < st->space) { STV_trim(st, st->len, 1); } } }