Пример #1
0
static int
vbf_beresp2obj(struct busyobj *bo)
{
	unsigned l, l2;
	char *b;
	uint8_t *bp;
	struct vsb *vary = NULL;
	int varyl = 0;

	l = 0;

	/* Create Vary instructions */
	if (!(bo->fetch_objcore->flags & OC_F_PRIVATE)) {
		varyl = VRY_Create(bo, &vary);
		if (varyl > 0) {
			AN(vary);
			assert(varyl == VSB_len(vary));
			l += PRNDUP((intptr_t)varyl);
		} else if (varyl < 0) {
			/*
			 * Vary parse error
			 * Complain about it, and make this a pass.
			 */
			VSLb(bo->vsl, SLT_Error,
			    "Illegal 'Vary' header from backend, "
			    "making this a pass.");
			bo->uncacheable = 1;
			AZ(vary);
		} else
			/* No vary */
			AZ(vary);
	}

	l2 = http_EstimateWS(bo->beresp,
	    bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS);
	l += l2;

	if (bo->uncacheable)
		bo->fetch_objcore->flags |= OC_F_PASS;

	if (!vbf_allocobj(bo, l))
		return (-1);

	if (vary != NULL) {
		b = ObjSetattr(bo->wrk, bo->fetch_objcore, OA_VARY, varyl,
		    VSB_data(vary));
		VSB_delete(vary);
	}

	AZ(ObjSetU32(bo->wrk, bo->fetch_objcore, OA_VXID, VXID(bo->vsl->wid)));

	/* for HTTP_Encode() VSLH call */
	bo->beresp->logtag = SLT_ObjMethod;

	/* Filter into object */
	bp = ObjSetattr(bo->wrk, bo->fetch_objcore, OA_HEADERS, l2, NULL);
	AN(bp);
	HTTP_Encode(bo->beresp, bp, l2,
	    bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS);

	if (http_GetHdr(bo->beresp, H_Last_Modified, &b))
		AZ(ObjSetDouble(bo->wrk, bo->fetch_objcore, OA_LASTMODIFIED,
		    VTIM_parse(b)));
	else
		AZ(ObjSetDouble(bo->wrk, bo->fetch_objcore, OA_LASTMODIFIED,
		    floor(bo->fetch_objcore->exp.t_origin)));

	return (0);
}
Пример #2
0
static enum fetch_step
vbf_stp_fetch(struct worker *wrk, struct busyobj *bo)
{
	struct http *hp, *hp2;
	char *b;
	uint16_t nhttp;
	unsigned l;
	struct vsb *vary = NULL;
	int varyl = 0;
	struct object *obj;

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

	assert(wrk->handling == VCL_RET_DELIVER);

	/*
	 * The VCL variables beresp.do_g[un]zip tells us how we want the
	 * object processed before it is stored.
	 *
	 * The backend Content-Encoding header tells us what we are going
	 * to receive, which we classify in the following three classes:
	 *
	 *	"Content-Encoding: gzip"	--> object is gzip'ed.
	 *	no Content-Encoding		--> object is not gzip'ed.
	 *	anything else			--> do nothing wrt gzip
	 *
	 * XXX: BS_NONE/cl==0 should avoid gzip/gunzip
	 */

	/* We do nothing unless the param is set */
	if (!cache_param->http_gzip_support)
		bo->do_gzip = bo->do_gunzip = 0;

	bo->is_gzip = http_HdrIs(bo->beresp, H_Content_Encoding, "gzip");

	bo->is_gunzip = !http_GetHdr(bo->beresp, H_Content_Encoding, NULL);

	/* It can't be both */
	assert(bo->is_gzip == 0 || bo->is_gunzip == 0);

	/* We won't gunzip unless it is gzip'ed */
	if (bo->do_gunzip && !bo->is_gzip)
		bo->do_gunzip = 0;

	/* If we do gunzip, remove the C-E header */
	if (bo->do_gunzip)
		http_Unset(bo->beresp, H_Content_Encoding);

	/* We wont gzip unless it is ungziped */
	if (bo->do_gzip && !bo->is_gunzip)
		bo->do_gzip = 0;

	/* If we do gzip, add the C-E header */
	if (bo->do_gzip)
		http_SetHeader(bo->beresp, "Content-Encoding: gzip");

	/* But we can't do both at the same time */
	assert(bo->do_gzip == 0 || bo->do_gunzip == 0);

	/* ESI takes precedence and handles gzip/gunzip itself */
	if (bo->do_esi)
		bo->vfp = &vfp_esi;
	else if (bo->do_gunzip)
		bo->vfp = &vfp_gunzip;
	else if (bo->do_gzip)
		bo->vfp = &vfp_gzip;
	else if (bo->is_gzip)
		bo->vfp = &vfp_testgzip;

	if (bo->fetch_objcore->flags & OC_F_PRIVATE)
		AN(bo->uncacheable);

	/* No reason to try streaming a non-existing body */
	if (bo->htc.body_status == BS_NONE)
		bo->do_stream = 0;

	l = 0;

	/* Create Vary instructions */
	if (!(bo->fetch_objcore->flags & OC_F_PRIVATE)) {
		varyl = VRY_Create(bo, &vary);
		if (varyl > 0) {
			AN(vary);
			assert(varyl == VSB_len(vary));
			l += varyl;
		} else if (varyl < 0) {
			/*
			 * Vary parse error
			 * Complain about it, and make this a pass.
			 */
			VSLb(bo->vsl, SLT_Error,
			    "Illegal 'Vary' header from backend, "
			    "making this a pass.");
			bo->uncacheable = 1;
			AZ(vary);
		} else
			/* No vary */
			AZ(vary);
	}

	l += http_EstimateWS(bo->beresp,
	    bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp);

	if (bo->uncacheable)
		bo->fetch_objcore->flags |= OC_F_PASS;

	if (bo->exp.ttl < cache_param->shortlived || bo->uncacheable == 1)
		bo->storage_hint = TRANSIENT_STORAGE;

	AZ(bo->stats);
	bo->stats = &wrk->stats;
	AN(bo->fetch_objcore);
	obj = STV_NewObject(bo, bo->storage_hint, l, nhttp);
	if (obj == NULL) {
		/*
		 * Try to salvage the transaction by allocating a
		 * shortlived object on Transient storage.
		 */
		if (bo->exp.ttl > cache_param->shortlived)
			bo->exp.ttl = cache_param->shortlived;
		bo->exp.grace = 0.0;
		bo->exp.keep = 0.0;
		obj = STV_NewObject(bo, TRANSIENT_STORAGE, l, nhttp);
	}
	bo->stats = NULL;
	if (obj == NULL) {
		(void)VFP_Error(bo, "Could not get storage");
		VDI_CloseFd(&bo->vbc);
		return (F_STP_DONE);
	}
	CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);

	bo->storage_hint = NULL;

	AZ(bo->fetch_obj);
	bo->fetch_obj = obj;

	if (bo->do_gzip || (bo->is_gzip && !bo->do_gunzip))
		obj->gziped = 1;

	if (vary != NULL) {
		obj->vary = (void *)WS_Copy(obj->http->ws,
		    VSB_data(vary), varyl);
		AN(obj->vary);
		VRY_Validate(obj->vary);
		VSB_delete(vary);
	}

	obj->vxid = bo->vsl->wid;
	obj->response = bo->err_code;
	WS_Assert(bo->ws_o);

	/* Filter into object */
	hp = bo->beresp;
	hp2 = obj->http;

	hp2->logtag = HTTP_Obj;
	http_FilterResp(hp, hp2, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS);
	http_CopyHome(hp2);

	if (http_GetHdr(hp, H_Last_Modified, &b))
		obj->last_modified = VTIM_parse(b);
	else
		obj->last_modified = floor(bo->exp.entered);

	assert(WRW_IsReleased(wrk));

	/*
	 * Ready to fetch the body
	 */

	assert(bo->refcount >= 1);

	if (!(bo->fetch_obj->objcore->flags & OC_F_PRIVATE)) {
		EXP_Insert(obj);
		AN(obj->objcore->ban);
	}

	AZ(bo->ws_o->overflow);
	if (bo->do_stream)
		HSH_Unbusy(&wrk->stats, obj->objcore);

	if (bo->vfp == NULL)
		bo->vfp = &VFP_nop;

	assert(bo->state == BOS_REQ_DONE);
	VBO_setstate(bo, BOS_FETCHING);

	V1F_fetch_body(wrk, bo);
	if (!bo->do_stream)
		HSH_Unbusy(&wrk->stats, obj->objcore);
	HSH_Complete(obj->objcore);

	assert(bo->refcount >= 1);

	if (bo->state != BOS_FAILED)
		VBO_setstate(bo, BOS_FINISHED);

VSLb(bo->vsl, SLT_Debug, "YYY REF %d %d", bo->refcount, bo->fetch_obj->objcore->refcnt);
	return (F_STP_DONE);
}
Пример #3
0
void
parse_string(char *buf, const struct cmds *cmd, void *priv, struct vtclog *vl)
{
	char *token_s[MAX_TOKENS], *token_e[MAX_TOKENS];
	struct vsb *token_exp[MAX_TOKENS];
	char *p, *q, *f;
	int nest_brace;
	int tn;
	const struct cmds *cp;

	assert(buf != NULL);
	for (p = buf; *p != '\0'; p++) {
		if (vtc_error || vtc_stop)
			break;
		/* Start of line */
		if (isspace(*p))
			continue;
		if (*p == '#') {
			for (; *p != '\0' && *p != '\n'; p++)
				;
			if (*p == '\0')
				break;
			continue;
		}

		/* First content on line, collect tokens */
		tn = 0;
		f = p;
		while (*p != '\0') {
			assert(tn < MAX_TOKENS);
			if (*p == '\n') { /* End on NL */
				break;
			}
			if (isspace(*p)) { /* Inter-token whitespace */
				p++;
				continue;
			}
			if (*p == '\\' && p[1] == '\n') { /* line-cont */
				p += 2;
				continue;
			}
			if (*p == '"') { /* quotes */
				token_s[tn] = ++p;
				q = p;
				for (; *p != '\0'; p++) {
					if (*p == '"')
						break;
					if (*p == '\\') {
						p += VAV_BackSlash(p, q) - 1;
						q++;
					} else {
						if (*p == '\n')
							vtc_log(vl, 0,
				"Unterminated quoted string in line: %*.*s",
				(int)(p - f), (int)(p - f), f);
						assert(*p != '\n');
						*q++ = *p;
					}
				}
				token_e[tn++] = q;
				p++;
			} else if (*p == '{') { /* Braces */
				nest_brace = 0;
				token_s[tn] = p + 1;
				for (; *p != '\0'; p++) {
					if (*p == '{')
						nest_brace++;
					else if (*p == '}') {
						if (--nest_brace == 0)
							break;
					}
				}
				assert(*p == '}');
				token_e[tn++] = p++;
			} else { /* other tokens */
				token_s[tn] = p;
				for (; *p != '\0' && !isspace(*p); p++)
					;
				token_e[tn++] = p;
			}
		}
		assert(tn < MAX_TOKENS);
		token_s[tn] = NULL;
		for (tn = 0; token_s[tn] != NULL; tn++) {
			token_exp[tn] = NULL;
			AN(token_e[tn]);	/*lint !e771 */
			*token_e[tn] = '\0';	/*lint !e771 */
			if (NULL == strstr(token_s[tn], "${"))
				continue;
			token_exp[tn] = macro_expand(vl, token_s[tn]);
			if (vtc_error)
				return;
			token_s[tn] = VSB_data(token_exp[tn]);
			token_e[tn] = strchr(token_s[tn], '\0');
		}

		for (cp = cmd; cp->name != NULL; cp++)
			if (!strcmp(token_s[0], cp->name))
				break;
		if (cp->name == NULL) {
			vtc_log(vl, 0, "Unknown command: \"%s\"", token_s[0]);
			return;
		}
		vtc_log(vl, 3, "%s", token_s[0]);

		assert(cp->cmd != NULL);
		cp->cmd(token_s, priv, cmd, vl);
	}
}
Пример #4
0
static void
pan_ic(const char *func, const char *file, int line, const char *cond,
    int err, int xxx)
{
	const char *q;
	const struct sess *sp;

	AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released,
						  we're going to die
						  anyway */
	switch(xxx) {
	case 3:
		VSB_printf(pan_vsp,
		    "Wrong turn at %s:%d:\n%s\n", file, line, cond);
		break;
	case 2:
		VSB_printf(pan_vsp,
		    "Panic from VCL:\n  %s\n", cond);
		break;
	case 1:
		VSB_printf(pan_vsp,
		    "Missing errorhandling code in %s(), %s line %d:\n"
		    "  Condition(%s) not true.",
		    func, file, line, cond);
		break;
	default:
	case 0:
		VSB_printf(pan_vsp,
		    "Assert error in %s(), %s line %d:\n"
		    "  Condition(%s) not true.\n",
		    func, file, line, cond);
		break;
	}
	if (err)
		VSB_printf(pan_vsp, "errno = %d (%s)\n", err, strerror(err));

	q = THR_GetName();
	if (q != NULL)
		VSB_printf(pan_vsp, "thread = (%s)\n", q);

	VSB_printf(pan_vsp, "ident = %s,%s\n",
	    VSB_data(vident) + 1, WAIT_GetName());

	pan_backtrace();

	if (!(cache_param->diag_bitmap & 0x2000)) {
		sp = THR_GetSession();
		if (sp != NULL)
			pan_sess(sp);
	}
	VSB_printf(pan_vsp, "\n");
	VSB_bcat(pan_vsp, "", 1);	/* NUL termination */

	if (cache_param->diag_bitmap & 0x4000)
		(void)fputs(heritage.panic_str, stderr);

	if (cache_param->diag_bitmap & 0x1000)
		exit(4);
	else
		abort();
}
Пример #5
0
static void
pan_ic(const char *func, const char *file, int line, const char *cond,
    int err, int xxx)
{
	const char *q;
	const struct sess *sp;

	AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released,
						  we're going to die
						  anyway */
	switch(xxx) {
	case 3:
		VSB_printf(vsp,
		    "Wrong turn at %s:%d:\n%s\n", file, line, cond);
		break;
	case 2:
		VSB_printf(vsp,
		    "Panic from VCL:\n  %s\n", cond);
		break;
	case 1:
		VSB_printf(vsp,
		    "Missing errorhandling code in %s(), %s line %d:\n"
		    "  Condition(%s) not true.",
		    func, file, line, cond);
		break;
	default:
	case 0:
		VSB_printf(vsp,
		    "Assert error in %s(), %s line %d:\n"
		    "  Condition(%s) not true.\n",
		    func, file, line, cond);
		break;
	}
	if (err)
		VSB_printf(vsp, "errno = %d (%s)\n", err, strerror(err));

	q = THR_GetName();
	if (q != NULL)
		VSB_printf(vsp, "thread = (%s)\n", q);

	VSB_printf(vsp, "ident = %s,%s\n",
	    VSB_data(vident) + 1, VCA_waiter_name());

	pan_backtrace();

	if (!(params->diag_bitmap & 0x2000)) {
		sp = THR_GetSession();
		if (sp != NULL)
			pan_sess(sp);
	}
	VSB_printf(vsp, "\n");
	VSB_bcat(vsp, "", 1);	/* NUL termination */

	if (params->diag_bitmap & 0x4000)
		(void)fputs(VSM_head->panicstr, stderr);

#ifdef HAVE_ABORT2
	if (params->diag_bitmap & 0x8000) {
		void *arg[1];
		char *p;

		for (p = VSM_head->panicstr; *p; p++)
			if (*p == '\n')
				*p = ' ';
		arg[0] = VSM_head->panicstr;
		abort2(VSM_head->panicstr, 1, arg);
	}
#endif
	if (params->diag_bitmap & 0x1000)
		exit(4);
	else
		abort();
}
Пример #6
0
static int
vbf_beresp2obj(struct busyobj *bo)
{
	unsigned l;
	char *b;
	struct vsb *vary = NULL;
	int varyl = 0;
	uint16_t nhttp;
	struct object *obj;
	struct http *hp, *hp2;

	l = 0;

	/* Create Vary instructions */
	if (!(bo->fetch_objcore->flags & OC_F_PRIVATE)) {
		varyl = VRY_Create(bo, &vary);
		if (varyl > 0) {
			AN(vary);
			assert(varyl == VSB_len(vary));
			l += varyl;
		} else if (varyl < 0) {
			/*
			 * Vary parse error
			 * Complain about it, and make this a pass.
			 */
			VSLb(bo->vsl, SLT_Error,
			    "Illegal 'Vary' header from backend, "
			    "making this a pass.");
			bo->uncacheable = 1;
			AZ(vary);
		} else
			/* No vary */
			AZ(vary);
	}

	l += http_EstimateWS(bo->beresp,
	    bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp);

	if (bo->uncacheable)
		bo->fetch_objcore->flags |= OC_F_PASS;

	obj = vbf_allocobj(bo, l, nhttp);

	if (obj == NULL)
		return (-1);

	CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);

	AZ(bo->fetch_obj);
	bo->fetch_obj = obj;

	if (vary != NULL) {
		obj->vary = (void *)WS_Copy(obj->http->ws,
		    VSB_data(vary), varyl);
		AN(obj->vary);
		(void)VRY_Validate(obj->vary);
		VSB_delete(vary);
	}

	obj->vxid = bo->vsl->wid;
	WS_Assert(bo->ws_o);

	/* Filter into object */
	hp = bo->beresp;
	hp2 = obj->http;

	hp2->logtag = SLT_ObjMethod;
	http_FilterResp(hp, hp2, bo->uncacheable ? HTTPH_R_PASS : HTTPH_A_INS);
	http_CopyHome(hp2);

	if (http_GetHdr(hp, H_Last_Modified, &b))
		obj->last_modified = VTIM_parse(b);
	else
		obj->last_modified = floor(bo->exp.t_origin);

	return (0);
}
Пример #7
0
static void
varnish_launch(struct varnish *v)
{
	struct vsb *vsb, *vsb1;
	int i, nfd, nap;
	struct vss_addr **ap;
	char abuf[128], pbuf[128];
	struct pollfd fd[2];
	enum VCLI_status_e u;
	char *r;

	v->vd = VSM_New();

	/* Create listener socket */
	nap = VSS_resolve("127.0.0.1", "0", &ap);
	AN(nap);
	v->cli_fd = VSS_listen(ap[0], 1);
	VTCP_myname(v->cli_fd, abuf, sizeof abuf, pbuf, sizeof pbuf);

	AZ(VSB_finish(v->args));
	vtc_log(v->vl, 2, "Launch");
	vsb = VSB_new_auto();
	AN(vsb);
	VSB_printf(vsb, "cd ${pwd} &&");
	VSB_printf(vsb, " ${varnishd} -d -d -n %s", v->workdir);
	VSB_printf(vsb, " -l 10m,1m,-");
	VSB_printf(vsb, " -p auto_restart=off");
	VSB_printf(vsb, " -p syslog_cli_traffic=off");
	VSB_printf(vsb, " -a '%s'", "127.0.0.1:0");
	VSB_printf(vsb, " -S %s/_S", v->workdir);
	VSB_printf(vsb, " -M '%s %s'", abuf, pbuf);
	VSB_printf(vsb, " -P %s/varnishd.pid", v->workdir);
	VSB_printf(vsb, " %s", VSB_data(v->storage));
	VSB_printf(vsb, " %s", VSB_data(v->args));
	AZ(VSB_finish(vsb));
	vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb));
	vsb1 = macro_expand(v->vl, VSB_data(vsb));
	AN(vsb1);
	VSB_delete(vsb);
	vsb = vsb1;
	vtc_log(v->vl, 3, "CMD: %s", VSB_data(vsb));
	AZ(pipe(&v->fds[0]));
	AZ(pipe(&v->fds[2]));
	v->pid = fork();
	assert(v->pid >= 0);
	if (v->pid == 0) {
		assert(dup2(v->fds[0], 0) == 0);
		assert(dup2(v->fds[3], 1) == 1);
		assert(dup2(1, 2) == 2);
		AZ(close(v->fds[0]));
		AZ(close(v->fds[1]));
		AZ(close(v->fds[2]));
		AZ(close(v->fds[3]));
		for (i = 3; i <getdtablesize(); i++)
			(void)close(i);
		AZ(execl("/bin/sh", "/bin/sh", "-c", VSB_data(vsb), (char*)0));
		exit(1);
	} else {
		vtc_log(v->vl, 3, "PID: %ld", (long)v->pid);
	}
	AZ(close(v->fds[0]));
	AZ(close(v->fds[3]));
	v->fds[0] = v->fds[2];
	v->fds[2] = v->fds[3] = -1;
	VSB_delete(vsb);
	AZ(pthread_create(&v->tp, NULL, varnish_thread, v));
	AZ(pthread_create(&v->tp_vsl, NULL, varnishlog_thread, v));

	/* Wait for the varnish to call home */
	memset(fd, 0, sizeof fd);
	fd[0].fd = v->cli_fd;
	fd[0].events = POLLIN;
	fd[1].fd = v->fds[0];
	fd[1].events = 0; /* Only care about POLLHUP, which is output-only */
	i = poll(fd, 2, 10000);
	vtc_log(v->vl, 4, "CLIPOLL %d 0x%x 0x%x",
	    i, fd[0].revents, fd[1].revents);
	if (i == 0) {
		vtc_log(v->vl, 0, "FAIL timeout waiting for CLI connection");
		return;
	}
	if (fd[1].revents & POLLHUP) {
		vtc_log(v->vl, 0, "FAIL debug pipe closed");
		return;
	}
	if (!(fd[0].revents & POLLIN)) {
		vtc_log(v->vl, 0, "FAIL CLI connection wait failure");
		return;
	}
	nfd = accept(v->cli_fd, NULL, NULL);
	if (nfd < 0) {
		vtc_log(v->vl, 0, "FAIL no CLI connection accepted");
		return;
	}

	AZ(close(v->cli_fd));
	v->cli_fd = nfd;

	vtc_log(v->vl, 3, "CLI connection fd = %d", v->cli_fd);
	assert(v->cli_fd >= 0);


	/* Receive the banner or auth response */
	u = varnish_ask_cli(v, NULL, &r);
	if (vtc_error)
		return;
	if (u != CLIS_AUTH)
		vtc_log(v->vl, 0, "CLI auth demand expected: %u %s", u, r);

	bprintf(abuf, "%s/_S", v->workdir);
	nfd = open(abuf, O_RDONLY);
	assert(nfd >= 0);

	assert(sizeof abuf >= CLI_AUTH_RESPONSE_LEN + 7);
	strcpy(abuf, "auth ");
	VCLI_AuthResponse(nfd, r, abuf + 5);
	AZ(close(nfd));
	free(r);
	strcat(abuf, "\n");

	u = varnish_ask_cli(v, abuf, &r);
	if (vtc_error)
		return;
	if (u != CLIS_OK)
		vtc_log(v->vl, 0, "CLI auth command failed: %u %s", u, r);
	free(r);

	(void)VSL_Arg(v->vd, 'n', v->workdir);
	AZ(VSM_Open(v->vd));
}
Пример #8
0
static enum req_fsm_nxt
cnt_synth(struct worker *wrk, struct req *req)
{
	struct http *h;
	double now;
	struct vsb *synth_body;
	ssize_t sz, szl;
	uint8_t *ptr;

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

	wrk->stats->s_synth++;

	now = W_TIM_real(wrk);
	VSLb_ts_req(req, "Process", now);

	if (req->err_code < 100 || req->err_code > 999)
		req->err_code = 501;


	HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
	h = req->resp;
	http_TimeHeader(h, "Date: ", now);
	http_SetHeader(h, "Server: Varnish");
	http_PrintfHeader(req->resp, "X-Varnish: %u", VXID(req->vsl->wid));
	http_PutResponse(h, "HTTP/1.1", req->err_code, req->err_reason);

	synth_body = VSB_new_auto();
	AN(synth_body);

	VCL_synth_method(req->vcl, wrk, req, NULL, synth_body);

	AZ(VSB_finish(synth_body));

	http_Unset(h, H_Content_Length);
	http_PrintfHeader(req->resp, "Content-Length: %zd",
	    VSB_len(synth_body));

	/* Discard any lingering request body before delivery */
	(void)VRB_Ignore(req);

	if (wrk->handling == VCL_RET_RESTART) {
		HTTP_Setup(h, req->ws, req->vsl, SLT_RespMethod);
		VSB_delete(synth_body);
		req->req_step = R_STP_RESTART;
		return (REQ_FSM_MORE);
	}
	assert(wrk->handling == VCL_RET_DELIVER);

	req->objcore = HSH_Private(wrk);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
	szl = -1;
	if (STV_NewObject(wrk, req->objcore, TRANSIENT_STORAGE, 1024)) {
		szl = VSB_len(synth_body);
		assert(szl >= 0);
		sz = szl;
		if (sz > 0 &&
		    ObjGetSpace(wrk, req->objcore, &sz, &ptr) && sz >= szl) {
			memcpy(ptr, VSB_data(synth_body), szl);
			ObjExtend(wrk, req->objcore, szl);
		} else if (sz > 0) {
			szl = -1;
		}
	}

	HSH_DerefBoc(wrk, req->objcore);
	VSB_delete(synth_body);

	if (szl < 0) {
		VSLb(req->vsl, SLT_Error, "Could not get storage");
		req->doclose = SC_OVERLOAD;
		VSLb_ts_req(req, "Resp", W_TIM_real(wrk));
		(void)HSH_DerefObjCore(wrk, &req->objcore);
		http_Teardown(req->resp);
		return (REQ_FSM_DONE);
	}

	req->req_step = R_STP_TRANSMIT;
	return (REQ_FSM_MORE);
}
Пример #9
0
static unsigned int
vcl_reply(struct http_request *request, void *data)
{
	struct agent_core_t *core = data;
	struct vcl_priv_t *vcl;
	struct http_response *resp;
	struct ipc_ret_t vret;
	char id[ID_LEN + 1];
	int ret;
	int status;

	GET_PRIV(core, vcl);

	if (request->method == M_GET) {
		if (!strcmp(request->url, "/vclactive") || !strcmp(request->url,"/vclactive/")) {
			/*
			 * vcl.list output:
			 *
			 * V3/4 : (active|available|discarded) (refcnt) (name)
			 * V4.1 : (active|available|discarded) (state) \
			 *            (busycnt|) (name)
			 */
			ipc_run(vcl->vadmin,&vret,"vcl.list");
			if (vret.status == 400) {
				http_reply(request->connection, 500, vret.answer);
			} else {
				char **tp, *tok[5];
				char *p, *last;
				char *line;

				memset(tok, '\0', sizeof(tok));
				for (p = vret.answer, last = NULL;
				    (line = strtok_r(p, "\n", &last));
				    p = NULL) {
					if (strncmp("active", line, 6))
						continue;
					last = NULL;
					for (p = line, tp = tok;
					    tp < &tok[4] &&
					    (*tp = strtok_r(p, " ", &last));
					    p = NULL) {
						if (**tp != '\0')
							tp++;
                                        }
				}
				if (!tok[2] || !tok[3]) {
					http_reply(request->connection,
					    500, "No active VCL");
				} else {
					strcpy(vret.answer,
					    tok[3] ? tok[3] : tok[2]);
					http_reply(request->connection,
					    200, vret.answer);
				}
			}
			free(vret.answer);
			return 0;
		} else if (!strcmp(request->url, "/vcl") || !strcmp(request->url,"/vcl/")) {
			ipc_run(vcl->vadmin, &vret, "vcl.list");
			if (vret.status == 400) {
				http_reply(request->connection, 500, vret.answer);
			} else {
				http_reply(request->connection, 200, vret.answer);
			}
			free(vret.answer);
			return 0;
		} else if (!strncmp(request->url,"/vcl/",strlen("/vcl/"))) {
			ipc_run(vcl->vadmin, &vret, "vcl.show %s", request->url + strlen("/vcl/"));
			if (vret.status == 400) {
				http_reply(request->connection, 500, vret.answer);
			} else {
				http_reply(request->connection, 200, vret.answer);
			}
			free(vret.answer);
			return 0;
		} else if(!strcmp(request->url, "/vcljson/")) {
			struct vsb *json;
			ipc_run(vcl->vadmin, &vret, "vcl.list");
			if (vret.status == 400) {
				http_reply(request->connection, 500, vret.answer);
			} else {
				json = vcl_list_json(vret.answer);
				assert(VSB_finish(json) == 0);
				resp = http_mkresp(request->connection, 200, NULL);
				resp->data = VSB_data(json);
				resp->ndata = VSB_len(json);
				http_add_header(resp, "Content-Type", "application/json");
				send_response(resp);
				http_free_resp(resp);
				VSB_clear(json);
				VSB_delete(json);
			}
			free(vret.answer);
			return 0;
		} else {
			http_reply(request->connection, 500, "Invalid VCL-url.");
			return 0;
		}
	} else if (request->method == M_POST) {
		snprintf(id, sizeof(id), "%ju", (uintmax_t) time(NULL));
		status = vcl_store(request, vcl, &vret, core, id);
		http_reply(request->connection, status, vret.answer);
		free(vret.answer);
		return 0;
	} else if (request->method == M_PUT) {
		if (!strncmp(request->url,"/vcl/",strlen("/vcl/"))) {
			if (strlen(request->url) >= 6) {
				status = vcl_store(request, vcl, &vret, core,
				                   request->url + strlen("/vcl/"));
				http_reply(request->connection, status, vret.answer);
				free(vret.answer);
				return 0;
			} else {
				http_reply(request->connection, 400, "Bad URL?");
				return 0;
			}
		} else if (!strncmp(request->url, "/vcldeploy/",strlen("/vcldeploy/"))) {
			ipc_run(vcl->vadmin, &vret, "vcl.use %s",
				request->url + strlen("/vcldeploy/"));
			if (vret.status == 200) {
				ret = vcl_persist_active(vcl->logger, request->url + strlen("/vcldeploy/"), core);
			}
			if (vret.status == 200 && ret)
				http_reply(request->connection, 500, "Deployed ok, but NOT PERSISTED.");
			else if (vret.status == 200 && ret == 0)
				http_reply(request->connection, 200, vret.answer);
			else
				http_reply(request->connection, 500, vret.answer);
			free(vret.answer);
			return 0;
		}
	} else if (request->method == M_DELETE) {
		if (!strncmp(request->url, "/vcl/", strlen("/vcl/"))) {
			ipc_run(vcl->vadmin, &vret, "vcl.discard %s",
				request->url + strlen("/vcl/"));
			if (vret.status == 400 || vret.status == 106) {
				http_reply(request->connection, 500, vret.answer);
			} else {
				http_reply(request->connection, 200, vret.answer);
			}
			free(vret.answer);
			return 0;
		}
	} else {
		return http_reply(request->connection, 500, "Unknown request?");
	}
	assert("Shouldn't get here" == NULL);
	return 0;
}
Пример #10
0
static void
vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
{
	struct token *t_field;
	struct token *t_val;
	struct token *t_host = NULL;
	struct token *t_port = NULL;
	struct token *t_hosthdr = NULL;
	struct fld_spec *fs;
	struct inifin *ifp;
	struct vsb *vsb;
	char *p;
	unsigned u;
	double t;

	fs = vcc_FldSpec(tl,
	    "!host",
	    "?port",
	    "?host_header",
	    "?connect_timeout",
	    "?first_byte_timeout",
	    "?between_bytes_timeout",
	    "?probe",
	    "?max_connections",
	    "?proxy_header",
	    NULL);

	SkipToken(tl, '{');

	vsb = VSB_new_auto();
	AN(vsb);
	tl->fb = vsb;

	Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n",
	    vgcname);

	Fb(tl, 0, "\t.magic = VRT_BACKEND_MAGIC,\n");
	Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(t_be));
	Fb(tl, 0, "\",\n");

	/* Check for old syntax */
	if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
		VSB_printf(tl->sb,
		    "NB: Backend Syntax has changed:\n"
		    "Remove \"set\" and \"backend\" in front"
		    " of backend fields.\n" );
		vcc_ErrToken(tl, tl->t);
		VSB_printf(tl->sb, " at ");
		vcc_ErrWhere(tl, tl->t);
		return;
	}

	while (tl->t->tok != '}') {

		vcc_IsField(tl, &t_field, fs);
		ERRCHK(tl);
		if (vcc_IdIs(t_field, "host")) {
			ExpectErr(tl, CSTR);
			assert(tl->t->dec != NULL);
			t_host = tl->t;
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "port")) {
			ExpectErr(tl, CSTR);
			assert(tl->t->dec != NULL);
			t_port = tl->t;
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "host_header")) {
			ExpectErr(tl, CSTR);
			assert(tl->t->dec != NULL);
			t_hosthdr = tl->t;
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "connect_timeout")) {
			Fb(tl, 0, "\t.connect_timeout = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fb(tl, 0, "%g,\n", t);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "first_byte_timeout")) {
			Fb(tl, 0, "\t.first_byte_timeout = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fb(tl, 0, "%g,\n", t);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
			Fb(tl, 0, "\t.between_bytes_timeout = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fb(tl, 0, "%g,\n", t);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "max_connections")) {
			u = vcc_UintVal(tl);
			ERRCHK(tl);
			SkipToken(tl, ';');
			Fb(tl, 0, "\t.max_connections = %u,\n", u);
		} else if (vcc_IdIs(t_field, "proxy_header")) {
			t_val = tl->t;
			u = vcc_UintVal(tl);
			ERRCHK(tl);
			if (u != 1 && u != 2) {
				VSB_printf(tl->sb,
				    ".proxy_header must be 1 or 2\n");
				vcc_ErrWhere(tl, t_val);
				return;
			}
			SkipToken(tl, ';');
			Fb(tl, 0, "\t.proxy_header = %u,\n", u);
		} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
			vcc_ParseProbeSpec(tl, NULL, &p);
			Fb(tl, 0, "\t.probe = &%s,\n", p);
			ERRCHK(tl);
		} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) {
			if (VCC_FindSymbol(tl, tl->t, SYM_PROBE) == NULL) {
				VSB_printf(tl->sb, "Probe %.*s not found\n",
				    PF(tl->t));
				vcc_ErrWhere(tl, tl->t);
				return;
			}
			Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t));
			vcc_AddRef(tl, tl->t, SYM_PROBE);
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "probe")) {
			VSB_printf(tl->sb,
			    "Expected '{' or name of probe, got ");
			vcc_ErrToken(tl, tl->t);
			VSB_printf(tl->sb, " at\n");
			vcc_ErrWhere(tl, tl->t);
			return;
		} else {
			ErrInternal(tl);
			return;
		}

	}

	vcc_FieldsOk(tl, fs);
	ERRCHK(tl);

	/* Check that the hostname makes sense */
	assert(t_host != NULL);
	Emit_Sockaddr(tl, t_host, t_port);
	ERRCHK(tl);

	ExpectErr(tl, '}');

	/* We have parsed it all, emit the ident string */

	/* Emit the hosthdr field, fall back to .host if not specified */
	Fb(tl, 0, "\t.hosthdr = ");
	if (t_hosthdr != NULL)
		EncToken(tl->fb, t_hosthdr);
	else
		EncToken(tl->fb, t_host);
	Fb(tl, 0, ",\n");

	/* Close the struct */
	Fb(tl, 0, "};\n");

	vcc_NextToken(tl);

	tl->fb = NULL;
	AZ(VSB_finish(vsb));
	Fh(tl, 0, "%s", VSB_data(vsb));
	VSB_destroy(&vsb);

	ifp = New_IniFin(tl);
	VSB_printf(ifp->ini,
	    "\t%s =\n\t    VRT_new_backend(ctx, &vgc_dir_priv_%s);",
	    vgcname, vgcname);
}
Пример #11
0
static void
mgt_reap_child(void)
{
	int i;
	int status = 0xffff;
	struct vsb *vsb;
	pid_t r = 0;

	assert(child_pid != -1);

	/*
	 * Close the CLI connections
	 * This signals orderly shut down to child
	 */
	mgt_cli_stop_child();
	if (child_cli_out >= 0)
		closex(&child_cli_out);
	if (child_cli_in >= 0)
		closex(&child_cli_in);

	/* Stop the poker */
	if (ev_poker != NULL) {
		vev_del(mgt_evb, ev_poker);
		free(ev_poker);
	}
	ev_poker = NULL;

	/* Stop the listener */
	if (ev_listen != NULL) {
		vev_del(mgt_evb, ev_listen);
		free(ev_listen);
		ev_listen = NULL;
	}

	/* Compose obituary */
	vsb = VSB_new_auto();
	XXXAN(vsb);

	/* Wait for child to die */
	for (i = 0; i < mgt_param.cli_timeout; i++) {
		r = waitpid(child_pid, &status, WNOHANG);
		if (r == child_pid)
			break;
		(void)sleep(1);
	}
	if (r == 0) {
		VSB_printf(vsb, "Child (%jd) not dying, killing", (intmax_t)r);

		/* Kick it Jim... */
		if (MGT_FEATURE(FEATURE_NO_COREDUMP))
			(void)kill(child_pid, SIGKILL);
		else
			(void)kill(child_pid, SIGQUIT);
		r = waitpid(child_pid, &status, 0);
	}
	if (r != child_pid)
		fprintf(stderr, "WAIT 0x%jx\n", (uintmax_t)r);
	assert(r == child_pid);

	MAC_reopen_sockets(NULL);

	VSB_printf(vsb, "Child (%jd) %s", (intmax_t)r,
	    status ? "died" : "ended");
	if (WIFEXITED(status) && WEXITSTATUS(status)) {
		VSB_printf(vsb, " status=%d", WEXITSTATUS(status));
		exit_status |= 0x20;
		if (WEXITSTATUS(status) == 1)
			VSC_C_mgt->child_exit = ++static_VSC_C_mgt.child_exit;
		else
			VSC_C_mgt->child_stop = ++static_VSC_C_mgt.child_stop;
	}
	if (WIFSIGNALED(status)) {
		VSB_printf(vsb, " signal=%d", WTERMSIG(status));
		exit_status |= 0x40;
		VSC_C_mgt->child_died = ++static_VSC_C_mgt.child_died;
	}
#ifdef WCOREDUMP
	if (WCOREDUMP(status)) {
		VSB_printf(vsb, " (core dumped)");
		exit_status |= 0x80;
		VSC_C_mgt->child_dump = ++static_VSC_C_mgt.child_dump;
	}
#endif
	AZ(VSB_finish(vsb));
	MGT_complain(status ? C_ERR : C_INFO, "%s", VSB_data(vsb));
	VSB_delete(vsb);

	/* Dispose of shared memory but evacuate panic messages first */
	if (heritage.panic_str[0] != '\0') {
		mgt_panic_record(r);
		mgt_SHM_Destroy(1);
		VSC_C_mgt->child_panic = ++static_VSC_C_mgt.child_panic;
	} else {
		mgt_SHM_Destroy(MGT_DO_DEBUG(DBG_VSM_KEEP));
	}
	mgt_SHM_Create();
	mgt_SHM_Commit();

	if (child_state == CH_RUNNING)
		child_state = CH_DIED;

	/* Pick up any stuff lingering on stdout/stderr */
	(void)child_listener(NULL, EV_RD);
	closex(&child_output);
	VLU_Destroy(child_std_vlu);

	child_pid = -1;

	MGT_complain(C_DEBUG, "Child cleanup complete");

	if (child_state == CH_DIED && mgt_param.auto_restart)
		mgt_launch_child(NULL);
	else if (child_state == CH_DIED)
		child_state = CH_STOPPED;
	else if (child_state == CH_STOPPING)
		child_state = CH_STOPPED;
}
Пример #12
0
static void
vcc_ParseHostDef(struct vcc *tl, int serial, const char *vgcname)
{
	struct token *t_field;
	struct token *t_host = NULL;
	struct token *t_port = NULL;
	struct token *t_hosthdr = NULL;
	unsigned saint = UINT_MAX;
	struct fld_spec *fs;
	struct vsb *vsb;
	unsigned u;
	double t;

	Fh(tl, 1, "\n#define VGC_backend_%s %d\n", vgcname, tl->ndirector);

	fs = vcc_FldSpec(tl,
	    "!host",
	    "?port",
	    "?host_header",
	    "?connect_timeout",
	    "?first_byte_timeout",
	    "?between_bytes_timeout",
	    "?probe",
	    "?max_connections",
	    "?saintmode_threshold",
	    NULL);

	SkipToken(tl, '{');

	vsb = VSB_new_auto();
	AN(vsb);
	tl->fb = vsb;

	Fb(tl, 0, "\nstatic const struct vrt_backend vgc_dir_priv_%s = {\n",
	    vgcname);

	Fb(tl, 0, "\t.vcl_name = \"%.*s", PF(tl->t_dir));
	if (serial >= 0)
		Fb(tl, 0, "[%d]", serial);
	Fb(tl, 0, "\",\n");

	/* Check for old syntax */
	if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
		VSB_printf(tl->sb,
		    "NB: Backend Syntax has changed:\n"
		    "Remove \"set\" and \"backend\" in front"
		    " of backend fields.\n" );
		vcc_ErrToken(tl, tl->t);
		VSB_printf(tl->sb, " at ");
		vcc_ErrWhere(tl, tl->t);
		return;
	}

	while (tl->t->tok != '}') {

		vcc_IsField(tl, &t_field, fs);
		ERRCHK(tl);
		if (vcc_IdIs(t_field, "host")) {
			ExpectErr(tl, CSTR);
			assert(tl->t->dec != NULL);
			t_host = tl->t;
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "port")) {
			ExpectErr(tl, CSTR);
			assert(tl->t->dec != NULL);
			t_port = tl->t;
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "host_header")) {
			ExpectErr(tl, CSTR);
			assert(tl->t->dec != NULL);
			t_hosthdr = tl->t;
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "connect_timeout")) {
			Fb(tl, 0, "\t.connect_timeout = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fb(tl, 0, "%g,\n", t);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "first_byte_timeout")) {
			Fb(tl, 0, "\t.first_byte_timeout = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fb(tl, 0, "%g,\n", t);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "between_bytes_timeout")) {
			Fb(tl, 0, "\t.between_bytes_timeout = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fb(tl, 0, "%g,\n", t);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "max_connections")) {
			u = vcc_UintVal(tl);
			ERRCHK(tl);
			SkipToken(tl, ';');
			Fb(tl, 0, "\t.max_connections = %u,\n", u);
		} else if (vcc_IdIs(t_field, "saintmode_threshold")) {
			u = vcc_UintVal(tl);
			/* UINT_MAX == magic number to mark as unset, so
			 * not allowed here.
			 */
			if (u == UINT_MAX) {
				VSB_printf(tl->sb,
				    "Value outside allowed range: ");
				vcc_ErrToken(tl, tl->t);
				VSB_printf(tl->sb, " at\n");
				vcc_ErrWhere(tl, tl->t);
			}
			ERRCHK(tl);
			saint = u;
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
			Fb(tl, 0, "\t.probe = &vgc_probe__%d,\n", tl->nprobe);
			vcc_ParseProbeSpec(tl);
			ERRCHK(tl);
		} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == ID) {
			Fb(tl, 0, "\t.probe = &vgc_probe_%.*s,\n", PF(tl->t));
			vcc_AddRef(tl, tl->t, SYM_PROBE);
			vcc_NextToken(tl);
			SkipToken(tl, ';');
		} else if (vcc_IdIs(t_field, "probe")) {
			VSB_printf(tl->sb,
			    "Expected '{' or name of probe.");
			vcc_ErrToken(tl, tl->t);
			VSB_printf(tl->sb, " at\n");
			vcc_ErrWhere(tl, tl->t);
			return;
		} else {
			ErrInternal(tl);
			return;
		}

	}

	vcc_FieldsOk(tl, fs);
	ERRCHK(tl);

	/* Check that the hostname makes sense */
	assert(t_host != NULL);
	if (t_port != NULL)
		Emit_Sockaddr(tl, t_host, t_port->dec);
	else
		Emit_Sockaddr(tl, t_host, "80");
	ERRCHK(tl);

	ExpectErr(tl, '}');

	/* We have parsed it all, emit the ident string */

	/* Emit the hosthdr field, fall back to .host if not specified */
	Fb(tl, 0, "\t.hosthdr = ");
	if (t_hosthdr != NULL)
		EncToken(tl->fb, t_hosthdr);
	else
		EncToken(tl->fb, t_host);
	Fb(tl, 0, ",\n");

	Fb(tl, 0, "\t.saintmode_threshold = %d,\n",saint);

	/* Close the struct */
	Fb(tl, 0, "};\n");

	vcc_NextToken(tl);

	tl->fb = NULL;
	AZ(VSB_finish(vsb));
	Fh(tl, 0, "%s", VSB_data(vsb));
	VSB_delete(vsb);

	Fi(tl, 0, "\tVRT_init_dir(cli, VCL_conf.director, \"simple\",\n"
	    "\t    VGC_backend_%s, &vgc_dir_priv_%s);\n", vgcname, vgcname);
	Ff(tl, 0, "\tVRT_fini_dir(cli, VGCDIR(%s));\n", vgcname);
	tl->ndirector++;
}
Пример #13
0
pan_ic(const char *func, const char *file, int line, const char *cond,
    int err, enum vas_e kind)
{
	const char *q;
	struct req *req;
	struct busyobj *bo;

	AZ(pthread_mutex_lock(&panicstr_mtx)); /* Won't be released,
						  we're going to die
						  anyway */
	switch(kind) {
	case VAS_WRONG:
		VSB_printf(pan_vsp,
		    "Wrong turn at %s:%d:\n%s\n", file, line, cond);
		break;
	case VAS_VCL:
		VSB_printf(pan_vsp,
		    "Panic from VCL:\n  %s\n", cond);
		break;
	case VAS_MISSING:
		VSB_printf(pan_vsp,
		    "Missing errorhandling code in %s(), %s line %d:\n"
		    "  Condition(%s) not true.",
		    func, file, line, cond);
		break;
	case VAS_INCOMPLETE:
		VSB_printf(pan_vsp,
		    "Incomplete code in %s(), %s line %d:\n",
		    func, file, line);
		break;
	default:
	case VAS_ASSERT:
		VSB_printf(pan_vsp,
		    "Assert error in %s(), %s line %d:\n"
		    "  Condition(%s) not true.\n",
		    func, file, line, cond);
		break;
	}
	if (err)
		VSB_printf(pan_vsp, "errno = %d (%s)\n", err, strerror(err));

	q = THR_GetName();
	if (q != NULL)
		VSB_printf(pan_vsp, "thread = (%s)\n", q);

	VSB_printf(pan_vsp, "ident = %s,%s\n",
	    VSB_data(vident) + 1, WAIT_GetName());

	pan_backtrace();

	if (!FEATURE(FEATURE_SHORT_PANIC)) {
		req = THR_GetRequest();
		if (req != NULL) {
			pan_req(req);
			VSL_Flush(req->vsl, 0);
		}
		bo = THR_GetBusyobj();
		if (bo != NULL) {
			pan_busyobj(bo);
			VSL_Flush(bo->vsl, 0);
		}
	}
	VSB_printf(pan_vsp, "\n");
	VSB_bcat(pan_vsp, "", 1);	/* NUL termination */

	if (FEATURE(FEATURE_NO_COREDUMP))
		exit(4);
	else
		abort();
}
Пример #14
0
int
VRY_Create(struct busyobj *bo, struct vsb **psb)
{
	const char *v, *p, *q, *h, *e;
	struct vsb *sb, *sbh;
	unsigned l;
	int error = 0;

	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	CHECK_OBJ_NOTNULL(bo->bereq, HTTP_MAGIC);
	CHECK_OBJ_NOTNULL(bo->beresp, HTTP_MAGIC);
	AN(psb);
	AZ(*psb);

	/* No Vary: header, no worries */
	if (!http_GetHdr(bo->beresp, H_Vary, &v))
		return (0);

	/* For vary matching string */
	sb = VSB_new_auto();
	AN(sb);

	/* For header matching strings */
	sbh = VSB_new_auto();
	AN(sbh);

	for (p = v; *p; p++) {

		/* Find next header-name */
		if (vct_issp(*p))
			continue;
		for (q = p; *q && !vct_issp(*q) && *q != ','; q++)
			continue;

		if (q - p > INT8_MAX) {
			VSLb(bo->vsl, SLT_Error,
			    "Vary header name length exceeded");
			error = 1;
			break;
		}

		/* Build a header-matching string out of it */
		VSB_clear(sbh);
		VSB_printf(sbh, "%c%.*s:%c",
		    (char)(1 + (q - p)), (int)(q - p), p, 0);
		AZ(VSB_finish(sbh));

		if (http_GetHdr(bo->bereq, VSB_data(sbh), &h)) {
			AZ(vct_issp(*h));
			/* Trim trailing space */
			e = strchr(h, '\0');
			while (e > h && vct_issp(e[-1]))
				e--;
			/* Encode two byte length and contents */
			l = e - h;
			if (l > 0xffff - 1) {
				VSLb(bo->vsl, SLT_Error,
				    "Vary header maximum length exceeded");
				error = 1;
				break;
			}
		} else {
			e = h;
			l = 0xffff;
		}
		VSB_printf(sb, "%c%c", (int)(l >> 8), (int)(l & 0xff));
		/* Append to vary matching string */
		VSB_bcat(sb, VSB_data(sbh), VSB_len(sbh));
		if (e != h)
			VSB_bcat(sb, h, e - h);

		while (vct_issp(*q))
			q++;
		if (*q == '\0')
			break;
		if (*q != ',') {
			VSLb(bo->vsl, SLT_Error, "Malformed Vary header");
			error = 1;
			break;
		}
		p = q;
	}

	if (error) {
		VSB_delete(sbh);
		VSB_delete(sb);
		return (-1);
	}

	/* Terminate vary matching string */
	VSB_printf(sb, "%c%c%c", 0xff, 0xff, 0);

	VSB_delete(sbh);
	AZ(VSB_finish(sb));
	*psb = sb;
	return (VSB_len(sb));
}
Пример #15
0
vep_do_include(struct vep_state *vep, enum dowhat what)
{
	const char *p, *q, *h;
	ssize_t l;

	Debug("DO_INCLUDE(%d)\n", what);
	if (what == DO_ATTR) {
		Debug("ATTR (%s) (%s)\n", vep->match_hit->match,
			VSB_data(vep->attr_vsb));
		if (vep->include_src != NULL) {
			vep_error(vep,
			    "ESI 1.0 <esi:include> "
			    "has multiple src= attributes");
			vep->state = VEP_TAGERROR;
			VSB_delete(vep->attr_vsb);
			VSB_delete(vep->include_src);
			vep->attr_vsb = NULL;
			vep->include_src = NULL;
			return;
		}
		vep->include_src = vep->attr_vsb;
		return;
	}
	assert(what == DO_TAG);
	if (!vep->emptytag)
		vep_warn(vep,
		    "ESI 1.0 <esi:include> lacks final '/'");
	if (vep->include_src == NULL) {
		vep_error(vep,
		    "ESI 1.0 <esi:include> lacks src attr");
		return;
	}

	/*
	 * Strictly speaking, we ought to spit out any piled up skip before
	 * emitting the VEC for the include, but objectively that makes no
	 * difference and robs us of a chance to collapse another skip into
	 * this on so we don't do that.
	 * However, we cannot tolerate any verbatim stuff piling up.
	 * The mark_skip() before calling dostuff should have taken
	 * care of that.  Make sure.
	 */
	assert(vep->o_wait == 0 || vep->last_mark == SKIP);
	/* XXX: what if it contains NUL bytes ?? */
	p = VSB_data(vep->include_src);
	l = VSB_len(vep->include_src);
	h = 0;

	if (l > 7 && !memcmp(p, "http://", 7)) {
		h = p + 7;
		p = strchr(h, '/');
		AN(p);
		Debug("HOST <%.*s> PATH <%s>\n", (int)(p-h),h, p);
		VSB_printf(vep->vsb, "%c", VEC_INCL);
		VSB_printf(vep->vsb, "Host: %.*s%c", (int)(p-h), h, 0);
	} else if (l > 8 && !memcmp(p, "https://", 8)) {
		if (!FEATURE(FEATURE_ESI_IGNORE_HTTPS)) {
			vep_warn(vep,
			    "ESI 1.0 <esi:include> with https:// ignored");
			vep->state = VEP_TAGERROR;
			vep->attr_vsb = NULL;
			vep->include_src = NULL;
			return;
		}
		vep_warn(vep,
		    "ESI 1.0 <esi:include> https:// treated as http://");
		h = p + 8;
		p = strchr(h, '/');
		AN(p);
		VSB_printf(vep->vsb, "%c", VEC_INCL);
		VSB_printf(vep->vsb, "Host: %.*s%c", (int)(p-h), h, 0);
	} else if (*p == '/') {
		VSB_printf(vep->vsb, "%c", VEC_INCL);
		VSB_printf(vep->vsb, "%c", 0);
	} else {
		VSB_printf(vep->vsb, "%c", VEC_INCL);
		VSB_printf(vep->vsb, "%c", 0);
		/* Look for the last / before a '?' */
		h = NULL;
		for (q = vep->url; *q && *q != '?'; q++)
			if (*q == '/')
				h = q;
		if (h == NULL)
			h = q + 1;

		Debug("INCL:: [%.*s]/[%s]\n",
		    (int)(h - vep->url), vep->url, p);
		VSB_printf(vep->vsb, "%.*s/", (int)(h - vep->url), vep->url);
	}
	l -= (p - VSB_data(vep->include_src));
	for (q = p; *q != '\0'; ) {
		if (*q == '&') {
#define R(w,f,r)							\
			if (q + w <= p + l && !memcmp(q, f, w)) { \
				VSB_printf(vep->vsb, "%c", r);	\
				q += w;				\
				continue;			\
			}
			R(6, "&apos;", '\'');
			R(6, "&quot;", '"');
			R(4, "&lt;", '<');
			R(4, "&gt;", '>');
			R(5, "&amp;", '&');
		}
		VSB_printf(vep->vsb, "%c", *q++);
	}
#undef R
	VSB_printf(vep->vsb, "%c", 0);

	VSB_delete(vep->include_src);
	vep->include_src = NULL;
}
Пример #16
0
static int
cnt_fetchbody(struct sess *sp)
{
    int i;
    struct http *hp, *hp2;
    char *b;
    uint16_t nhttp;
    unsigned l;
    struct vsb *vary = NULL;
    int varyl = 0, pass;
    struct worker *wrk;

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

    assert(sp->handling == VCL_RET_HIT_FOR_PASS ||
           sp->handling == VCL_RET_DELIVER);

    if (wrk->objcore == NULL) {
        /* This is a pass from vcl_recv */
        pass = 1;
        /* VCL may have fiddled this, but that doesn't help */
        wrk->busyobj->exp.ttl = -1.;
    } else if (sp->handling == VCL_RET_HIT_FOR_PASS) {
        /* pass from vcl_fetch{} -> hit-for-pass */
        /* XXX: the bereq was not filtered pass... */
        pass = 1;
    } else {
        /* regular object */
        pass = 0;
    }

    /*
     * The VCL variables beresp.do_g[un]zip tells us how we want the
     * object processed before it is stored.
     *
     * The backend Content-Encoding header tells us what we are going
     * to receive, which we classify in the following three classes:
     *
     *	"Content-Encoding: gzip"	--> object is gzip'ed.
     *	no Content-Encoding		--> object is not gzip'ed.
     *	anything else			--> do nothing wrt gzip
     *
     */

    /* We do nothing unless the param is set */
    if (!cache_param->http_gzip_support)
        wrk->busyobj->do_gzip = wrk->busyobj->do_gunzip = 0;

    wrk->busyobj->is_gzip =
        http_HdrIs(wrk->busyobj->beresp, H_Content_Encoding, "gzip");

    wrk->busyobj->is_gunzip =
        !http_GetHdr(wrk->busyobj->beresp, H_Content_Encoding, NULL);

    /* It can't be both */
    assert(wrk->busyobj->is_gzip == 0 || wrk->busyobj->is_gunzip == 0);

    /* We won't gunzip unless it is gzip'ed */
    if (wrk->busyobj->do_gunzip && !wrk->busyobj->is_gzip)
        wrk->busyobj->do_gunzip = 0;

    /* If we do gunzip, remove the C-E header */
    if (wrk->busyobj->do_gunzip)
        http_Unset(wrk->busyobj->beresp, H_Content_Encoding);

    /* We wont gzip unless it is ungziped */
    if (wrk->busyobj->do_gzip && !wrk->busyobj->is_gunzip)
        wrk->busyobj->do_gzip = 0;

    /* If we do gzip, add the C-E header */
    if (wrk->busyobj->do_gzip)
        http_SetHeader(wrk, sp->vsl_id, wrk->busyobj->beresp,
                       "Content-Encoding: gzip");

    /* But we can't do both at the same time */
    assert(wrk->busyobj->do_gzip == 0 || wrk->busyobj->do_gunzip == 0);

    /* ESI takes precedence and handles gzip/gunzip itself */
    if (wrk->busyobj->do_esi)
        wrk->busyobj->vfp = &vfp_esi;
    else if (wrk->busyobj->do_gunzip)
        wrk->busyobj->vfp = &vfp_gunzip;
    else if (wrk->busyobj->do_gzip)
        wrk->busyobj->vfp = &vfp_gzip;
    else if (wrk->busyobj->is_gzip)
        wrk->busyobj->vfp = &vfp_testgzip;

    if (wrk->busyobj->do_esi || sp->esi_level > 0)
        wrk->busyobj->do_stream = 0;
    if (!sp->wantbody)
        wrk->busyobj->do_stream = 0;

    l = http_EstimateWS(wrk->busyobj->beresp,
                        pass ? HTTPH_R_PASS : HTTPH_A_INS, &nhttp);

    /* Create Vary instructions */
    if (wrk->objcore != NULL) {
        CHECK_OBJ_NOTNULL(wrk->objcore, OBJCORE_MAGIC);
        vary = VRY_Create(sp, wrk->busyobj->beresp);
        if (vary != NULL) {
            varyl = VSB_len(vary);
            assert(varyl > 0);
            l += varyl;
        }
    }

    /*
     * Space for producing a Content-Length: header including padding
     * A billion gigabytes is enough for anybody.
     */
    l += strlen("Content-Length: XxxXxxXxxXxxXxxXxx") + sizeof(void *);

    if (wrk->busyobj->exp.ttl < cache_param->shortlived ||
            wrk->objcore == NULL)
        wrk->storage_hint = TRANSIENT_STORAGE;

    wrk->obj = STV_NewObject(wrk, wrk->storage_hint, l, nhttp);
    if (wrk->obj == NULL) {
        /*
         * Try to salvage the transaction by allocating a
         * shortlived object on Transient storage.
         */
        wrk->obj = STV_NewObject(wrk, TRANSIENT_STORAGE, l, nhttp);
        if (wrk->busyobj->exp.ttl > cache_param->shortlived)
            wrk->busyobj->exp.ttl = cache_param->shortlived;
        wrk->busyobj->exp.grace = 0.0;
        wrk->busyobj->exp.keep = 0.0;
    }
    if (wrk->obj == NULL) {
        sp->err_code = 503;
        sp->step = STP_ERROR;
        VDI_CloseFd(wrk, &wrk->busyobj->vbc);
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        return (0);
    }
    CHECK_OBJ_NOTNULL(wrk->obj, OBJECT_MAGIC);

    wrk->storage_hint = NULL;

    if (wrk->busyobj->do_gzip ||
            (wrk->busyobj->is_gzip && !wrk->busyobj->do_gunzip))
        wrk->obj->gziped = 1;

    if (vary != NULL) {
        wrk->obj->vary = (void *)WS_Alloc(wrk->obj->http->ws, varyl);
        AN(wrk->obj->vary);
        memcpy(wrk->obj->vary, VSB_data(vary), varyl);
        VRY_Validate(wrk->obj->vary);
        VSB_delete(vary);
    }

    wrk->obj->xid = sp->xid;
    wrk->obj->response = sp->err_code;
    WS_Assert(wrk->obj->ws_o);

    /* Filter into object */
    hp = wrk->busyobj->beresp;
    hp2 = wrk->obj->http;

    hp2->logtag = HTTP_Obj;
    http_CopyResp(hp2, hp);
    http_FilterFields(wrk, sp->vsl_id, hp2, hp,
                      pass ? HTTPH_R_PASS : HTTPH_A_INS);
    http_CopyHome(wrk, sp->vsl_id, hp2);

    if (http_GetHdr(hp, H_Last_Modified, &b))
        wrk->obj->last_modified = VTIM_parse(b);
    else
        wrk->obj->last_modified = floor(wrk->busyobj->exp.entered);

    assert(WRW_IsReleased(wrk));

    /*
     * If we can deliver a 304 reply, we don't bother streaming.
     * Notice that vcl_deliver{} could still nuke the headers
     * that allow the 304, in which case we return 200 non-stream.
     */
    if (wrk->obj->response == 200 &&
            sp->http->conds &&
            RFC2616_Do_Cond(sp))
        wrk->busyobj->do_stream = 0;

    AssertObjCorePassOrBusy(wrk->obj->objcore);

    if (wrk->busyobj->do_stream) {
        sp->step = STP_PREPRESP;
        return (0);
    }

    /* Use unmodified headers*/
    i = FetchBody(wrk, wrk->obj);

    http_Setup(wrk->busyobj->bereq, NULL);
    http_Setup(wrk->busyobj->beresp, NULL);
    wrk->busyobj->vfp = NULL;
    assert(WRW_IsReleased(wrk));
    AZ(wrk->busyobj->vbc);
    AN(sp->director);

    if (i) {
        HSH_Drop(wrk);
        VBO_DerefBusyObj(wrk, &wrk->busyobj);
        AZ(wrk->obj);
        sp->err_code = 503;
        sp->step = STP_ERROR;
        return (0);
    }

    if (wrk->obj->objcore != NULL) {
        EXP_Insert(wrk->obj);
        AN(wrk->obj->objcore);
        AN(wrk->obj->objcore->ban);
        HSH_Unbusy(wrk);
    }
    VBO_DerefBusyObj(wrk, &wrk->busyobj);
    wrk->acct_tmp.fetch++;
    sp->step = STP_PREPRESP;
    return (0);
}
Пример #17
0
{
	struct vsmwseg *seg;

	vsmw_lock();
	CHECK_OBJ_NOTNULL(vsmw, VSMW_MAGIC);
	(void)vc;

	ALLOC_OBJ(seg, VSMWSEG_MAGIC);
	AN(seg);
	REPLACE(seg->class, class);
	seg->len = PRNDUP(payload);

	VSB_clear(vsmw->vsb);
	VSB_vprintf(vsmw->vsb, fmt, va);
	AZ(VSB_finish(vsmw->vsb));
	REPLACE(seg->id, VSB_data(vsmw->vsb));

	if (vc == NULL)
		vc = vsmw_newcluster(vsmw, seg->len, class);
	AN(vc);
	vc->refs++;

	seg->cluster = vc;
	seg->off = vc->next;
	vc->next += seg->len;
	assert(vc->next <= vc->len);
	seg->ptr = seg->off + (char*)vc->ptr;

	vsmw_addseg(vsmw, seg);

	vsmw_unlock();
Пример #18
0
struct vsb *
VRY_Create(const struct sess *sp, const struct http *hp)
{
	char *v, *p, *q, *h, *e;
	struct vsb *sb, *sbh;
	int l;

	/* No Vary: header, no worries */
	if (!http_GetHdr(hp, H_Vary, &v))
		return (NULL);

	/* For vary matching string */
	sb = VSB_new_auto();
	AN(sb);

	/* For header matching strings */
	sbh = VSB_new_auto();
	AN(sbh);

	if (*v == ':') {
		WSP(sp, SLT_Error, "Vary header had extra ':', fix backend");
		v++;
	}
	for (p = v; *p; p++) {

		/* Find next header-name */
		if (vct_issp(*p))
			continue;
		for (q = p; *q && !vct_issp(*q) && *q != ','; q++)
			continue;

		/* Build a header-matching string out of it */
		VSB_clear(sbh);
		VSB_printf(sbh, "%c%.*s:%c",
		    (char)(1 + (q - p)), (int)(q - p), p, 0);
		AZ(VSB_finish(sbh));

		if (http_GetHdr(sp->http, VSB_data(sbh), &h)) {
			AZ(vct_issp(*h));
			/* Trim trailing space */
			e = strchr(h, '\0');
			while (e > h && vct_issp(e[-1]))
				e--;
			/* Encode two byte length and contents */
			l = e - h;
			assert(!(l & ~0xffff));
		} else {
			e = h;
			l = 0xffff;
		}
		VSB_printf(sb, "%c%c", (unsigned)l >> 8, l & 0xff);
		/* Append to vary matching string */
		VSB_bcat(sb, VSB_data(sbh), VSB_len(sbh));
		if (e != h)
			VSB_bcat(sb, h, e - h);

		while (vct_issp(*q))
			q++;
		if (*q == '\0')
			break;
		xxxassert(*q == ',');
		p = q;
	}
	/* Terminate vary matching string */
	VSB_printf(sb, "%c%c%c", 0xff, 0xff, 0);

	VSB_delete(sbh);
	AZ(VSB_finish(sb));
	return(sb);
}
Пример #19
0
const char *
BAN_Commit(struct ban_proto *bp)
{
	struct ban  *b, *bi;
	ssize_t ln;
	double t0;

	CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
	AN(bp->vsb);

	if (ban_shutdown)
		return (ban_error(bp, "Shutting down"));

	AZ(VSB_finish(bp->vsb));
	ln = VSB_len(bp->vsb);
	assert(ln >= 0);

	ALLOC_OBJ(b, BAN_MAGIC);
	if (b == NULL)
		return (ban_error(bp, ban_build_err_no_mem));
	VTAILQ_INIT(&b->objcore);

	b->spec = malloc(ln + BANS_HEAD_LEN);
	if (b->spec == NULL) {
		free(b);
		return (ban_error(bp, ban_build_err_no_mem));
	}

	b->flags = bp->flags;

	memset(b->spec, 0, BANS_HEAD_LEN);
	t0 = VTIM_real();
	memcpy(b->spec + BANS_TIMESTAMP, &t0, sizeof t0);
	b->spec[BANS_FLAGS] = b->flags & 0xff;
	memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln);
	ln += BANS_HEAD_LEN;
	vbe32enc(b->spec + BANS_LENGTH, ln);

	Lck_Lock(&ban_mtx);
	if (ban_shutdown) {
		/* We could have raced a shutdown */
		Lck_Unlock(&ban_mtx);
		BAN_Free(b);
		return (ban_error(bp, "Shutting down"));
	}
	bi = VTAILQ_FIRST(&ban_head);
	VTAILQ_INSERT_HEAD(&ban_head, b, list);
	ban_start = b;

	VSC_C_main->bans++;
	VSC_C_main->bans_added++;
	VSC_C_main->bans_persisted_bytes += ln;

	if (b->flags & BANS_FLAG_OBJ)
		VSC_C_main->bans_obj++;
	if (b->flags & BANS_FLAG_REQ)
		VSC_C_main->bans_req++;

	if (bi != NULL)
		ban_info_new(b->spec, ln);	/* Notify stevedores */

	if (cache_param->ban_dups) {
		/* Hunt down duplicates, and mark them as completed */
		for (bi = VTAILQ_NEXT(b, list); bi != NULL;
		    bi = VTAILQ_NEXT(bi, list)) {
			if (!(bi->flags & BANS_FLAG_COMPLETED) &&
			    ban_equal(b->spec, bi->spec)) {
				ban_mark_completed(bi);
				VSC_C_main->bans_dups++;
			}
		}
	}
	if (!(b->flags & BANS_FLAG_REQ))
		ban_kick_lurker();
	Lck_Unlock(&ban_mtx);

	BAN_Abandon(bp);
	return (NULL);
}
Пример #20
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);
}
Пример #21
0
char *
mgt_VccCompile(struct cli *cli, struct vclprog *vcl, const char *vclname,
    const char *vclsrc, const char *vclsrcfile, int C_flag)
{
	struct vcc_priv vp;
	struct vsb *sb;
	unsigned status;
	char buf[1024];
	FILE *fcs;
	char **av;
	int ac;

	AN(cli);

	sb = VSB_new_auto();
	XXXAN(sb);

	INIT_OBJ(&vp, VCC_PRIV_MAGIC);
	vp.vclsrc = vclsrc;
	vp.vclsrcfile = vclsrcfile;

	/*
	 * The subdirectory must have a unique name to 100% certain evade
	 * the refcounting semantics of dlopen(3).
	 *
	 * Bad implementations of dlopen(3) think the shlib you are opening
	 * is the same, if the filename is the same as one already opened.
	 *
	 * Sensible implementations do a stat(2) and requires st_ino and
	 * st_dev to also match.
	 *
	 * A correct implementation would run on filesystems which tickle
	 * st_gen, and also insist that be the identical, before declaring
	 * a match.
	 *
	 * Since no correct implementations are known to exist, we are subject
	 * to really interesting races if you do something like:
	 *
	 *	(running on 'boot' vcl)
	 *	vcl.load foo /foo.vcl
	 *	vcl.use foo
	 *	few/slow requests
	 *	vcl.use boot
	 *	vcl.discard foo
	 *	vcl.load foo /foo.vcl	// dlopen(3) says "same-same"
	 *	vcl.use foo
	 *
	 * Because discard of the first 'foo' lingers on non-zero reference
	 * count, and when it finally runs, it trashes the second 'foo' because
	 * dlopen(3) decided they were really the same thing.
	 *
	 * The Best way to reproduce this is to have regexps in the VCL.
	 */
	VSB_printf(sb, "vcl_%s.%.9f", vclname, VTIM_real());
	AZ(VSB_finish(sb));
	vp.dir = strdup(VSB_data(sb));
	AN(vp.dir);

	if (VJ_make_subdir(vp.dir, "VCL", cli->sb)) {
		free(vp.dir);
		VSB_destroy(&sb);
		VCLI_Out(cli, "VCL compilation failed");
		VCLI_SetResult(cli, CLIS_PARAM);
		return (NULL);
	}

	VSB_clear(sb);
	VSB_printf(sb, "%s/%s", vp.dir, VGC_SRC);
	AZ(VSB_finish(sb));
	vp.csrcfile = strdup(VSB_data(sb));
	AN(vp.csrcfile);
	VSB_clear(sb);

	VSB_printf(sb, "%s/%s", vp.dir, VGC_LIB);
	AZ(VSB_finish(sb));
	vp.libfile = strdup(VSB_data(sb));
	AN(vp.csrcfile);
	VSB_clear(sb);

	status = mgt_vcc_compile(&vp, sb, C_flag);

	AZ(VSB_finish(sb));
	if (VSB_len(sb) > 0)
		VCLI_Out(cli, "%s", VSB_data(sb));
	VSB_destroy(&sb);

	if (status || C_flag) {
		(void)unlink(vp.csrcfile);
		free(vp.csrcfile);
		(void)unlink(vp.libfile);
		free(vp.libfile);
		(void)rmdir(vp.dir);
		free(vp.dir);
		if (status) {
			VCLI_Out(cli, "VCL compilation failed");
			VCLI_SetResult(cli, CLIS_PARAM);
		}
		return (NULL);
	}

	fcs = fopen(vp.csrcfile, "r");
	AN(fcs);
	while (1) {
		AN(fgets(buf, sizeof buf, fcs));
		if (memcmp(buf, VCC_INFO_PREFIX, strlen(VCC_INFO_PREFIX)))
			break;
		av = VAV_Parse(buf, &ac, 0);
		AN(av);
		AZ(av[0]);
		AZ(strcmp(av[1], "/*"));
		AZ(strcmp(av[ac-1], "*/"));
		if (!strcmp(av[3], "VCL"))
			mgt_vcl_depends(vcl, av[4]);
		else if (!strcmp(av[3], "VMOD"))
			mgt_vcl_vmod(vcl, av[4], av[5]);
		else
			WRONG("Wrong VCCINFO");
		VAV_Free(av);
	}
	AZ(fclose(fcs));

	(void)unlink(vp.csrcfile);
	free(vp.csrcfile);

	free(vp.dir);

	VCLI_Out(cli, "VCL compiled.\n");

	return (vp.libfile);
}
Пример #22
0
static char
*test_HDR_List(void)
{
    struct hdrt_node *hdrt;
    struct vsb *sb = VSB_new_auto();

    printf("... testing HDR_List()\n");

    HDR_List(NULL, sb);
    VSB_finish(sb);
    MASSERT(VSB_error(sb) == 0);
    MASSERT(VSB_len(sb) == 0);

    VSB_clear(sb);
    hdrt = HDR_InsertIdx(NULL, "Foo", 4711);
    HDR_List(hdrt, sb);
    VSB_finish(sb);
    MASSERT(VSB_error(sb) == 0);
    MASSERT(strcasecmp(VSB_data(sb), "Foo,") == 0);

#define EXP "Accept,Accept-Charset,Accept-Datetime,Accept-Encoding," \
            "Accept-Language,"
    VSB_clear(sb);
    hdrt = HDR_InsertIdx(NULL, "Accept-Encoding", 1);
    hdrt = HDR_InsertIdx(hdrt, "Accept", 2);
    hdrt = HDR_InsertIdx(hdrt, "Accept-Charset", 3);
    hdrt = HDR_InsertIdx(hdrt, "Accept-Language", 4);
    hdrt = HDR_InsertIdx(hdrt, "Accept-Datetime", 5);
    HDR_List(hdrt, sb);
    VSB_finish(sb);
    MASSERT(VSB_error(sb) == 0);
    MASSERT(strcasecmp(VSB_data(sb), EXP) == 0);
#undef EXP

#define EXP "Content-Disposition,Content-Encoding,Content-Language," \
            "Content-Length,Content-Location,Content-MD5,Content-Range," \
            "Content-Type,"
    VSB_clear(sb);
    hdrt = HDR_InsertIdx(NULL, "Content-Disposition", 1);
    hdrt = HDR_InsertIdx(hdrt, "Content-Encoding", 2);
    hdrt = HDR_InsertIdx(hdrt, "Content-Language", 3);
    hdrt = HDR_InsertIdx(hdrt, "Content-Length", 4);
    hdrt = HDR_InsertIdx(hdrt, "Content-Location", 5);
    hdrt = HDR_InsertIdx(hdrt, "Content-MD5", 6);
    hdrt = HDR_InsertIdx(hdrt, "Content-Range", 7);
    hdrt = HDR_InsertIdx(hdrt, "Content-Type", 8);
    HDR_List(hdrt, sb);
    VSB_finish(sb);
    MASSERT(VSB_error(sb) == 0);
    MASSERT(strcasecmp(VSB_data(sb), EXP) == 0);
#undef EXP

#define EXP "X-Csrf-Token,X-Forwarded-For,X-Forwarded-Host,X-Forwarded-Proto,"
    VSB_clear(sb);
    hdrt = HDR_InsertIdx(NULL, "X-Csrf-Token", 1);
    hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-For", 2);
    hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Host", 3);
    hdrt = HDR_InsertIdx(hdrt, "X-Forwarded-Proto", 4);
    HDR_List(hdrt, sb);
    VSB_finish(sb);
    MASSERT(VSB_error(sb) == 0);
    MASSERT(strcasecmp(VSB_data(sb), EXP) == 0);
#undef EXP

#define EXP "Bereq,Beresp,BerespBody,"
    VSB_clear(sb);
    hdrt = HDR_InsertIdx(NULL, "Beresp", 0);
    hdrt = HDR_InsertIdx(hdrt, "BerespBody", 1);
    hdrt = HDR_InsertIdx(hdrt, "Bereq", 2);
    HDR_List(hdrt, sb);
    VSB_finish(sb);
    MASSERT(VSB_error(sb) == 0);
    MASSERT(strcasecmp(VSB_data(sb), EXP) == 0);
#undef EXP

    VSB_destroy(&sb);

    return NULL;
}
Пример #23
0
static enum fetch_step
vbf_stp_error(struct worker *wrk, struct busyobj *bo)
{
	ssize_t l, ll, o;
	double now;
	uint8_t *ptr;
	char time_str[VTIM_FORMAT_SIZE];

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
	assert(bo->director_state == DIR_S_NULL);

	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_PutResponse(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->fetch_objcore->exp.t_origin = bo->t_prev;
	bo->fetch_objcore->exp.ttl = 0;
	bo->fetch_objcore->exp.grace = 0;
	bo->fetch_objcore->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);
		return (F_STP_FAIL);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	VFP_Setup(bo->vfc);
	bo->vfc->bo = bo;
	bo->vfc->wrk = bo->wrk;
	bo->vfc->oc = bo->fetch_objcore;
	bo->vfc->http = bo->beresp;
	bo->vfc->esi_req = bo->bereq;

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

	ll = VSB_len(bo->synth_body);
	o = 0;
	while (ll > 0) {
		l = ll;
		if (VFP_GetStorage(bo->vfc, &l, &ptr) != VFP_OK)
			break;
		memcpy(ptr, VSB_data(bo->synth_body) + o, l);
		VBO_extend(bo, l);
		ll -= l;
		o += l;
	}
	VSB_delete(bo->synth_body);
	bo->synth_body = NULL;

	HSH_Unbusy(wrk, bo->fetch_objcore);
	VBO_setstate(bo, BOS_FINISHED);
	return (F_STP_DONE);
}
Пример #24
0
static void
vcc_ParseProbeSpec(struct vcc *tl, const struct symbol *sym, char **name)
{
	struct fld_spec *fs;
	struct token *t_field;
	struct token *t_did = NULL, *t_window = NULL, *t_threshold = NULL;
	struct token *t_initial = NULL;
	struct vsb *vsb;
	char *retval;
	unsigned window, threshold, initial, status;
	double t;

	fs = vcc_FldSpec(tl,
	    "?url",
	    "?request",
	    "?expected_response",
	    "?timeout",
	    "?interval",
	    "?window",
	    "?threshold",
	    "?initial",
	    NULL);

	SkipToken(tl, '{');

	vsb = VSB_new_auto();
	AN(vsb);
	if (sym != NULL)
		VSB_cat(vsb, sym->rname);
	else
		VSB_printf(vsb, "vgc_probe__%d", tl->nprobe++);
	AZ(VSB_finish(vsb));
	retval = TlDup(tl, VSB_data(vsb));
	AN(retval);
	VSB_destroy(&vsb);
	if (name != NULL)
		*name = retval;

	window = 0;
	threshold = 0;
	initial = 0;
	status = 0;
	Fh(tl, 0, "static const struct vrt_backend_probe %s[] = {{\n", retval);
	Fh(tl, 0, "\t.magic = VRT_BACKEND_PROBE_MAGIC,\n");
	while (tl->t->tok != '}') {

		vcc_IsField(tl, &t_field, fs);
		ERRCHK(tl);
		if (vcc_IdIs(t_field, "url")) {
			vcc_Redef(tl, "Probe request", &t_did, t_field);
			ERRCHK(tl);
			ExpectErr(tl, CSTR);
			Fh(tl, 0, "\t.url = ");
			EncToken(tl->fh, tl->t);
			Fh(tl, 0, ",\n");
			vcc_NextToken(tl);
		} else if (vcc_IdIs(t_field, "request")) {
			vcc_Redef(tl, "Probe request", &t_did, t_field);
			ERRCHK(tl);
			ExpectErr(tl, CSTR);
			Fh(tl, 0, "\t.request =\n");
			while (tl->t->tok == CSTR) {
				Fh(tl, 0, "\t\t");
				EncToken(tl->fh, tl->t);
				Fh(tl, 0, " \"\\r\\n\"\n");
				vcc_NextToken(tl);
			}
			Fh(tl, 0, "\t\t\"\\r\\n\",\n");
		} else if (vcc_IdIs(t_field, "timeout")) {
			Fh(tl, 0, "\t.timeout = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fh(tl, 0, "%g,\n", t);
		} else if (vcc_IdIs(t_field, "interval")) {
			Fh(tl, 0, "\t.interval = ");
			vcc_Duration(tl, &t);
			ERRCHK(tl);
			Fh(tl, 0, "%g,\n", t);
		} else if (vcc_IdIs(t_field, "window")) {
			t_window = tl->t;
			window = vcc_UintVal(tl);
			ERRCHK(tl);
		} else if (vcc_IdIs(t_field, "initial")) {
			t_initial = tl->t;
			initial = vcc_UintVal(tl);
			ERRCHK(tl);
		} else if (vcc_IdIs(t_field, "expected_response")) {
			status = vcc_UintVal(tl);
			if (status < 100 || status > 999) {
				VSB_printf(tl->sb,
				    "Must specify .expected_response with "
				    "exactly three digits "
				    "(100 <= x <= 999)\n");
				vcc_ErrWhere(tl, tl->t);
				return;
			}
			ERRCHK(tl);
		} else if (vcc_IdIs(t_field, "threshold")) {
			t_threshold = tl->t;
			threshold = vcc_UintVal(tl);
			ERRCHK(tl);
		} else {
			vcc_ErrToken(tl, t_field);
			vcc_ErrWhere(tl, t_field);
			ErrInternal(tl);
			return;
		}

		SkipToken(tl, ';');
	}

	if (t_threshold != NULL || t_window != NULL) {
		if (t_threshold == NULL && t_window != NULL) {
			VSB_printf(tl->sb,
			    "Must specify .threshold with .window\n");
			vcc_ErrWhere(tl, t_window);
			return;
		} else if (t_threshold != NULL && t_window == NULL) {
			if (threshold > 64) {
				VSB_printf(tl->sb,
				    "Threshold must be 64 or less.\n");
				vcc_ErrWhere(tl, t_threshold);
				return;
			}
			window = threshold + 1;
		} else if (window > 64) {
			AN(t_window);
			VSB_printf(tl->sb, "Window must be 64 or less.\n");
			vcc_ErrWhere(tl, t_window);
			return;
		}
		if (threshold > window ) {
			VSB_printf(tl->sb,
			    "Threshold can not be greater than window.\n");
			AN(t_threshold);
			vcc_ErrWhere(tl, t_threshold);
			AN(t_window);
			vcc_ErrWhere(tl, t_window);
		}
		Fh(tl, 0, "\t.window = %u,\n", window);
		Fh(tl, 0, "\t.threshold = %u,\n", threshold);
	}
	if (t_initial != NULL)
		Fh(tl, 0, "\t.initial = %u,\n", initial);
	else
		Fh(tl, 0, "\t.initial = ~0U,\n");
	if (status > 0)
		Fh(tl, 0, "\t.exp_status = %u,\n", status);
	Fh(tl, 0, "}};\n");
	SkipToken(tl, '}');
}
Пример #25
0
static unsigned int vlog_reply(struct http_request *request, void *data)
{
	struct vlog_priv_t *vlog;
	int ret;
	char *limit = NULL;
	char *p;
	char *tag = NULL;
	char *itag = NULL;
	struct agent_core_t *core = data;
	GET_PRIV(data,vlog);
	p = next_slash(request->url + 1);

	assert(vlog->tag==NULL);
	assert(vlog->answer == NULL);

	if (p) {
		limit = strdup(p);
		assert(limit);
		char *tmp2 = index(limit,'/');
		if (tmp2 && *tmp2) *tmp2 = '\0';

		if(!(atoi(limit) > 0)) {
			free(limit);
			send_response_fail(request->connection,"Not a number");
			return 0;
		}
		p = next_slash(p);
	}
	if (p) {
		tag = strdup(p);
		char *tmp2 = index(tag,'/');
		if (tmp2 && *tmp2) *tmp2 = '\0';
		p = next_slash(p);
	}
	if (p) {
		itag = strdup(p);
		char *tmp2 = index(itag,'/');
		if (tmp2 && *tmp2) *tmp2 = '\0';
		p = next_slash(p);
	}
	vlog->answer = VSB_new_auto();
	assert(vlog->answer != NULL);
	vlog->vd = VSM_New();
	assert(VSL_Arg(vlog->vd, 'n', core->config->n_arg));
	VSL_Setup(vlog->vd);
	VSL_Arg(vlog->vd, 'd', "");
	if (tag) {
		VSL_Arg(vlog->vd, 'i', tag);
		if (itag)
			VSL_Arg(vlog->vd,'I',itag);
	} else {
		VSL_Arg(vlog->vd, 'k', limit ? limit : "10");
	}

	if (limit)
		free(limit);
	VSB_printf(vlog->answer, "{ \"log\": [");
	ret = VSL_Open(vlog->vd, 1);
	if (ret) {
		send_response_fail(request->connection, "Error in opening shmlog");
		goto cleanup;
	}

	if (tag == NULL) {
		do_order(vlog);
	} else {
		do_unorder(vlog);
	}

	VSB_printf(vlog->answer, "\n] }\n");
	assert(VSB_finish(vlog->answer) == 0);
	if (VSB_len(vlog->answer) > 1) {
		struct http_response *resp = http_mkresp(request->connection, 200, NULL);
		resp->data = VSB_data(vlog->answer);
		resp->ndata = VSB_len(vlog->answer);
		http_add_header(resp,"Content-Type","application/json");
		send_response2(resp);
		http_free_resp(resp);
	} else {
		send_response_fail(request->connection, "FAIL");
	}

 cleanup:
	free(tag);
	free(itag);
	VSB_clear(vlog->answer);
	VSB_delete(vlog->answer);
	VSM_Delete(vlog->vd);
	vlog->answer = NULL;
	vlog->entries = 0;
	return 0;
}