[master] 036bd79 Move the req.body stuff to its own source-file, its not HTTP1 specific.
Poul-Henning Kamp
phk at FreeBSD.org
Mon Sep 15 10:50:32 CEST 2014
commit 036bd79f6e6d851bef2af330b909ba769e0d9917
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Mon Sep 15 08:50:14 2014 +0000
Move the req.body stuff to its own source-file, its not HTTP1 specific.
diff --git a/bin/varnishd/Makefile.am b/bin/varnishd/Makefile.am
index ddbd1d2..edb0e31 100644
--- a/bin/varnishd/Makefile.am
+++ b/bin/varnishd/Makefile.am
@@ -37,6 +37,7 @@ varnishd_SOURCES = \
cache/cache_panic.c \
cache/cache_pipe.c \
cache/cache_pool.c \
+ cache/cache_req_body.c \
cache/cache_req_fsm.c \
cache/cache_http1_deliver.c \
cache/cache_rfc2616.c \
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h
index df8b562..c76f7c1 100644
--- a/bin/varnishd/cache/cache.h
+++ b/bin/varnishd/cache/cache.h
@@ -812,9 +812,6 @@ void V1F_Setup_Fetch(struct vfp_ctx *vfc, struct http_conn *htc);
/* cache_http1_fsm.c [HTTP1] */
typedef int (req_body_iter_f)(struct req *, void *priv, void *ptr, size_t);
void HTTP1_Session(struct worker *, struct req *);
-int HTTP1_DiscardReqBody(struct req *req);
-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];
@@ -823,6 +820,11 @@ unsigned V1D_FlushReleaseAcct(struct req *req);
void V1D_Deliver(struct req *, struct busyobj *);
void V1D_Deliver_Synth(struct req *req);
+/* cache_req_body.c */
+int VRB_Ignore(struct req *req);
+int VRB_Cache(struct req *req, ssize_t maxsize);
+int VRB_Iterate(struct req *req, req_body_iter_f *func, void *priv);
+void VRB_Free(struct req *req);
static inline int
VDP_bytes(struct req *req, enum vdp_action act, const void *ptr, ssize_t len)
diff --git a/bin/varnishd/cache/cache_http1_fetch.c b/bin/varnishd/cache/cache_http1_fetch.c
index c593c32..3874fb5 100644
--- a/bin/varnishd/cache/cache_http1_fetch.c
+++ b/bin/varnishd/cache/cache_http1_fetch.c
@@ -129,7 +129,7 @@ V1F_fetch_hdr(struct worker *wrk, struct busyobj *bo, struct req *req)
if (req != NULL) {
if (do_chunked)
WRW_Chunked(wrk);
- i = HTTP1_IterateReqBody(req, vbf_iter_req_body, wrk);
+ i = VRB_Iterate(req, vbf_iter_req_body, wrk);
if (req->req_body_status == REQ_BODY_TAKEN) {
retry = -1;
diff --git a/bin/varnishd/cache/cache_http1_fsm.c b/bin/varnishd/cache/cache_http1_fsm.c
index 499c7b9..2a6b781 100644
--- a/bin/varnishd/cache/cache_http1_fsm.c
+++ b/bin/varnishd/cache/cache_http1_fsm.c
@@ -431,235 +431,3 @@ HTTP1_Session(struct worker *wrk, struct req *req)
}
}
}
-
-/*----------------------------------------------------------------------
- * Iterate over the req.body.
- *
- * This can be done exactly once if uncached, and multiple times if the
- * req.body is cached.
- */
-
-int
-HTTP1_IterateReqBody(struct req *req, req_body_iter_f *func, void *priv)
-{
- char buf[8192];
- struct storage *st;
- ssize_t l;
- int i;
- struct vfp_ctx *vfc;
- enum vfp_status vfps = VFP_ERROR;
-
- CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
- AN(func);
-
- switch(req->req_body_status) {
- case REQ_BODY_CACHED:
- VTAILQ_FOREACH(st, &req->body->list, list) {
- i = func(req, priv, st->ptr, st->len);
- if (i)
- return (i);
- }
- return (0);
- case REQ_BODY_NONE:
- return (0);
- case REQ_BODY_WITH_LEN:
- case REQ_BODY_WITHOUT_LEN:
- break;
- case REQ_BODY_TAKEN:
- VSLb(req->vsl, SLT_VCL_Error,
- "Uncached req.body can only be consumed once.");
- return (-1);
- case REQ_BODY_FAIL:
- VSLb(req->vsl, SLT_FetchError,
- "Had failed reading req.body before.");
- return (-1);
- default:
- WRONG("Wrong req_body_status in HTTP1_IterateReqBody()");
- }
- Lck_Lock(&req->sp->mtx);
- if (req->req_body_status == REQ_BODY_WITH_LEN ||
- req->req_body_status == REQ_BODY_WITHOUT_LEN) {
- req->req_body_status = REQ_BODY_TAKEN;
- i = 0;
- } else
- i = -1;
- Lck_Unlock(&req->sp->mtx);
- if (i) {
- VSLb(req->vsl, SLT_VCL_Error,
- "Multiple attempts to access non-cached req.body");
- return (i);
- }
-
- CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC);
- vfc = req->htc->vfc;
- VFP_Setup(vfc);
- vfc->http = req->http;
- vfc->vsl = req->vsl;
- V1F_Setup_Fetch(vfc, req->htc);
- if (VFP_Open(vfc) < 0) {
- VSLb(req->vsl, SLT_FetchError, "Could not open Fetch Pipeline");
- return (-1);
- }
-
- do {
- l = sizeof buf;
- vfps = VFP_Suck(vfc, buf, &l);
- if (vfps == VFP_ERROR) {
- req->req_body_status = REQ_BODY_FAIL;
- l = -1;
- break;
- } else if (l > 0) {
- req->req_bodybytes += l;
- req->acct.req_bodybytes += l;
- l = func(req, priv, buf, l);
- if (l) {
- req->req_body_status = REQ_BODY_FAIL;
- break;
- }
- }
- } while (vfps == VFP_OK);
- VFP_Close(vfc);
- VSLb_ts_req(req, "ReqBody", VTIM_real());
-
- return (l);
-}
-
-/*----------------------------------------------------------------------
- * DiscardReqBody() is a dedicated function, because we might
- * be able to disuade or terminate its transmission in some protocols.
- * For HTTP1 we have no such luck, and we just iterate it into oblivion.
- */
-
-static int __match_proto__(req_body_iter_f)
-httpq_req_body_discard(struct req *req, void *priv, void *ptr, size_t len)
-{
-
- CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
- (void)priv;
- (void)ptr;
- (void)len;
- return (0);
-}
-
-int
-HTTP1_DiscardReqBody(struct req *req)
-{
-
- if (req->req_body_status == REQ_BODY_WITH_LEN ||
- req->req_body_status == REQ_BODY_WITHOUT_LEN)
- (void)HTTP1_IterateReqBody(req, httpq_req_body_discard, NULL);
- return(0);
-}
-
-/*----------------------------------------------------------------------
- * Cache the req.body if it is smaller than the given size
- *
- * This function must be called before any backend fetches are kicked
- * off to prevent parallelism.
- */
-
-int
-HTTP1_CacheReqBody(struct req *req, ssize_t maxsize)
-{
- struct storage *st;
- ssize_t l, yet;
- struct vfp_ctx *vfc;
- enum vfp_status vfps = VFP_ERROR;
-
- CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
-
- assert (req->req_step == R_STP_RECV);
- switch(req->req_body_status) {
- case REQ_BODY_CACHED:
- return (0);
- case REQ_BODY_FAIL:
- return (-1);
- case REQ_BODY_NONE:
- return (0);
- case REQ_BODY_WITHOUT_LEN:
- case REQ_BODY_WITH_LEN:
- break;
- default:
- WRONG("Wrong req_body_status in HTTP1_CacheReqBody()");
- }
-
- CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC);
- vfc = req->htc->vfc;
-
- if (req->htc->content_length > maxsize) {
- req->req_body_status = REQ_BODY_FAIL;
- (void)VFP_Error(vfc, "Request body too big to cache");
- return (-1);
- }
-
- VFP_Setup(vfc);
- vfc->http = req->http;
- vfc->vsl = req->vsl;
- V1F_Setup_Fetch(vfc, req->htc);
-
- if (VFP_Open(vfc) < 0) {
- req->req_body_status = REQ_BODY_FAIL;
- return (-1);
- }
-
- yet = req->htc->content_length;
- if (yet < 0)
- yet = 0;
- st = NULL;
- do {
- if (st == NULL) {
- st = STV_alloc_transient(
- yet ? yet : cache_param->fetch_chunksize);
- if (st == NULL) {
- req->req_body_status = REQ_BODY_FAIL;
- l = -1;
- break;
- } else {
- VTAILQ_INSERT_TAIL(&req->body->list, st, list);
- }
- }
- l = st->space - st->len;
- vfps = VFP_Suck(vfc, st->ptr + st->len, &l);
- if (vfps == VFP_ERROR) {
- req->req_body_status = REQ_BODY_FAIL;
- l = -1;
- break;
- }
- if (l > 0) {
- req->req_bodybytes += l;
- req->acct.req_bodybytes += l;
- if (yet > 0)
- yet -= l;
- st->len += l;
- if (st->space == st->len)
- st = NULL;
- l = 0;
- }
- if (req->req_bodybytes > maxsize) {
- req->req_body_status = REQ_BODY_FAIL;
- l = -1;
- break;
- }
- } while (vfps == VFP_OK);
- VFP_Close(vfc);
-
- if (l == 0) {
-
- if (req->req_bodybytes != req->htc->content_length) {
- /* We must update also the "pristine" req.* copy */
- http_Unset(req->http0, H_Content_Length);
- http_Unset(req->http0, H_Transfer_Encoding);
- http_PrintfHeader(req->http0, "Content-Length: %ju",
- (uintmax_t)req->req_bodybytes);
-
- http_Unset(req->http, H_Content_Length);
- http_Unset(req->http, H_Transfer_Encoding);
- http_PrintfHeader(req->http, "Content-Length: %ju",
- (uintmax_t)req->req_bodybytes);
- }
-
- req->req_body_status = REQ_BODY_CACHED;
- }
- VSLb_ts_req(req, "ReqBody", VTIM_real());
- return (l);
-}
diff --git a/bin/varnishd/cache/cache_req_body.c b/bin/varnishd/cache/cache_req_body.c
new file mode 100644
index 0000000..6c96f74
--- /dev/null
+++ b/bin/varnishd/cache/cache_req_body.c
@@ -0,0 +1,288 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2014 Varnish Software AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <stdlib.h>
+
+#include "cache.h"
+#include "vtim.h"
+
+/*----------------------------------------------------------------------
+ * Iterate over the req.body.
+ *
+ * This can be done exactly once if uncached, and multiple times if the
+ * req.body is cached.
+ */
+
+int
+VRB_Iterate(struct req *req, req_body_iter_f *func, void *priv)
+{
+ char buf[8192];
+ struct storage *st;
+ ssize_t l;
+ int i;
+ struct vfp_ctx *vfc;
+ enum vfp_status vfps = VFP_ERROR;
+
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+ AN(func);
+
+ switch(req->req_body_status) {
+ case REQ_BODY_CACHED:
+ VTAILQ_FOREACH(st, &req->body->list, list) {
+ i = func(req, priv, st->ptr, st->len);
+ if (i)
+ return (i);
+ }
+ return (0);
+ case REQ_BODY_NONE:
+ return (0);
+ case REQ_BODY_WITH_LEN:
+ case REQ_BODY_WITHOUT_LEN:
+ break;
+ case REQ_BODY_TAKEN:
+ VSLb(req->vsl, SLT_VCL_Error,
+ "Uncached req.body can only be consumed once.");
+ return (-1);
+ case REQ_BODY_FAIL:
+ VSLb(req->vsl, SLT_FetchError,
+ "Had failed reading req.body before.");
+ return (-1);
+ default:
+ WRONG("Wrong req_body_status in VRB_IterateReqBody()");
+ }
+ Lck_Lock(&req->sp->mtx);
+ if (req->req_body_status == REQ_BODY_WITH_LEN ||
+ req->req_body_status == REQ_BODY_WITHOUT_LEN) {
+ req->req_body_status = REQ_BODY_TAKEN;
+ i = 0;
+ } else
+ i = -1;
+ Lck_Unlock(&req->sp->mtx);
+ if (i) {
+ VSLb(req->vsl, SLT_VCL_Error,
+ "Multiple attempts to access non-cached req.body");
+ return (i);
+ }
+
+ CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC);
+ vfc = req->htc->vfc;
+ VFP_Setup(vfc);
+ vfc->http = req->http;
+ vfc->vsl = req->vsl;
+ V1F_Setup_Fetch(vfc, req->htc);
+ if (VFP_Open(vfc) < 0) {
+ VSLb(req->vsl, SLT_FetchError, "Could not open Fetch Pipeline");
+ return (-1);
+ }
+
+ do {
+ l = sizeof buf;
+ vfps = VFP_Suck(vfc, buf, &l);
+ if (vfps == VFP_ERROR) {
+ req->req_body_status = REQ_BODY_FAIL;
+ l = -1;
+ break;
+ } else if (l > 0) {
+ req->req_bodybytes += l;
+ req->acct.req_bodybytes += l;
+ l = func(req, priv, buf, l);
+ if (l) {
+ req->req_body_status = REQ_BODY_FAIL;
+ break;
+ }
+ }
+ } while (vfps == VFP_OK);
+ VFP_Close(vfc);
+ VSLb_ts_req(req, "ReqBody", VTIM_real());
+
+ return (l);
+}
+
+/*----------------------------------------------------------------------
+ * DiscardReqBody() is a dedicated function, because we might
+ * be able to disuade or terminate its transmission in some protocols.
+ * For HTTP1 we have no such luck, and we just iterate it into oblivion.
+ */
+
+static int __match_proto__(req_body_iter_f)
+httpq_req_body_discard(struct req *req, void *priv, void *ptr, size_t len)
+{
+
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+ (void)priv;
+ (void)ptr;
+ (void)len;
+ return (0);
+}
+
+int
+VRB_Ignore(struct req *req)
+{
+
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+
+ if (req->req_body_status == REQ_BODY_WITH_LEN ||
+ req->req_body_status == REQ_BODY_WITHOUT_LEN)
+ (void)VRB_Iterate(req, httpq_req_body_discard, NULL);
+ return(0);
+}
+
+/*----------------------------------------------------------------------
+ */
+
+void
+VRB_Free(struct req *req)
+{
+ struct storage *st;
+
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+
+ while (!VTAILQ_EMPTY(&req->body->list)) {
+ st = VTAILQ_FIRST(&req->body->list);
+ VTAILQ_REMOVE(&req->body->list, st, list);
+ STV_free(st);
+ }
+}
+
+/*----------------------------------------------------------------------
+ * Cache the req.body if it is smaller than the given size
+ *
+ * This function must be called before any backend fetches are kicked
+ * off to prevent parallelism.
+ */
+
+int
+VRB_Cache(struct req *req, ssize_t maxsize)
+{
+ struct storage *st;
+ ssize_t l, yet;
+ struct vfp_ctx *vfc;
+ enum vfp_status vfps = VFP_ERROR;
+
+ CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
+
+ assert (req->req_step == R_STP_RECV);
+ switch(req->req_body_status) {
+ case REQ_BODY_CACHED:
+ return (0);
+ case REQ_BODY_FAIL:
+ return (-1);
+ case REQ_BODY_NONE:
+ return (0);
+ case REQ_BODY_WITHOUT_LEN:
+ case REQ_BODY_WITH_LEN:
+ break;
+ default:
+ WRONG("Wrong req_body_status in VRB_CacheReqBody()");
+ }
+
+ CHECK_OBJ_NOTNULL(req->htc, HTTP_CONN_MAGIC);
+ vfc = req->htc->vfc;
+
+ if (req->htc->content_length > maxsize) {
+ req->req_body_status = REQ_BODY_FAIL;
+ (void)VFP_Error(vfc, "Request body too big to cache");
+ return (-1);
+ }
+
+ VFP_Setup(vfc);
+ vfc->http = req->http;
+ vfc->vsl = req->vsl;
+ V1F_Setup_Fetch(vfc, req->htc);
+
+ if (VFP_Open(vfc) < 0) {
+ req->req_body_status = REQ_BODY_FAIL;
+ return (-1);
+ }
+
+ yet = req->htc->content_length;
+ if (yet < 0)
+ yet = 0;
+ st = NULL;
+ do {
+ if (st == NULL) {
+ st = STV_alloc_transient(
+ yet ? yet : cache_param->fetch_chunksize);
+ if (st == NULL) {
+ req->req_body_status = REQ_BODY_FAIL;
+ l = -1;
+ break;
+ } else {
+ VTAILQ_INSERT_TAIL(&req->body->list, st, list);
+ }
+ }
+ l = st->space - st->len;
+ vfps = VFP_Suck(vfc, st->ptr + st->len, &l);
+ if (vfps == VFP_ERROR) {
+ req->req_body_status = REQ_BODY_FAIL;
+ l = -1;
+ break;
+ }
+ if (l > 0) {
+ req->req_bodybytes += l;
+ req->acct.req_bodybytes += l;
+ if (yet > 0)
+ yet -= l;
+ st->len += l;
+ if (st->space == st->len)
+ st = NULL;
+ l = 0;
+ }
+ if (req->req_bodybytes > maxsize) {
+ req->req_body_status = REQ_BODY_FAIL;
+ l = -1;
+ break;
+ }
+ } while (vfps == VFP_OK);
+ VFP_Close(vfc);
+
+ if (l == 0) {
+
+ if (req->req_bodybytes != req->htc->content_length) {
+ /* We must update also the "pristine" req.* copy */
+ http_Unset(req->http0, H_Content_Length);
+ http_Unset(req->http0, H_Transfer_Encoding);
+ http_PrintfHeader(req->http0, "Content-Length: %ju",
+ (uintmax_t)req->req_bodybytes);
+
+ http_Unset(req->http, H_Content_Length);
+ http_Unset(req->http, H_Transfer_Encoding);
+ http_PrintfHeader(req->http, "Content-Length: %ju",
+ (uintmax_t)req->req_bodybytes);
+ }
+
+ req->req_body_status = REQ_BODY_CACHED;
+ }
+ VSLb_ts_req(req, "ReqBody", VTIM_real());
+ return (l);
+}
diff --git a/bin/varnishd/cache/cache_req_fsm.c b/bin/varnishd/cache/cache_req_fsm.c
index 1f0189e..1125e36 100644
--- a/bin/varnishd/cache/cache_req_fsm.c
+++ b/bin/varnishd/cache/cache_req_fsm.c
@@ -259,7 +259,7 @@ cnt_synth(struct worker *wrk, struct req *req)
req->doclose = SC_RESP_CLOSE;
/* Discard any lingering request body before delivery */
- (void)HTTP1_DiscardReqBody(req);
+ (void)VRB_Ignore(req);
V1D_Deliver_Synth(req);
@@ -296,7 +296,7 @@ cnt_fetch(struct worker *wrk, struct req *req)
CHECK_OBJ_NOTNULL(req->objcore, OBJCORE_MAGIC);
wrk->stats.s_fetch++;
- (void)HTTP1_DiscardReqBody(req);
+ (void)VRB_Ignore(req);
if (req->objcore->flags & OC_F_FAILED) {
req->err_code = 503;
@@ -420,7 +420,7 @@ cnt_lookup(struct worker *wrk, struct req *req)
AZ(boc->busyobj);
VBF_Fetch(wrk, req, boc, oc, VBF_BACKGROUND);
} else {
- (void)HTTP1_DiscardReqBody(req);// XXX: handle err
+ (void)VRB_Ignore(req);// XXX: handle err
}
wrk->stats.cache_hit++;
req->req_step = R_STP_DELIVER;
@@ -866,7 +866,6 @@ enum req_fsm_nxt
CNT_Request(struct worker *wrk, struct req *req)
{
enum req_fsm_nxt nxt;
- struct storage *st;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
@@ -920,11 +919,7 @@ CNT_Request(struct worker *wrk, struct req *req)
VSLb(req->vsl, SLT_ESI_BodyBytes, "%ju",
(uintmax_t)req->resp_bodybytes);
- while (!VTAILQ_EMPTY(&req->body->list)) {
- st = VTAILQ_FIRST(&req->body->list);
- VTAILQ_REMOVE(&req->body->list, st, list);
- STV_free(st);
- }
+ VRB_Free(req);
req->wrk = NULL;
}
assert(WRW_IsReleased(wrk));
diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index f2c2065..dcb07ba 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -488,7 +488,7 @@ VRT_CacheReqBody(const struct vrt_ctx *ctx, long long maxsize)
"req.body can only be cached in vcl_recv{}");
return (0);
}
- return (HTTP1_CacheReqBody(ctx->req, maxsize));
+ return (VRB_Cache(ctx->req, maxsize));
}
/*--------------------------------------------------------------------
More information about the varnish-commit
mailing list