]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
In HTTP/1.1, whether or not a request message contains a body
authorRoy T. Fielding <fielding@apache.org>
Sat, 19 Jul 1997 20:17:41 +0000 (20:17 +0000)
committerRoy T. Fielding <fielding@apache.org>
Sat, 19 Jul 1997 20:17:41 +0000 (20:17 +0000)
is independent of the request method and based solely on the presence
of a Content-Length or Transfer-Encoding.  Therefore, our default
handlers need to be prepared to read a body even if they don't know
what to do with it; otherwise, the body would be mistaken for the
next request on a persistent connection.  discard_request_body()
has been added to take care of that.

PR: 378
Reviewed by: Dean Gaudet

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3@78677 13f79535-47bb-0310-9956-ffa450edef68

APACHE_1_2_X/src/CHANGES
APACHE_1_2_X/src/include/http_protocol.h
APACHE_1_2_X/src/main/http_core.c
APACHE_1_2_X/src/main/http_protocol.c
APACHE_1_2_X/src/main/http_request.c

index 999452f5d78b1671f054507dbffa170ed1893f7a..f9f4ba62800c4131a8b123569665d539691a3e6f 100644 (file)
@@ -1,5 +1,13 @@
 Changes with Apache 1.2.2
 
+  *) API: In HTTP/1.1, whether or not a request message contains a body
+     is independent of the request method and based solely on the presence
+     of a Content-Length or Transfer-Encoding.  Therefore, our default
+     handlers need to be prepared to read a body even if they don't know
+     what to do with it; otherwise, the body would be mistaken for the
+     next request on a persistent connection.  discard_request_body()
+     has been added to take care of that.  [Roy Fielding] PR#378
+
   *) API: Symbol APACHE_RELEASE provides a numeric form of the Apache
      release version number, such that it always increases along the
      same lines as our source code branching.  [Roy Fielding]
index 85687b48a3e262ea1d840b211aa024ff5a762954..db608c253e955ea41b3b41ff03dd6f557939ee62 100644 (file)
@@ -134,6 +134,7 @@ int index_of_response (int status);
 int setup_client_block (request_rec *r, int read_policy);
 int should_client_block (request_rec *r);
 long get_client_block (request_rec *r, char *buffer, int bufsiz);
+int discard_request_body (request_rec *r);
 
 /* Sending a byterange */
 
index 39a6e6bc8f6097318bc1bf1bc6c3ba282d8127e9..6a9edf12c937d773e16e024cc77fb1375b62f886 100644 (file)
@@ -1324,9 +1324,14 @@ int default_handler (request_rec *r)
       (core_dir_config *)get_module_config(r->per_dir_config, &core_module);
     int rangestatus, errstatus;
     FILE *f;
-    
+
+    /* This handler has no use for a request body (yet), but we still
+     * need to read and discard it if the client sent one.
+     */
+    if ((errstatus = discard_request_body(r)) != OK)
+        return errstatus;
+
     r->allowed |= (1 << M_GET);
-    r->allowed |= (1 << M_TRACE);
     r->allowed |= (1 << M_OPTIONS);
 
     if (r->method_number == M_INVALID) {
index ac143b0345091a17746fb58e9561e37dfa85c4d5..822ad68c6ccdf29108cd2facbf8ef2a46221c9e8 100644 (file)
@@ -1087,34 +1087,31 @@ static void terminate_header (BUFF *client)
     bputs("\015\012", client);    /* Send the terminating empty line */
 }
 
+/* Build the Allow field-value from the request handler method mask.
+ * Note that we always allow TRACE, since it is handled below.
+ */
 static char *make_allow(request_rec *r)
 {
-    int allowed = r->allowed;
-
-    if( allowed == 0 ) {
-       /* RFC2068 #14.7, Allow must contain at least one method.  So rather
-        * than deal with the possibility of trying not to emit an Allow:
-        * header, i.e. #10.4.6 says 405 Method Not Allowed MUST include
-        * an Allow header, we'll just say TRACE is valid.
-        */
-       return( "TRACE" );
-    }
-
-    return 2 + pstrcat(r->pool, (allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
-                      (allowed & (1 << M_POST)) ? ", POST" : "",
-                      (allowed & (1 << M_PUT)) ? ", PUT" : "",
-                      (allowed & (1 << M_DELETE)) ? ", DELETE" : "",
-                      (allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
-                      (allowed & (1 << M_TRACE)) ? ", TRACE" : "",
-                      NULL);
-    
+    return 2 + pstrcat(r->pool,
+                       (r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
+                       (r->allowed & (1 << M_POST)) ? ", POST" : "",
+                       (r->allowed & (1 << M_PUT)) ? ", PUT" : "",
+                       (r->allowed & (1 << M_DELETE)) ? ", DELETE" : "",
+                       (r->allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
+                       ", TRACE",
+                       NULL);
 }
 
 int send_http_trace (request_rec *r)
 {
+    int rv;
+
     /* Get the original request */
     while (r->prev) r = r->prev;
 
+    if ((rv = setup_client_block(r, REQUEST_NO_BODY)))
+        return rv;
+
     hard_timeout("send TRACE", r);
 
     r->content_type = "message/http";
@@ -1514,6 +1511,43 @@ long get_client_block (request_rec *r, char *buffer, int bufsiz)
     return (chunk_start + len_read);
 }
 
+/* In HTTP/1.1, any method can have a body.  However, most GET handlers
+ * wouldn't know what to do with a request body if they received one.
+ * This helper routine tests for and reads any message body in the request,
+ * simply discarding whatever it receives.  We need to do this because
+ * failing to read the request body would cause it to be interpreted
+ * as the next request on a persistent connection.  
+ *
+ * Since we return an error status if the request is malformed, this
+ * routine should be called at the beginning of a no-body handler, e.g.,
+ *
+ *    if ((retval = discard_request_body(r)) != OK)
+ *        return retval;
+ */
+int discard_request_body(request_rec *r)
+{
+    int rv;
+
+    if ((rv = setup_client_block(r, REQUEST_CHUNKED_PASS)))
+        return rv;
+
+    if (should_client_block(r)) {
+        char dumpbuf[HUGE_STRING_LEN];
+
+        hard_timeout("reading request body", r);
+        while ((rv = get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0)
+            continue;
+        kill_timeout(r);
+
+        if (rv < 0)
+            return HTTP_BAD_REQUEST;
+    }
+    return OK;
+}
+
+/*
+ * Send the body of a response to the client.
+ */
 long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); }
 
 long send_fd_length(FILE *f, request_rec *r, long length)
index c2d4884280121e272922e7234edaad90412ca251..047a6c36ffb475651ebe2e119815625a0a6614ba 100644 (file)
@@ -910,8 +910,10 @@ void process_request_internal (request_rec *r)
          * we handle it specially.
          */
         if (r->method_number == M_TRACE) {
-            send_http_trace(r);
-            finalize_request_protocol(r);
+            if ((access_status = send_http_trace(r)))
+               die(access_status, r);
+            else
+                finalize_request_protocol(r);
             return;
         }