void V1D_Deliver(struct req *req, struct busyobj *bo) { const char *r; enum objiter_status ois; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC); req->res_mode = 0; /* * Determine ESI status first. Not dependent on wantbody, because * we want ESI to supress C-L in HEAD too. */ if (!req->disable_esi && ObjGetattr(req->wrk, req->objcore, OA_ESIDATA, NULL) != NULL) req->res_mode |= RES_ESI; /* * ESI-childen don't care about headers -> early escape */ if (req->esi_level > 0) { ESI_DeliverChild(req, bo); return; } if (req->res_mode & RES_ESI) { RFC2616_Weaken_Etag(req->resp); } else if (http_IsStatus(req->resp, 304)) { http_Unset(req->resp, H_Content_Length); req->wantbody = 0; } else if (bo == NULL && !http_GetHdr(req->resp, H_Content_Length, NULL)) { http_PrintfHeader(req->resp, "Content-Length: %ju", (uintmax_t)ObjGetLen( req->wrk, req->objcore)); } if (cache_param->http_gzip_support && ObjCheckFlag(req->wrk, req->objcore, OF_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_GUNZIP; VDP_push(req, VDP_gunzip, NULL, 0); } if (req->res_mode & RES_ESI) { /* Gunzip could have added back a C-L */ http_Unset(req->resp, H_Content_Length); } /* * Range comes after the others and pushes on bottom because it * can generate a correct C-L header. */ if (cache_param->http_range_support && http_IsStatus(req->resp, 200)) { http_SetHeader(req->resp, "Accept-Ranges: bytes"); if (req->wantbody && http_GetHdr(req->http, H_Range, &r)) VRG_dorange(req, bo, r); } if (http_GetHdr(req->resp, H_Content_Length, NULL)) req->res_mode |= RES_LEN; if (req->wantbody && !(req->res_mode & RES_LEN)) { if (req->http->protover >= 11) { req->res_mode |= RES_CHUNKED; http_SetHeader(req->resp, "Transfer-Encoding: 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->doclose) { if (!http_HdrIs(req->resp, H_Connection, "close")) { http_Unset(req->resp, H_Connection); http_SetHeader(req->resp, "Connection: close"); } } else if (!http_GetHdr(req->resp, H_Connection, NULL)) http_SetHeader(req->resp, "Connection: keep-alive"); VDP_push(req, v1d_bytes, NULL, 1); V1L_Reserve(req->wrk, req->ws, &req->sp->fd, req->vsl, req->t_prev); req->acct.resp_hdrbytes += HTTP1_Write(req->wrk, req->resp, HTTP1_Resp); if (DO_DEBUG(DBG_FLUSH_HEAD)) (void)V1L_Flush(req->wrk); ois = OIS_DONE; if (req->wantbody) { if (req->res_mode & RES_CHUNKED) V1L_Chunked(req->wrk); ois = VDP_DeliverObj(req); (void)VDP_bytes(req, VDP_FLUSH, NULL, 0); if (ois == OIS_DONE && (req->res_mode & RES_CHUNKED)) V1L_EndChunk(req->wrk); } if ((V1L_FlushRelease(req->wrk) || ois != OIS_DONE) && req->sp->fd >= 0) SES_Close(req->sp, SC_REM_CLOSE); VDP_close(req); }
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); }