1 /* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * 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 * core_filters.c --- Core input/output network filters.
22 #include "apr_strings.h"
24 #include "apr_fnmatch.h"
26 #include "apr_thread_proc.h" /* for RLIMIT stuff */
27 #include "apr_hooks.h"
29 #define APR_WANT_IOVEC
30 #define APR_WANT_STRFUNC
31 #define APR_WANT_MEMFUNC
35 #include "ap_config.h"
37 #include "http_config.h"
38 #include "http_core.h"
39 #include "http_protocol.h" /* For index_of_response(). Grump. */
40 #include "http_request.h"
41 #include "http_vhost.h"
42 #include "http_main.h" /* For the default_handler below... */
45 #include "http_connection.h"
46 #include "apr_buckets.h"
47 #include "util_filter.h"
48 #include "util_ebcdic.h"
50 #include "mpm_common.h"
51 #include "scoreboard.h"
53 #include "mod_proxy.h"
54 #include "ap_listen.h"
56 #include "mod_so.h" /* for ap_find_loaded_module_symbol */
58 #define AP_MIN_SENDFILE_BYTES (256)
60 typedef struct net_time_filter_ctx {
63 } net_time_filter_ctx_t;
65 int ap_net_time_filter(ap_filter_t *f, apr_bucket_brigade *b,
66 ap_input_mode_t mode, apr_read_type_e block,
69 net_time_filter_ctx_t *ctx = f->ctx;
70 int keptalive = f->c->keepalive == AP_CONN_KEEPALIVE;
73 f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx));
75 ctx->csd = ap_get_module_config(f->c->conn_config, &core_module);
78 if (mode != AP_MODE_INIT && mode != AP_MODE_EATCRLF) {
79 if (ctx->first_line) {
80 apr_socket_timeout_set(ctx->csd,
82 ? f->c->base_server->keep_alive_timeout
83 : f->c->base_server->timeout);
88 apr_socket_timeout_set(ctx->csd, f->c->base_server->timeout);
92 return ap_get_brigade(f->next, b, mode, block, readbytes);
96 * Remove all zero length buckets from the brigade.
98 #define BRIGADE_NORMALIZE(b) \
100 apr_bucket *e = APR_BRIGADE_FIRST(b); \
102 if (e->length == 0 && !APR_BUCKET_IS_METADATA(e)) { \
104 d = APR_BUCKET_NEXT(e); \
105 apr_bucket_delete(e); \
108 e = APR_BUCKET_NEXT(e); \
109 } while (!APR_BRIGADE_EMPTY(b) && (e != APR_BRIGADE_SENTINEL(b))); \
112 int ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
113 ap_input_mode_t mode, apr_read_type_e block,
118 core_net_rec *net = f->ctx;
119 core_ctx_t *ctx = net->in_ctx;
123 if (mode == AP_MODE_INIT) {
125 * this mode is for filters that might need to 'initialize'
126 * a connection before reading request data from a client.
127 * NNTP over SSL for example needs to handshake before the
128 * server sends the welcome message.
129 * such filters would have changed the mode before this point
130 * is reached. however, protocol modules such as NNTP should
131 * not need to know anything about SSL. given the example, if
132 * SSL is not in the filter chain, AP_MODE_INIT is a noop.
139 ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
140 ctx->b = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
142 /* seed the brigade with the client socket. */
143 e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
144 APR_BRIGADE_INSERT_TAIL(ctx->b, e);
147 else if (APR_BRIGADE_EMPTY(ctx->b)) {
151 /* ### This is bad. */
152 BRIGADE_NORMALIZE(ctx->b);
154 /* check for empty brigade again *AFTER* BRIGADE_NORMALIZE()
155 * If we have lost our socket bucket (see above), we are EOF.
157 * Ideally, this should be returning SUCCESS with EOS bucket, but
158 * some higher-up APIs (spec. read_request_line via ap_rgetline)
159 * want an error code. */
160 if (APR_BRIGADE_EMPTY(ctx->b)) {
164 if (mode == AP_MODE_GETLINE) {
165 /* we are reading a single LF line, e.g. the HTTP headers */
166 rv = apr_brigade_split_line(b, ctx->b, block, HUGE_STRING_LEN);
167 /* We should treat EAGAIN here the same as we do for EOF (brigade is
168 * empty). We do this by returning whatever we have read. This may
169 * or may not be bogus, but is consistent (for now) with EOF logic.
171 if (APR_STATUS_IS_EAGAIN(rv)) {
177 /* ### AP_MODE_PEEK is a horrific name for this mode because we also
178 * eat any CRLFs that we see. That's not the obvious intention of
179 * this mode. Determine whether anyone actually uses this or not. */
180 if (mode == AP_MODE_EATCRLF) {
184 /* The purpose of this loop is to ignore any CRLF (or LF) at the end
185 * of a request. Many browsers send extra lines at the end of POST
186 * requests. We use the PEEK method to determine if there is more
187 * data on the socket, so that we know if we should delay sending the
188 * end of one request until we have served the second request in a
189 * pipelined situation. We don't want to actually delay sending a
190 * response if the server finds a CRLF (or LF), becuause that doesn't
191 * mean that there is another request, just a blank line.
194 if (APR_BRIGADE_EMPTY(ctx->b))
197 e = APR_BRIGADE_FIRST(ctx->b);
199 rv = apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ);
201 if (rv != APR_SUCCESS)
205 while (c < str + len) {
206 if (*c == APR_ASCII_LF)
208 else if (*c == APR_ASCII_CR && *(c + 1) == APR_ASCII_LF)
214 /* If we reach here, we were a bucket just full of CRLFs, so
215 * just toss the bucket. */
216 /* FIXME: Is this the right thing to do in the core? */
217 apr_bucket_delete(e);
222 /* If mode is EXHAUSTIVE, we want to just read everything until the end
223 * of the brigade, which in this case means the end of the socket.
224 * To do this, we attach the brigade that has currently been setaside to
225 * the brigade that was passed down, and send that brigade back.
227 * NOTE: This is VERY dangerous to use, and should only be done with
228 * extreme caution. However, the Perchild MPM needs this feature
229 * if it is ever going to work correctly again. With this, the Perchild
230 * MPM can easily request the socket and all data that has been read,
231 * which means that it can pass it to the correct child process.
233 if (mode == AP_MODE_EXHAUSTIVE) {
236 /* Tack on any buckets that were set aside. */
237 APR_BRIGADE_CONCAT(b, ctx->b);
239 /* Since we've just added all potential buckets (which will most
240 * likely simply be the socket bucket) we know this is the end,
241 * so tack on an EOS too. */
242 /* We have read until the brigade was empty, so we know that we
244 e = apr_bucket_eos_create(f->c->bucket_alloc);
245 APR_BRIGADE_INSERT_TAIL(b, e);
249 /* read up to the amount they specified. */
250 if (mode == AP_MODE_READBYTES || mode == AP_MODE_SPECULATIVE) {
252 apr_bucket_brigade *newbb;
254 AP_DEBUG_ASSERT(readbytes > 0);
256 e = APR_BRIGADE_FIRST(ctx->b);
257 rv = apr_bucket_read(e, &str, &len, block);
259 if (APR_STATUS_IS_EAGAIN(rv)) {
262 else if (rv != APR_SUCCESS) {
265 else if (block == APR_BLOCK_READ && len == 0) {
266 /* We wanted to read some bytes in blocking mode. We read
267 * 0 bytes. Hence, we now assume we are EOS.
269 * When we are in normal mode, return an EOS bucket to the
271 * When we are in speculative mode, leave ctx->b empty, so
272 * that the next call returns an EOS bucket.
274 apr_bucket_delete(e);
276 if (mode == AP_MODE_READBYTES) {
277 e = apr_bucket_eos_create(f->c->bucket_alloc);
278 APR_BRIGADE_INSERT_TAIL(b, e);
283 /* We can only return at most what we read. */
284 if (len < readbytes) {
288 rv = apr_brigade_partition(ctx->b, readbytes, &e);
289 if (rv != APR_SUCCESS) {
293 /* Must do split before CONCAT */
294 newbb = apr_brigade_split(ctx->b, e);
296 if (mode == AP_MODE_READBYTES) {
297 APR_BRIGADE_CONCAT(b, ctx->b);
299 else if (mode == AP_MODE_SPECULATIVE) {
300 apr_bucket *copy_bucket;
302 for (e = APR_BRIGADE_FIRST(ctx->b);
303 e != APR_BRIGADE_SENTINEL(ctx->b);
304 e = APR_BUCKET_NEXT(e))
306 rv = apr_bucket_copy(e, ©_bucket);
307 if (rv != APR_SUCCESS) {
310 APR_BRIGADE_INSERT_TAIL(b, copy_bucket);
314 /* Take what was originally there and place it back on ctx->b */
315 APR_BRIGADE_CONCAT(ctx->b, newbb);
320 static apr_status_t writev_it_all(apr_socket_t *s,
321 struct iovec *vec, int nvec,
322 apr_size_t len, apr_size_t *nbytes)
324 apr_size_t bytes_written = 0;
331 /* XXX handle checking for non-blocking socket */
332 while (bytes_written != len) {
333 rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
336 if (rv != APR_SUCCESS)
339 /* If the write did not complete, adjust the iovecs and issue
340 * apr_socket_sendv again
342 if (bytes_written < len) {
343 /* Skip over the vectors that have already been written */
344 apr_size_t cnt = vec[i].iov_len;
345 while (n >= cnt && i + 1 < nvec) {
347 cnt += vec[i].iov_len;
351 /* Handle partial write of vec i */
352 vec[i].iov_base = (char *) vec[i].iov_base +
353 (vec[i].iov_len - (cnt - n));
354 vec[i].iov_len = cnt -n;
358 n = len - bytes_written;
365 * send the entire file using sendfile()
366 * handle partial writes
367 * return only when all bytes have been sent or an error is encountered.
371 static apr_status_t sendfile_it_all(core_net_rec *c,
374 apr_off_t file_offset,
375 apr_size_t file_bytes_left,
376 apr_size_t total_bytes_left,
377 apr_size_t *bytes_sent,
382 apr_interval_time_t timeout = 0;
385 AP_DEBUG_ASSERT((apr_socket_timeout_get(c->client_socket, &timeout)
387 && timeout > 0); /* socket must be in timeout mode */
389 /* Reset the bytes_sent field */
393 apr_size_t tmplen = file_bytes_left;
395 rv = apr_socket_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen,
397 *bytes_sent += tmplen;
398 total_bytes_left -= tmplen;
399 if (!total_bytes_left || rv != APR_SUCCESS) {
400 return rv; /* normal case & error exit */
403 AP_DEBUG_ASSERT(total_bytes_left > 0 && tmplen > 0);
405 /* partial write, oooh noooo...
406 * Skip over any header data which was written
408 while (tmplen && hdtr->numheaders) {
409 if (tmplen >= hdtr->headers[0].iov_len) {
410 tmplen -= hdtr->headers[0].iov_len;
415 char *iov_base = (char *)hdtr->headers[0].iov_base;
417 hdtr->headers[0].iov_len -= tmplen;
419 hdtr->headers[0].iov_base = iov_base;
424 /* Skip over any file data which was written */
426 if (tmplen <= file_bytes_left) {
427 file_offset += tmplen;
428 file_bytes_left -= tmplen;
432 tmplen -= file_bytes_left;
436 /* Skip over any trailer data which was written */
438 while (tmplen && hdtr->numtrailers) {
439 if (tmplen >= hdtr->trailers[0].iov_len) {
440 tmplen -= hdtr->trailers[0].iov_len;
445 char *iov_base = (char *)hdtr->trailers[0].iov_base;
447 hdtr->trailers[0].iov_len -= tmplen;
449 hdtr->trailers[0].iov_base = iov_base;
459 * Sends the contents of file fd along with header/trailer bytes, if any,
460 * to the network. emulate_sendfile will return only when all the bytes have been
461 * sent (i.e., it handles partial writes) or on a network error condition.
463 static apr_status_t emulate_sendfile(core_net_rec *c, apr_file_t *fd,
464 apr_hdtr_t *hdtr, apr_off_t offset,
465 apr_size_t length, apr_size_t *nbytes)
467 apr_status_t rv = APR_SUCCESS;
468 apr_size_t togo; /* Remaining number of bytes in the file to send */
469 apr_size_t sendlen = 0;
470 apr_size_t bytes_sent;
472 apr_off_t o; /* Track the file offset for partial writes */
478 * writev_it_all handles partial writes.
479 * XXX: optimization... if headers are less than MIN_WRITE_SIZE, copy
482 if (hdtr && hdtr->numheaders > 0 ) {
483 for (i = 0; i < hdtr->numheaders; i++) {
484 sendlen += hdtr->headers[i].iov_len;
487 rv = writev_it_all(c->client_socket, hdtr->headers, hdtr->numheaders,
488 sendlen, &bytes_sent);
489 *nbytes += bytes_sent; /* track total bytes sent */
492 /* Seek the file to 'offset' */
493 if (offset >= 0 && rv == APR_SUCCESS) {
494 rv = apr_file_seek(fd, APR_SET, &offset);
497 /* Send the file, making sure to handle partial writes */
499 while (rv == APR_SUCCESS && togo) {
500 sendlen = togo > sizeof(buffer) ? sizeof(buffer) : togo;
502 rv = apr_file_read(fd, buffer, &sendlen);
503 while (rv == APR_SUCCESS && sendlen) {
504 bytes_sent = sendlen;
505 rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
506 *nbytes += bytes_sent;
507 if (rv == APR_SUCCESS) {
508 sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */
509 o += bytes_sent; /* o is where we are in the buffer */
510 togo -= bytes_sent; /* track how much of the file we've sent */
516 * XXX: optimization... if it will fit, send this on the last send in the
520 if ( rv == APR_SUCCESS && hdtr && hdtr->numtrailers > 0 ) {
521 for (i = 0; i < hdtr->numtrailers; i++) {
522 sendlen += hdtr->trailers[i].iov_len;
524 rv = writev_it_all(c->client_socket, hdtr->trailers, hdtr->numtrailers,
525 sendlen, &bytes_sent);
526 *nbytes += bytes_sent;
532 #ifndef APR_MAX_IOVEC_SIZE
533 #define MAX_IOVEC_TO_WRITE 16
535 #if APR_MAX_IOVEC_SIZE > 16
536 #define MAX_IOVEC_TO_WRITE 16
538 #define MAX_IOVEC_TO_WRITE APR_MAX_IOVEC_SIZE
542 /* Optional function coming from mod_logio, used for logging of output
545 extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *logio_add_bytes_out;
547 apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
550 apr_bucket_brigade *more;
552 core_net_rec *net = f->ctx;
553 core_output_filter_ctx_t *ctx = net->out_ctx;
554 apr_read_type_e eblock = APR_NONBLOCK_READ;
555 apr_pool_t *input_pool = b->p;
558 ctx = apr_pcalloc(c->pool, sizeof(*ctx));
562 /* If we have a saved brigade, concatenate the new brigade to it */
564 APR_BRIGADE_CONCAT(ctx->b, b);
569 /* Perform multiple passes over the brigade, sending batches of output
570 to the connection. */
571 while (b && !APR_BRIGADE_EMPTY(b)) {
572 apr_size_t nbytes = 0;
573 apr_bucket *last_e = NULL; /* initialized for debugging */
576 /* one group of iovecs per pass over the brigade */
578 apr_size_t nvec_trailers = 0;
579 struct iovec vec[MAX_IOVEC_TO_WRITE];
580 struct iovec vec_trailers[MAX_IOVEC_TO_WRITE];
582 /* one file per pass over the brigade */
583 apr_file_t *fd = NULL;
585 apr_off_t foffset = 0;
587 /* keep track of buckets that we've concatenated
588 * to avoid small writes
590 apr_bucket *last_merged_bucket = NULL;
592 /* tail of brigade if we need another pass */
595 /* Iterate over the brigade: collect iovecs and/or a file */
596 for (e = APR_BRIGADE_FIRST(b);
597 e != APR_BRIGADE_SENTINEL(b);
598 e = APR_BUCKET_NEXT(e))
600 /* keep track of the last bucket processed */
602 if (APR_BUCKET_IS_EOS(e) || AP_BUCKET_IS_EOC(e)) {
605 else if (APR_BUCKET_IS_FLUSH(e)) {
606 if (e != APR_BRIGADE_LAST(b)) {
607 more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
612 /* It doesn't make any sense to use sendfile for a file bucket
613 * that represents 10 bytes.
615 else if (APR_BUCKET_IS_FILE(e)
616 && (e->length >= AP_MIN_SENDFILE_BYTES)) {
617 apr_bucket_file *a = e->data;
619 /* We can't handle more than one file bucket at a time
620 * so we split here and send the file we have already
624 more = apr_brigade_split(b, e);
636 rv = apr_bucket_read(e, &str, &n, eblock);
637 if (APR_STATUS_IS_EAGAIN(rv)) {
638 /* send what we have so far since we shouldn't expect more
639 * output for a while... next time we read, block
641 more = apr_brigade_split(b, e);
642 eblock = APR_BLOCK_READ;
645 eblock = APR_NONBLOCK_READ;
648 if (nvec == MAX_IOVEC_TO_WRITE) {
649 /* woah! too many. buffer them up, for use later. */
650 apr_bucket *temp, *next;
651 apr_bucket_brigade *temp_brig;
653 if (nbytes >= AP_MIN_BYTES_TO_WRITE) {
654 /* We have enough data in the iovec
655 * to justify doing a writev
657 more = apr_brigade_split(b, e);
661 /* Create a temporary brigade as a means
662 * of concatenating a bunch of buckets together
664 if (last_merged_bucket) {
665 /* If we've concatenated together small
666 * buckets already in a previous pass,
667 * the initial buckets in this brigade
668 * are heap buckets that may have extra
669 * space left in them (because they
670 * were created by apr_brigade_write()).
671 * We can take advantage of this by
672 * building the new temp brigade out of
673 * these buckets, so that the content
674 * in them doesn't have to be copied again.
676 apr_bucket_brigade *bb;
677 bb = apr_brigade_split(b,
678 APR_BUCKET_NEXT(last_merged_bucket));
683 temp_brig = apr_brigade_create(f->c->pool,
687 temp = APR_BRIGADE_FIRST(b);
690 rv = apr_bucket_read(temp, &str, &n, APR_BLOCK_READ);
691 apr_brigade_write(temp_brig, NULL, NULL, str, n);
693 temp = APR_BUCKET_NEXT(temp);
694 apr_bucket_delete(d);
699 temp = APR_BRIGADE_FIRST(temp_brig);
700 APR_BUCKET_REMOVE(temp);
701 APR_BRIGADE_INSERT_HEAD(b, temp);
702 apr_bucket_read(temp, &str, &n, APR_BLOCK_READ);
703 vec[nvec].iov_base = (char*) str;
704 vec[nvec].iov_len = n;
707 /* Just in case the temporary brigade has
708 * multiple buckets, recover the rest of
709 * them and put them in the brigade that
712 for (next = APR_BRIGADE_FIRST(temp_brig);
713 next != APR_BRIGADE_SENTINEL(temp_brig);
714 next = APR_BRIGADE_FIRST(temp_brig)) {
715 APR_BUCKET_REMOVE(next);
716 APR_BUCKET_INSERT_AFTER(temp, next);
718 apr_bucket_read(next, &str, &n,
720 vec[nvec].iov_base = (char*) str;
721 vec[nvec].iov_len = n;
725 apr_brigade_destroy(temp_brig);
727 last_merged_bucket = temp;
732 vec[nvec].iov_base = (char*) str;
733 vec[nvec].iov_len = n;
738 /* The bucket is a trailer to a file bucket */
740 if (nvec_trailers == MAX_IOVEC_TO_WRITE) {
741 /* woah! too many. stop now. */
742 more = apr_brigade_split(b, e);
746 vec_trailers[nvec_trailers].iov_base = (char*) str;
747 vec_trailers[nvec_trailers].iov_len = n;
757 /* Completed iterating over the brigade, now determine if we want
758 * to buffer the brigade or send the brigade out on the network.
760 * Save if we haven't accumulated enough bytes to send, the connection
761 * is not about to be closed, and:
763 * 1) we didn't see a file, we don't have more passes over the
764 * brigade to perform, AND we didn't stop at a FLUSH bucket.
765 * (IOW, we will save plain old bytes such as HTTP headers)
767 * 2) we hit the EOS and have a keep-alive connection
768 * (IOW, this response is a bit more complex, but we save it
769 * with the hope of concatenating with another response)
771 if (nbytes + flen < AP_MIN_BYTES_TO_WRITE
772 && !AP_BUCKET_IS_EOC(last_e)
773 && ((!fd && !more && !APR_BUCKET_IS_FLUSH(last_e))
774 || (APR_BUCKET_IS_EOS(last_e)
775 && c->keepalive == AP_CONN_KEEPALIVE))) {
777 /* NEVER save an EOS in here. If we are saving a brigade with
778 * an EOS bucket, then we are doing keepalive connections, and
779 * we want to process to second request fully.
781 if (APR_BUCKET_IS_EOS(last_e)) {
783 int file_bucket_saved = 0;
784 apr_bucket_delete(last_e);
785 for (bucket = APR_BRIGADE_FIRST(b);
786 bucket != APR_BRIGADE_SENTINEL(b);
787 bucket = APR_BUCKET_NEXT(bucket)) {
789 /* Do a read on each bucket to pull in the
790 * data from pipe and socket buckets, so
791 * that we don't leave their file descriptors
792 * open indefinitely. Do the same for file
793 * buckets, with one exception: allow the
794 * first file bucket in the brigade to remain
795 * a file bucket, so that we don't end up
796 * doing an mmap+memcpy every time a client
797 * requests a <8KB file over a keepalive
800 if (APR_BUCKET_IS_FILE(bucket) && !file_bucket_saved) {
801 file_bucket_saved = 1;
806 rv = apr_bucket_read(bucket, &buf, &len,
808 if (rv != APR_SUCCESS) {
809 ap_log_cerror(APLOG_MARK, APLOG_ERR, rv,
810 c, "core_output_filter:"
811 " Error reading from bucket.");
812 return HTTP_INTERNAL_SERVER_ERROR;
817 if (!ctx->deferred_write_pool) {
818 apr_pool_create(&ctx->deferred_write_pool, c->pool);
819 apr_pool_tag(ctx->deferred_write_pool, "deferred_write");
821 ap_save_brigade(f, &ctx->b, &b, ctx->deferred_write_pool);
828 apr_size_t bytes_sent;
831 apr_int32_t flags = 0;
834 memset(&hdtr, '\0', sizeof(hdtr));
836 hdtr.numheaders = nvec;
841 hdtr.numtrailers = nvec_trailers;
842 hdtr.trailers = vec_trailers;
846 if (apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) {
848 if (c->keepalive == AP_CONN_CLOSE && APR_BUCKET_IS_EOS(last_e)) {
849 /* Prepare the socket to be reused */
850 flags |= APR_SENDFILE_DISCONNECT_SOCKET;
853 rv = sendfile_it_all(net, /* the network information */
854 fd, /* the file to send */
855 &hdtr, /* header and trailer iovecs */
856 foffset, /* offset in the file to begin
858 flen, /* length of file */
859 nbytes + flen, /* total length including
861 &bytes_sent, /* how many bytes were
863 flags); /* apr_sendfile flags */
868 rv = emulate_sendfile(net, fd, &hdtr, foffset, flen,
872 if (logio_add_bytes_out && bytes_sent > 0)
873 logio_add_bytes_out(c, bytes_sent);
878 apr_size_t bytes_sent;
880 rv = writev_it_all(net->client_socket,
882 nbytes, &bytes_sent);
884 if (logio_add_bytes_out && bytes_sent > 0)
885 logio_add_bytes_out(c, bytes_sent);
888 apr_brigade_destroy(b);
890 /* drive cleanups for resources which were set aside
891 * this may occur before or after termination of the request which
892 * created the resource
894 if (ctx->deferred_write_pool) {
895 if (more && more->p == ctx->deferred_write_pool) {
896 /* "more" belongs to the deferred_write_pool,
897 * which is about to be cleared.
899 if (APR_BRIGADE_EMPTY(more)) {
903 /* uh oh... change more's lifetime
904 * to the input brigade's lifetime
906 apr_bucket_brigade *tmp_more = more;
908 ap_save_brigade(f, &more, &tmp_more, input_pool);
911 apr_pool_clear(ctx->deferred_write_pool);
914 if (rv != APR_SUCCESS) {
915 ap_log_cerror(APLOG_MARK, APLOG_INFO, rv, c,
916 "core_output_filter: writing data to the network");
919 apr_brigade_destroy(more);
921 /* No need to check for SUCCESS, we did that above. */
922 if (!APR_STATUS_IS_EAGAIN(rv)) {
926 /* The client has aborted, but the request was successful. We
927 * will report success, and leave it to the access and error
928 * logs to note that the connection was aborted.