]> err.no Git - varnish/commitdiff
Rework the handling of message-bodies in requests to be closer to
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Wed, 16 Jan 2008 15:15:39 +0000 (15:15 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Wed, 16 Jan 2008 15:15:39 +0000 (15:15 +0000)
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
varnish-cache/bin/varnishd/cache_center.c
varnish-cache/bin/varnishd/cache_fetch.c
varnish-cache/bin/varnishd/mgt_vcc.c
varnish-cache/include/http_headers.h

index 0b45e391f066668948aba7c08f262b027b912bee..a10d75bf5f0370dbc1c7f59ed4cb377207826ae7 100644 (file)
@@ -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);
index 88f2ce178d712f12369210b727dc3d75b4045804..dcb0a5f85e4ae04e63d59024b2483296fdef1bca 100644 (file)
@@ -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 */
index 62de6643f8f1ee01690140b1885e6128f3e71bbe..cae88124acfe7eeff736b359b2fe2d53a65435f4 100644 (file)
@@ -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)) {
index c6fd3185a7af7037670dcf9542360141c7df022b..544fbca316b847f2edd7b52d6317d9714a36ed61 100644 (file)
@@ -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"
index 05cd7599cfef7caa56ded0199ce2c182a5914903..f153438480263504a9b66760dee4e2f2975fe1fb 100644 (file)
@@ -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 */