AP_HOOK_LINK(default_port)
)
-#define SET_BYTES_SENT(r) \
- do { if (r->sent_bodyct) \
- ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
- } while (0)
-
-
/* if this is the first error, then log an INFO message and shut down the
* connection.
*/
return EOF;
}
- SET_BYTES_SENT(r);
return n;
}
void ap_finalize_sub_req_protocol(request_rec *sub)
{
end_output_stream(sub);
-
- SET_BYTES_SENT(sub->main);
}
/*
terminate_header(buff);
- ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
+ r->bytes_sent = 0;
bb = ap_brigade_create(r->pool);
b = ap_bucket_create_pool(buff, strlen(buff), r->pool);
struct content_length_ctx {
ap_bucket_brigade *saved;
+ int hold_data; /* Whether or not to buffer the data. */
};
+/* This filter computes the content length, but it also computes the number
+ * of bytes sent to the client. This means that this filter will always run
+through all of the buckets in all brigades */
AP_CORE_DECLARE_NONSTD(apr_status_t) ap_content_length_filter(ap_filter_t *f,
ap_bucket_brigade *b)
{
struct content_length_ctx *ctx;
apr_status_t rv;
ap_bucket *e;
+ int send_it = 0;
ctx = f->ctx;
if (!ctx) { /* first time through */
+ f->ctx = ctx = apr_pcalloc(r->pool, sizeof(struct content_length_ctx));
+
/* We won't compute a content length if one of the following is true:
* . subrequest
* . HTTP/0.9
|| 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);
+ "chunked")) {
+ ctx->hold_data = 0;
+ }
+ else {
+ ctx->hold_data = 1;
}
-
- 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;
+ AP_BRIGADE_FOREACH(e, b) {
+ const char *ignored;
+ apr_ssize_t length;
- if (ctx->saved) {
- AP_BRIGADE_CONCAT(ctx->saved, b);
- b = ctx->saved;
+ if (AP_BUCKET_IS_EOS(e) || AP_BUCKET_IS_FLUSH(e)) {
+ ctx->hold_data = 0;
+ send_it = 1;
}
-
- 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, AP_BLOCK_READ);
- if (rv != APR_SUCCESS) {
- return rv;
- }
- content_length += e->length;
- }
- }
+ rv = ap_bucket_read(e, &ignored, &length, AP_BLOCK_READ);
+ if (rv != APR_SUCCESS) {
+ return rv;
}
-
- ap_set_content_length(r, content_length);
- return ap_pass_brigade(f->next, b);
+ r->bytes_sent += length;
}
- /* check for flush bucket... if there is one, we have to scratch
- * the idea of providing content length because the output should
- * flow immediately (for streaming dynamic content)
+ /* save the brigade; we can't pass any data to the next
+ * filter until we have the entire content length
*/
+ if (ctx->hold_data && !send_it) {
+ ap_save_brigade(f, &ctx->saved, &b);
+ return APR_SUCCESS;
+ }
- AP_BRIGADE_FOREACH(e, b) {
- if (AP_BUCKET_IS_FLUSH(e)) {
- AP_BRIGADE_CONCAT(ctx->saved, b);
- ap_remove_output_filter(f);
- return ap_pass_brigade(f->next, ctx->saved);
- }
+ if (ctx->saved) {
+ AP_BRIGADE_CONCAT(ctx->saved, b);
+ b = ctx->saved;
}
- /* 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_set_content_length(r, r->bytes_sent);
+ return ap_pass_brigade(f->next, b);
}
AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, ap_bucket_brigade *b)
{
int i;
- const long int zero = 0L;
char *date = NULL;
request_rec *r = f->r;
char *buff, *buff_start;
AP_DEBUG_ASSERT(!r->main);
if (r->assbackwards) {
+ r->bytes_sent = 0;
r->sent_bodyct = 1;
ap_remove_output_filter(f);
return ap_pass_brigade(f->next, b);
terminate_header(buff);
- ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
r->sent_bodyct = 1; /* Whatever follows is real body stuff... */
b2 = ap_brigade_create(r->pool);
total_bytes_sent += o;
}
- SET_BYTES_SENT(r);
*nbytes = total_bytes_sent;
return rv;
}