On Thu, 30 Dec 2004 13:54:05 -0500, Jeff Trawick <[EMAIL PROTECTED]> wrote:
> An interesting issue is that what is in 2.0 now is optimal when it
> works, and it works in a common real-world scenario (client sends C-L
> and no filters modify the request body size). At present, we don't
> have any proposed solution which would preserve this common, optimal
> situation. That will be a painful regression for some, since the
> request body will be buffered in memory in order to re-calculate the
> C-L.
Here is a patch which preserves the C-L setting and streams the
request body when the client specified C-L and there are no input
filters which could possibly muck with the request body. (Some
filters might be in place which don't modify the request body length,
but we can't check that. An envvar could be used to indicate that it
is safe to preserve the C-L even though there is an input filter.)
Index: modules/proxy/proxy_http.c
===================================================================
--- modules/proxy/proxy_http.c (revision 123727)
+++ modules/proxy/proxy_http.c (working copy)
@@ -247,7 +247,7 @@
apr_bucket *e, *last_header_bucket = NULL;
const apr_array_header_t *headers_in_array;
const apr_table_entry_t *headers_in;
- int counter, seen_eos, send_chunks;
+ int counter, seen_eos, send_chunks, same_cl;
apr_status_t status;
apr_bucket_brigade *header_brigade, *body_brigade, *input_brigade;
apr_off_t transferred = 0;
@@ -282,15 +282,26 @@
/* By default, we can not send chunks. That means we must buffer
* the entire request before sending it along to ensure we have
- * the correct Content-Length attached.
+ * the correct Content-Length attached. A special case is when
+ * the client specifies Content-Length and there are no filters
+ * to muck with the request body. In that situation, we don't
+ * have to buffer the entire request and can still send the
+ * Content-Length.
*/
+
+ same_cl = 0;
send_chunks = 0;
+ if (apr_table_get(r->headers_in, "Content-Length") &&
+ r->input_filters == r->proto_input_filters) {
+ same_cl = 1; /* content-length will remain the same */
+ }
+
if (apr_table_get(r->subprocess_env, "force-proxy-request-1.0")) {
buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.0" CRLF, NULL);
} else {
buf = apr_pstrcat(p, r->method, " ", url, " HTTP/1.1" CRLF, NULL);
- if (apr_table_get(r->subprocess_env, "proxy-sendchunks")) {
+ if (!same_cl && apr_table_get(r->subprocess_env, "proxy-sendchunks")) {
send_chunks = 1;
}
}
@@ -470,6 +481,15 @@
e = apr_bucket_pool_create(buf, sizeof(te_hdr)-1, p, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(header_brigade, e);
}
+ else if (same_cl) {
+ buf = apr_pstrcat(p, "Content-Length: ",
+ apr_table_get(r->headers_in, "Content-Length"),
+ CRLF,
+ NULL);
+ ap_xlate_proto_to_ascii(buf, strlen(buf));
+ e = apr_bucket_pool_create(buf, strlen(buf), p, c->bucket_alloc);
+ APR_BRIGADE_INSERT_TAIL(header_brigade, e);
+ }
else {
last_header_bucket = APR_BRIGADE_LAST(header_brigade);
}
@@ -487,7 +507,7 @@
apr_brigade_length(header_brigade, 0, &transferred);
if (transferred != -1)
conn->worker->s->transferred += transferred;
- if (send_chunks) {
+ if (send_chunks || same_cl) {
status = ap_pass_brigade(origin->output_filters, header_brigade);
if (status != APR_SUCCESS) {
@@ -550,7 +570,7 @@
e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(input_brigade, e);
}
- else {
+ else if (!same_cl) {
/* The send_chunks case does not need to be setaside, but this
* case does because we may have transient buckets that may get
* overwritten in the next iteration of the loop.
@@ -567,7 +587,7 @@
APR_BRIGADE_CONCAT(body_brigade, input_brigade);
- if (send_chunks) {
+ if (send_chunks || same_cl) {
status = ap_pass_brigade(origin->output_filters, body_brigade);
if (status != APR_SUCCESS) {
@@ -591,7 +611,7 @@
APR_BRIGADE_INSERT_TAIL(body_brigade, e);
}
- if (!send_chunks) {
+ if (!send_chunks && !same_cl) {
apr_off_t bytes;
apr_brigade_length(body_brigade, 1, &bytes);