You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by fi...@hyperreal.org on 1998/10/06 21:06:11 UTC

cvs commit: apache-1.3/src/main http_protocol.c http_request.c

fielding    98/10/06 12:06:11

  Modified:    src      CHANGES
               src/include httpd.h
               src/main http_protocol.c http_request.c
  Log:
  Added a complete implementation of the Expect header field as
  specified in rev-05 of HTTP/1.1.  Used that implementation as a means
  of disabling the 100 Continue response when we already know the final
  status, which is mighty useful for PUT responses that result in 302 or 401.
  
  Moved two ugly protocol condition checks that were in http_request.c
  over to where they belong in http_protocol.c.  They were put there
  originally because ap_read_request formerly could not return an
  error response, but I added that capability in 1.3.2.
  
  Added removal of extra trailing whitespace from the getline results as part
  of the protocol processing, which is extra nice because it works
  between continuation lines, is almost no cost in the normal case
  of no extra whitespace, and saves memory.
  
  Revision  Changes    Path
  1.1103    +10 -0     apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1102
  retrieving revision 1.1103
  diff -u -r1.1102 -r1.1103
  --- CHANGES	1998/10/05 22:11:14	1.1102
  +++ CHANGES	1998/10/06 19:06:06	1.1103
  @@ -1,5 +1,15 @@
   Changes with Apache 1.3.3
   
  +  *) Added a complete implementation of the Expect header field as
  +     specified in rev-05 of HTTP/1.1.  Disabled the 100 Continue
  +     response when we already know the final status, which is mighty
  +     useful for PUT responses that result in 302 or 401. [Roy Fielding]
  +
  +  *) Remove extra trailing whitespace from the getline results as part
  +     of the protocol processing, which is extra nice because it works
  +     between continuation lines, is almost no cost in the normal case
  +     of no extra whitespace, and saves memory. [Roy Fielding]
  +
     *) Added new HTTP status codes and default response bodies from the
        revised HTTP/1.1 (307, 416, 417), WebDAV (102, 207, 422, 423), and 
        HTTP Extension Framework (510) specifications.  Did not add the
  
  
  
  1.246     +7 -0      apache-1.3/src/include/httpd.h
  
  Index: httpd.h
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/include/httpd.h,v
  retrieving revision 1.245
  retrieving revision 1.246
  diff -u -r1.245 -r1.246
  --- httpd.h	1998/10/05 22:11:16	1.245
  +++ httpd.h	1998/10/06 19:06:08	1.246
  @@ -752,6 +752,13 @@
    * that way, a sub request's list can (temporarily) point to a parent's list
    */
       const struct htaccess_result *htaccess;
  +
  +/* Things placed at the end of the record to avoid breaking binary
  + * compatibility.  It would be nice to remember to reorder the entire
  + * record to improve 64bit alignment the next time we need to break
  + * binary compatibility for some other reason.
  + */
  +    unsigned expecting_100;     /* is client waiting for a 100 response? */
   };
   
   
  
  
  
  1.243     +93 -13    apache-1.3/src/main/http_protocol.c
  
  Index: http_protocol.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/http_protocol.c,v
  retrieving revision 1.242
  retrieving revision 1.243
  diff -u -r1.242 -r1.243
  --- http_protocol.c	1998/10/05 22:11:16	1.242
  +++ http_protocol.c	1998/10/06 19:06:09	1.243
  @@ -551,6 +551,17 @@
           total += retval;        /* and how long s has become               */
   
           if (*pos == '\n') {     /* Did we get a full line of input?        */
  +            /*
  +             * Trim any extra trailing spaces or tabs except for the first
  +             * space or tab at the beginning of a blank string.  This makes
  +             * it much easier to check field values for exact matches, and
  +             * saves memory as well.  Terminate string at end of line.
  +             */
  +            while (pos > (s + 1) && (*(pos - 1) == ' ' || *(pos - 1) == '\t')) {
  +                --pos;          /* trim extra trailing spaces or tabs      */
  +                --total;        /* but not one at the beginning of line    */
  +                ++n;
  +            }
               *pos = '\0';
               --total;
               ++n;
  @@ -767,8 +778,6 @@
           while (*value == ' ' || *value == '\t')
               ++value;            /* Skip to start of value   */
   
  -        /* XXX: should strip trailing whitespace as well */
  -
   	ap_table_addn(tmp_headers, copy, value);
       }
   
  @@ -778,8 +787,9 @@
   request_rec *ap_read_request(conn_rec *conn)
   {
       request_rec *r;
  -    int access_status;
       pool *p;
  +    const char *expect;
  +    int access_status;
   
       p = ap_make_sub_pool(conn->pool);
       r = ap_pcalloc(p, sizeof(request_rec));
  @@ -846,6 +856,23 @@
       }
       else {
           ap_kill_timeout(r);
  +
  +        if (r->header_only) {
  +            /*
  +             * Client asked for headers only with HTTP/0.9, which doesn't send
  +             * headers! Have to dink things just to make sure the error message
  +             * comes through...
  +             */
  +            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  +                          "client sent invalid HTTP/0.9 request: HEAD %s",
  +                          r->uri);
  +            r->header_only = 0;
  +            r->status = HTTP_BAD_REQUEST;
  +            ap_send_error_response(r, 0);
  +            ap_bflush(r->connection->client);
  +            ap_log_transaction(r);
  +            return r;
  +        }
       }
   
       r->status = HTTP_OK;                         /* Until further notice. */
  @@ -860,6 +887,49 @@
   
       conn->keptalive = 0;        /* We now have a request to play with */
   
  +    if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) ||
  +        ((r->proto_num == HTTP_VERSION(1,1)) &&
  +         !ap_table_get(r->headers_in, "Host"))) {
  +        /*
  +         * Client sent us an HTTP/1.1 or later request without telling us the
  +         * hostname, either with a full URL or a Host: header. We therefore
  +         * need to (as per the 1.1 spec) send an error.  As a special case,
  +         * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
  +         * a Host: header, and the server MUST respond with 400 if it doesn't.
  +         */
  +        r->status = HTTP_BAD_REQUEST;
  +        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  +                      "client sent HTTP/1.1 request without hostname "
  +                      "(see RFC2068 section 9, and 14.23): %s", r->uri);
  +        ap_send_error_response(r, 0);
  +        ap_bflush(r->connection->client);
  +        ap_log_transaction(r);
  +        return r;
  +    }
  +    if (((expect = ap_table_get(r->headers_in, "Expect")) != NULL) &&
  +        (expect[0] != '\0')) {
  +        /*
  +         * The Expect header field was added to HTTP/1.1 after RFC 2068
  +         * as a means to signal when a 100 response is desired and,
  +         * unfortunately, to signal a poor man's mandatory extension that
  +         * the server must understand or return 417 Expectation Failed.
  +         */
  +        if (strcasecmp(expect, "100-continue") == 0) {
  +            r->expecting_100 = 1;
  +        }
  +        else {
  +            r->status = HTTP_EXPECTATION_FAILED;
  +            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
  +                          "client sent an unrecognized expectation value of "
  +                          "Expect: %s", expect);
  +            ap_send_error_response(r, 0);
  +            ap_bflush(r->connection->client);
  +            (void) ap_discard_request_body(r);
  +            ap_log_transaction(r);
  +            return r;
  +        }
  +    }
  +
       if ((access_status = ap_run_post_read_request(r))) {
           ap_die(access_status, r);
           ap_log_transaction(r);
  @@ -895,6 +965,7 @@
       rnew->err_headers_out = ap_make_table(rnew->pool, 5);
       rnew->notes           = ap_make_table(rnew->pool, 5);
   
  +    rnew->expecting_100   = r->expecting_100;
       rnew->read_length     = r->read_length;
       rnew->read_body       = REQUEST_NO_BODY;
   
  @@ -1457,7 +1528,7 @@
       if (r->read_length || (!r->read_chunked && (r->remaining <= 0)))
           return 0;
   
  -    if (r->proto_num >= HTTP_VERSION(1,1)) {
  +    if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) {
           /* sending 100 Continue interim response */
           ap_bvputs(r->connection->client,
                  SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012",
  @@ -1669,6 +1740,11 @@
       if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_PASS)))
           return rv;
   
  +    /* If we are discarding the request body, then we must already know
  +     * the final status code, therefore disable the sending of 100 continue.
  +     */
  +    r->expecting_100 = 0;
  +
       if (ap_should_client_block(r)) {
           char dumpbuf[HUGE_STRING_LEN];
   
  @@ -2266,22 +2342,26 @@
   	    break;
   	case HTTP_RANGE_NOT_SATISFIABLE:
   	    ap_bputs("None of the range-specifier values in the Range\n"
  -                     "request-header field overlap the current extent\n"
  -                     "of the selected resource.\n", fd);
  +	             "request-header field overlap the current extent\n"
  +	             "of the selected resource.\n", fd);
   	    break;
   	case HTTP_EXPECTATION_FAILED:
  -	    ap_bputs("The expectation given in the Expect request-header\n"
  -                     "field could not be met by this server.\n", fd);
  +	    ap_bvputs(fd, "The expectation given in the Expect request-header"
  +	              "\nfield could not be met by this server.<P>\n"
  +	              "The client sent<PRE>\n    Expect: ",
  +	              ap_table_get(r->headers_in, "Expect"), "\n</PRE>\n"
  +	              "but we only allow the 100-continue expectation.\n",
  +	              NULL);
   	    break;
   	case HTTP_UNPROCESSABLE_ENTITY:
  -            ap_bputs("The server understands the media type of the\n"
  -                     "request entity, but was unable to process the\n"
  -                     "contained instructions.\n", fd);
  +	    ap_bputs("The server understands the media type of the\n"
  +	             "request entity, but was unable to process the\n"
  +	             "contained instructions.\n", fd);
   	    break;
   	case HTTP_LOCKED:
   	    ap_bputs("The requested resource is currently locked.\n"
  -                     "The lock must be released or proper identification\n"
  -                     "given before the method can be applied.\n", fd);
  +	             "The lock must be released or proper identification\n"
  +	             "given before the method can be applied.\n", fd);
   	    break;
   	case HTTP_SERVICE_UNAVAILABLE:
   	    ap_bputs("The server is temporarily unable to service your\n"
  
  
  
  1.133     +0 -33     apache-1.3/src/main/http_request.c
  
  Index: http_request.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/main/http_request.c,v
  retrieving revision 1.132
  retrieving revision 1.133
  diff -u -r1.132 -r1.133
  --- http_request.c	1998/10/03 14:42:28	1.132
  +++ http_request.c	1998/10/06 19:06:09	1.133
  @@ -1024,39 +1024,6 @@
   {
       int access_status;
   
  -    /*
  -     * Kluge to be reading the assbackwards field outside of protocol.c, but
  -     * we've got to check for this sort of nonsense somewhere...
  -     */
  -
  -    if (r->assbackwards && r->header_only) {
  -        /*
  -         * Client asked for headers only with HTTP/0.9, which doesn't send
  -         * headers!  Have to dink things even to make sure the error message
  -         * comes through...
  -         */
  -        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  -                    "client sent illegal HTTP/0.9 request: %s", r->uri);
  -        r->header_only = 0;
  -        ap_die(BAD_REQUEST, r);
  -        return;
  -    }
  -
  -    if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) ||
  -        ((r->proto_num == HTTP_VERSION(1,1)) && !ap_table_get(r->headers_in, "Host"))) {
  -        /*
  -         * Client sent us a HTTP/1.1 or later request without telling us the
  -         * hostname, either with a full URL or a Host: header. We therefore
  -         * need to (as per the 1.1 spec) send an error.  As a special case,
  -	 * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
  -	 * a Host: header, and the server MUST respond with 400 if it doesn't.
  -         */
  -        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  -               "client sent HTTP/1.1 request without hostname (see RFC2068 section 9, and 14.23): %s", r->uri);
  -        ap_die(BAD_REQUEST, r);
  -        return;
  -    }
  -
       /* Ignore embedded %2F's in path for proxy requests */
       if (!r->proxyreq && r->parsed_uri.path) {
   	access_status = ap_unescape_url(r->parsed_uri.path);