httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jeff Trawick <trawi...@bellsouth.net>
Subject Re: providing content-length
Date Fri, 27 Oct 2000 02:33:18 GMT
Jeff Trawick <trawickj@bellsouth.net> writes:

> We should be able to modify the http header filter to recognize that
> there is no content-length and that we're using HTTP/1.0, and have it
> provide the content length (easier said than done, of course).  With
> such code, we can use a filter which zaps the content length field
> (since it expects to invalidate it) but still have Netscape behave
> suitably. 
> 
> Does anybody have any ideas about controls over when we provide the
> Content-Length?  Obviously there are some performance issues
> involved.  It may be quite painful for certain systems to provide
> Content-Length on certain pages.

Here is a patch to provide content length.  I'm not sure when the
content-length calculator should kick in...  Under directive control?
Note that it doesn't currently implement the check for r->chunked
because r->chunked hasn't been calculated yet.  But hey, we get nice
progress bars with Content-Length anyway... who needs chunked? (only
3% serious)

Comments?

Index: main/http_core.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/main/http_core.c,v
retrieving revision 1.190
diff -u -r1.190 http_core.c
--- main/http_core.c	2000/10/26 12:03:07	1.190
+++ main/http_core.c	2000/10/27 02:25:34
@@ -3578,6 +3578,8 @@
     ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE);
     ap_register_input_filter("CORE_IN", core_input_filter, AP_FTYPE_NETWORK);
     ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, AP_FTYPE_HTTP_HEADER);
+    ap_register_output_filter("CONTENT_LENGTH", ap_content_length_filter, 
+                              AP_FTYPE_HTTP_HEADER);
     ap_register_output_filter("CORE", core_output_filter, AP_FTYPE_NETWORK);
     ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter, 
                               AP_FTYPE_CONTENT);
Index: main/http_protocol.c
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/main/http_protocol.c,v
retrieving revision 1.209
diff -u -r1.209 http_protocol.c
--- main/http_protocol.c	2000/10/26 11:05:07	1.209
+++ main/http_protocol.c	2000/10/27 02:25:38
@@ -1417,6 +1417,7 @@
                ? &r->server->keep_alive_timeout
                : &r->server->timeout);
 
+    ap_add_output_filter("CONTENT_LENGTH", NULL, r, r->connection);
     ap_add_output_filter("HTTP_HEADER", NULL, r, r->connection);
 
     /* Get the request... */
@@ -2227,6 +2228,70 @@
 
 AP_DECLARE(void) ap_send_http_header(request_rec *r)
 {
+}
+
+struct content_length_ctx {
+    apr_size_t content_length;
+    ap_bucket_brigade *saved;
+};
+
+AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(ap_filter_t *f,
+                                                              ap_bucket_brigade *b)
+{
+    request_rec *r = f->r;
+    struct content_length_ctx *ctx;
+    apr_status_t rv;
+    ap_bucket *e;
+
+    /* We'll go to the trouble of providing a content-length only if it is
+     * . not a subrequest
+     * . HTTP/1.0 or higher
+     * . no content length already
+     * . not chunked              XXX no logic for this currently
+     */
+    if (r->assbackwards ||
+        apr_table_get(r->headers_out, "Content-Length")) {
+        ap_remove_output_filter(f);
+        return ap_pass_brigade(f->next, b);
+    }
+
+    ctx = f->ctx;
+    if (!ctx) {
+        f->ctx = ctx = apr_pcalloc(r->pool, sizeof(struct content_length_ctx));
+    }
+
+    AP_BRIGADE_FOREACH(e, b) {
+        if (!AP_BUCKET_IS_EOS(e)) {
+            if (e->length >= 0) {
+                ctx->content_length += e->length;
+            }
+            else {
+                const char *ignored;
+                apr_ssize_t length;
+
+                rv = ap_bucket_read(e, &ignored, &length, 1);
+                if (rv != APR_SUCCESS) {
+                    return rv;
+                }
+                ctx->content_length += e->length;
+            }
+        }
+    }
+
+    if (AP_BUCKET_IS_EOS(AP_BRIGADE_LAST(b))) {
+        ap_set_content_length(r, ctx->content_length);
+        if (ctx->saved) {
+            AP_BRIGADE_CONCAT(ctx->saved, b);
+            b = ctx->saved;
+        }
+        return ap_pass_brigade(f->next, b);
+    }
+
+    /* save the brigade; we can't pass any data to the next
+     * filter until we have the entire content length
+     */
+    ap_save_brigade(f, &ctx->saved, &b);
+    return APR_SUCCESS;
 }
 
 AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, ap_bucket_brigade
*b)
Index: include/http_protocol.h
===================================================================
RCS file: /home/cvspublic/apache-2.0/src/include/http_protocol.h,v
retrieving revision 1.35
diff -u -r1.35 http_protocol.h
--- include/http_protocol.h	2000/10/22 13:09:23	1.35
+++ include/http_protocol.h	2000/10/27 02:25:39
@@ -113,6 +113,8 @@
 AP_DECLARE(void) ap_send_http_header(request_rec *l);
 
 AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, ap_bucket_brigade
*b);
+AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(ap_filter_t *, 
+                                                              ap_bucket_brigade *);
 
 /* Send the response to special method requests */
 
@@ -533,6 +535,7 @@
 
 apr_status_t ap_http_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode);
 apr_status_t ap_dechunk_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode);
+
 
   /* Hooks */
   /*

-- 
Jeff Trawick | trawick@ibm.net | PGP public key at web site:
     http://www.geocities.com/SiliconValley/Park/9289/
          Born in Roswell... married an alien...

Mime
View raw message