Exemplo n.º 1
0
http1_unwait(struct worker *wrk, void *arg)
{
	struct sess *sp;
	struct req *req;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CAST_OBJ_NOTNULL(sp, arg, SESS_MAGIC);
	WS_Release(sp->ws, 0);
	req = Req_New(wrk, sp);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	req->htc->rfd = &sp->fd;
	HTC_RxInit(req->htc, req->ws);
	http1_setstate(sp, H1NEWREQ);
	wrk->task.func = http1_req;
	wrk->task.priv = req;
}
Exemplo n.º 2
0
http1_new_session(struct worker *wrk, void *arg)
{
	struct sess *sp;
	struct req *req;
	uintptr_t *u;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
	sp = req->sp;
	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);

	HTC_RxInit(req->htc, req->ws);
	SES_Reserve_proto_priv(sp, &u);
	http1_setstate(sp, H1NEWREQ);
	wrk->task.func = http1_req;
	wrk->task.priv = req;
}
Exemplo n.º 3
0
int
V1F_FetchRespHdr(struct busyobj *bo)
{

	struct http *hp;
	int i;
	double t;
	struct http_conn *htc;
	enum htc_status_e hs;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC);
	CHECK_OBJ_ORNULL(bo->req, REQ_MAGIC);

	htc = bo->htc;
	assert(*htc->rfd > 0);

	VSC_C_main->backend_req++;

	/* Receive response */

	HTC_RxInit(htc, bo->ws);
	CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
	CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC);

	t = VTIM_real() + htc->first_byte_timeout;
	hs = HTC_RxStuff(htc, HTTP1_Complete, NULL, NULL,
	    t, t + htc->between_bytes_timeout, cache_param->http_resp_size);
	if (hs != HTC_S_COMPLETE) {
		bo->acct.beresp_hdrbytes +=
		    htc->rxbuf_e - htc->rxbuf_b;
		switch (hs) {
		case HTC_S_JUNK:
			VSLb(bo->vsl, SLT_FetchError, "Received junk");
			htc->doclose = SC_RX_JUNK;
			break;
		case HTC_S_CLOSE:
			VSLb(bo->vsl, SLT_FetchError, "backend closed");
			htc->doclose = SC_RESP_CLOSE;
			break;
		case HTC_S_TIMEOUT:
			VSLb(bo->vsl, SLT_FetchError, "timeout");
			htc->doclose = SC_RX_TIMEOUT;
			break;
		case HTC_S_OVERFLOW:
			VSLb(bo->vsl, SLT_FetchError, "overflow");
			htc->doclose = SC_RX_OVERFLOW;
			break;
		default:
			VSLb(bo->vsl, SLT_FetchError, "HTC %s (%d)",
			     HTC_Status(hs), hs);
			htc->doclose = SC_RX_BAD;
			break;
		}
		return (htc->rxbuf_e == htc->rxbuf_b ? 1 : -1);
	}
	VTCP_set_read_timeout(*htc->rfd, htc->between_bytes_timeout);

	hp = bo->beresp;

	i = HTTP1_DissectResponse(htc, hp, bo->bereq);
	bo->acct.beresp_hdrbytes += htc->rxbuf_e - htc->rxbuf_b;
	if (i) {
		VSLb(bo->vsl, SLT_FetchError, "http format error");
		htc->doclose = SC_RX_JUNK;
		return (-1);
	}

	htc->doclose = http_DoConnection(hp);
	RFC2616_Response_Body(bo->wrk, bo);

	assert(bo->vfc->resp == bo->beresp);
	if (bo->htc->body_status != BS_NONE &&
	    bo->htc->body_status != BS_ERROR)
		if (V1F_Setup_Fetch(bo->vfc, bo->htc)) {
			VSLb(bo->vsl, SLT_FetchError, "overflow");
			htc->doclose = SC_RX_OVERFLOW;
			return (-1);
		}

	return (0);
}
Exemplo n.º 4
0
static void
HTTP1_Session(struct worker *wrk, struct req *req)
{
	enum htc_status_e hs;
	struct sess *sp;
	const char *st;
	int i;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	sp = req->sp;
	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);

	/*
	 * Whenever we come in from the acceptor or waiter, we need to set
	 * blocking mode.  It would be simpler to do this in the acceptor
	 * or waiter, but we'd rather do the syscall in the worker thread.
	 */
	if (http1_getstate(sp) == H1NEWREQ)
		VTCP_blocking(sp->fd);

	req->transport = &HTTP1_transport;

	while (1) {
		st = http1_getstate(sp);
		if (st == H1NEWREQ) {
			CHECK_OBJ_NOTNULL(req->transport, TRANSPORT_MAGIC);
			assert(isnan(req->t_prev));
			assert(isnan(req->t_req));
			AZ(req->vcl);
			AZ(req->esi_level);
			AN(req->htc->ws->r);

			hs = HTC_RxStuff(req->htc, HTTP1_Complete,
			    &req->t_first, &req->t_req,
			    sp->t_idle + cache_param->timeout_linger,
			    sp->t_idle + cache_param->timeout_idle,
			    NAN,
			    cache_param->http_req_size);
			AZ(req->htc->ws->r);
			if (hs < HTC_S_EMPTY) {
				req->acct.req_hdrbytes +=
				    req->htc->rxbuf_e - req->htc->rxbuf_b;
				Req_Cleanup(sp, wrk, req);
				Req_Release(req);
				switch (hs) {
				case HTC_S_CLOSE:
					SES_Delete(sp, SC_REM_CLOSE, NAN);
					return;
				case HTC_S_TIMEOUT:
					SES_Delete(sp, SC_RX_TIMEOUT, NAN);
					return;
				case HTC_S_OVERFLOW:
					SES_Delete(sp, SC_RX_OVERFLOW, NAN);
					return;
				case HTC_S_EOF:
					SES_Delete(sp, SC_REM_CLOSE, NAN);
					return;
				default:
					WRONG("htc_status (bad)");
				}
			}
			if (hs == HTC_S_IDLE) {
				wrk->stats->sess_herd++;
				Req_Cleanup(sp, wrk, req);
				Req_Release(req);
				SES_Wait(sp, &HTTP1_transport);
				return;
			}
			if (hs != HTC_S_COMPLETE)
				WRONG("htc_status (nonbad)");

			if (H2_prism_complete(req->htc) == HTC_S_COMPLETE) {
				if (!FEATURE(FEATURE_HTTP2)) {
					SES_Close(req->sp, SC_REQ_HTTP20);
					AZ(req->ws->r);
					AZ(wrk->aws->r);
					http1_setstate(sp, H1CLEANUP);
					continue;
				}
				http1_setstate(sp, NULL);
				H2_PU_Sess(wrk, sp, req);
				return;
			}

			i = http1_dissect(wrk, req);
			req->acct.req_hdrbytes +=
			    req->htc->rxbuf_e - req->htc->rxbuf_b;
			if (i) {
				assert(req->doclose > 0);
				SES_Close(req->sp, req->doclose);
				AZ(req->ws->r);
				AZ(wrk->aws->r);
				http1_setstate(sp, H1CLEANUP);
				continue;
			}
			if (http_HdrIs(req->http, H_Upgrade, "h2c")) {
				if (!FEATURE(FEATURE_HTTP2)) {
					VSLb(req->vsl, SLT_Debug,
					    "H2 upgrade attempt");
				} else if (req->htc->body_status != BS_NONE) {
					VSLb(req->vsl, SLT_Debug,
					    "H2 upgrade attempt has body");
				} else {
					http1_setstate(sp, NULL);
					req->err_code = 2;
					H2_OU_Sess(wrk, sp, req);
					return;
				}
			}
			req->req_step = R_STP_TRANSPORT;
			http1_setstate(sp, H1PROC);
		} else if (st == H1PROC) {
			req->task.func = http1_req;
			req->task.priv = req;
			wrk->stats->client_req++;
			CNT_Embark(wrk, req);
			if (req->req_step == R_STP_TRANSPORT)
				VCL_TaskEnter(req->vcl, req->privs);
			if (CNT_Request(req) == REQ_FSM_DISEMBARK)
				return;
			AZ(req->vcl0);
			req->task.func = NULL;
			req->task.priv = NULL;
			AZ(req->ws->r);
			AZ(wrk->aws->r);
			http1_setstate(sp, H1CLEANUP);
		} else if (st == H1CLEANUP) {

			AZ(wrk->aws->r);
			AZ(req->ws->r);

			if (sp->fd >= 0 && req->doclose != SC_NULL)
				SES_Close(sp, req->doclose);

			if (sp->fd < 0) {
				wrk->stats->sess_closed++;
				Req_Cleanup(sp, wrk, req);
				Req_Release(req);
				SES_Delete(sp, SC_NULL, NAN);
				return;
			}

			Req_Cleanup(sp, wrk, req);
			HTC_RxInit(req->htc, req->ws);
			if (req->htc->rxbuf_e != req->htc->rxbuf_b)
				wrk->stats->sess_readahead++;
			http1_setstate(sp, H1NEWREQ);
		} else {
			WRONG("Wrong H1 session state");
		}
	}
}
Exemplo n.º 5
0
void
HTTP1_Session(struct worker *wrk, struct req *req)
{
	enum htc_status_e hs;
	struct sess *sp;
	const char *st;
	int i;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	sp = req->sp;
	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);

	/*
	 * Whenever we come in from the acceptor or waiter, we need to set
	 * blocking mode.  It would be simpler to do this in the acceptor
	 * or waiter, but we'd rather do the syscall in the worker thread.
	 * On systems which return errors for ioctl, we close early
	 */
	if (http1_getstate(sp) == H1NEWREQ && VTCP_blocking(sp->fd)) {
		if (errno == ECONNRESET)
			SES_Close(sp, SC_REM_CLOSE);
		else
			SES_Close(sp, SC_TX_ERROR);
		AN(Req_Cleanup(sp, wrk, req));
		return;
	}

	while (1) {
		st = http1_getstate(sp);
		if (st == H1NEWREQ) {
			assert(isnan(req->t_prev));
			assert(isnan(req->t_req));
			AZ(req->vcl);
			AZ(req->esi_level);

			hs = HTC_RxStuff(req->htc, HTTP1_Complete,
			    &req->t_first, &req->t_req,
			    sp->t_idle + cache_param->timeout_linger,
			    sp->t_idle + cache_param->timeout_idle,
			    cache_param->http_req_size);
			XXXAZ(req->htc->ws->r);
			if (hs < HTC_S_EMPTY) {
				req->acct.req_hdrbytes +=
				    req->htc->rxbuf_e - req->htc->rxbuf_b;
				CNT_AcctLogCharge(wrk->stats, req);
				Req_Release(req);
				switch(hs) {
				case HTC_S_CLOSE:
					SES_Delete(sp, SC_REM_CLOSE, NAN);
					return;
				case HTC_S_TIMEOUT:
					SES_Delete(sp, SC_RX_TIMEOUT, NAN);
					return;
				case HTC_S_OVERFLOW:
					SES_Delete(sp, SC_RX_OVERFLOW, NAN);
					return;
				case HTC_S_EOF:
					SES_Delete(sp, SC_REM_CLOSE, NAN);
					return;
				default:
					WRONG("htc_status (bad)");
				}
			}
			if (hs == HTC_S_IDLE) {
				wrk->stats->sess_herd++;
				Req_Release(req);
				SES_Wait(sp, &HTTP1_transport);
				return;
			}
			if (hs != HTC_S_COMPLETE)
				WRONG("htc_status (nonbad)");

			i = http1_dissect(wrk, req);
			req->acct.req_hdrbytes +=
			    req->htc->rxbuf_e - req->htc->rxbuf_b;
			if (i) {
				SES_Close(req->sp, req->doclose);
				http1_setstate(sp, H1CLEANUP);
			} else {
				req->req_step = R_STP_RECV;
				http1_setstate(sp, H1PROC);
			}
		} else if (st == H1BUSY) {
			/*
			 * Return from waitinglist.
			 * Check to see if the remote has left.
			 */
			if (VTCP_check_hup(sp->fd)) {
				AN(req->hash_objhead);
				(void)HSH_DerefObjHead(wrk, &req->hash_objhead);
				AZ(req->hash_objhead);
				SES_Close(sp, SC_REM_CLOSE);
				AN(Req_Cleanup(sp, wrk, req));
				return;
			}
			http1_setstate(sp, H1PROC);
		} else if (st == H1PROC) {
			req->transport = &HTTP1_transport;
			if (CNT_Request(wrk, req) == REQ_FSM_DISEMBARK) {
				req->task.func = http1_req;
				req->task.priv = req;
				http1_setstate(sp, H1BUSY);
				return;
			}
			req->transport = NULL;
			http1_setstate(sp, H1CLEANUP);
		} else if (st == H1CLEANUP) {
			if (Req_Cleanup(sp, wrk, req))
				return;
			HTC_RxInit(req->htc, req->ws);
			if (req->htc->rxbuf_e != req->htc->rxbuf_b)
				wrk->stats->sess_readahead++;
			http1_setstate(sp, H1NEWREQ);
		} else {
			WRONG("Wrong H1 session state");
		}
	}
}