From b6fd189a4e59a181121fb7f8e03e385f407081b1 Mon Sep 17 00:00:00 2001 From: phk Date: Wed, 16 Jan 2008 15:15:39 +0000 Subject: [PATCH] Rework the handling of message-bodies in requests to be closer to RFC2616 and catch things we don't deal with better. Move code to receive body from request into separate function, FetchReqBody() so it can be invoked when center::STP_HIT. Check read errors and make FetchReqBody() return an error code for client/server side so we don't penalize backends for client trouble. Make it a client error, for now, to send chunked encoding. This also isolates the big stack buffer from the subsequent function calls in Fetch() and will be saner if we ever add chunked-encoding handling. Only send the body to the backend on pass, otherwise discard it. This is controlled via the sp->sendbody flag which is reset in at STP_RECV and set it at STP_PASS. In STP_HIT, on deliver, call FetchReqBody() to dispose of any body the request might contain. Filter Content-Length: headers out (c->b) on fetches, but not for pass. Rewrite default vcl_recv{} to be take advantage of our new capabilities. This should make PUT, DELETE, OPTIONS, and TRACE work as well as POST. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2353 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/cache.h | 2 + varnish-cache/bin/varnishd/cache_center.c | 4 ++ varnish-cache/bin/varnishd/cache_fetch.c | 76 +++++++++++++++-------- varnish-cache/bin/varnishd/mgt_vcc.c | 15 ++++- varnish-cache/include/http_headers.h | 2 +- 5 files changed, 71 insertions(+), 28 deletions(-) diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index 0b45e391..a10d75bf 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -329,6 +329,7 @@ struct sess { enum step step; unsigned cur_method; unsigned handling; + unsigned char sendbody; unsigned char wantbody; int err_code; const char *err_reason; @@ -469,6 +470,7 @@ int EXP_NukeOne(struct sess *sp); /* cache_fetch.c */ int Fetch(struct sess *sp); +int FetchReqBody(struct sess *sp); /* cache_hash.c */ void HSH_Prealloc(struct sess *sp); diff --git a/varnish-cache/bin/varnishd/cache_center.c b/varnish-cache/bin/varnishd/cache_center.c index 88f2ce17..dcb0a5f8 100644 --- a/varnish-cache/bin/varnishd/cache_center.c +++ b/varnish-cache/bin/varnishd/cache_center.c @@ -451,6 +451,8 @@ cnt_hit(struct sess *sp) VCL_hit_method(sp); if (sp->handling == VCL_RET_DELIVER) { + /* Dispose of any body part of the request */ + FetchReqBody(sp); sp->step = STP_DELIVER; return (0); } @@ -682,6 +684,7 @@ cnt_pass(struct sess *sp) sp->obj = sp->wrk->nobj; sp->wrk->nobj = NULL; sp->obj->busy = 1; + sp->sendbody = 1; sp->step = STP_FETCH; return (0); } @@ -760,6 +763,7 @@ cnt_recv(struct sess *sp) VCL_recv_method(sp); sp->wantbody = (strcmp(sp->http->hd[HTTP_HDR_REQ].b, "HEAD") != 0); + sp->sendbody = 0; switch(sp->handling) { case VCL_RET_LOOKUP: /* XXX: discard req body, if any */ diff --git a/varnish-cache/bin/varnishd/cache_fetch.c b/varnish-cache/bin/varnishd/cache_fetch.c index 62de6643..cae88124 100644 --- a/varnish-cache/bin/varnishd/cache_fetch.c +++ b/varnish-cache/bin/varnishd/cache_fetch.c @@ -246,6 +246,49 @@ fetch_eof(struct sess *sp, struct http_conn *htc) return (1); } +/*-------------------------------------------------------------------- + * Fetch any body attached to the incoming request, and either write it + * to the backend (if we pass) or discard it (anything else). + * This is mainly a separate function to isolate the stack buffer and + * to contain the complexity when we start handling chunked encoding. + */ + +int +FetchReqBody(struct sess *sp) +{ + unsigned long content_length; + char buf[8192]; + char *ptr, *endp; + int read; + + if (http_GetHdr(sp->http, H_Content_Length, &ptr)) { + + content_length = strtoul(ptr, &endp, 10); + /* XXX should check result of conversion */ + while (content_length) { + if (content_length > sizeof buf) + read = sizeof buf; + else + read = content_length; + read = HTC_Read(sp->htc, buf, read); + if (read < 0) + return (1); + content_length -= read; + if (!sp->sendbody) + continue; + WRK_Write(sp->wrk, buf, read); + if (WRK_Flush(sp->wrk)) + return (2); + } + } + if (http_GetHdr(sp->http, H_Transfer_Encoding, NULL)) { + /* XXX: Handle chunked encoding. */ + WSL(sp->wrk, SLT_Debug, sp->fd, "Transfer-Encoding in request"); + return (1); + } + return (0); +} + /*--------------------------------------------------------------------*/ int @@ -261,7 +304,6 @@ Fetch(struct sess *sp) int mklen, is_head; struct http_conn htc[1]; int i; - char *ptr, *endp; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); @@ -289,31 +331,13 @@ Fetch(struct sess *sp) WRK_Reset(w, &vc->fd); http_Write(w, hp, 0); - /* - * If a POST request was passed to fetch, we must send any - * pipelined bytes to the backend as well - */ - if (http_GetHdr(sp->http, H_Content_Length, &ptr)) { - unsigned long content_length; - char buf[8192]; - int read; - - content_length = strtoul(ptr, &endp, 10); - /* XXX should check result of conversion */ - while (content_length) { - if (content_length > sizeof buf) - read = sizeof buf; - else - read = content_length; - read = HTC_Read(sp->htc, buf, read); - WRK_Write(w, buf, read); - if (WRK_Flush(w)) { - VBE_UpdateHealth(sp, vc, -1); - VBE_ClosedFd(sp->wrk, vc); - return (__LINE__); - } - content_length -= read; - } + /* Deal with any message-body the request might have */ + i = FetchReqBody(sp); + if (i > 0) { + if (i > 1) + VBE_UpdateHealth(sp, vc, -1); + VBE_ClosedFd(sp->wrk, vc); + return (__LINE__); } if (WRK_Flush(w)) { diff --git a/varnish-cache/bin/varnishd/mgt_vcc.c b/varnish-cache/bin/varnishd/mgt_vcc.c index c6fd3185..544fbca3 100644 --- a/varnish-cache/bin/varnishd/mgt_vcc.c +++ b/varnish-cache/bin/varnishd/mgt_vcc.c @@ -77,13 +77,26 @@ char *mgt_cc_cmd; */ static const char *default_vcl = "sub vcl_recv {\n" - " if (req.request != \"GET\" && req.request != \"HEAD\") {\n" + " if (req.request != \"GET\" &&\n" + " req.request != \"HEAD\" &&\n" + " req.request != \"PUT\" &&\n" + " req.request != \"POST\" &&\n" + " req.request != \"TRACE\" &&\n" + " req.request != \"OPTIONS\" &&\n" + " req.request != \"DELETE\") {\n" + " /* Non-RFC2616 or CONNECT which is weird. */\n" " pipe;\n" " }\n" " if (req.http.Expect) {\n" + " /* Expect is just too hard at present. */\n" " pipe;\n" " }\n" + " if (req.request != \"GET\" && req.request != \"HEAD\") {\n" + " /* We only deal with GET and HEAD by default */\n" + " pass;\n" + " }\n" " if (req.http.Authenticate || req.http.Cookie) {\n" + " /* Not cacheable by default */\n" " pass;\n" " }\n" " lookup;\n" diff --git a/varnish-cache/include/http_headers.h b/varnish-cache/include/http_headers.h index 05cd7599..f1534384 100644 --- a/varnish-cache/include/http_headers.h +++ b/varnish-cache/include/http_headers.h @@ -65,7 +65,7 @@ HTTPH("Cache-Control", H_Cache_Control, 3, 3, HTTPH_R_PASS|HTTPH_R_FETCH, 0, 0) HTTPH("Connection", H_Connection, 3, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0) /* RFC2616 14.10 */ HTTPH("Content-Encoding", H_Content_Encoding, 2, 0, 0, 0, 0) /* RFC2616 14.11 */ HTTPH("Content-Langugae", H_Content_Language, 2, 0, 0, 0, 0) /* RFC2616 14.12 */ -HTTPH("Content-Length", H_Content_Length, 2, 2, HTTPH_A_INS, 0, 0) /* RFC2616 14.13 */ +HTTPH("Content-Length", H_Content_Length, 2, 2, HTTPH_R_FETCH|HTTPH_A_INS, 0, 0) /* RFC2616 14.13 */ HTTPH("Content-Location", H_Content_Location, 2, 0, 0, 0, 0) /* RFC2616 14.14 */ HTTPH("Content-MD5", H_Content_MD5, 2, 0, 0, 0, 0) /* RFC2616 14.15 */ HTTPH("Content-Range", H_Content_Range, 2, 3, HTTPH_R_PASS|HTTPH_A_PASS|HTTPH_R_FETCH|HTTPH_A_INS, 0, 0) /* RFC2616 14.16 */ -- 2.39.5