fielding 96/11/25 03:22:06
Modified: src httpd.h http_config.h http_protocol.h
http_protocol.c mod_cgi.c mod_fastcgi.c
util_script.c
src/modules/proxy mod_proxy.c proxy_http.c
Log:
Added ability for modules to select the policy for reading a request
message body as part of the call to setup_client_block(). The code can
now reject a message body, require Content-Length if there is a body,
transparently dechunk a chunked body, or pass the chunks to the module.
Added read_body (to remember the policy) and read_length (to keep track
of the amount of bytes read) to the request_rec structure.
Added code to force an end to keepalive if the client input is errored,
since this might not be caught by a CGI script and might result in
a hanging connection til timeout, or a double response to the remaining
input as if it were an additional request. Fixed a bug in get_client_block
not checking for a negative (error) result from the read routines, and
made the corresponding changes to the calls from mod_cgi, mod_fastcgi,
and mod_proxy. Removed the method-dependent code from the three module
input routines, since the question of whether or not the request message
contains a body is solely determined by the presence of a non-zero
Content-Length or Transfer-Encoding field.
This is an interface change, so the API version has been bumped.
Fixed a bug in outgoing CGI responses, due to not checking for a script
sending Content-Length or Transfer-Encoding, that was causing keepalive
to end in 1.1.1 and an invalid combination of Content-Length and
Transfer-Encoding in the current version.
Fixed a bug in the proxy in regards to how it was clearing the Connection
header field and fields indicated by it.
Reviewed by: Randy Terbush, Brian Behlendorf, Jim Jagielski
Revision Changes Path
1.63 +14 -1 apache/src/httpd.h
Index: httpd.h
===================================================================
RCS file: /export/home/cvs/apache/src/httpd.h,v
retrieving revision 1.62
retrieving revision 1.63
diff -C3 -r1.62 -r1.63
*** httpd.h 1996/11/23 23:18:52 1.62
--- httpd.h 1996/11/25 11:21:58 1.63
***************
*** 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
1.22 +1 -1 apache/src/http_config.h
Index: http_config.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_config.h,v
retrieving revision 1.21
retrieving revision 1.22
diff -C3 -r1.21 -r1.22
*** http_config.h 1996/11/12 05:22:03 1.21
--- http_config.h 1996/11/25 11:21:58 1.22
***************
*** 225,231 ****
* handle it back-compatibly, or at least signal an error).
*/
! #define MODULE_MAGIC_NUMBER 19961007
#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, NULL
/* Generic accessors for other modules to get at their own module-specific
--- 225,231 ----
* handle it back-compatibly, or at least signal an error).
*/
! #define MODULE_MAGIC_NUMBER 19961125
#define STANDARD_MODULE_STUFF MODULE_MAGIC_NUMBER, -1, __FILE__, NULL
/* Generic accessors for other modules to get at their own module-specific
1.13 +1 -1 apache/src/http_protocol.h
Index: http_protocol.h
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.h,v
retrieving revision 1.12
retrieving revision 1.13
diff -C3 -r1.12 -r1.13
*** http_protocol.h 1996/10/20 18:03:32 1.12
--- http_protocol.h 1996/11/25 11:21:59 1.13
***************
*** 124,130 ****
/* Reading a block of data from the client connection (e.g., POST arg) */
! int setup_client_block (request_rec *r);
int should_client_block (request_rec *r);
long get_client_block (request_rec *r, char *buffer, int bufsiz);
--- 124,130 ----
/* Reading a block of data from the client connection (e.g., POST arg) */
! 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);
1.77 +214 -90 apache/src/http_protocol.c
Index: http_protocol.c
===================================================================
RCS file: /export/home/cvs/apache/src/http_protocol.c,v
retrieving revision 1.76
retrieving revision 1.77
diff -C3 -r1.76 -r1.77
*** http_protocol.c 1996/11/23 20:51:45 1.76
--- http_protocol.c 1996/11/25 11:21:59 1.77
***************
*** 206,218 ****
int set_keepalive(request_rec *r)
{
! char *conn = table_get (r->headers_in, "Connection");
! 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)))) &&
(!find_token(r->pool, conn, "close")) &&
((ka_sent = find_token(r->pool, conn, "keep-alive")) ||
--- 206,221 ----
int set_keepalive(request_rec *r)
{
! char *conn = table_get(r->headers_in, "Connection");
! char *length = table_get(r->headers_out, "Content-Length");
! char *tenc = table_get(r->headers_out, "Transfer-Encoding");
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 || tenc ||
((r->proto_num >= 1001) && (r->byterange > 1 || (r->chunked = 1)))) &&
(!find_token(r->pool, conn, "close")) &&
((ka_sent = find_token(r->pool, conn, "keep-alive")) ||
***************
*** 633,638 ****
--- 636,644 ----
r->per_dir_config = r->server->lookup_defaults; /* For now. */
r->sent_bodyct = 0; /* bytect isn't for body */
+
+ r->read_length = 0;
+ r->read_body = REQUEST_NO_BODY;
r->status = HTTP_OK; /* Until further notice.
* Only changed by die(), or (bletch!)
***************
*** 703,708 ****
--- 709,717 ----
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;
}
***************
*** 1056,1112 ****
}
! /* 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,1147 ----
}
! /* 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. 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. The second parameter selects the policy to
! * apply if the request message indicates a body, and how a chunked
! * transfer-coding should be interpreted. Choose 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.
*
! * In order to use the last two options, the caller MUST provide a buffer
! * large enough to hold a chunk-size line, including any extensions.
*
+ * 2. 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.
+ *
+ * 3. 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, int read_policy)
{
! char *tenc = table_get(r->headers_in, "Transfer-Encoding");
! char *lenp = table_get(r->headers_in, "Content-length");
! r->read_body = read_policy;
! r->read_chunked = 0;
! r->remaining = 0;
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 (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED;
! }
!
! r->read_chunked = 1;
}
! 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;
***************
*** 1114,1124 ****
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
*/
--- 1149,1155 ----
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
*/
***************
*** 1130,1196 ****
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); }
--- 1161,1318 ----
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.
+ * Returns 0 on End-of-body, -1 on error or premature chunk end.
+ *
+ * Reading the chunked encoding requires a buffer size large enough to
+ * hold a chunk-size line, including any extensions. For now, we'll leave
+ * that to the caller, at least until we can come up with a better solution.
+ */
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 (bufsiz <= 0)
! return -1; /* Cannot read chunked with a small buffer */
!
! 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); }
***************
*** 1469,1478 ****
"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);
--- 1591,1602 ----
"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);
1.21 +9 -4 apache/src/mod_cgi.c
Index: mod_cgi.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_cgi.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -C3 -r1.20 -r1.21
*** mod_cgi.c 1996/10/20 18:03:34 1.20
--- mod_cgi.c 1996/11/25 11:22:00 1.21
***************
*** 381,387 ****
return log_scripterror(r, conf, FORBIDDEN,
"file permissions deny server execution");
! if ((retval = setup_client_block(r)))
return retval;
add_common_vars (r);
--- 381,387 ----
return log_scripterror(r, conf, FORBIDDEN,
"file permissions deny server execution");
! if ((retval = setup_client_block(r, REQUEST_CHUNKED_ERROR)))
return retval;
add_common_vars (r);
***************
*** 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;
}
}
--- 422,442 ----
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;
}
}
1.3 +1 -1 apache/src/mod_fastcgi.c
Index: mod_fastcgi.c
===================================================================
RCS file: /export/home/cvs/apache/src/mod_fastcgi.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -C3 -r1.2 -r1.3
*** mod_fastcgi.c 1996/10/22 20:38:11 1.2
--- mod_fastcgi.c 1996/11/25 11:22:00 1.3
***************
*** 3673,3679 ****
reqPtr->filename, reqPtr);
return NOT_FOUND;
}
! status = setup_client_block(reqPtr);
if(status != OK) {
return status;
}
--- 3673,3679 ----
reqPtr->filename, reqPtr);
return NOT_FOUND;
}
! status = setup_client_block(reqPtr, REQUEST_CHUNKED_ERROR);
if(status != OK) {
return status;
}
1.27 +6 -0 apache/src/util_script.c
Index: util_script.c
===================================================================
RCS file: /export/home/cvs/apache/src/util_script.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -C3 -r1.26 -r1.27
*** util_script.c 1996/11/12 06:02:54 1.26
--- util_script.c 1996/11/25 11:22:01 1.27
***************
*** 327,332 ****
--- 327,338 ----
else if(!strcasecmp(w,"Location")) {
table_set (r->headers_out, w, l);
}
+ else if(!strcasecmp(w,"Content-Length")) {
+ table_set (r->headers_out, w, l);
+ }
+ else if(!strcasecmp(w,"Transfer-Encoding")) {
+ table_set (r->headers_out, w, l);
+ }
/* The HTTP specification says that it is legal to merge duplicate
* headers into one. Some browsers that support Cookies don't like
1.6 +1 -1 apache/src/modules/proxy/mod_proxy.c
Index: mod_proxy.c
===================================================================
RCS file: /export/home/cvs/apache/src/modules/proxy/mod_proxy.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C3 -r1.5 -r1.6
*** mod_proxy.c 1996/10/20 23:58:59 1.5
--- mod_proxy.c 1996/11/25 11:22:05 1.6
***************
*** 196,202 ****
if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
! if ((rc = setup_client_block(r)))
return rc;
url = r->filename + 6;
--- 196,202 ----
if (strncmp(r->filename, "proxy:", 6) != 0) return DECLINED;
! if ((rc = setup_client_block(r, REQUEST_CHUNKED_ERROR)))
return rc;
url = r->filename + 6;
1.6 +23 -2 apache/src/modules/proxy/proxy_http.c
Index: proxy_http.c
===================================================================
RCS file: /export/home/cvs/apache/src/modules/proxy/proxy_http.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C3 -r1.5 -r1.6
*** proxy_http.c 1996/10/27 18:29:57 1.5
--- proxy_http.c 1996/11/25 11:22:05 1.6
***************
*** 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);