[master] affd96d Generalize v1f_pull_chunked() into HTTP1_Chunked() which can also be used on requests.

Poul-Henning Kamp phk at FreeBSD.org
Mon Jun 23 11:14:05 CEST 2014


commit affd96d46f7be3e11b2db6747b13271ea9f63246
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Mon Jun 23 09:13:25 2014 +0000

    Generalize v1f_pull_chunked() into HTTP1_Chunked() which can also be
    used on requests.

diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index 38e597b..2b10f59 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -859,6 +859,14 @@ int HTTP1_CacheReqBody(struct req *req, ssize_t maxsize);
 int HTTP1_IterateReqBody(struct req *req, req_body_iter_f *func, void *priv);
 extern const int HTTP1_Req[3];
 extern const int HTTP1_Resp[3];
+enum http1_chunked_ret {
+	H1CR_ERROR,
+	H1CR_MORE,
+	H1CR_END,
+};
+enum http1_chunked_ret
+HTTP1_Chunked(struct http_conn *htc, intptr_t *priv, const char **error,
+    int64_t *statp, void *ptr, ssize_t *lp);
 
 /* cache_http1_deliver.c */
 unsigned V1D_FlushReleaseAcct(struct req *req);
diff --git a/bin/varnishd/cache/cache_http1_fetch.c b/bin/varnishd/cache/cache_http1_fetch.c
index 1c3ef53..aa009f2 100644
--- a/bin/varnishd/cache/cache_http1_fetch.c
+++ b/bin/varnishd/cache/cache_http1_fetch.c
@@ -40,7 +40,6 @@
 
 #include "cache_backend.h"
 #include "vcli_priv.h"
-#include "vct.h"
 #include "vtcp.h"
 #include "vtim.h"
 
@@ -110,10 +109,7 @@ v1f_pull_straight(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
 static enum vfp_status __match_proto__(vfp_pull_f)
 v1f_pull_chunked(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
 {
-	int i;
-	char buf[20];		/* XXX: 20 is arbitrary */
-	unsigned u;
-	ssize_t cl, l, lr;
+	const char *err;
 
 	CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
 	if (p == vfp_init)
@@ -123,77 +119,18 @@ v1f_pull_chunked(struct busyobj *bo, void *p, ssize_t *lp, intptr_t *priv)
 	AN(p);
 	AN(lp);
 	AN(priv);
-	l = *lp;
-	*lp = 0;
-	if (*priv == -1) {
-		/* Skip leading whitespace */
-		do {
-			lr = HTTP1_Read(&bo->htc, buf, 1);
-			if (lr <= 0)
-				return (VFP_Error(bo, "chunked read err"));
-			bo->acct.beresp_bodybytes += lr;
-		} while (vct_islws(buf[0]));
-
-		if (!vct_ishex(buf[0]))
-			 return (VFP_Error(bo, "chunked header non-hex"));
-
-		/* Collect hex digits, skipping leading zeros */
-		for (u = 1; u < sizeof buf; u++) {
-			do {
-				lr = HTTP1_Read(&bo->htc, buf + u, 1);
-				if (lr <= 0)
-					return (VFP_Error(bo,
-					    "chunked read err"));
-				bo->acct.beresp_bodybytes += lr;
-			} while (u == 1 && buf[0] == '0' && buf[u] == '0');
-			if (!vct_ishex(buf[u]))
-				break;
-		}
-
-		if (u >= sizeof buf)
-			return (VFP_Error(bo,"chunked header too long"));
-
-		/* Skip trailing white space */
-		while(vct_islws(buf[u]) && buf[u] != '\n') {
-			lr = HTTP1_Read(&bo->htc, buf + u, 1);
-			if (lr <= 0)
-				return (VFP_Error(bo, "chunked read err"));
-			bo->acct.beresp_bodybytes += lr;
-		}
 
-		if (buf[u] != '\n')
-			return (VFP_Error(bo,"chunked header no NL"));
-
-		buf[u] = '\0';
-
-		cl = vbf_fetch_number(buf, 16);
-		if (cl < 0)
-			return (VFP_Error(bo,"chunked header number syntax"));
-		*priv = cl;
-	}
-	if (*priv > 0) {
-		if (*priv < l)
-			l = *priv;
-		lr = HTTP1_Read(&bo->htc, p, l);
-		if (lr <= 0)
-			return (VFP_Error(bo, "straight insufficient bytes"));
-		bo->acct.beresp_bodybytes += lr;
-		*lp = lr;
-		*priv -= lr;
-		if (*priv == 0)
-			*priv = -1;
+	switch (HTTP1_Chunked(&bo->htc, priv, &err,
+	    &bo->acct.beresp_bodybytes, p, lp)) {
+	case H1CR_ERROR:
+		return (VFP_Error(bo, "%s", err));
+	case H1CR_MORE:
 		return (VFP_OK);
+	case H1CR_END:
+		return (VFP_END);
+	default:
+		WRONG("invalid HTTP1_Chunked return");
 	}
-	AZ(*priv);
-	i = HTTP1_Read(&bo->htc, buf, 1);
-	if (i <= 0)
-		return (VFP_Error(bo, "chunked read err"));
-	bo->acct.beresp_bodybytes += i;
-	if (buf[0] == '\r' && HTTP1_Read(&bo->htc, buf, 1) <= 0)
-		return (VFP_Error(bo, "chunked read err"));
-	if (buf[0] != '\n')
-		return (VFP_Error(bo,"chunked tail no NL"));
-	return (VFP_END);
 }
 
 /*--------------------------------------------------------------------*/
diff --git a/bin/varnishd/cache/cache_http1_proto.c b/bin/varnishd/cache/cache_http1_proto.c
index 7f7852c..0dc5fe8 100644
--- a/bin/varnishd/cache/cache_http1_proto.c
+++ b/bin/varnishd/cache/cache_http1_proto.c
@@ -45,6 +45,8 @@
 
 #include "config.h"
 
+#include <inttypes.h>
+
 #include "cache.h"
 
 #include "vct.h"
@@ -524,3 +526,106 @@ HTTP1_Write(const struct worker *w, const struct http *hp, const int *hf)
 	l += WRW_Write(w, "\r\n", -1);
 	return (l);
 }
+
+/*--------------------------------------------------------------------
+ * Read a chunked body.
+ *
+ * XXX: Reading one byte at a time is pretty pessimal.
+ */
+
+enum http1_chunked_ret
+HTTP1_Chunked(struct http_conn *htc, intptr_t *priv, const char **error,
+    int64_t *statp, void *ptr, ssize_t *lp)
+{
+	int i;
+	char buf[20];		/* XXX: 20 is arbitrary */
+	char *q;
+	unsigned u;
+	uintmax_t cll;
+	ssize_t cl, l, lr;
+
+#define  ERR(x) do { *error = (x); return (H1CR_ERROR); } while (0)
+
+	CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
+	AN(priv);
+	AN(error);
+	AN(statp);
+	AN(ptr);
+	AN(lp);
+	l = *lp;
+	*lp = 0;
+	if (*priv == -1) {
+		/* Skip leading whitespace */
+		do {
+			lr = HTTP1_Read(htc, buf, 1);
+			if (lr <= 0)
+				ERR("chunked read err");
+			*statp += lr;
+		} while (vct_islws(buf[0]));
+
+		if (!vct_ishex(buf[0]))
+			 ERR("chunked header non-hex");
+
+		/* Collect hex digits, skipping leading zeros */
+		for (u = 1; u < sizeof buf; u++) {
+			do {
+				lr = HTTP1_Read(htc, buf + u, 1);
+				if (lr <= 0)
+					ERR("chunked read err");
+				*statp += lr;
+			} while (u == 1 && buf[0] == '0' && buf[u] == '0');
+			if (!vct_ishex(buf[u]))
+				break;
+		}
+
+		if (u >= sizeof buf)
+			ERR("chunked header too long");
+
+		/* Skip trailing white space */
+		while(vct_islws(buf[u]) && buf[u] != '\n') {
+			lr = HTTP1_Read(htc, buf + u, 1);
+			if (lr <= 0)
+				ERR("chunked read err");
+			*statp += lr;
+		}
+
+		if (buf[u] != '\n')
+			ERR("chunked header no NL");
+
+		buf[u] = '\0';
+
+		cll = strtoumax(buf, &q, 16);
+		if (q == NULL || *q != '\0')
+			ERR("chunked header number syntax");
+		cl = (ssize_t)cll;
+		if((uintmax_t)cl != cll)
+			ERR("bogusly large chunk size");
+
+		*priv = cl;
+	}
+	if (*priv > 0) {
+		if (*priv < l)
+			l = *priv;
+		lr = HTTP1_Read(htc, ptr, l);
+		if (lr <= 0)
+			ERR("straight insufficient bytes");
+		*statp += lr;
+		*lp = lr;
+		*priv -= lr;
+		if (*priv == 0)
+			*priv = -1;
+		return (H1CR_MORE);
+	}
+	AZ(*priv);
+	i = HTTP1_Read(htc, buf, 1);
+	if (i <= 0)
+		ERR("chunked read err");
+	*statp += i;
+	if (buf[0] == '\r' && HTTP1_Read(htc, buf, 1) <= 0)
+		ERR("chunked read err");
+	if (buf[0] != '\n')
+		ERR("chunked tail no NL");
+	return (H1CR_END);
+#undef ERR
+}
+



More information about the varnish-commit mailing list