httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Randy Terbush <ra...@zyzzyva.com>
Subject Re: what to do about CGI and chunked
Date Sun, 24 Nov 1996 06:25:46 GMT
This doesn't seem to break anything that I can tell. Who knows if
it works. :)

+1


> Here is my solution.  I've added a couple request_rec values for
> determining how the message body should be read and how much has
> been read.  This allows a module to select whatever level of
> sophistication they want, while ensuring that the data being read
> is complete and correct, and killing keepalive if it isn't (since
> otherwise the server would interpret the leftover garbage as a
> second request and send a second error response after the CGI response).
> Normal CGI scripts are not affected by the changes (other than the bug fixes).
> 
> I tested all of the options by modifying the read_body value in
> mod_cgi.  Unfortunately, I can't test the changes to mod_fastcgi
> and mod_proxy (aside from compiling them). I'm not sure whether
> fastcgi should require Content-Length or not, so I set it so that
> it would dechunk and signal errors with -1.
> 
> It is difficult to see how valuable this change is without a module or
> proxy that uses the more poweful chunking options.  All I can say is
> that we can't build an HTTP/1.1 gateway or proxy without them.
> It would also be nice if we had a configurable directive for limiting
> the size of a request message, since this gives the ability to enforce it.
> 
> This is an API change, so we'll need to bump the version when this
> is committed.  That's also why it *really* needs to be reviewed now
> and not later.
> 
> .....Roy
> 
> Index: httpd.h
> ===================================================================
> RCS file: /export/home/cvs/apache/src/httpd.h,v
> retrieving revision 1.61
> diff -c -r1.61 httpd.h
> *** httpd.h	1996/11/14 07:24:42	1.61
> --- httpd.h	1996/11/23 09:54:22
> ***************
> *** 341,346 ****
> --- 341,357 ----
>   #define LF 10
>   #define CR 13
>   
> + /* Possible values for request_rec.read_body (set by handling module):
> +  *    REQUEST_NO_BODY          Send 413 error if message has any body
> +  *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
> +  *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
> +  *    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
> +  */
> + #define REQUEST_NO_BODY          0
> + #define REQUEST_CHUNKED_ERROR    1
> + #define REQUEST_CHUNKED_DECHUNK  2
> + #define REQUEST_CHUNKED_PASS     3
> + 
>   /* Things which may vary per file-lookup WITHIN a request ---
>    * e.g., state of MIME config.  Basically, the name of an object, info
>    * about the object, and any other info we may ahve which may need to
> ***************
> *** 426,432 ****
>     char *range;			/* The Range: header */
>     long clength;			/* The "real" content length */
>   
> !   long int remaining;		/* bytes left to read */
>     int read_chunked;		/* reading chunked transfer-coding */
>   
>     /* MIME header environments, in and out.  Also, an array containing
> --- 437,445 ----
>     char *range;			/* The Range: header */
>     long clength;			/* The "real" content length */
>   
> !   long remaining;		/* bytes left to read */
> !   long read_length;		/* bytes that have been read */
> !   int read_body;   		/* how the request body should be read */
>     int read_chunked;		/* reading chunked transfer-coding */
>   
>     /* MIME header environments, in and out.  Also, an array containing
> Index: http_protocol.c
> ===================================================================
> RCS file: /export/home/cvs/apache/src/http_protocol.c,v
> retrieving revision 1.75
> diff -c -r1.75 http_protocol.c
> *** http_protocol.c	1996/11/14 07:35:49	1.75
> --- http_protocol.c	1996/11/23 09:54:22
> ***************
> *** 210,216 ****
>       char *length = table_get (r->headers_out, "Content-length");
>       int ka_sent;
>   
> !     if ((r->server->keep_alive > r->connection->keepalives) &&
>   	(r->server->keep_alive_timeout > 0) &&
>   	(r->header_only || length ||
>   	 ((r->proto_num >= 1001) && (r->byterange > 1 || (r->chunked
= 1)))) &&
> --- 210,218 ----
>       char *length = table_get (r->headers_out, "Content-length");
>       int ka_sent;
>   
> !     if (r->connection->keepalive == -1)  /* Did we get bad input? */
> !         r->connection->keepalive = 0;
> !     else if ((r->server->keep_alive > r->connection->keepalives) &&
>   	(r->server->keep_alive_timeout > 0) &&
>   	(r->header_only || length ||
>   	 ((r->proto_num >= 1001) && (r->byterange > 1 || (r->chunked
= 1)))) &&
> ***************
> *** 633,638 ****
> --- 635,645 ----
>       r->per_dir_config = r->server->lookup_defaults; /* For now. */
>   
>       r->sent_bodyct = 0; /* bytect isn't for body */
> + 
> +     r->remaining    = 0;
> +     r->read_length  = 0;
> +     r->read_body    = REQUEST_NO_BODY;
> +     r->read_chunked = 0;
>       
>       r->status = HTTP_OK;	/* Until further notice.
>   				 * Only changed by die(), or (bletch!)
> ***************
> *** 703,708 ****
> --- 710,718 ----
>       rnew->err_headers_out = make_table (rnew->pool, 5);
>       rnew->notes = make_table (rnew->pool, 5);
>       
> +     rnew->read_length = r->read_length;
> +     rnew->read_body   = REQUEST_NO_BODY;
> +     
>       rnew->main = (request_rec *)r;
>   }
>   
> ***************
> *** 1055,1111 ****
>   
>   }
>   
> ! /* Here we deal with getting input from the client. This can be in the
> !  * form of POST or PUT (other methods can be added later), and may be
> !  * transmitted in either a fixed content-length or via chunked
> !  * transfer-coding.
>    *
>    * Note that this is more complicated than it was in Apache 1.1 and prior
>    * versions, because chunked support means that the module does less.
>    *
>    * The proper procedure is this:
> !  * 1. Call setup_client_block() near the beginning of the request
> !  *    handler. This will set up all the neccessary properties, and
>    *    will return either OK, or an error code. If the latter,
>    *    the module should return that error code.
>    *
> !  * 2. When you are ready to possibly accept input, call should_client_block().
>    *    This will tell the module whether or not to read input. If it is 0,
> !  *    the module should assume that the input is of a non-entity type
> !  *    (e.g. a GET request). This step also sends a 100 Continue response
> !  *    to HTTP/1.1 clients, so should not be called until the module
> !  *    is *definitely* ready to read content. (otherwise, the point of the
> !  *    100 response is defeated). Never call this function more than once.
> !  *
> !  * 3. Finally, call get_client_block in a loop. Pass it a buffer and its
> !  *    size. It will put data into the buffer (not neccessarily the full
> !  *    buffer, in the case of chunked inputs), and return the length of
> !  *    the input block. When it is done reading, it will return 0.
>    *
>    */
>   
>   int setup_client_block (request_rec *r)
>   {
> !     char *tenc = table_get (r->headers_in, "Transfer-Encoding");
> !     char *lenp = table_get (r->headers_in, "Content-length");
> ! 
> !     if ((r->method_number != M_POST) && (r->method_number != M_PUT))
> ! 	return OK;
>   
>       if (tenc) {
> ! 	if (strcasecmp(tenc, "chunked")) {
> ! 	    log_printf(r->server, "Unknown Transfer-Encoding %s", tenc);
> ! 	    return BAD_REQUEST;
> ! 	}
> ! 	r->read_chunked = 1;
> ! 	r->remaining = 0;
>       }
> !     else {
> ! 	if (!lenp) {
> ! 	    log_reason("POST or PUT without Content-length:", r->filename, r);
> ! 	    return LENGTH_REQUIRED;
> ! 	}
> ! 	r->remaining = atol(lenp);
>       }
>   
>       return OK;
> --- 1065,1143 ----
>   
>   }
>   
> ! /* Here we deal with getting the request message body from the client.
> !  * Whether or not the request contains a body is signaled by the presence
> !  * of a non-zero Content-Length or by a Transfer-Encoding: chunked.
>    *
>    * Note that this is more complicated than it was in Apache 1.1 and prior
>    * versions, because chunked support means that the module does less.
>    *
>    * The proper procedure is this:
> !  *
> !  * 1. Set the request record's r->read_body field to select the policy
> !  *    to apply if the request message indicates a body and how a chunked
> !  *    tranfer-coding should be interpreted.  Set it to one of
> !  *
> !  *    REQUEST_NO_BODY          Send 413 error if message has any body
> !  *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
> !  *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
> !  *    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
> !  *
> !  * 2. Call setup_client_block() near the beginning of the request
> !  *    handler. This will set up all the necessary properties, and
>    *    will return either OK, or an error code. If the latter,
>    *    the module should return that error code.
>    *
> !  * 3. When you are ready to read a body (if any), call should_client_block().
>    *    This will tell the module whether or not to read input. If it is 0,
> !  *    the module should assume that there is no message body to read.
> !  *    This step also sends a 100 Continue response to HTTP/1.1 clients,
> !  *    so should not be called until the module is *definitely* ready to
> !  *    read content. (otherwise, the point of the 100 response is defeated).
> !  *    Never call this function more than once.
>    *
> +  * 4. Finally, call get_client_block in a loop. Pass it a buffer and its size.
> +  *    It will put data into the buffer (not necessarily a full buffer), and
> +  *    return the length of the input block. When it is done reading, it will
> +  *    return 0 if EOF, or -1 if there was an error.
> +  *    If an error occurs on input, we force an end to keepalive.
>    */
>   
>   int setup_client_block (request_rec *r)
>   {
> !     char *tenc = table_get(r->headers_in, "Transfer-Encoding");
> !     char *lenp = table_get(r->headers_in, "Content-length");
>   
>       if (tenc) {
> !         if (strcasecmp(tenc, "chunked")) {
> !             log_printf(r->server, "Unknown Transfer-Encoding %s", tenc);
> !             return HTTP_BAD_REQUEST;
> !         }
> !         if (r->read_body == REQUEST_CHUNKED_ERROR) {
> !             log_reason("chunked Transfer-Encoding forbidden", r->uri, r);
> !             return HTTP_LENGTH_REQUIRED;
> !         }
> ! 
> !         r->read_chunked = 1;
> !         r->remaining = 0;
>       }
> !     else if (lenp) {
> !         char *pos = lenp;
> ! 
> !         while (isdigit(*pos) || isspace(*pos)) ++pos;
> !         if (*pos != '\0') {
> !             log_printf(r->server, "Invalid Content-Length %s", lenp);
> !             return HTTP_BAD_REQUEST;
> !         }
> ! 
> !         r->remaining = atol(lenp);
> !     }
> ! 
> !     if ((r->read_body == REQUEST_NO_BODY) &&
> !         (r->read_chunked || (r->remaining > 0))) {
> !         log_printf(r->server, "%s with body is not allowed for %s",
> !                    r->method, r->uri);
> !         return HTTP_REQUEST_ENTITY_TOO_LARGE;
>       }
>   
>       return OK;
> ***************
> *** 1113,1123 ****
>   
>   int should_client_block (request_rec *r)
>   {
> !     /* The following should involve a test of whether the request message
> !      * included a Content-Length or Transfer-Encoding header field, since
> !      * methods are supposed to be extensible.  However, this'll do for now.
> !      */
> !     if (r->method_number != M_POST && r->method_number != M_PUT)
>           return 0;
>   
>       if (r->proto_num >= 1001) {    /* sending 100 Continue interim response */
> --- 1145,1151 ----
>   
>   int should_client_block (request_rec *r)
>   {
> !     if (!r->read_chunked && (r->remaining <= 0))
>           return 0;
>   
>       if (r->proto_num >= 1001) {    /* sending 100 Continue interim response */
> ***************
> *** 1129,1195 ****
>       return 1;
>   }
>   
> ! static int rd_chunk_size (BUFF *b)
>   {
> !     int chunksize = 0;
> !     int c;
>   
> !     while ((c = bgetc (b)) != EOF && isxdigit (c)) {
>           int xvalue = 0;
>   
> !         if (c >= '0' && c <= '9') xvalue = c - '0';
> !         else if (c >= 'A' && c <= 'F') xvalue = c - 'A' + 0xa;
> !         else if (c >= 'a' && c <= 'f') xvalue = c - 'a' + 0xa;
>   
>           chunksize = (chunksize << 4) | xvalue;
>       }
>   
> !     /* Skip to end of line, bypassing chunk options, if present */
> ! 
> !     while (c != '\n' && c != EOF)
> !         c = bgetc (b);
> ! 
> !     return (c == EOF) ? -1 : chunksize;
>   }
>   
>   long get_client_block (request_rec *r, char *buffer, int bufsiz)
>   {
> !     long c, len_read, len_to_read = r->remaining;
>   
> !     if (!r->read_chunked) {	/* Content-length read */
> ! 	if (len_to_read > bufsiz)
> ! 	    len_to_read = bufsiz;
> ! 	len_read = bread(r->connection->client, buffer, len_to_read);
> ! 	r->remaining -= len_read;
> ! 	return len_read;
> !     }
> ! 
> !     /* Handle chunked reading */
> !     if (len_to_read == 0) {
> ! 	len_to_read = rd_chunk_size(r->connection->client);
> ! 	if (len_to_read == 0) {
> ! 	    /* Read any footers - the module may not notice them,
> ! 	     * but they're there, and so we read them */
> ! 	    get_mime_headers(r);
> ! 	    return 0;
> ! 	}
>       }
> !     if (len_to_read > bufsiz) {
> ! 	r->remaining = len_to_read - bufsiz;
> ! 	len_to_read = bufsiz;
>       }
> !     else
> ! 	r->remaining = 0;
>       
>       len_read = bread(r->connection->client, buffer, len_to_read);
> !     if (r->remaining == 0) {
> ! 	/* Read the newline at the end of the chunk
> ! 	 * (and any other garbage that might be present) */
> ! 	do c = bgetc (r->connection->client);
> ! 	while (c != '\n' && c != EOF);
>       }
>   
> !     return len_read;
>   }
>   
>   long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); }
> --- 1157,1309 ----
>       return 1;
>   }
>   
> ! static long get_chunk_size (char *b)
>   {
> !     long chunksize = 0;
>   
> !     while (isxdigit(*b)) {
>           int xvalue = 0;
>   
> !         if (*b >= '0' && *b <= '9')      xvalue = *b - '0';
> !         else if (*b >= 'A' && *b <= 'F') xvalue = *b - 'A' + 0xa;
> !         else if (*b >= 'a' && *b <= 'f') xvalue = *b - 'a' + 0xa;
>   
>           chunksize = (chunksize << 4) | xvalue;
> +         ++b;
>       }
>   
> !     return chunksize;
>   }
>   
> + /* get_client_block is called in a loop to get the request message body.
> +  * This is quite simple if the client includes a content-length
> +  * (the normal case), but gets messy if the body is chunked. Note that
> +  * r->remaining is used to maintain state across calls and that
> +  * r->read_length is the total number of bytes given to the caller
> +  * across all invocations.  It is messy because we have to be careful not
> +  * to read past the data provided by the client, since these reads block.
> +  * Assumes that caller will never pass a bufsiz <= 2; that would be dumb.
> +  * Returns 0 on End-of-body, -1 on error or premature chunk end.
> +  */
>   long get_client_block (request_rec *r, char *buffer, int bufsiz)
>   {
> !     int c;
> !     long len_read, len_to_read;
> !     long chunk_start = 0;
>   
> !     if (!r->read_chunked) {                 /* Content-length read */
> !         len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
> !         len_read = bread(r->connection->client, buffer, len_to_read);
> !         if (len_read <= 0) {
> !             if (len_read < 0) r->connection->keepalive = -1;
> !             return len_read;
> !         }
> !         r->read_length += len_read;
> !         r->remaining   -= len_read;
> !         return len_read;
>       }
> ! 
> !     /* Handle chunked reading
> !      * Note: we are careful to shorten the input bufsiz so that there
> !      * will always be enough space for us to add a CRLF (if necessary).
> !      */
> !     if (r->read_body == REQUEST_CHUNKED_PASS)
> !         bufsiz -= 2;
> ! 
> !     if (r->remaining == 0) {         /* Start of new chunk */
> ! 
> !         chunk_start = getline(buffer, bufsiz, r->connection->client, 0);
> !         if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1))
> !                                || !isxdigit(*buffer)) {
> !             r->connection->keepalive = -1;
> !             return -1;
> !         }
> ! 
> !         len_to_read = get_chunk_size(buffer);
> ! 
> !         if (len_to_read == 0) {      /* Last chunk indicated, get footers */
> !             if (r->read_body == REQUEST_CHUNKED_DECHUNK) {
> !                 get_mime_headers(r);
> !                 sprintf(buffer, "%ld", r->read_length);
> !                 table_unset(r->headers_in, "Transfer-Encoding");
> !                 table_set(r->headers_in, "Content-Length", buffer);
> !                 return 0;
> !             }
> !             r->remaining = -1;       /* Indicate footers in-progress */
> !         }
> !         else {
> !             r->remaining = len_to_read;
> !         }
> !         if (r->read_body == REQUEST_CHUNKED_PASS) {
> !             buffer[chunk_start++] = CR;  /* Restore chunk-size line end  */
> !             buffer[chunk_start++] = LF;
> !             buffer += chunk_start;       /* and pass line on to caller   */
> !             bufsiz -= chunk_start;
> !         }
>       }
> !                                      /* When REQUEST_CHUNKED_PASS, we are */
> !     if (r->remaining == -1) {        /* reading footers until empty line  */
> !         len_read = chunk_start;
> ! 
> !         while ((bufsiz > 1) && ((len_read =
> !                 getline(buffer, bufsiz, r->connection->client, 1)) > 0)) {
> ! 
> !             if (len_read != (bufsiz - 1)) {
> !                 buffer[len_read++] = CR;  /* Restore footer line end  */
> !                 buffer[len_read++] = LF;
> !             }
> !             chunk_start += len_read;
> !             buffer      += len_read;
> !             bufsiz      -= len_read;
> !         }
> !         if (len_read < 0) {
> !             r->connection->keepalive = -1;
> !             return -1;
> !         }
> ! 
> !         if (len_read == 0) {         /* Indicates an empty line */
> !             buffer[0] = CR;
> !             buffer[1] = LF;
> !             chunk_start += 2;
> !             r->remaining = -2;
> !         }
> !         r->read_length += chunk_start;
> !         return chunk_start;
> !     }
> !                                      /* When REQUEST_CHUNKED_PASS, we     */
> !     if (r->remaining == -2) {        /* finished footers when last called */
> !         r->remaining = 0;            /*     so now we must signal EOF     */
> !         return 0;
> !     }
> ! 
> !     /* Otherwise, we are in the midst of reading a chunk of data */
> ! 
> !     len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
>       
>       len_read = bread(r->connection->client, buffer, len_to_read);
> !     if (len_read <= 0) {
> !         r->connection->keepalive = -1;
> !         return -1;
>       }
>   
> !     r->remaining -= len_read;
> ! 
> !     if (r->remaining == 0) {         /* End of chunk, get trailing CRLF */
> !         if ((c = bgetc(r->connection->client)) == CR) {
> !            c = bgetc(r->connection->client);
> !         }
> !         if (c != LF) {
> !             r->connection->keepalive = -1;
> !             return -1;
> !         }
> !         if (r->read_body == REQUEST_CHUNKED_PASS) {
> !             buffer[len_read++] = CR;
> !             buffer[len_read++] = LF;
> !         }
> !     }
> !     r->read_length += (chunk_start + len_read);
> ! 
> !     return (chunk_start + len_read);
>   }
>   
>   long send_fd(FILE *f, request_rec *r) { return send_fd_length(f, r, -1); }
> ***************
> *** 1468,1477 ****
>   	           "Please remove all references to this resource.\n", NULL);
>     	    break;
>   	case HTTP_REQUEST_ENTITY_TOO_LARGE:
> ! 	    bputs("The supplied request data exceeds the capacity\n", fd);
> ! 	    bputs("limit placed on this resource. The request data \n", fd);
> ! 	    bputs("must be reduced before the request can proceed.\n", fd);
> !   	    break;
>   	case HTTP_REQUEST_URI_TOO_LARGE:
>   	    bputs("The requested URL's length exceeds the capacity\n", fd);
>   	    bputs("limit for this server.\n", fd);
> --- 1582,1593 ----
>   	           "Please remove all references to this resource.\n", NULL);
>     	    break;
>   	case HTTP_REQUEST_ENTITY_TOO_LARGE:
> ! 	    bvputs(fd, "The requested resource<BR>",
> ! 	           escape_html(r->pool, r->uri), "<BR>\n",
> ! 	           "does not allow request data with ", r->method,
> ! 	           " requests, or the amount of data provided in\n",
> ! 	           "the request exceeds the capacity limit.\n", NULL);
> ! 	    break;
>   	case HTTP_REQUEST_URI_TOO_LARGE:
>   	    bputs("The requested URL's length exceeds the capacity\n", fd);
>   	    bputs("limit for this server.\n", fd);
> Index: mod_cgi.c
> ===================================================================
> RCS file: /export/home/cvs/apache/src/mod_cgi.c,v
> retrieving revision 1.20
> diff -c -r1.20 mod_cgi.c
> *** mod_cgi.c	1996/10/20 18:03:34	1.20
> --- mod_cgi.c	1996/11/23 09:54:22
> ***************
> *** 381,386 ****
> --- 381,388 ----
>   	return log_scripterror(r, conf, FORBIDDEN,
>   			       "file permissions deny server execution");
>       
> +     r->read_body = REQUEST_CHUNKED_ERROR; /* Require Content-Length if body */
> + 
>       if ((retval = setup_client_block(r)))
>   	return retval;
>   
> ***************
> *** 422,437 ****
>           hard_timeout ("copy script args", r);
>           handler = signal (SIGPIPE, SIG_IGN);
>       
> ! 	while ((len_read = get_client_block (r, argsbuffer, HUGE_STRING_LEN)))
>   	{
> - 	    if (fwrite (argsbuffer, 1, len_read, script_out) == 0)
> - 		break;
>   	    if (conf->logname) {
>   		if ((dbpos + len_read) > conf->bufbytes)
>   		    dbsize = conf->bufbytes - dbpos;
>   		else dbsize = len_read;
>   		strncpy(dbuf + dbpos, argsbuffer, dbsize);
>   		dbpos += dbsize;
>   	    }
>   	}
>   
> --- 424,444 ----
>           hard_timeout ("copy script args", r);
>           handler = signal (SIGPIPE, SIG_IGN);
>       
> ! 	while ((len_read =
> !                 get_client_block(r, argsbuffer, HUGE_STRING_LEN)) > 0)
>   	{
>   	    if (conf->logname) {
>   		if ((dbpos + len_read) > conf->bufbytes)
>   		    dbsize = conf->bufbytes - dbpos;
>   		else dbsize = len_read;
>   		strncpy(dbuf + dbpos, argsbuffer, dbsize);
>   		dbpos += dbsize;
> + 	    }
> + 	    if (fwrite(argsbuffer, 1, len_read, script_out) < len_read) {
> + 		/* silly script stopped reading, soak up remaining message */
> + 	        while (get_client_block(r, argsbuffer, HUGE_STRING_LEN) > 0)
> + 	            ; /* dump it */
> + 	        break;
>   	    }
>   	}
>   
> Index: mod_fastcgi.c
> ===================================================================
> RCS file: /export/home/cvs/apache/src/mod_fastcgi.c,v
> retrieving revision 1.2
> diff -c -r1.2 mod_fastcgi.c
> *** mod_fastcgi.c	1996/10/22 20:38:11	1.2
> --- mod_fastcgi.c	1996/11/23 09:54:23
> ***************
> *** 3673,3678 ****
> --- 3673,3679 ----
>                   reqPtr->filename, reqPtr);
>           return NOT_FOUND;
>       }
> +     reqPtr->read_body = REQUEST_CHUNKED_DECHUNK;
>       status = setup_client_block(reqPtr);
>       if(status != OK) {
>           return status;
> Index: modules/proxy/mod_proxy.c
> ===================================================================
> RCS file: /export/home/cvs/apache/src/modules/proxy/mod_proxy.c,v
> retrieving revision 1.5
> diff -c -r1.5 mod_proxy.c
> *** mod_proxy.c	1996/10/20 23:58:59	1.5
> --- mod_proxy.c	1996/11/23 09:54:23
> ***************
> *** 196,201 ****
> --- 196,203 ----
>   
>       if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
>   
> +     r->read_body = REQUEST_CHUNKED_ERROR; /* Require Content-Length if body */
> +  
>       if ((rc = setup_client_block(r)))
>   	return rc;
>   
> Index: modules/proxy/proxy_http.c
> ===================================================================
> RCS file: /export/home/cvs/apache/src/modules/proxy/proxy_http.c,v
> retrieving revision 1.5
> diff -c -r1.5 proxy_http.c
> *** proxy_http.c	1996/10/27 18:29:57	1.5
> --- proxy_http.c	1996/11/23 09:54:23
> ***************
> *** 108,113 ****
> --- 108,133 ----
>       return OK;
>   }
>   
> + /* Clear all connection-based headers from the incoming headers table */
> + static void clear_connection (table *headers)
> + {
> +     char *name;
> +     char *next = table_get(headers, "Connection");
> + 
> +     if (!next) return;
> + 
> +     while (*next) {
> +         name = next;
> +         while (*next && !isspace(*next) && (*next != ',')) ++next;
> +         while (*next && (isspace(*next) || (*next == ','))) {
> +             *next = '\0';
> +             ++next;
> +         }
> +         table_unset(headers, name);
> +     }
> +     table_unset(headers, "Connection");
> + }
> + 
>   /*
>    * This handles http:// URLs, and other URLs using a remote proxy over http
>    * If proxyhost is NULL, then contact the server directly, otherwise
> ***************
> *** 193,198 ****
> --- 213,220 ----
>   	else return proxyerror(r, "Could not connect to remote machine");
>       }
>   
> +     clear_connection(r->headers_in);   /* Strip connection-based headers */
> + 
>       f = bcreate(pool, B_RDWR);
>       bpushfd(f, sock, sock);
>   
> ***************
> *** 204,210 ****
>       for (i=0; i < reqhdrs_arr->nelts; i++)
>       {
>   	if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL) continue;
> - 	if (!strcasecmp(reqhdrs[i].key, "Connection")) continue;
>   	bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, "\015\012", NULL);
>       }
>   
> --- 226,231 ----
> ***************
> *** 213,219 ****
>   
>       if (should_client_block(r))
>       {
> ! 	while ((i = get_client_block (r, buffer, HUGE_STRING_LEN)))
>               bwrite(f, buffer, i);
>       }
>       bflush(f);
> --- 234,240 ----
>   
>       if (should_client_block(r))
>       {
> ! 	while ((i = get_client_block(r, buffer, HUGE_STRING_LEN)) > 0)
>               bwrite(f, buffer, i);
>       }
>       bflush(f);




Mime
View raw message