1
0
mirror of https://github.com/apache/httpd.git synced 2025-08-08 15:02:10 +03:00

Compute the content length (and add appropriate header field) for

the response when no content length is available and we can't use
chunked encoding.

This is going to be painful when the response body is huge, so I
suspect we'll have additional criteria in the future.


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86775 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jeff Trawick
2000-10-31 12:30:22 +00:00
parent 5403b81ddb
commit ad7545f0b4
3 changed files with 84 additions and 0 deletions

View File

@@ -113,6 +113,8 @@ AP_DECLARE(void) ap_basic_http_header(request_rec *r);
AP_DECLARE(void) ap_send_http_header(request_rec *l); 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_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 */ /* Send the response to special method requests */
@@ -534,6 +536,7 @@ AP_DECLARE(const char *) ap_method_name_of(int methnum);
apr_status_t ap_http_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode); 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); apr_status_t ap_dechunk_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_t mode);
/* Hooks */ /* Hooks */
/* /*
* post_read_request --- run right after read_request or internal_redirect, * post_read_request --- run right after read_request or internal_redirect,

View File

@@ -3578,6 +3578,8 @@ static void register_hooks(void)
ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE); 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_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("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("CORE", core_output_filter, AP_FTYPE_NETWORK);
ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter, ap_register_output_filter("SUBREQ_CORE", ap_sub_req_output_filter,
AP_FTYPE_CONTENT); AP_FTYPE_CONTENT);

View File

@@ -1417,6 +1417,7 @@ request_rec *ap_read_request(conn_rec *conn)
? &r->server->keep_alive_timeout ? &r->server->keep_alive_timeout
: &r->server->timeout); : &r->server->timeout);
ap_add_output_filter("CONTENT_LENGTH", NULL, r, r->connection);
ap_add_output_filter("HTTP_HEADER", NULL, r, r->connection); ap_add_output_filter("HTTP_HEADER", NULL, r, r->connection);
/* Get the request... */ /* Get the request... */
@@ -2229,6 +2230,84 @@ AP_DECLARE(void) ap_send_http_header(request_rec *r)
{ {
} }
struct content_length_ctx {
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;
ctx = f->ctx;
if (!ctx) { /* first time through */
/* We won't compute a content length if one of the following is true:
* . subrequest
* . HTTP/0.9
* . status HTTP_NOT_MODIFIED or HTTP_NO_CONTENT
* . HEAD
* . content length already computed
* . can be chunked
* . body already chunked
* Much of this should correspond to checks in ap_set_keepalive().
*/
if (r->assbackwards
|| r->status == HTTP_NOT_MODIFIED
|| r->status == HTTP_NO_CONTENT
|| r->header_only
|| apr_table_get(r->headers_out, "Content-Length")
|| r->proto_num == HTTP_VERSION(1,1)
|| ap_find_last_token(f->r->pool,
apr_table_get(r->headers_out,
"Transfer-Encoding"),
"chunked")) {
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, b);
}
f->ctx = ctx = apr_pcalloc(r->pool, sizeof(struct content_length_ctx));
}
if (AP_BUCKET_IS_EOS(AP_BRIGADE_LAST(b))) {
apr_ssize_t content_length = 0;
if (ctx->saved) {
AP_BRIGADE_CONCAT(ctx->saved, b);
b = ctx->saved;
}
AP_BRIGADE_FOREACH(e, b) {
if (!AP_BUCKET_IS_EOS(e)) {
if (e->length >= 0) {
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;
}
content_length += e->length;
}
}
}
ap_set_content_length(r, content_length);
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) AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, ap_bucket_brigade *b)
{ {
int i; int i;