[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