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:
@@ -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,
|
||||||
|
@@ -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);
|
||||||
|
@@ -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;
|
||||||
|
Reference in New Issue
Block a user