예제 #1
0
static void
make_it_503(struct busyobj *bo)
{

	HTTP_Setup(bo->beresp, bo->ws, bo->vsl, HTTP_Beresp);
	bo->err_code = 503;
	http_SetH(bo->beresp, HTTP_HDR_PROTO, "HTTP/1.1");
	http_SetResp(bo->beresp,
	    "HTTP/1.1", 503, "Backend fetch failed");
	http_SetHeader(bo->beresp, "Content-Length: 0");
	http_SetHeader(bo->beresp, "Connection: close");
}
예제 #2
0
static enum fetch_step
vbf_stp_fetchhdr(struct worker *wrk, struct busyobj *bo)
{
	int i;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	xxxassert (wrk->handling == VCL_RET_FETCH);

	HTTP_Setup(bo->beresp, bo->ws, bo->vsl, HTTP_Beresp);

	if (!bo->do_pass)
		vbf_release_req(bo); /* XXX: retry ?? */

	assert(bo->state == BOS_INVALID);

	i = V1F_fetch_hdr(wrk, bo, bo->req);
	/*
	 * If we recycle a backend connection, there is a finite chance
	 * that the backend closed it before we get a request to it.
	 * Do a single retry in that case.
	 */
	if (i == 1) {
		VSC_C_main->backend_retry++;
		i = V1F_fetch_hdr(wrk, bo, bo->req);
	}

	if (bo->do_pass)
		vbf_release_req(bo); /* XXX : retry ?? */

	AZ(bo->req);

	if (i) {
		AZ(bo->vbc);
		bo->err_code = 503;
		http_SetH(bo->beresp, HTTP_HDR_PROTO, "HTTP/1.1");
		http_SetResp(bo->beresp,
		    "HTTP/1.1", 503, "Backend fetch failed");
		http_SetHeader(bo->beresp, "Content-Length: 0");
		http_SetHeader(bo->beresp, "Connection: close");
	} else {
		AN(bo->vbc);
	}

	/*
	 * These two headers can be spread over multiple actual headers
	 * and we rely on their content outside of VCL, so collect them
	 * into one line here.
	 */
	http_CollectHdr(bo->beresp, H_Cache_Control);
	http_CollectHdr(bo->beresp, H_Vary);

	/*
	 * Figure out how the fetch is supposed to happen, before the
	 * headers are adultered by VCL
	 * NB: Also sets other wrk variables
	 */
	bo->htc.body_status = RFC2616_Body(bo, &wrk->stats);

	bo->err_code = http_GetStatus(bo->beresp);

	/*
	 * What does RFC2616 think about TTL ?
	 */
	EXP_Clr(&bo->exp);
	bo->exp.entered = W_TIM_real(wrk);
	RFC2616_Ttl(bo);

	/* pass from vclrecv{} has negative TTL */
	if (bo->fetch_objcore->objhead == NULL)
		bo->exp.ttl = -1.;

	AZ(bo->do_esi);

	VCL_backend_response_method(bo->vcl, wrk, NULL, bo, bo->beresp->ws);

	if (bo->do_esi)
		bo->do_stream = 0;

	if (wrk->handling == VCL_RET_DELIVER)
		return (F_STP_FETCH);
	if (wrk->handling == VCL_RET_RETRY) {
		assert(bo->state == BOS_INVALID);
		bo->retries++;
		if (bo->retries <= cache_param->max_retries) {
			VDI_CloseFd(&bo->vbc);
			return (F_STP_STARTFETCH);
		}
		// XXX: wrk->handling = VCL_RET_SYNTH;
	}

	return (F_STP_NOTYET);
}
예제 #3
0
static enum fetch_step
vbf_stp_error(struct worker *wrk, struct busyobj *bo)
{
	struct storage *st;
	ssize_t l;
	double now;
	char time_str[VTIM_FORMAT_SIZE];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);

	now = W_TIM_real(wrk);
	VSLb_ts_busyobj(bo, "Error", now);

	AN(bo->fetch_objcore->flags & OC_F_BUSY);

	AZ(bo->synth_body);
	bo->synth_body = VSB_new_auto();
	AN(bo->synth_body);

	// XXX: reset all beresp flags ?

	HTTP_Setup(bo->beresp, bo->ws, bo->vsl, SLT_BerespMethod);
	http_SetResp(bo->beresp, "HTTP/1.1", 503, "Backend fetch failed");
	VTIM_format(now, time_str);
	http_PrintfHeader(bo->beresp, "Date: %s", time_str);
	http_SetHeader(bo->beresp, "Server: Varnish");

	bo->exp.t_origin = bo->t_prev;
	bo->exp.ttl = 0;
	bo->exp.grace = 0;
	bo->exp.keep = 0;

	VCL_backend_error_method(bo->vcl, wrk, NULL, bo, bo->bereq->ws);

	AZ(VSB_finish(bo->synth_body));

	if (wrk->handling == VCL_RET_RETRY) {
		VSB_delete(bo->synth_body);
		bo->synth_body = NULL;
		if (bo->retries++ < cache_param->max_retries)
			return (F_STP_RETRY);
		bo->synth_body = NULL;
		return (F_STP_FAIL);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	if (vbf_beresp2obj(bo))
		return (F_STP_FAIL);

	l = VSB_len(bo->synth_body);
	if (l > 0) {
		st = VFP_GetStorage(bo, l);
		if (st != NULL) {
			if (st->space < l) {
				VSLb(bo->vsl, SLT_Error,
				    "No space for %zd bytes of synth body", l);
			} else {
				memcpy(st->ptr, VSB_data(bo->synth_body), l);
				VBO_extend(bo, l);
			}
		}
	}
	VSB_delete(bo->synth_body);
	bo->synth_body = NULL;

	HSH_Unbusy(&wrk->stats, bo->fetch_objcore);
	VBO_setstate(bo, BOS_FINISHED);
	return (F_STP_DONE);
}
예제 #4
0
static void
v1d_dorange(struct req *req, const char *r)
{
	ssize_t low, high, has_low;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	assert(req->obj->response == 200);
	if (strncmp(r, "bytes=", 6))
		return;
	r += 6;

	/* The low end of range */
	has_low = low = 0;
	if (!vct_isdigit(*r) && *r != '-')
		return;
	while (vct_isdigit(*r)) {
		has_low = 1;
		low *= 10;
		low += *r - '0';
		r++;
	}

	if (low >= req->obj->len)
		return;

	if (*r != '-')
		return;
	r++;

	/* The high end of range */
	if (vct_isdigit(*r)) {
		high = 0;
		while (vct_isdigit(*r)) {
			high *= 10;
			high += *r - '0';
			r++;
		}
		if (!has_low) {
			low = req->obj->len - high;
			if (low < 0)
				low = 0;
			high = req->obj->len - 1;
		}
	} else
		high = req->obj->len - 1;
	if (*r != '\0')
		return;

	if (high >= req->obj->len)
		high = req->obj->len - 1;

	if (low > high)
		return;

	http_PrintfHeader(req->resp, "Content-Range: bytes %jd-%jd/%jd",
	    (intmax_t)low, (intmax_t)high, (intmax_t)req->obj->len);
	http_Unset(req->resp, H_Content_Length);
	if (req->res_mode & RES_LEN)
		http_PrintfHeader(req->resp, "Content-Length: %jd",
		    (intmax_t)(1 + high - low));
	http_SetResp(req->resp, "HTTP/1.1", 206, "Partial Content");

	req->range_off = 0;
	req->range_low = low;
	req->range_high = high + 1;
	VDP_push(req, v1d_range_bytes);
}
예제 #5
0
static enum req_fsm_nxt
cnt_deliver(struct worker *wrk, struct req *req)
{
	char time_str[30];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore->objhead, OBJHEAD_MAGIC);
	CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC);
	assert(WRW_IsReleased(wrk));

	assert(req->obj->objcore->refcnt > 0);

	req->t_resp = W_TIM_real(wrk);
	if (!(req->obj->objcore->flags & OC_F_PRIVATE)) {
		if ((req->t_resp - req->obj->objcore->last_lru) >
		    cache_param->lru_timeout && EXP_Touch(req->obj->objcore))
			req->obj->objcore->last_lru = req->t_resp;
		if (!cache_param->obj_readonly)
			req->obj->last_use = req->t_resp; /* XXX: locking ? */
	}

	HTTP_Setup(req->resp, req->ws, req->vsl, HTTP_Resp);

	http_ClrHeader(req->resp);
	http_FilterResp(req->obj->http, req->resp, 0);

	http_Unset(req->resp, H_Date);
	VTIM_format(req->t_resp, time_str);
	http_PrintfHeader(req->resp, "Date: %s", time_str);

	if (req->wrk->stats.cache_hit)
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u %u", req->vsl->wid & VSL_IDENTMASK,
		    req->obj->vxid & VSL_IDENTMASK);
	else
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK);

	http_PrintfHeader(req->resp, "Age: %.0f",
	    req->obj->exp.age + req->t_resp - req->obj->exp.entered);

	http_SetHeader(req->resp, "Via: 1.1 varnish");

	VCL_deliver_method(req->vcl, wrk, req, NULL, req->http->ws);

	/* Stop the insanity before it turns "Hotel California" on us */
	if (req->restarts >= cache_param->max_restarts)
		wrk->handling = VCL_RET_DELIVER;

	if (wrk->handling == VCL_RET_RESTART) {
		(void)HSH_DerefObj(&wrk->stats, &req->obj);
		AZ(req->obj);
		http_Teardown(req->resp);
		req->req_step = R_STP_RESTART;
		return (REQ_FSM_MORE);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	if (!(req->obj->objcore->flags & OC_F_PASS)
	    && req->obj->response == 200
	    && req->http->conds && RFC2616_Do_Cond(req)) {
		req->wantbody = 0;
		http_SetResp(req->resp, "HTTP/1.1", 304, "Not Modified");
		// http_Unset(req->resp, H_Content_Length);
	}

	V1D_Deliver(req);

	/* No point in saving the body if it is hit-for-pass */
	if (req->obj->objcore->flags & OC_F_PASS)
		STV_Freestore(req->obj);

	assert(WRW_IsReleased(wrk));
VSLb(req->vsl, SLT_Debug, "XXX REF %d", req->obj->objcore->refcnt);
	(void)HSH_DerefObj(&wrk->stats, &req->obj);
	http_Teardown(req->resp);
	return (REQ_FSM_DONE);
}
예제 #6
0
static enum req_fsm_nxt
cnt_deliver(struct worker *wrk, struct req *req)
{
	char time_str[30];
	double now;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore, OBJCORE_MAGIC);
	CHECK_OBJ_NOTNULL(req->obj->objcore->objhead, OBJHEAD_MAGIC);
	CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC);
	assert(WRW_IsReleased(wrk));

	assert(req->obj->objcore->refcnt > 0);

	now = W_TIM_real(wrk);
	VSLb_ts_req(req, "Process", now);
	if (req->obj->objcore->exp_flags & OC_EF_EXP)
		EXP_Touch(req->obj->objcore, now);

	HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);

	http_ClrHeader(req->resp);
	http_FilterResp(req->obj->http, req->resp, 0);

	http_Unset(req->resp, H_Date);
	VTIM_format(now, time_str);
	http_PrintfHeader(req->resp, "Date: %s", time_str);

	if (req->wrk->stats.cache_hit)
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u %u", req->vsl->wid & VSL_IDENTMASK,
		    req->obj->vxid & VSL_IDENTMASK);
	else
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u", req->vsl->wid & VSL_IDENTMASK);

	http_PrintfHeader(req->resp, "Age: %.0f",
	    now - req->obj->exp.t_origin);

	http_SetHeader(req->resp, "Via: 1.1 varnish (v4)");

	if (cache_param->http_gzip_support && req->obj->gziped &&
	    !RFC2616_Req_Gzip(req->http))
		RFC2616_Weaken_Etag(req->resp);

	VCL_deliver_method(req->vcl, wrk, req, NULL, req->http->ws);

	/* Stop the insanity before it turns "Hotel California" on us */
	if (req->restarts >= cache_param->max_restarts)
		wrk->handling = VCL_RET_DELIVER;

	if (wrk->handling == VCL_RET_RESTART) {
		(void)HSH_DerefObj(&wrk->stats, &req->obj);
		AZ(req->obj);
		http_Teardown(req->resp);
		req->req_step = R_STP_RESTART;
		return (REQ_FSM_MORE);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	if (!(req->obj->objcore->flags & OC_F_PASS)
	    && req->esi_level == 0
	    && http_GetStatus(req->obj->http) == 200
	    && req->http->conds && RFC2616_Do_Cond(req))
		http_SetResp(req->resp, "HTTP/1.1", 304, "Not Modified");

	V1D_Deliver(req);
	VSLb_ts_req(req, "Resp", W_TIM_real(wrk));

	if (http_HdrIs(req->resp, H_Connection, "close"))
		req->doclose = SC_RESP_CLOSE;

	if (req->obj->objcore->flags & OC_F_PASS) {
		/*
		 * No point in saving the body if it is hit-for-pass,
		 * but we can't yank it until the fetching thread has
		 * finished/abandoned also.
		 */
		while (req->obj->objcore->busyobj != NULL)
			(void)usleep(100000);
		STV_Freestore(req->obj);
	}

	assert(WRW_IsReleased(wrk));
VSLb(req->vsl, SLT_Debug, "XXX REF %d", req->obj->objcore->refcnt);
	(void)HSH_DerefObj(&wrk->stats, &req->obj);
	http_Teardown(req->resp);
	return (REQ_FSM_DONE);
}