Exemplo n.º 1
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.º 2
0
int
V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, struct req *req)
{
	struct vbc *vc;
	struct http *hp;
	enum htc_status_e hs;
	int retry = -1;
	int i, first;
	struct http_conn *htc;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_ORNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	htc = &bo->htc;

	AN(bo->director);

	hp = bo->bereq;

	bo->vbc = VDI_GetFd(NULL, bo);
	if (bo->vbc == NULL) {
		VSLb(bo->vsl, SLT_FetchError, "no backend connection");
		return (-1);
	}
	vc = bo->vbc;
	if (vc->recycled)
		retry = 1;

	/*
	 * 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))
		VDI_AddHostHeader(bo->bereq, vc);

	(void)VTCP_blocking(vc->fd);	/* XXX: we should timeout instead */
	WRW_Reserve(wrk, &vc->fd, bo->vsl, bo->t_fetch);
	bo->t_send = VTIM_mono();
	(void)HTTP1_Write(wrk, hp, 0);	/* XXX: stats ? */

	/* Deal with any message-body the request might (still) have */
	i = 0;

	if (req != NULL) {
		i = HTTP1_IterateReqBody(req, vbf_iter_req_body, wrk);
		if (req->req_body_status == REQ_BODY_DONE)
			retry = -1;
		if (req->req_body_status == REQ_BODY_FAIL) {
			VSLb(bo->vsl, SLT_FetchError,
			    "req.body read error: %d (%s)",
			    errno, strerror(errno));
			req->doclose = SC_RX_BODY;
			retry = -1;
		}
	}

	if (WRW_FlushRelease(wrk) || i != 0) {
		VSLb(bo->vsl, SLT_FetchError, "backend write error: %d (%s)",
		    errno, strerror(errno));
		VDI_CloseFd(&bo->vbc);
		/* XXX: other cleanup ? */
		return (retry);
	}

	VSC_C_main->backend_req++;
	bo->t_sent = VTIM_mono();

	/* Receive response */

	HTTP1_Init(htc, bo->ws, vc->fd, vc->vsl,
	    cache_param->http_resp_size,
	    cache_param->http_resp_hdr_len);

	VTCP_set_read_timeout(vc->fd, vc->first_byte_timeout);

	first = 1;
	do {
		hs = HTTP1_Rx(htc);
		if (hs == HTTP1_OVERFLOW) {
			VSLb(bo->vsl, SLT_FetchError,
			    "http %sread error: overflow",
			    first ? "first " : "");
			VDI_CloseFd(&bo->vbc);
			/* XXX: other cleanup ? */
			return (-1);
		}
		if (hs == HTTP1_ERROR_EOF) {
			VSLb(bo->vsl, SLT_FetchError, "http %sread error: EOF",
			    first ? "first " : "");
			VDI_CloseFd(&bo->vbc);
			/* XXX: other cleanup ? */
			return (retry);
		}
		if (first) {
			retry = -1;
			first = 0;
			VTCP_set_read_timeout(vc->fd,
			    vc->between_bytes_timeout);
		}
	} while (hs != HTTP1_COMPLETE);
	bo->t_hdr = VTIM_mono();

	hp = bo->beresp;

	if (HTTP1_DissectResponse(hp, htc)) {
		VSLb(bo->vsl, SLT_FetchError, "http format error");
		VDI_CloseFd(&bo->vbc);
		/* XXX: other cleanup ? */
		return (-1);
	}
	return (0);
}
int
V1F_FetchRespHdr(struct busyobj *bo)
{

	struct http *hp;
	enum htc_status_e hs;
	int first;
	struct http_conn *htc;

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

	htc = bo->htc;

	VSC_C_main->backend_req++;

	/* Receive response */

	SES_RxInit(htc, bo->ws, cache_param->http_resp_size,
	    cache_param->http_resp_hdr_len);
	CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
	CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC);

	VTCP_set_read_timeout(htc->fd, htc->first_byte_timeout);

	first = 1;
	do {
		hs = SES_Rx(htc, 0);
		if (hs == HTC_S_MORE)
			hs = HTTP1_Complete(htc);
		if (hs == HTC_S_OVERFLOW) {
			WS_ReleaseP(htc->ws, htc->rxbuf_b);
			bo->acct.beresp_hdrbytes +=
			    htc->rxbuf_e - htc->rxbuf_b;
			VSLb(bo->vsl, SLT_FetchError,
			    "http %sread error: overflow",
			    first ? "first " : "");
			htc->doclose = SC_RX_OVERFLOW;
			return (-1);
		}
		if (hs == HTC_S_EOF) {
			WS_ReleaseP(htc->ws, htc->rxbuf_b);
			bo->acct.beresp_hdrbytes +=
			    htc->rxbuf_e - htc->rxbuf_b;
			VSLb(bo->vsl, SLT_FetchError, "http %sread error: EOF",
			    first ? "first " : "");
			htc->doclose = SC_RX_TIMEOUT;
			return (first ? 1 : -1);
		}
		if (first) {
			first = 0;
			VTCP_set_read_timeout(htc->fd,
			    htc->between_bytes_timeout);
		}
	} while (hs != HTC_S_COMPLETE);
	bo->acct.beresp_hdrbytes += htc->rxbuf_e - htc->rxbuf_b;

	hp = bo->beresp;

	if (HTTP1_DissectResponse(hp, htc)) {
		VSLb(bo->vsl, SLT_FetchError, "http format error");
		htc->doclose = SC_RX_JUNK;
		return (-1);
	}

	htc->doclose = http_DoConnection(hp);

	return (0);
}
Exemplo n.º 4
0
int
FetchHdr(struct sess *sp, int need_host_hdr)
{
	struct vbc *vc;
	struct worker *wrk;
	struct http *hp;
	int retry = -1;
	int i;
	struct http_conn *htc;

	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
	CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
	wrk = sp->wrk;
	CHECK_OBJ_NOTNULL(wrk->busyobj, BUSYOBJ_MAGIC);
	htc = &wrk->busyobj->htc;

	AN(sp->req->director);
	AZ(sp->req->obj);

	if (sp->req->objcore != NULL) {		/* pass has no objcore */
		CHECK_OBJ_NOTNULL(sp->req->objcore, OBJCORE_MAGIC);
		AN(sp->req->objcore->flags & OC_F_BUSY);
	}

	hp = wrk->busyobj->bereq;

	sp->wrk->busyobj->vbc = VDI_GetFd(NULL, sp);
	if (sp->wrk->busyobj->vbc == NULL) {
		WSP(sp, SLT_FetchError, "no backend connection");
		return (-1);
	}
	vc = sp->wrk->busyobj->vbc;
	if (vc->recycled)
		retry = 1;

	/*
	 * 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 (need_host_hdr)
		VDI_AddHostHeader(sp->wrk, vc);

	(void)VTCP_blocking(vc->fd);	/* XXX: we should timeout instead */
	WRW_Reserve(wrk, &vc->fd);
	(void)http_Write(wrk, vc->vsl_id, hp, 0);	/* XXX: stats ? */

	/* Deal with any message-body the request might have */
	i = FetchReqBody(sp);
	if (WRW_FlushRelease(wrk) || i > 0) {
		WSP(sp, SLT_FetchError, "backend write error: %d (%s)",
		    errno, strerror(errno));
		VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc);
		/* XXX: other cleanup ? */
		return (retry);
	}

	/* Checkpoint the vsl.here */
	WSL_Flush(wrk, 0);

	/* XXX is this the right place? */
	VSC_C_main->backend_req++;

	/* Receive response */

	HTC_Init(htc, wrk->ws, vc->fd, vc->vsl_id,
	    cache_param->http_resp_size,
	    cache_param->http_resp_hdr_len);

	VTCP_set_read_timeout(vc->fd, vc->first_byte_timeout);

	i = HTC_Rx(htc);

	if (i < 0) {
		WSP(sp, SLT_FetchError, "http first read error: %d %d (%s)",
		    i, errno, strerror(errno));
		VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc);
		/* XXX: other cleanup ? */
		/* Retryable if we never received anything */
		return (i == -1 ? retry : -1);
	}

	VTCP_set_read_timeout(vc->fd, vc->between_bytes_timeout);

	while (i == 0) {
		i = HTC_Rx(htc);
		if (i < 0) {
			WSP(sp, SLT_FetchError,
			    "http first read error: %d %d (%s)",
			    i, errno, strerror(errno));
			VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc);
			/* XXX: other cleanup ? */
			return (-1);
		}
	}

	hp = wrk->busyobj->beresp;

	if (http_DissectResponse(wrk, htc, hp)) {
		WSP(sp, SLT_FetchError, "http format error");
		VDI_CloseFd(sp->wrk, &sp->wrk->busyobj->vbc);
		/* XXX: other cleanup ? */
		return (-1);
	}
	return (0);
}
Exemplo n.º 5
0
int
V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, const char *def_host)
{
	struct http *hp;
	enum http1_status_e hs;
	int retry = 1;
	int j, first;
	ssize_t i;
	struct http_conn *htc;
	int do_chunked = 0;

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

	htc = bo->htc;
	hp = bo->bereq;

	/*
	 * 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) && def_host != NULL)
		http_PrintfHeader(hp, "Host: %s", def_host);

	if (bo->req != NULL &&
	    bo->req->req_body_status == REQ_BODY_WITHOUT_LEN) {
		http_PrintfHeader(hp, "Transfer-Encoding: chunked");
		do_chunked = 1;
	}

	(void)VTCP_blocking(htc->fd);	/* XXX: we should timeout instead */
	V1L_Reserve(wrk, wrk->aws, &htc->fd, bo->vsl, bo->t_prev);
	bo->acct.bereq_hdrbytes = HTTP1_Write(wrk, hp, HTTP1_Req);

	/* Deal with any message-body the request might (still) have */
	i = 0;

	if (bo->req != NULL) {
		if (do_chunked)
			V1L_Chunked(wrk);
		i = VRB_Iterate(bo->req, vbf_iter_req_body, bo);

		if (bo->req->req_body_status == REQ_BODY_TAKEN) {
			retry = -1;
		} else if (bo->req->req_body_status == REQ_BODY_FAIL) {
			VSLb(bo->vsl, SLT_FetchError,
			    "req.body read error: %d (%s)",
			    errno, strerror(errno));
			bo->req->doclose = SC_RX_BODY;
			retry = -1;
		}
		if (do_chunked)
			V1L_EndChunk(wrk);
	}

	j = V1L_FlushRelease(wrk);
	if (j != 0 || i < 0) {
		VSLb(bo->vsl, SLT_FetchError, "backend write error: %d (%s)",
		    errno, strerror(errno));
		VSLb_ts_busyobj(bo, "Bereq", W_TIM_real(wrk));
		bo->doclose = SC_TX_ERROR;
		return (retry);
	}
	VSLb_ts_busyobj(bo, "Bereq", W_TIM_real(wrk));

	VSC_C_main->backend_req++;

	/* Receive response */

	HTTP1_RxInit(htc, bo->ws, cache_param->http_resp_size,
	    cache_param->http_resp_hdr_len);
	CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
	CHECK_OBJ_NOTNULL(bo->htc, HTTP_CONN_MAGIC);

	VTCP_set_read_timeout(htc->fd, htc->first_byte_timeout);

	first = 1;
	do {
		hs = HTTP1_Rx(htc);
		if (hs == HTTP1_OVERFLOW) {
			bo->acct.beresp_hdrbytes +=
			    htc->rxbuf_e - htc->rxbuf_b;
			VSLb(bo->vsl, SLT_FetchError,
			    "http %sread error: overflow",
			    first ? "first " : "");
			bo->doclose = SC_RX_OVERFLOW;
			return (-1);
		}
		if (hs == HTTP1_ERROR_EOF) {
			bo->acct.beresp_hdrbytes +=
			    htc->rxbuf_e - htc->rxbuf_b;
			VSLb(bo->vsl, SLT_FetchError, "http %sread error: EOF",
			    first ? "first " : "");
			bo->doclose = SC_RX_TIMEOUT;
			return (retry);
		}
		if (first) {
			retry = -1;
			first = 0;
			VTCP_set_read_timeout(htc->fd,
			    htc->between_bytes_timeout);
		}
	} while (hs != HTTP1_COMPLETE);
	bo->acct.beresp_hdrbytes += htc->rxbuf_e - htc->rxbuf_b;

	hp = bo->beresp;

	if (HTTP1_DissectResponse(hp, htc)) {
		VSLb(bo->vsl, SLT_FetchError, "http format error");
		bo->doclose = SC_RX_JUNK;
		return (-1);
	}

	bo->doclose = http_DoConnection(hp);

	return (0);
}