1
/* Licensed to the Apache Software Foundation (ASF) under one or more
2
* contributor license agreements. See the NOTICE file distributed with
3
* this work for additional information regarding copyright ownership.
4
* The ASF licenses this file to You under the Apache License, Version 2.0
5
* (the "License"); you may not use this file except in compliance with
6
* the License. You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
18
* @file core_filters.c
19
* @brief Core input/output network filters.
23
#include "apr_strings.h"
25
#include "apr_fnmatch.h"
27
#include "apr_thread_proc.h" /* for RLIMIT stuff */
28
#include "apr_hooks.h"
30
#define APR_WANT_IOVEC
31
#define APR_WANT_STRFUNC
32
#define APR_WANT_MEMFUNC
36
#include "ap_config.h"
38
#include "http_config.h"
39
#include "http_core.h"
40
#include "http_protocol.h" /* For index_of_response(). Grump. */
41
#include "http_request.h"
42
#include "http_vhost.h"
43
#include "http_main.h" /* For the default_handler below... */
46
#include "http_connection.h"
47
#include "apr_buckets.h"
48
#include "util_filter.h"
49
#include "util_ebcdic.h"
51
#include "mpm_common.h"
52
#include "scoreboard.h"
54
#include "mod_proxy.h"
55
#include "ap_listen.h"
57
#include "mod_so.h" /* for ap_find_loaded_module_symbol */
59
#define AP_MIN_SENDFILE_BYTES (256)
62
* Remove all zero length buckets from the brigade.
64
#define BRIGADE_NORMALIZE(b) \
66
apr_bucket *e = APR_BRIGADE_FIRST(b); \
68
if (e->length == 0 && !APR_BUCKET_IS_METADATA(e)) { \
70
d = APR_BUCKET_NEXT(e); \
71
apr_bucket_delete(e); \
75
e = APR_BUCKET_NEXT(e); \
77
} while (!APR_BRIGADE_EMPTY(b) && (e != APR_BRIGADE_SENTINEL(b))); \
82
* Split the contents of a brigade after bucket 'e' to an existing brigade
84
* XXXX: Should this function be added to APR-Util?
86
static void brigade_move(apr_bucket_brigade *b, apr_bucket_brigade *a,
91
if (e != APR_BRIGADE_SENTINEL(b)) {
92
f = APR_RING_LAST(&b->list);
93
APR_RING_UNSPLICE(e, f, link);
94
APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link);
97
APR_BRIGADE_CHECK_CONSISTENCY(a);
98
APR_BRIGADE_CHECK_CONSISTENCY(b);
101
int ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
102
ap_input_mode_t mode, apr_read_type_e block,
107
core_net_rec *net = f->ctx;
108
core_ctx_t *ctx = net->in_ctx;
112
if (mode == AP_MODE_INIT) {
114
* this mode is for filters that might need to 'initialize'
115
* a connection before reading request data from a client.
116
* NNTP over SSL for example needs to handshake before the
117
* server sends the welcome message.
118
* such filters would have changed the mode before this point
119
* is reached. however, protocol modules such as NNTP should
120
* not need to know anything about SSL. given the example, if
121
* SSL is not in the filter chain, AP_MODE_INIT is a noop.
128
ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
129
ctx->b = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
130
ctx->tmpbb = apr_brigade_create(ctx->b->p, ctx->b->bucket_alloc);
131
/* seed the brigade with the client socket. */
132
e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
133
APR_BRIGADE_INSERT_TAIL(ctx->b, e);
136
else if (APR_BRIGADE_EMPTY(ctx->b)) {
140
/* ### This is bad. */
141
BRIGADE_NORMALIZE(ctx->b);
143
/* check for empty brigade again *AFTER* BRIGADE_NORMALIZE()
144
* If we have lost our socket bucket (see above), we are EOF.
146
* Ideally, this should be returning SUCCESS with EOS bucket, but
147
* some higher-up APIs (spec. read_request_line via ap_rgetline)
148
* want an error code. */
149
if (APR_BRIGADE_EMPTY(ctx->b)) {
153
if (mode == AP_MODE_GETLINE) {
154
/* we are reading a single LF line, e.g. the HTTP headers */
155
rv = apr_brigade_split_line(b, ctx->b, block, HUGE_STRING_LEN);
156
/* We should treat EAGAIN here the same as we do for EOF (brigade is
157
* empty). We do this by returning whatever we have read. This may
158
* or may not be bogus, but is consistent (for now) with EOF logic.
160
if (APR_STATUS_IS_EAGAIN(rv)) {
166
/* ### AP_MODE_PEEK is a horrific name for this mode because we also
167
* eat any CRLFs that we see. That's not the obvious intention of
168
* this mode. Determine whether anyone actually uses this or not. */
169
if (mode == AP_MODE_EATCRLF) {
173
/* The purpose of this loop is to ignore any CRLF (or LF) at the end
174
* of a request. Many browsers send extra lines at the end of POST
175
* requests. We use the PEEK method to determine if there is more
176
* data on the socket, so that we know if we should delay sending the
177
* end of one request until we have served the second request in a
178
* pipelined situation. We don't want to actually delay sending a
179
* response if the server finds a CRLF (or LF), becuause that doesn't
180
* mean that there is another request, just a blank line.
183
if (APR_BRIGADE_EMPTY(ctx->b))
186
e = APR_BRIGADE_FIRST(ctx->b);
188
rv = apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ);
190
if (rv != APR_SUCCESS)
194
while (c < str + len) {
195
if (*c == APR_ASCII_LF)
197
else if (*c == APR_ASCII_CR && *(c + 1) == APR_ASCII_LF)
203
/* If we reach here, we were a bucket just full of CRLFs, so
204
* just toss the bucket. */
205
/* FIXME: Is this the right thing to do in the core? */
206
apr_bucket_delete(e);
211
/* If mode is EXHAUSTIVE, we want to just read everything until the end
212
* of the brigade, which in this case means the end of the socket.
213
* To do this, we attach the brigade that has currently been setaside to
214
* the brigade that was passed down, and send that brigade back.
216
* NOTE: This is VERY dangerous to use, and should only be done with
217
* extreme caution. However, the Perchild MPM needs this feature
218
* if it is ever going to work correctly again. With this, the Perchild
219
* MPM can easily request the socket and all data that has been read,
220
* which means that it can pass it to the correct child process.
222
if (mode == AP_MODE_EXHAUSTIVE) {
225
/* Tack on any buckets that were set aside. */
226
APR_BRIGADE_CONCAT(b, ctx->b);
228
/* Since we've just added all potential buckets (which will most
229
* likely simply be the socket bucket) we know this is the end,
230
* so tack on an EOS too. */
231
/* We have read until the brigade was empty, so we know that we
233
e = apr_bucket_eos_create(f->c->bucket_alloc);
234
APR_BRIGADE_INSERT_TAIL(b, e);
238
/* read up to the amount they specified. */
239
if (mode == AP_MODE_READBYTES || mode == AP_MODE_SPECULATIVE) {
242
AP_DEBUG_ASSERT(readbytes > 0);
244
e = APR_BRIGADE_FIRST(ctx->b);
245
rv = apr_bucket_read(e, &str, &len, block);
247
if (APR_STATUS_IS_EAGAIN(rv)) {
250
else if (rv != APR_SUCCESS) {
253
else if (block == APR_BLOCK_READ && len == 0) {
254
/* We wanted to read some bytes in blocking mode. We read
255
* 0 bytes. Hence, we now assume we are EOS.
257
* When we are in normal mode, return an EOS bucket to the
259
* When we are in speculative mode, leave ctx->b empty, so
260
* that the next call returns an EOS bucket.
262
apr_bucket_delete(e);
264
if (mode == AP_MODE_READBYTES) {
265
e = apr_bucket_eos_create(f->c->bucket_alloc);
266
APR_BRIGADE_INSERT_TAIL(b, e);
271
/* We can only return at most what we read. */
272
if (len < readbytes) {
276
rv = apr_brigade_partition(ctx->b, readbytes, &e);
277
if (rv != APR_SUCCESS) {
281
/* Must do move before CONCAT */
282
brigade_move(ctx->b, ctx->tmpbb, e);
284
if (mode == AP_MODE_READBYTES) {
285
APR_BRIGADE_CONCAT(b, ctx->b);
287
else if (mode == AP_MODE_SPECULATIVE) {
288
apr_bucket *copy_bucket;
290
for (e = APR_BRIGADE_FIRST(ctx->b);
291
e != APR_BRIGADE_SENTINEL(ctx->b);
292
e = APR_BUCKET_NEXT(e))
294
rv = apr_bucket_copy(e, ©_bucket);
295
if (rv != APR_SUCCESS) {
298
APR_BRIGADE_INSERT_TAIL(b, copy_bucket);
302
/* Take what was originally there and place it back on ctx->b */
303
APR_BRIGADE_CONCAT(ctx->b, ctx->tmpbb);
308
static apr_status_t writev_it_all(apr_socket_t *s,
309
struct iovec *vec, int nvec,
310
apr_size_t len, apr_size_t *nbytes)
312
apr_size_t bytes_written = 0;
319
/* XXX handle checking for non-blocking socket */
320
while (bytes_written != len) {
321
rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
324
if (rv != APR_SUCCESS)
327
/* If the write did not complete, adjust the iovecs and issue
328
* apr_socket_sendv again
330
if (bytes_written < len) {
331
/* Skip over the vectors that have already been written */
332
apr_size_t cnt = vec[i].iov_len;
333
while (n >= cnt && i + 1 < nvec) {
335
cnt += vec[i].iov_len;
339
/* Handle partial write of vec i */
340
vec[i].iov_base = (char *) vec[i].iov_base +
341
(vec[i].iov_len - (cnt - n));
342
vec[i].iov_len = cnt -n;
346
n = len - bytes_written;
353
* send the entire file using sendfile()
354
* handle partial writes
355
* return only when all bytes have been sent or an error is encountered.
359
static apr_status_t sendfile_it_all(core_net_rec *c,
362
apr_off_t file_offset,
363
apr_size_t file_bytes_left,
364
apr_size_t total_bytes_left,
365
apr_size_t *bytes_sent,
370
apr_interval_time_t timeout = 0;
373
AP_DEBUG_ASSERT((apr_socket_timeout_get(c->client_socket, &timeout)
375
&& timeout > 0); /* socket must be in timeout mode */
377
/* Reset the bytes_sent field */
381
apr_size_t tmplen = file_bytes_left;
383
rv = apr_socket_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen,
385
*bytes_sent += tmplen;
386
total_bytes_left -= tmplen;
387
if (!total_bytes_left || rv != APR_SUCCESS) {
388
return rv; /* normal case & error exit */
391
AP_DEBUG_ASSERT(total_bytes_left > 0 && tmplen > 0);
393
/* partial write, oooh noooo...
394
* Skip over any header data which was written
396
while (tmplen && hdtr->numheaders) {
397
if (tmplen >= hdtr->headers[0].iov_len) {
398
tmplen -= hdtr->headers[0].iov_len;
403
char *iov_base = (char *)hdtr->headers[0].iov_base;
405
hdtr->headers[0].iov_len -= tmplen;
407
hdtr->headers[0].iov_base = iov_base;
412
/* Skip over any file data which was written */
414
if (tmplen <= file_bytes_left) {
415
file_offset += tmplen;
416
file_bytes_left -= tmplen;
420
tmplen -= file_bytes_left;
424
/* Skip over any trailer data which was written */
426
while (tmplen && hdtr->numtrailers) {
427
if (tmplen >= hdtr->trailers[0].iov_len) {
428
tmplen -= hdtr->trailers[0].iov_len;
433
char *iov_base = (char *)hdtr->trailers[0].iov_base;
435
hdtr->trailers[0].iov_len -= tmplen;
437
hdtr->trailers[0].iov_base = iov_base;
447
* Sends the contents of file fd along with header/trailer bytes, if any,
448
* to the network. emulate_sendfile will return only when all the bytes have been
449
* sent (i.e., it handles partial writes) or on a network error condition.
451
static apr_status_t emulate_sendfile(core_net_rec *c, apr_file_t *fd,
452
apr_hdtr_t *hdtr, apr_off_t offset,
453
apr_size_t length, apr_size_t *nbytes)
455
apr_status_t rv = APR_SUCCESS;
456
apr_size_t togo; /* Remaining number of bytes in the file to send */
457
apr_size_t sendlen = 0;
458
apr_size_t bytes_sent;
460
apr_off_t o; /* Track the file offset for partial writes */
466
* writev_it_all handles partial writes.
467
* XXX: optimization... if headers are less than MIN_WRITE_SIZE, copy
470
if (hdtr && hdtr->numheaders > 0 ) {
471
for (i = 0; i < hdtr->numheaders; i++) {
472
sendlen += hdtr->headers[i].iov_len;
475
rv = writev_it_all(c->client_socket, hdtr->headers, hdtr->numheaders,
476
sendlen, &bytes_sent);
477
*nbytes += bytes_sent; /* track total bytes sent */
480
/* Seek the file to 'offset' */
481
if (offset >= 0 && rv == APR_SUCCESS) {
482
rv = apr_file_seek(fd, APR_SET, &offset);
485
/* Send the file, making sure to handle partial writes */
487
while (rv == APR_SUCCESS && togo) {
488
sendlen = togo > sizeof(buffer) ? sizeof(buffer) : togo;
490
rv = apr_file_read(fd, buffer, &sendlen);
491
while (rv == APR_SUCCESS && sendlen) {
492
bytes_sent = sendlen;
493
rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
494
*nbytes += bytes_sent;
495
if (rv == APR_SUCCESS) {
496
sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */
497
o += bytes_sent; /* o is where we are in the buffer */
498
togo -= bytes_sent; /* track how much of the file we've sent */
504
* XXX: optimization... if it will fit, send this on the last send in the
508
if ( rv == APR_SUCCESS && hdtr && hdtr->numtrailers > 0 ) {
509
for (i = 0; i < hdtr->numtrailers; i++) {
510
sendlen += hdtr->trailers[i].iov_len;
512
rv = writev_it_all(c->client_socket, hdtr->trailers, hdtr->numtrailers,
513
sendlen, &bytes_sent);
514
*nbytes += bytes_sent;
520
#ifndef APR_MAX_IOVEC_SIZE
521
#define MAX_IOVEC_TO_WRITE 16
523
#if APR_MAX_IOVEC_SIZE > 16
524
#define MAX_IOVEC_TO_WRITE 16
526
#define MAX_IOVEC_TO_WRITE APR_MAX_IOVEC_SIZE
530
/* Optional function coming from mod_logio, used for logging of output
533
extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *logio_add_bytes_out;
535
apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
538
apr_bucket_brigade *more;
540
core_net_rec *net = f->ctx;
541
core_output_filter_ctx_t *ctx = net->out_ctx;
542
apr_read_type_e eblock = APR_NONBLOCK_READ;
543
apr_pool_t *input_pool = b->p;
546
ctx = apr_pcalloc(c->pool, sizeof(*ctx));
550
/* If we have a saved brigade, concatenate the new brigade to it */
552
APR_BRIGADE_CONCAT(ctx->b, b);
557
/* Perform multiple passes over the brigade, sending batches of output
558
to the connection. */
559
while (b && !APR_BRIGADE_EMPTY(b)) {
560
apr_size_t nbytes = 0;
561
apr_bucket *last_e = NULL; /* initialized for debugging */
564
/* one group of iovecs per pass over the brigade */
566
apr_size_t nvec_trailers = 0;
567
struct iovec vec[MAX_IOVEC_TO_WRITE];
568
struct iovec vec_trailers[MAX_IOVEC_TO_WRITE];
570
/* one file per pass over the brigade */
571
apr_file_t *fd = NULL;
573
apr_off_t foffset = 0;
575
/* keep track of buckets that we've concatenated
576
* to avoid small writes
578
apr_bucket *last_merged_bucket = NULL;
580
/* tail of brigade if we need another pass */
583
/* Iterate over the brigade: collect iovecs and/or a file */
584
for (e = APR_BRIGADE_FIRST(b);
585
e != APR_BRIGADE_SENTINEL(b);
586
e = APR_BUCKET_NEXT(e))
588
/* keep track of the last bucket processed */
590
if (APR_BUCKET_IS_EOS(e) || AP_BUCKET_IS_EOC(e)) {
593
else if (APR_BUCKET_IS_FLUSH(e)) {
594
if (e != APR_BRIGADE_LAST(b)) {
595
more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
600
/* It doesn't make any sense to use sendfile for a file bucket
601
* that represents 10 bytes.
603
else if (APR_BUCKET_IS_FILE(e)
604
&& (e->length >= AP_MIN_SENDFILE_BYTES)) {
605
apr_bucket_file *a = e->data;
607
/* We can't handle more than one file bucket at a time
608
* so we split here and send the file we have already
612
more = apr_brigade_split(b, e);
624
rv = apr_bucket_read(e, &str, &n, eblock);
625
if (APR_STATUS_IS_EAGAIN(rv)) {
626
/* send what we have so far since we shouldn't expect more
627
* output for a while... next time we read, block
629
more = apr_brigade_split(b, e);
630
eblock = APR_BLOCK_READ;
633
eblock = APR_NONBLOCK_READ;
636
if (nvec == MAX_IOVEC_TO_WRITE) {
637
/* woah! too many. buffer them up, for use later. */
638
apr_bucket *temp, *next;
639
apr_bucket_brigade *temp_brig;
641
if (nbytes >= AP_MIN_BYTES_TO_WRITE) {
642
/* We have enough data in the iovec
643
* to justify doing a writev
645
more = apr_brigade_split(b, e);
649
/* Create a temporary brigade as a means
650
* of concatenating a bunch of buckets together
652
if (last_merged_bucket) {
653
/* If we've concatenated together small
654
* buckets already in a previous pass,
655
* the initial buckets in this brigade
656
* are heap buckets that may have extra
657
* space left in them (because they
658
* were created by apr_brigade_write()).
659
* We can take advantage of this by
660
* building the new temp brigade out of
661
* these buckets, so that the content
662
* in them doesn't have to be copied again.
664
apr_bucket_brigade *bb;
665
bb = apr_brigade_split(b,
666
APR_BUCKET_NEXT(last_merged_bucket));
671
temp_brig = apr_brigade_create(f->c->pool,
675
temp = APR_BRIGADE_FIRST(b);
678
rv = apr_bucket_read(temp, &str, &n, APR_BLOCK_READ);
679
apr_brigade_write(temp_brig, NULL, NULL, str, n);
681
temp = APR_BUCKET_NEXT(temp);
682
apr_bucket_delete(d);
687
temp = APR_BRIGADE_FIRST(temp_brig);
688
APR_BUCKET_REMOVE(temp);
689
APR_BRIGADE_INSERT_HEAD(b, temp);
690
apr_bucket_read(temp, &str, &n, APR_BLOCK_READ);
691
vec[nvec].iov_base = (char*) str;
692
vec[nvec].iov_len = n;
695
/* Just in case the temporary brigade has
696
* multiple buckets, recover the rest of
697
* them and put them in the brigade that
700
for (next = APR_BRIGADE_FIRST(temp_brig);
701
next != APR_BRIGADE_SENTINEL(temp_brig);
702
next = APR_BRIGADE_FIRST(temp_brig)) {
703
APR_BUCKET_REMOVE(next);
704
APR_BUCKET_INSERT_AFTER(temp, next);
706
apr_bucket_read(next, &str, &n,
708
vec[nvec].iov_base = (char*) str;
709
vec[nvec].iov_len = n;
713
apr_brigade_destroy(temp_brig);
715
last_merged_bucket = temp;
720
vec[nvec].iov_base = (char*) str;
721
vec[nvec].iov_len = n;
726
/* The bucket is a trailer to a file bucket */
728
if (nvec_trailers == MAX_IOVEC_TO_WRITE) {
729
/* woah! too many. stop now. */
730
more = apr_brigade_split(b, e);
734
vec_trailers[nvec_trailers].iov_base = (char*) str;
735
vec_trailers[nvec_trailers].iov_len = n;
745
/* Completed iterating over the brigade, now determine if we want
746
* to buffer the brigade or send the brigade out on the network.
748
* Save if we haven't accumulated enough bytes to send, the connection
749
* is not about to be closed, and:
751
* 1) we didn't see a file, we don't have more passes over the
752
* brigade to perform, AND we didn't stop at a FLUSH bucket.
753
* (IOW, we will save plain old bytes such as HTTP headers)
755
* 2) we hit the EOS and have a keep-alive connection
756
* (IOW, this response is a bit more complex, but we save it
757
* with the hope of concatenating with another response)
759
if (nbytes + flen < AP_MIN_BYTES_TO_WRITE
760
&& !AP_BUCKET_IS_EOC(last_e)
761
&& ((!fd && !more && !APR_BUCKET_IS_FLUSH(last_e))
762
|| (APR_BUCKET_IS_EOS(last_e)
763
&& c->keepalive == AP_CONN_KEEPALIVE))) {
765
/* NEVER save an EOS in here. If we are saving a brigade with
766
* an EOS bucket, then we are doing keepalive connections, and
767
* we want to process to second request fully.
769
if (APR_BUCKET_IS_EOS(last_e)) {
771
int file_bucket_saved = 0;
772
apr_bucket_delete(last_e);
773
for (bucket = APR_BRIGADE_FIRST(b);
774
bucket != APR_BRIGADE_SENTINEL(b);
775
bucket = APR_BUCKET_NEXT(bucket)) {
777
/* Do a read on each bucket to pull in the
778
* data from pipe and socket buckets, so
779
* that we don't leave their file descriptors
780
* open indefinitely. Do the same for file
781
* buckets, with one exception: allow the
782
* first file bucket in the brigade to remain
783
* a file bucket, so that we don't end up
784
* doing an mmap+memcpy every time a client
785
* requests a <8KB file over a keepalive
788
if (APR_BUCKET_IS_FILE(bucket) && !file_bucket_saved) {
789
file_bucket_saved = 1;
794
rv = apr_bucket_read(bucket, &buf, &len,
796
if (rv != APR_SUCCESS) {
797
ap_log_cerror(APLOG_MARK, APLOG_ERR, rv,
798
c, "core_output_filter:"
799
" Error reading from bucket.");
800
return HTTP_INTERNAL_SERVER_ERROR;
805
if (!ctx->deferred_write_pool) {
806
apr_pool_create(&ctx->deferred_write_pool, c->pool);
807
apr_pool_tag(ctx->deferred_write_pool, "deferred_write");
809
ap_save_brigade(f, &ctx->b, &b, ctx->deferred_write_pool);
816
apr_size_t bytes_sent;
819
apr_int32_t flags = 0;
822
memset(&hdtr, '\0', sizeof(hdtr));
824
hdtr.numheaders = nvec;
829
hdtr.numtrailers = nvec_trailers;
830
hdtr.trailers = vec_trailers;
834
if (apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) {
836
if (c->keepalive == AP_CONN_CLOSE && APR_BUCKET_IS_EOS(last_e)) {
837
/* Prepare the socket to be reused */
838
flags |= APR_SENDFILE_DISCONNECT_SOCKET;
841
rv = sendfile_it_all(net, /* the network information */
842
fd, /* the file to send */
843
&hdtr, /* header and trailer iovecs */
844
foffset, /* offset in the file to begin
846
flen, /* length of file */
847
nbytes + flen, /* total length including
849
&bytes_sent, /* how many bytes were
851
flags); /* apr_sendfile flags */
856
rv = emulate_sendfile(net, fd, &hdtr, foffset, flen,
860
if (logio_add_bytes_out && bytes_sent > 0)
861
logio_add_bytes_out(c, bytes_sent);
866
apr_size_t bytes_sent;
868
rv = writev_it_all(net->client_socket,
870
nbytes, &bytes_sent);
872
if (logio_add_bytes_out && bytes_sent > 0)
873
logio_add_bytes_out(c, bytes_sent);
876
apr_brigade_destroy(b);
878
/* drive cleanups for resources which were set aside
879
* this may occur before or after termination of the request which
880
* created the resource
882
if (ctx->deferred_write_pool) {
883
if (more && more->p == ctx->deferred_write_pool) {
884
/* "more" belongs to the deferred_write_pool,
885
* which is about to be cleared.
887
if (APR_BRIGADE_EMPTY(more)) {
891
/* uh oh... change more's lifetime
892
* to the input brigade's lifetime
894
apr_bucket_brigade *tmp_more = more;
896
ap_save_brigade(f, &more, &tmp_more, input_pool);
899
apr_pool_clear(ctx->deferred_write_pool);
902
if (rv != APR_SUCCESS) {
903
ap_log_cerror(APLOG_MARK, APLOG_INFO, rv, c,
904
"core_output_filter: writing data to the network");
907
apr_brigade_destroy(more);
909
/* No need to check for SUCCESS, we did that above. */
910
if (!APR_STATUS_IS_EAGAIN(rv)) {
914
/* The client has aborted, but the request was successful. We
915
* will report success, and leave it to the access and error
916
* logs to note that the connection was aborted.