static enum sess_close vbe_dir_http1pipe(const struct director *d, struct req *req, struct busyobj *bo) { int i; enum sess_close retval; struct backend *bp; struct v1p_acct v1a; struct vbc *vbc; CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CAST_OBJ_NOTNULL(bp, d->priv, BACKEND_MAGIC); memset(&v1a, 0, sizeof v1a); /* This is hackish... */ v1a.req = req->acct.req_hdrbytes; req->acct.req_hdrbytes = 0; req->res_mode = RES_PIPE; vbc = vbe_dir_getfd(req->wrk, bp, bo); if (vbc == NULL) { VSLb(bo->vsl, SLT_FetchError, "no backend connection"); retval = SC_TX_ERROR; } else { i = V1F_SendReq(req->wrk, bo, &v1a.bereq, 1); VSLb_ts_req(req, "Pipe", W_TIM_real(req->wrk)); if (vbc->state == VBC_STATE_STOLEN) VBT_Wait(req->wrk, vbc); if (i == 0) V1P_Process(req, vbc->fd, &v1a); VSLb_ts_req(req, "PipeSess", W_TIM_real(req->wrk)); bo->htc->doclose = SC_TX_PIPE; vbe_dir_finish(d, req->wrk, bo); retval = SC_TX_PIPE; } V1P_Charge(req, &v1a, bp->vsc); return (retval); }
vbe_dir_finish(const struct director *d, struct worker *wrk, struct busyobj *bo) { struct backend *bp; struct vbc *vbc; CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CAST_OBJ_NOTNULL(bp, d->priv, BACKEND_MAGIC); CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC); CAST_OBJ_NOTNULL(vbc, bo->htc->priv, VBC_MAGIC); bo->htc->priv = NULL; if (vbc->state != VBC_STATE_USED) VBT_Wait(wrk, vbc); if (bo->htc->doclose != SC_NULL || bp->proxy_header != 0) { VSLb(bo->vsl, SLT_BackendClose, "%d %s", vbc->fd, bp->display_name); VBT_Close(bp->tcp_pool, &vbc); Lck_Lock(&bp->mtx); } else { VSLb(bo->vsl, SLT_BackendReuse, "%d %s", vbc->fd, bp->display_name); Lck_Lock(&bp->mtx); VSC_C_main->backend_recycle++; VBT_Recycle(wrk, bp->tcp_pool, &vbc); } assert(bp->n_conn > 0); bp->n_conn--; #define ACCT(foo) bp->vsc->foo += bo->acct.foo; #include "tbl/acct_fields_bereq.h" #undef ACCT Lck_Unlock(&bp->mtx); bo->htc = NULL; }
void V1P_Process(struct req *req, struct busyobj *bo, int fd) { struct worker *wrk; struct pollfd fds[2]; int i; struct acct_pipe acct_pipe; CHECK_OBJ_NOTNULL(req, REQ_MAGIC); CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC); wrk = req->wrk; CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); assert(fd > 0); req->res_mode = RES_PIPE; memset(&acct_pipe, 0, sizeof acct_pipe); acct_pipe.req = req->acct.req_hdrbytes; req->acct.req_hdrbytes = 0; CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC); CHECK_OBJ_NOTNULL(bo->htc->vbc, VBC_MAGIC); bo->wrk = req->wrk; bo->director_state = DIR_S_BODY; (void)VTCP_blocking(fd); V1L_Reserve(wrk, wrk->aws, &fd, bo->vsl, req->t_req); acct_pipe.bereq += HTTP1_Write(wrk, bo->bereq, HTTP1_Req); if (req->htc->pipeline_b != NULL) acct_pipe.in += V1L_Write(wrk, req->htc->pipeline_b, req->htc->pipeline_e - req->htc->pipeline_b); i = V1L_FlushRelease(wrk); VSLb_ts_req(req, "Pipe", W_TIM_real(wrk)); if (i == 0) { if (bo->htc->vbc->state == VBC_STATE_STOLEN) VBT_Wait(req->wrk, bo->htc->vbc); memset(fds, 0, sizeof fds); fds[0].fd = fd; fds[0].events = POLLIN | POLLERR; fds[1].fd = req->sp->fd; fds[1].events = POLLIN | POLLERR; while (fds[0].fd > -1 || fds[1].fd > -1) { fds[0].revents = 0; fds[1].revents = 0; i = poll(fds, 2, (int)(cache_param->pipe_timeout * 1e3)); if (i < 1) break; if (fds[0].revents && rdf(fd, req->sp->fd, &acct_pipe.out)) { if (fds[1].fd == -1) break; (void)shutdown(fd, SHUT_RD); (void)shutdown(req->sp->fd, SHUT_WR); fds[0].events = 0; fds[0].fd = -1; } if (fds[1].revents && rdf(req->sp->fd, fd, &acct_pipe.in)) { if (fds[0].fd == -1) break; (void)shutdown(req->sp->fd, SHUT_RD); (void)shutdown(fd, SHUT_WR); fds[1].events = 0; fds[1].fd = -1; } } } VSLb_ts_req(req, "PipeSess", W_TIM_real(wrk)); pipecharge(req, &acct_pipe, bo->htc->vbc->backend->vsc); SES_Close(req->sp, SC_TX_PIPE); bo->doclose = SC_TX_PIPE; }
vbe_dir_gethdrs(const struct director *d, struct worker *wrk, struct busyobj *bo) { int i, extrachance = 1; struct backend *bp; struct vbc *vbc; CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC); CAST_OBJ_NOTNULL(bp, d->priv, BACKEND_MAGIC); /* * Now that we know our backend, we can set a default Host: * header if one is necessary. This cannot be done in the VCL * because the backend may be chosen by a director. */ if (!http_GetHdr(bo->bereq, H_Host, NULL) && bp->hosthdr != NULL) http_PrintfHeader(bo->bereq, "Host: %s", bp->hosthdr); do { vbc = vbe_dir_getfd(wrk, bp, bo); if (vbc == NULL) { VSLb(bo->vsl, SLT_FetchError, "no backend connection"); return (-1); } AN(bo->htc); if (vbc->state != VBC_STATE_STOLEN) extrachance = 0; i = V1F_SendReq(wrk, bo, &bo->acct.bereq_hdrbytes, 0); if (vbc->state != VBC_STATE_USED) VBT_Wait(wrk, vbc); assert(vbc->state == VBC_STATE_USED); if (i == 0) i = V1F_FetchRespHdr(bo); if (i == 0) { AN(bo->htc->priv); return (0); } /* * If we recycled a backend connection, there is a finite chance * that the backend closed it before we got the bereq to it. * In that case do a single automatic retry if req.body allows. */ vbe_dir_finish(d, wrk, bo); AZ(bo->htc); if (i < 0) break; if (bo->req != NULL && bo->req->req_body_status != REQ_BODY_NONE && bo->req->req_body_status != REQ_BODY_CACHED) break; VSC_C_main->backend_retry++; } while (extrachance); return (-1); }