VED_Deliver(struct req *req, struct busyobj *bo, int wantbody)
{
	int i;
	struct ecx *ecx;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_ORNULL(bo, BUSYOBJ_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, bo);
	} 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);
	}
	VDP_close(req);
}
Esempio n. 2
0
V1D_Deliver(struct req *req, struct boc *boc, int sendbody)
{
	int err = 0;

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

	if (sendbody) {
		if (http_GetHdr(req->resp, H_Content_Length, NULL))
			req->res_mode |= RES_LEN;
		else 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");

	if (sendbody && req->resp_len != 0)
		VDP_push(req, v1d_bytes, NULL, 1);

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

	if (WS_Overflowed(req->ws)) {
		v1d_error(req, "workspace_client overflow");
		AZ(req->wrk->v1l);
		return;
	}

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

	if (sendbody && req->resp_len != 0) {
		if (req->res_mode & RES_CHUNKED)
			V1L_Chunked(req->wrk);
		err = VDP_DeliverObj(req);
		if (!err && (req->res_mode & RES_CHUNKED))
			V1L_EndChunk(req->wrk);
	}

	if ((V1L_FlushRelease(req->wrk) || err) && req->sp->fd >= 0)
		SES_Close(req->sp, SC_REM_CLOSE);
	AZ(req->wrk->v1l);
	VDP_close(req);
}
Esempio n. 3
0
h2_deliver(struct req *req, struct boc *boc, int sendbody)
{
	ssize_t sz, sz1;
	uint8_t *p;
	unsigned u;
	const char *r;
	struct http *hp;
	struct sess *sp;
	struct h2_req *r2;
	int i, err;
	const struct hpack_static *hps;

	CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
	CHECK_OBJ_ORNULL(boc, BOC_MAGIC);
	CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
	CAST_OBJ_NOTNULL(r2, req->transport_priv, H2_REQ_MAGIC);
	sp = req->sp;
	CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
	(void)sendbody;

	VSLb(req->vsl, SLT_Debug, "H2: Deliver");

	(void)WS_Reserve(req->ws, 0);
	p = (void*)req->ws->f;

	switch (req->resp->status) {
	case 200: *p++ = 0x80 |  8; break;
	case 204: *p++ = 0x80 |  9; break;
	case 206: *p++ = 0x80 | 10; break;
	case 304: *p++ = 0x80 | 11; break;
	case 400: *p++ = 0x80 | 12; break;
	case 404: *p++ = 0x80 | 13; break;
	case 500: *p++ = 0x80 | 14; break;
	default:
		*p++ = 0x18;
		*p++ = 0x03;

		(void)sprintf((char*)p, "%03d", req->resp->status);
		p += 3;
		break;
	}

	hp = req->resp;
	for (u = HTTP_HDR_FIRST; u < hp->nhd; u++) {
		assert((char*)p < req->ws->e);

		r = strchr(hp->hd[u].b, ':');
		AN(r);

		hps = hp_idx[tolower(*hp->hd[u].b)];
		sz = 1 + r - hp->hd[u].b;
		assert(sz > 0);
		while (hps != NULL && hps->idx > 0) {
			i = strncasecmp(hps->name, hp->hd[u].b, sz);
			if (i < 0) {
				hps++;
				continue;
			}
			if (i > 0)
				hps = NULL;
			break;
		}
		if (hps != NULL) {
			VSLb(req->vsl, SLT_Debug,
			    "HP {%d, \"%s\", \"%s\"} <%s>",
			    hps->idx, hps->name, hps->val, hp->hd[u].b);
			if (hps->idx < 15) {
				*p++ = 0x10 | hps->idx;
			} else {
				*p++ = 0x1f;
				*p++ = hps->idx - 0x0f;
			}
		} else {

			*p++ = 0x10;
			sz--;
			if (sz < 127) {
				*p++ = (uint8_t)sz;
			} else {
				*p++ = 0x7f;
				*p++ = (uint8_t)sz - 0x7f;
			}

			for(sz1 = 0; sz1 < sz; sz1++)
				*p++ = (uint8_t)tolower(hp->hd[u].b[sz1]);

		}

		while(vct_islws(*++r))
			continue;
		sz = hp->hd[u].e - r;
		assert(sz <= 254);
		if (sz < 127) {
			*p++ = (uint8_t)sz;
		} else if (sz < 127 * 2) {
			*p++ = 0x7f;
			*p++ = (uint8_t)sz - 0x7f;
		}

		memcpy(p, r, sz);
		p += sz;
		assert((char*)p < req->ws->e);
	}
	sz = (char*)p - req->ws->f;

	/* XXX: Optimize !sendbody case */
	H2_Send(req->wrk, r2, 1, H2_FRAME_HEADERS, H2FF_HEADERS_END_HEADERS,
	    sz, req->ws->f);

	WS_Release(req->ws, 0);

	if (sendbody && req->resp_len != 0)
		VDP_push(req, h2_bytes, NULL, 1, "H2");

	AZ(req->wrk->v1l);

	if (sendbody && req->resp_len != 0)
		err = VDP_DeliverObj(req);
	/*XXX*/(void)err;

	H2_Send(req->wrk, r2, 1, H2_FRAME_DATA, H2FF_DATA_END_STREAM, 0, NULL);

	AZ(req->wrk->v1l);
	VDP_close(req);
}
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);
}