Ejemplo n.º 1
0
VDP_gunzip(struct req *req, enum vdp_action act, void **priv,
    const void *ptr, ssize_t len)
{
	enum vgzret_e vr;
	ssize_t dl;
	const void *dp;
	struct worker *wrk;
	struct vgz *vg;
	const char *p;
	uint64_t u;

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

	if (act == VDP_INIT) {
		vg = VGZ_NewUngzip(req->vsl, "U D -");
		AN(vg);
		if (vgz_getmbuf(vg)) {
			(void)VGZ_Destroy(&vg);
			return (-1);
		}

		req->res_mode |= RES_GUNZIP;
		VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
		*priv = vg;

		http_Unset(req->resp, H_Content_Encoding);

		req->resp_len = -1;
		if (req->objcore->boc != NULL)
			return (0);	/* No idea about length (yet) */

		p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &dl);
		if (p == NULL || dl != 32)
			return (0); /* No OA_GZIPBITS yet */

		u = vbe64dec(p + 24);
		/*
		 * If the size is non-zero AND we are the top
		 * VDP (ie: no ESI), we know what size the output will be.
		 */
		if (u != 0 && VTAILQ_FIRST(&req->vdp)->func == VDP_gunzip)
			req->resp_len = u;

		return (0);
	}

	CAST_OBJ_NOTNULL(vg, *priv, VGZ_MAGIC);
	AN(vg->m_buf);

	if (act == VDP_FINI) {
		/* NB: Gunzip'ing may or may not have completed successfully. */
		AZ(len);
		(void)VGZ_Destroy(&vg);
		*priv = NULL;
		return (0);
	}

	if (len == 0)
		return (0);

	VGZ_Ibuf(vg, ptr, len);
	do {
		vr = VGZ_Gunzip(vg, &dp, &dl);
		vg->m_len += dl;
		if (vr < VGZ_OK)
			return (-1);
		if (vg->m_len == vg->m_sz || vr != VGZ_OK) {
			if (VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len))
				return (req->vdp_retval);
			vg->m_len = 0;
			VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
		}
	} while (!VGZ_IbufEmpty(vg));
	assert(vr == VGZ_STUCK || vr == VGZ_OK || vr == VGZ_END);
	return (0);
}
Ejemplo n.º 2
0
static void
ved_stripgzip(struct req *req, const struct boc *boc)
{
	ssize_t l;
	char *p;
	uint32_t icrc;
	uint32_t ilen;
	uint8_t *dbits;
	struct ecx *ecx;
	struct ved_foo foo;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
	CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);

	INIT_OBJ(&foo, VED_FOO_MAGIC);
	foo.req = req;
	foo.preq = ecx->preq;
	memset(foo.tailbuf, 0xdd, sizeof foo.tailbuf);

	/* OA_GZIPBITS is not valid until BOS_FINISHED */
	if (boc != NULL)
		ObjWaitState(req->objcore, BOS_FINISHED);

	AN(ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED));

	/*
	 * This is the interesting case: Deliver all the deflate
	 * blocks, stripping the "LAST" bit of the last one and
	 * padding it, as necessary, to a byte boundary.
	 */

	p = ObjGetAttr(req->wrk, req->objcore, OA_GZIPBITS, &l);
	AN(p);
	assert(l == 32);
	foo.start = vbe64dec(p);
	foo.last = vbe64dec(p + 8);
	foo.stop = vbe64dec(p + 16);
	foo.olen = ObjGetLen(req->wrk, req->objcore);
	assert(foo.start > 0 && foo.start < foo.olen * 8);
	assert(foo.last > 0 && foo.last < foo.olen * 8);
	assert(foo.stop > 0 && foo.stop < foo.olen * 8);
	assert(foo.last >= foo.start);
	assert(foo.last < foo.stop);

	/* The start bit must be byte aligned. */
	AZ(foo.start & 7);

	dbits = WS_Alloc(req->ws, 8);
	AN(dbits);
	foo.dbits = dbits;
	(void)ObjIterate(req->wrk, req->objcore, &foo, ved_objiterate);
	/* XXX: error check ?? */
	(void)ved_bytes(req, foo.preq, VDP_FLUSH, NULL, 0);

	icrc = vle32dec(foo.tailbuf);
	ilen = vle32dec(foo.tailbuf + 4);

	ecx->crc = crc32_combine(ecx->crc, icrc, ilen);
	ecx->l_crc += ilen;
}
Ejemplo n.º 3
0
static enum req_fsm_nxt
cnt_deliver(struct worker *wrk, struct req *req)
{

	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore->objhead, OBJHEAD_MAGIC);
	AN(req->vcl);

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

	ObjTouch(req->wrk, req->objcore, req->t_prev);

	HTTP_Setup(req->resp, req->ws, req->vsl, SLT_RespMethod);
	if (HTTP_Decode(req->resp,
	    ObjGetAttr(req->wrk, req->objcore, OA_HEADERS, NULL))) {
		req->err_code = 500;
		req->req_step = R_STP_SYNTH;
		return (REQ_FSM_MORE);
	}
	http_ForceField(req->resp, HTTP_HDR_PROTO, "HTTP/1.1");

	if (req->is_hit)
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u %u", VXID(req->vsl->wid),
		    ObjGetXID(wrk, req->objcore));
	else
		http_PrintfHeader(req->resp,
		    "X-Varnish: %u", VXID(req->vsl->wid));

	/*
	 * We base Age calculation upon the last timestamp taken during
	 * client request processing. This gives some inaccuracy, but
	 * since Age is only full second resolution that shouldn't
	 * matter. (Last request timestamp could be a Start timestamp
	 * taken before the object entered into cache leading to negative
	 * age. Truncate to zero in that case).
	 */
	http_PrintfHeader(req->resp, "Age: %.0f",
	    fmax(0., req->t_prev - req->objcore->t_origin));

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

	if (cache_param->http_gzip_support &&
	    ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) &&
	    !RFC2616_Req_Gzip(req->http))
		RFC2616_Weaken_Etag(req->resp);

	VCL_deliver_method(req->vcl, wrk, req, NULL, NULL);
	VSLb_ts_req(req, "Process", W_TIM_real(wrk));

	/* 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_DELIVER) {
		(void)HSH_DerefObjCore(wrk, &req->objcore);
		http_Teardown(req->resp);

		switch (wrk->handling) {
		case VCL_RET_RESTART:
			req->req_step = R_STP_RESTART;
			break;
		case VCL_RET_SYNTH:
			req->req_step = R_STP_SYNTH;
			break;
		default:
			WRONG("Illegal return from vcl_deliver{}");
		}

		return (REQ_FSM_MORE);
	}

	assert(wrk->handling == VCL_RET_DELIVER);

	if (!(req->objcore->flags & OC_F_PASS)
	    && req->esi_level == 0
	    && http_IsStatus(req->resp, 200)
	    && req->http->conds && RFC2616_Do_Cond(req))
		http_PutResponse(req->resp, "HTTP/1.1", 304, NULL);

	req->req_step = R_STP_TRANSMIT;
	return (REQ_FSM_MORE);
}
Ejemplo n.º 4
0
VDP_ESI(struct req *req, enum vdp_action act, void **priv,
    const void *ptr, ssize_t len)
{
	uint8_t *q, *r;
	ssize_t l = 0;
	uint32_t icrc = 0;
	uint8_t tailbuf[8 + 5];
	const uint8_t *pp;
	struct ecx *ecx, *pecx;
	int retval = 0;

	if (act == VDP_INIT) {
		AZ(*priv);
		ALLOC_OBJ(ecx, ECX_MAGIC);
		AN(ecx);
		ecx->preq = req;
		*priv = ecx;
		RFC2616_Weaken_Etag(req->resp);
		req->res_mode |= RES_ESI;
		if (req->resp_len != 0)
			req->resp_len = -1;
		return (0);
	}
	CAST_OBJ_NOTNULL(ecx, *priv, ECX_MAGIC);
	if (act == VDP_FINI) {
		FREE_OBJ(ecx);
		*priv = NULL;
		return (0);
	}
	pp = ptr;

	while (1) {
		switch (ecx->state) {
		case 0:
			ecx->p = ObjGetAttr(req->wrk, req->objcore,
			    OA_ESIDATA, &l);
			AN(ecx->p);
			assert(l > 0);
			ecx->e = ecx->p + l;

			if (*ecx->p == VEC_GZ) {
				ecx->isgzip = 1;
				ecx->p++;
			}

			if (req->esi_level == 0) {
				/*
				 * Only the top level document gets to
				 * decide this.
				 */
				if (ecx->isgzip) {
					assert(sizeof gzip_hdr == 10);
					/* Send out the gzip header */
					retval = VDP_bytes(req, VDP_NULL,
					    gzip_hdr, 10);
					ecx->l_crc = 0;
					ecx->crc = crc32(0L, Z_NULL, 0);
				}
			}
			ecx->state = 1;

			break;
		case 1:
			if (ecx->p >= ecx->e) {
				ecx->state = 2;
				break;
			}
			switch (*ecx->p) {
			case VEC_V1:
			case VEC_V2:
			case VEC_V8:
				ecx->l = ved_decode_len(req, &ecx->p);
				if (ecx->l < 0)
					return (-1);
				if (ecx->isgzip) {
					assert(*ecx->p == VEC_C1 ||
					    *ecx->p == VEC_C2 ||
					    *ecx->p == VEC_C8);
					l = ved_decode_len(req, &ecx->p);
					if (l < 0)
						return (-1);
					icrc = vbe32dec(ecx->p);
					ecx->p += 4;
					if (ecx->isgzip) {
						ecx->crc = crc32_combine(
						    ecx->crc, icrc, l);
						ecx->l_crc += l;
					}
				}
				ecx->state = 3;
				break;
			case VEC_S1:
			case VEC_S2:
			case VEC_S8:
				ecx->l = ved_decode_len(req, &ecx->p);
				if (ecx->l < 0)
					return (-1);
				Debug("SKIP1(%d)\n", (int)ecx->l);
				ecx->state = 4;
				break;
			case VEC_INCL:
				ecx->p++;
				q = (void*)strchr((const char*)ecx->p, '\0');
				AN(q);
				q++;
				r = (void*)strchr((const char*)q, '\0');
				AN(r);
				if (VDP_bytes(req, VDP_FLUSH, NULL, 0)) {
					ecx->p = ecx->e;
					break;
				}
				Debug("INCL [%s][%s] BEGIN\n", q, ecx->p);
				ved_include(req,
				    (const char*)q, (const char*)ecx->p, ecx);
				Debug("INCL [%s][%s] END\n", q, ecx->p);
				ecx->p = r + 1;
				break;
			default:
				VSLb(req->vsl, SLT_Error,
				    "ESI corruption line %d 0x%02x [%s]\n",
				    __LINE__, *ecx->p, ecx->p);
				WRONG("ESI-codes: Illegal code");
			}
			break;
		case 2:
			if (ecx->isgzip && req->esi_level == 0) {
				/*
				 * We are bytealigned here, so simply emit
				 * a gzip literal block with finish bit set.
				 */
				tailbuf[0] = 0x01;
				tailbuf[1] = 0x00;
				tailbuf[2] = 0x00;
				tailbuf[3] = 0xff;
				tailbuf[4] = 0xff;

				/* Emit CRC32 */
				vle32enc(tailbuf + 5, ecx->crc);

				/* MOD(2^32) length */
				vle32enc(tailbuf + 9, ecx->l_crc);

				(void)VDP_bytes(req, VDP_NULL, tailbuf, 13);
			}
			if (req->transport->deliver == VED_Deliver) {
				CAST_OBJ_NOTNULL(pecx, req->transport_priv,
				    ECX_MAGIC);
				pecx->crc = crc32_combine(pecx->crc,
				    ecx->crc, ecx->l_crc);
				pecx->l_crc += ecx->l_crc;
			}
			retval = VDP_bytes(req, VDP_FLUSH, NULL, 0);
			ecx->state = 99;
			return (retval);
		case 3:
		case 4:
			/*
			 * There is no guarantee that the 'l' bytes are all
			 * in the same storage segment, so loop over storage
			 * until we have processed them all.
			 */
			if (ecx->l <= len) {
				if (ecx->state == 3)
					retval = VDP_bytes(req, act,
					    pp, ecx->l);
				len -= ecx->l;
				pp += ecx->l;
				ecx->state = 1;
				break;
			}
			if (ecx->state == 3 && len > 0)
				retval = VDP_bytes(req, act, pp, len);
			ecx->l -= len;
			return (retval);
		case 99:
			/*
			 * VEP does not account for the PAD+CRC+LEN
			 * so we can see up to approx 15 bytes here.
			 */
			return (retval);
		default:
			WRONG("FOO");
			break;
		}
		if (retval)
			return (retval);
	}
}