Пример #1
0
v1d_range_bytes(struct req *req, enum vdp_action act, const void *ptr,
    ssize_t len)
{
	int retval = 0;
	ssize_t l;
	const char *p = ptr;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	l = req->range_low - req->range_off;
	if (l > 0) {
		if (l > len)
			l = len;
		req->range_off += l;
		p += l;
		len -= l;
	}
	l = req->range_high - req->range_off;
	if (l > len)
		l = len;
	if (l > 0)
		retval = VDP_bytes(req, act, p, l);
	else if (act > VDP_NULL)
		retval = VDP_bytes(req, act, p, 0);
	req->range_off += len;
	return (retval);
}
Пример #2
0
static void
v1d_WriteDirObj(struct req *req)
{
	enum objiter_status ois;
	ssize_t len;
	struct objiter *oi;
	void *ptr;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

	oi = ObjIterBegin(req->wrk, req->obj);
	XXXAN(oi);

	do {
		ois = ObjIter(oi, &ptr, &len);
		switch(ois) {
		case OIS_DONE:
			AZ(len);
			break;
		case OIS_ERROR:
			break;
		case OIS_DATA:
		case OIS_STREAM:
			if (VDP_bytes(req,
			     ois == OIS_DATA ? VDP_NULL : VDP_FLUSH,  ptr, len))
				ois = OIS_ERROR;
			break;
		default:
			WRONG("Wrong OIS value");
		}
	} while (ois == OIS_DATA || ois == OIS_STREAM);
	(void)VDP_bytes(req, VDP_FINISH,  NULL, 0);
	ObjIterEnd(&oi);
}
Пример #3
0
/*
 * Account body bytes on req
 * Push bytes to preq
 */
static inline int
ved_bytes(struct req *req, struct req *preq, enum vdp_action act,
    const void *ptr, ssize_t len)
{
	req->acct.resp_bodybytes += len;
	return (VDP_bytes(preq, act, ptr, len));
}
Пример #4
0
VED_Deliver(struct req *req, struct boc *boc, int wantbody)
{
	int i;
	struct ecx *ecx;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_ORNULL(boc, BOC_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);

	CAST_OBJ_NOTNULL(ecx, req->transport_priv, ECX_MAGIC);

	if (wantbody == 0)
		return;

	req->res_mode |= RES_ESI_CHILD;
	i = ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED);
	if (ecx->isgzip && i && !(req->res_mode & RES_ESI)) {
		ved_stripgzip(req, boc);
	} else {
		if (ecx->isgzip && !i)
			VDP_push(req, ved_pretend_gzip, ecx, 1);
		else
			VDP_push(req, ved_vdp_bytes, ecx->preq, 1);
		(void)VDP_DeliverObj(req);
		(void)VDP_bytes(req, VDP_FLUSH, NULL, 0);
	}
	VDP_close(req);
}
Пример #5
0
VDP_dump(struct req *req, enum vdp_action act, void **priv,
    const void *ptr, ssize_t len)
{
	//priv fmt
	// flg(Complete the header output)@1Byte + [workspace]
	if (act == VDP_INIT){
		VSLb(req->vsl, SLT_Debug,"%s-S: RES", VMOD_DUMP_PRE);
		VSLb(req->vsl, SLT_Debug,"%s-V: %s", VMOD_DUMP_PRE, (char *)*priv);
		*priv = malloc(cache_param->vsl_reclen + 1);
		AN(*priv);
		*((char **)priv)[0] = 0;
		return(0);
	}else if(act == VDP_FINI){
		VSLb(req->vsl, SLT_Debug,"%s-S: END", VMOD_DUMP_PRE);
		free(*priv);
		*priv = NULL;
		return(0);
	}

	if(len){
		if(*((char **)priv)[0] == 0){
			work_head(req, *priv+1, cache_param->vsl_reclen,  req->resp,HTTP1_Resp);
			*((char **)priv)[0] = 1;
		}
		work_body(req, *priv+1, cache_param->vsl_reclen,  (void*)ptr, len, req->resp);
	}
	return(VDP_bytes(req, act, ptr, len)); 
}
Пример #6
0
VDP_gunzip(struct req *req, enum vdp_action act, const void *ptr, ssize_t len)
{
	enum vgzret_e vr;
	size_t dl;
	const void *dp;
	struct worker *wrk;
	struct vgz *vg;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	wrk = req->wrk;
	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	vg = req->vgz;
	CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
	AN(vg->m_buf);

	if (len == 0) {
		AN(act > VDP_NULL);
		return (VDP_bytes(req, act, vg->m_buf, vg->m_len));
	}

	VGZ_Ibuf(vg, ptr, len);
	do {
		if (vg->m_len == vg->m_sz)
			vr = VGZ_STUCK;
		else {
			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_STUCK) {
			if (VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len))
				return (-1);
			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);
}
Пример #7
0
enum objiter_status
VDP_DeliverObj(struct req *req)
{
	enum objiter_status ois;
	ssize_t len;
	void *oi;
	void *ptr;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);

	oi = ObjIterBegin(req->wrk, req->objcore);
	XXXAN(oi);
	AZ(req->synth_body);

	do {
		ois = ObjIter(req->objcore, oi, &ptr, &len);
		switch(ois) {
		case OIS_DONE:
			AZ(len);
			break;
		case OIS_ERROR:
			break;
		case OIS_DATA:
		case OIS_STREAM:
			if (VDP_bytes(req,
			     ois == OIS_DATA ? VDP_NULL : VDP_FLUSH,  ptr, len))
				ois = OIS_ERROR;
			break;
		default:
			WRONG("Wrong OIS value");
		}
	} while (ois == OIS_DATA || ois == OIS_STREAM);
	(void)VDP_bytes(req, VDP_FLUSH, NULL, 0);
	ObjIterEnd(req->objcore, &oi);
	return (ois);
}
Пример #8
0
void
VGZ_WrwFlush(struct req *req, struct vgz *vg)
{
	struct worker *wrk;

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

	if (vg->m_len ==  0)
		return;

	(void)VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len);
	vg->m_len = 0;
	VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
}
Пример #9
0
enum vgzret_e
VGZ_WrwGunzip(struct req *req, struct vgz *vg, const void *ibuf,
    ssize_t ibufl)
{
	enum vgzret_e vr;
	size_t dl;
	const void *dp;
	struct worker *wrk;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	wrk = req->wrk;
	CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
	CHECK_OBJ_NOTNULL(vg, VGZ_MAGIC);
	AN(vg->m_buf);
	VGZ_Ibuf(vg, ibuf, ibufl);
	if (ibufl == 0)
		return (VGZ_OK);
	do {
		if (vg->m_len == vg->m_sz)
			vr = VGZ_STUCK;
		else {
			vr = VGZ_Gunzip(vg, &dp, &dl);
			vg->m_len += dl;
		}
		if (vr < VGZ_OK)
			return (vr);
		if (vg->m_len == vg->m_sz || vr == VGZ_STUCK) {
			(void)VDP_bytes(req, VDP_FLUSH, vg->m_buf, vg->m_len);
			vg->m_len = 0;
			VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
		}
	} while (!VGZ_IbufEmpty(vg));
	if (vr == VGZ_STUCK)
		vr = VGZ_OK;
	return (vr);
}
Пример #10
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;
		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);
	}
}
Пример #11
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);
}
Пример #12
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;
	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);
		}
		VGZ_Obuf(vg, vg->m_buf, vg->m_sz);
		*priv = vg;

		http_Unset(req->resp, H_Content_Length);
		p = ObjGetattr(req->wrk, req->objcore, OA_GZIPBITS, &dl);
		if (p != NULL && dl == 32) {
			u = vbe64dec(p + 24);
			/* XXX: Zero is suspect: OA_GZIPBITS wasn't set */
			if (u != 0)
				http_PrintfHeader(req->resp,
				    "Content-Length: %ju", (uintmax_t)u);
		}
		http_Unset(req->resp, H_Content_Encoding);
		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 (-1);
			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);
}
Пример #13
0
void
V1D_Deliver(struct req *req, struct busyobj *bo)
{
	const char *r;
	enum objiter_status ois;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);

	req->res_mode = 0;

	/*
	 * Determine ESI status first.  Not dependent on wantbody, because
	 * we want ESI to supress C-L in HEAD too.
	 */
	if (!req->disable_esi &&
	    ObjGetattr(req->wrk, req->objcore, OA_ESIDATA, NULL) != NULL)
		req->res_mode |= RES_ESI;

	/*
	 * ESI-childen don't care about headers -> early escape
	 */
	if (req->esi_level > 0) {
		ESI_DeliverChild(req, bo);
		return;
	}

	if (req->res_mode & RES_ESI) {
		RFC2616_Weaken_Etag(req->resp);
	} else if (http_IsStatus(req->resp, 304)) {
		http_Unset(req->resp, H_Content_Length);
		req->wantbody = 0;
	} else if (bo == NULL &&
	    !http_GetHdr(req->resp, H_Content_Length, NULL)) {
		http_PrintfHeader(req->resp,
		    "Content-Length: %ju", (uintmax_t)ObjGetLen(
		    req->wrk, req->objcore));
	}

	if (cache_param->http_gzip_support &&
	    ObjCheckFlag(req->wrk, req->objcore, OF_GZIPED) &&
	    !RFC2616_Req_Gzip(req->http)) {
		/*
		 * We don't know what it uncompresses to
		 * XXX: we could cache that, but would still deliver
		 * XXX: with multiple writes because of the gunzip buffer
		 */
		req->res_mode |= RES_GUNZIP;
		VDP_push(req, VDP_gunzip, NULL, 0);
	}

	if (req->res_mode & RES_ESI) {
		/* Gunzip could have added back a C-L */
		http_Unset(req->resp, H_Content_Length);
	}

	/*
	 * Range comes after the others and pushes on bottom because it
	 * can generate a correct C-L header.
	 */
	if (cache_param->http_range_support && http_IsStatus(req->resp, 200)) {
		http_SetHeader(req->resp, "Accept-Ranges: bytes");
		if (req->wantbody && http_GetHdr(req->http, H_Range, &r))
			VRG_dorange(req, bo, r);
	}


	if (http_GetHdr(req->resp, H_Content_Length, NULL))
		req->res_mode |= RES_LEN;

	if (req->wantbody && !(req->res_mode & RES_LEN)) {
		if (req->http->protover >= 11) {
			req->res_mode |= RES_CHUNKED;
			http_SetHeader(req->resp, "Transfer-Encoding: chunked");
		} else {
			req->res_mode |= RES_EOF;
			req->doclose = SC_TX_EOF;
		}
	}

	VSLb(req->vsl, SLT_Debug, "RES_MODE %x", req->res_mode);

	if (req->doclose) {
		if (!http_HdrIs(req->resp, H_Connection, "close")) {
			http_Unset(req->resp, H_Connection);
			http_SetHeader(req->resp, "Connection: close");
		}
	} else if (!http_GetHdr(req->resp, H_Connection, NULL))
		http_SetHeader(req->resp, "Connection: keep-alive");

	VDP_push(req, v1d_bytes, NULL, 1);

	V1L_Reserve(req->wrk, req->ws, &req->sp->fd, req->vsl, req->t_prev);

	req->acct.resp_hdrbytes += HTTP1_Write(req->wrk, req->resp, HTTP1_Resp);
	if (DO_DEBUG(DBG_FLUSH_HEAD))
		(void)V1L_Flush(req->wrk);

	ois = OIS_DONE;
	if (req->wantbody) {
		if (req->res_mode & RES_CHUNKED)
			V1L_Chunked(req->wrk);

		ois = VDP_DeliverObj(req);
		(void)VDP_bytes(req, VDP_FLUSH, NULL, 0);

		if (ois == OIS_DONE && (req->res_mode & RES_CHUNKED))
			V1L_EndChunk(req->wrk);
	}

	if ((V1L_FlushRelease(req->wrk) || ois != OIS_DONE) && req->sp->fd >= 0)
		SES_Close(req->sp, SC_REM_CLOSE);
	VDP_close(req);
}