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); }
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); }