]> granicus.if.org Git - apache/blob - server/core_filters.c
No functional Change: Removing trailing whitespace. This also
[apache] / server / core_filters.c
1 /* Copyright 2001-2005 The Apache Software Foundation or its licensors, as
2  * applicable.
3  *
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
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 /**
18  * @file  core_filters.c
19  * @brief Core input/output network filters.
20  */
21
22 #include "apr.h"
23 #include "apr_strings.h"
24 #include "apr_lib.h"
25 #include "apr_fnmatch.h"
26 #include "apr_hash.h"
27 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
28 #include "apr_hooks.h"
29 #include "apr_support.h"
30
31 #define APR_WANT_IOVEC
32 #define APR_WANT_STRFUNC
33 #define APR_WANT_MEMFUNC
34 #include "apr_want.h"
35
36 #define CORE_PRIVATE
37 #include "ap_config.h"
38 #include "httpd.h"
39 #include "http_config.h"
40 #include "http_core.h"
41 #include "http_protocol.h" /* For index_of_response().  Grump. */
42 #include "http_request.h"
43 #include "http_vhost.h"
44 #include "http_main.h"     /* For the default_handler below... */
45 #include "http_log.h"
46 #include "util_md5.h"
47 #include "http_connection.h"
48 #include "apr_buckets.h"
49 #include "util_filter.h"
50 #include "util_ebcdic.h"
51 #include "mpm.h"
52 #include "mpm_common.h"
53 #include "scoreboard.h"
54 #include "mod_core.h"
55 #include "mod_proxy.h"
56 #include "ap_listen.h"
57
58 #include "mod_so.h" /* for ap_find_loaded_module_symbol */
59
60 #define AP_MIN_SENDFILE_BYTES           (256)
61
62 /**
63  * Remove all zero length buckets from the brigade.
64  */
65 #define BRIGADE_NORMALIZE(b) \
66 do { \
67     apr_bucket *e = APR_BRIGADE_FIRST(b); \
68     do {  \
69         if (e->length == 0 && !APR_BUCKET_IS_METADATA(e)) { \
70             apr_bucket *d; \
71             d = APR_BUCKET_NEXT(e); \
72             apr_bucket_delete(e); \
73             e = d; \
74         } \
75         else { \
76             e = APR_BUCKET_NEXT(e); \
77         } \
78     } while (!APR_BRIGADE_EMPTY(b) && (e != APR_BRIGADE_SENTINEL(b))); \
79 } while (0)
80
81
82 /**
83  * Split the contents of a brigade after bucket 'e' to an existing brigade
84  *
85  * XXXX: Should this function be added to APR-Util?
86  */
87 static void brigade_move(apr_bucket_brigade *b, apr_bucket_brigade *a,
88                          apr_bucket *e)
89 {
90     apr_bucket *f;
91
92     if (e != APR_BRIGADE_SENTINEL(b)) {
93         f = APR_RING_LAST(&b->list);
94         APR_RING_UNSPLICE(e, f, link);
95         APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link);
96     }
97
98     APR_BRIGADE_CHECK_CONSISTENCY(a);
99     APR_BRIGADE_CHECK_CONSISTENCY(b);
100 }
101
102 int ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
103                          ap_input_mode_t mode, apr_read_type_e block,
104                          apr_off_t readbytes)
105 {
106     apr_bucket *e;
107     apr_status_t rv;
108     core_net_rec *net = f->ctx;
109     core_ctx_t *ctx = net->in_ctx;
110     const char *str;
111     apr_size_t len;
112
113     if (mode == AP_MODE_INIT) {
114         /*
115          * this mode is for filters that might need to 'initialize'
116          * a connection before reading request data from a client.
117          * NNTP over SSL for example needs to handshake before the
118          * server sends the welcome message.
119          * such filters would have changed the mode before this point
120          * is reached.  however, protocol modules such as NNTP should
121          * not need to know anything about SSL.  given the example, if
122          * SSL is not in the filter chain, AP_MODE_INIT is a noop.
123          */
124         return APR_SUCCESS;
125     }
126
127     if (!ctx)
128     {
129         ctx = apr_pcalloc(f->c->pool, sizeof(*ctx));
130         ctx->b = apr_brigade_create(f->c->pool, f->c->bucket_alloc);
131         ctx->tmpbb = apr_brigade_create(ctx->b->p, ctx->b->bucket_alloc);
132         /* seed the brigade with the client socket. */
133         e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
134         APR_BRIGADE_INSERT_TAIL(ctx->b, e);
135         net->in_ctx = ctx;
136     }
137     else if (APR_BRIGADE_EMPTY(ctx->b)) {
138         return APR_EOF;
139     }
140
141     /* ### This is bad. */
142     BRIGADE_NORMALIZE(ctx->b);
143
144     /* check for empty brigade again *AFTER* BRIGADE_NORMALIZE()
145      * If we have lost our socket bucket (see above), we are EOF.
146      *
147      * Ideally, this should be returning SUCCESS with EOS bucket, but
148      * some higher-up APIs (spec. read_request_line via ap_rgetline)
149      * want an error code. */
150     if (APR_BRIGADE_EMPTY(ctx->b)) {
151         return APR_EOF;
152     }
153
154     if (mode == AP_MODE_GETLINE) {
155         /* we are reading a single LF line, e.g. the HTTP headers */
156         rv = apr_brigade_split_line(b, ctx->b, block, HUGE_STRING_LEN);
157         /* We should treat EAGAIN here the same as we do for EOF (brigade is
158          * empty).  We do this by returning whatever we have read.  This may
159          * or may not be bogus, but is consistent (for now) with EOF logic.
160          */
161         if (APR_STATUS_IS_EAGAIN(rv)) {
162             rv = APR_SUCCESS;
163         }
164         return rv;
165     }
166
167     /* ### AP_MODE_PEEK is a horrific name for this mode because we also
168      * eat any CRLFs that we see.  That's not the obvious intention of
169      * this mode.  Determine whether anyone actually uses this or not. */
170     if (mode == AP_MODE_EATCRLF) {
171         apr_bucket *e;
172         const char *c;
173
174         /* The purpose of this loop is to ignore any CRLF (or LF) at the end
175          * of a request.  Many browsers send extra lines at the end of POST
176          * requests.  We use the PEEK method to determine if there is more
177          * data on the socket, so that we know if we should delay sending the
178          * end of one request until we have served the second request in a
179          * pipelined situation.  We don't want to actually delay sending a
180          * response if the server finds a CRLF (or LF), becuause that doesn't
181          * mean that there is another request, just a blank line.
182          */
183         while (1) {
184             if (APR_BRIGADE_EMPTY(ctx->b))
185                 return APR_EOF;
186
187             e = APR_BRIGADE_FIRST(ctx->b);
188
189             rv = apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ);
190
191             if (rv != APR_SUCCESS)
192                 return rv;
193
194             c = str;
195             while (c < str + len) {
196                 if (*c == APR_ASCII_LF)
197                     c++;
198                 else if (*c == APR_ASCII_CR && *(c + 1) == APR_ASCII_LF)
199                     c += 2;
200                 else
201                     return APR_SUCCESS;
202             }
203
204             /* If we reach here, we were a bucket just full of CRLFs, so
205              * just toss the bucket. */
206             /* FIXME: Is this the right thing to do in the core? */
207             apr_bucket_delete(e);
208         }
209         return APR_SUCCESS;
210     }
211
212     /* If mode is EXHAUSTIVE, we want to just read everything until the end
213      * of the brigade, which in this case means the end of the socket.
214      * To do this, we attach the brigade that has currently been setaside to
215      * the brigade that was passed down, and send that brigade back.
216      *
217      * NOTE:  This is VERY dangerous to use, and should only be done with
218      * extreme caution.  However, the Perchild MPM needs this feature
219      * if it is ever going to work correctly again.  With this, the Perchild
220      * MPM can easily request the socket and all data that has been read,
221      * which means that it can pass it to the correct child process.
222      */
223     if (mode == AP_MODE_EXHAUSTIVE) {
224         apr_bucket *e;
225
226         /* Tack on any buckets that were set aside. */
227         APR_BRIGADE_CONCAT(b, ctx->b);
228
229         /* Since we've just added all potential buckets (which will most
230          * likely simply be the socket bucket) we know this is the end,
231          * so tack on an EOS too. */
232         /* We have read until the brigade was empty, so we know that we
233          * must be EOS. */
234         e = apr_bucket_eos_create(f->c->bucket_alloc);
235         APR_BRIGADE_INSERT_TAIL(b, e);
236         return APR_SUCCESS;
237     }
238
239     /* read up to the amount they specified. */
240     if (mode == AP_MODE_READBYTES || mode == AP_MODE_SPECULATIVE) {
241         apr_bucket *e;
242
243         AP_DEBUG_ASSERT(readbytes > 0);
244
245         e = APR_BRIGADE_FIRST(ctx->b);
246         rv = apr_bucket_read(e, &str, &len, block);
247
248         if (APR_STATUS_IS_EAGAIN(rv)) {
249             return APR_SUCCESS;
250         }
251         else if (rv != APR_SUCCESS) {
252             return rv;
253         }
254         else if (block == APR_BLOCK_READ && len == 0) {
255             /* We wanted to read some bytes in blocking mode.  We read
256              * 0 bytes.  Hence, we now assume we are EOS.
257              *
258              * When we are in normal mode, return an EOS bucket to the
259              * caller.
260              * When we are in speculative mode, leave ctx->b empty, so
261              * that the next call returns an EOS bucket.
262              */
263             apr_bucket_delete(e);
264
265             if (mode == AP_MODE_READBYTES) {
266                 e = apr_bucket_eos_create(f->c->bucket_alloc);
267                 APR_BRIGADE_INSERT_TAIL(b, e);
268             }
269             return APR_SUCCESS;
270         }
271
272         /* We can only return at most what we read. */
273         if (len < readbytes) {
274             readbytes = len;
275         }
276
277         rv = apr_brigade_partition(ctx->b, readbytes, &e);
278         if (rv != APR_SUCCESS) {
279             return rv;
280         }
281
282         /* Must do move before CONCAT */
283         brigade_move(ctx->b, ctx->tmpbb, e);
284
285         if (mode == AP_MODE_READBYTES) {
286             APR_BRIGADE_CONCAT(b, ctx->b);
287         }
288         else if (mode == AP_MODE_SPECULATIVE) {
289             apr_bucket *copy_bucket;
290
291             for (e = APR_BRIGADE_FIRST(ctx->b);
292                  e != APR_BRIGADE_SENTINEL(ctx->b);
293                  e = APR_BUCKET_NEXT(e))
294             {
295                 rv = apr_bucket_copy(e, &copy_bucket);
296                 if (rv != APR_SUCCESS) {
297                     return rv;
298                 }
299                 APR_BRIGADE_INSERT_TAIL(b, copy_bucket);
300             }
301         }
302
303         /* Take what was originally there and place it back on ctx->b */
304         APR_BRIGADE_CONCAT(ctx->b, ctx->tmpbb);
305     }
306     return APR_SUCCESS;
307 }
308
309 static void setaside_remaining_output(ap_filter_t *f,
310                                       core_output_filter_ctx_t *ctx,
311                                       apr_bucket_brigade *bb,
312                                       int make_a_copy, conn_rec *c);
313
314 static apr_status_t send_brigade_nonblocking(apr_socket_t *s,
315                                              apr_bucket_brigade *bb,
316                                              apr_size_t *bytes_written,
317                                              conn_rec *c);
318
319 static void remove_empty_buckets(apr_bucket_brigade *bb);
320
321 static apr_status_t send_brigade_blocking(apr_socket_t *s,
322                                           apr_bucket_brigade *bb,
323                                           apr_size_t *bytes_written,
324                                           conn_rec *c);
325
326 static apr_status_t writev_nonblocking(apr_socket_t *s,
327                                        struct iovec *vec, apr_size_t nvec,
328                                        apr_bucket_brigade *bb,
329                                        apr_size_t *cumulative_bytes_written,
330                                        conn_rec *c);
331
332 static apr_status_t sendfile_nonblocking(apr_socket_t *s,
333                                          apr_bucket_brigade *bb,
334                                          apr_size_t *cumulative_bytes_written,
335                                          conn_rec *c);
336
337 #define THRESHOLD_MIN_WRITE 4096
338 #define THRESHOLD_MAX_BUFFER 65536
339
340 /* Optional function coming from mod_logio, used for logging of output
341  * traffic
342  */
343 extern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *logio_add_bytes_out;
344
345 apr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *new_bb)
346 {
347     conn_rec *c = f->c;
348     core_net_rec *net = f->ctx;
349     core_output_filter_ctx_t *ctx = net->out_ctx;
350     apr_bucket_brigade *bb;
351     apr_bucket *bucket, *next;
352     apr_size_t bytes_in_brigade, non_file_bytes_in_brigade;
353
354     if (ctx == NULL) {
355         apr_status_t rv;
356         ctx = apr_pcalloc(c->pool, sizeof(*ctx));
357         net->out_ctx = (core_output_filter_ctx_t *)ctx;
358         rv = apr_socket_opt_set(net->client_socket, APR_SO_NONBLOCK, 1);
359         if (rv != APR_SUCCESS) {
360             return rv;
361         }
362     }
363
364     if (new_bb != NULL) {
365         for (bucket = APR_BRIGADE_FIRST(new_bb); bucket != APR_BRIGADE_SENTINEL(new_bb); bucket = APR_BUCKET_NEXT(bucket)) {
366             if (bucket->length > 0) {
367                 ctx->bytes_in += bucket->length;
368             }
369         }
370     }
371
372     if ((ctx->buffered_bb != NULL) &&
373         !APR_BRIGADE_EMPTY(ctx->buffered_bb)) {
374         bb = ctx->buffered_bb;
375         ctx->buffered_bb = NULL;
376         if (new_bb != NULL) {
377             APR_BRIGADE_CONCAT(bb, new_bb);
378         }
379         c->data_in_output_filters = 0;
380     }
381     else if (new_bb != NULL) {
382         bb = new_bb;
383     }
384     else {
385         return APR_SUCCESS;
386     }
387
388     /* Scan through the brigade and decide whether to attempt a write,
389      * based on the following rules:
390      *
391      *  1) The new_bb is null: Do a nonblocking write of as much as
392      *     possible: do a nonblocking write of as much data as possible,
393      *     then save the rest in ctx->buffered_bb.  (If new_bb == NULL,
394      *     it probably means that the MPM is doing asynchronous write
395      *     completion and has just determined that this connection
396      *     is writable.)
397      *
398      *  2) The brigade contains a flush bucket: Do a blocking write
399      *     of everything up that point.
400      *
401      *  3) The request is in CONN_STATE_HANLDER state, and the brigade
402      *     contains at least THRESHOLD_MAX_BUFFER bytes in non-file
403      *     buckets: Do blocking writes until the amount of data in the
404      *     buffer is less than THRESHOLD_MAX_BUFFER.  (The point of this
405      *     rule is to provide flow control, in case a handler is
406      *     streaming out lots of data faster than the data can be
407      *     sent to the client.)
408      *
409      *  4) The brigade contains at least THRESHOLD_MIN_WRITE
410      *     bytes: Do a nonblocking write of as much data as possible,
411      *     then save the rest in ctx->buffered_bb.
412      */
413
414     if (new_bb == NULL) {
415         apr_status_t rv = send_brigade_nonblocking(net->client_socket, bb,
416                                                    &(ctx->bytes_written), c);
417         if (APR_STATUS_IS_EAGAIN(rv)) {
418             rv = APR_SUCCESS;
419         }
420         setaside_remaining_output(f, ctx, bb, 0, c);
421         return rv;
422     }
423
424     bytes_in_brigade = 0;
425     non_file_bytes_in_brigade = 0;
426     for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb);
427          bucket = next) {
428         next = APR_BUCKET_NEXT(bucket);
429         if (APR_BUCKET_IS_FLUSH(bucket)) {
430             apr_bucket_brigade *remainder = apr_brigade_split(bb, next);
431             apr_status_t rv = send_brigade_blocking(net->client_socket, bb,
432                                                     &(ctx->bytes_written), c);
433             if (rv != APR_SUCCESS) {
434                 return rv;
435             }
436             bb = remainder;
437             next = APR_BRIGADE_FIRST(bb);
438             bytes_in_brigade = 0;
439             non_file_bytes_in_brigade = 0;
440         }
441         else if (!APR_BUCKET_IS_METADATA(bucket)) {
442             if (bucket->length < 0) {
443                 const char *data;
444                 apr_size_t length;
445                 /* XXX support nonblocking read here? */
446                 apr_status_t rv =
447                     apr_bucket_read(bucket, &data, &length, APR_BLOCK_READ);
448                 if (rv != APR_SUCCESS) {
449                     return rv;
450                 }
451                 /* reading may have split the bucket, so recompute next: */
452                 next = APR_BUCKET_NEXT(bucket);
453             }
454             bytes_in_brigade += bucket->length;
455             if (!APR_BUCKET_IS_FILE(bucket)) {
456                 non_file_bytes_in_brigade += bucket->length;
457             }
458         }
459     }
460
461     if (non_file_bytes_in_brigade >= THRESHOLD_MAX_BUFFER) {
462         /* ### Writing the entire brigade may be excessive; we really just
463          * ### need to send enough data to be under THRESHOLD_MAX_BUFFER.
464          */
465         apr_status_t rv = send_brigade_blocking(net->client_socket, bb,
466                                                 &(ctx->bytes_written), c);
467         if (rv != APR_SUCCESS) {
468             return rv;
469         }
470     }
471     else if (bytes_in_brigade >= THRESHOLD_MIN_WRITE) {
472         apr_status_t rv = send_brigade_nonblocking(net->client_socket, bb,
473                                                    &(ctx->bytes_written), c);
474         if ((rv != APR_SUCCESS) && (!APR_STATUS_IS_EAGAIN(rv))) {
475             return rv;
476         }
477     }
478
479     setaside_remaining_output(f, ctx, bb, 1, c);
480     return APR_SUCCESS;
481 }
482
483 static void setaside_remaining_output(ap_filter_t *f,
484                                       core_output_filter_ctx_t *ctx,
485                                       apr_bucket_brigade *bb,
486                                       int make_a_copy, conn_rec *c)
487 {
488     if (bb == NULL) {
489         return;
490     }
491     remove_empty_buckets(bb);
492     if (!APR_BRIGADE_EMPTY(bb)) {
493         c->data_in_output_filters = 1;
494         if (make_a_copy) {
495             /* XXX should this use a separate deferred write pool, like
496              * the original ap_core_output_filter?
497              */
498             ap_save_brigade(f, &(ctx->buffered_bb), &bb, c->pool);
499             apr_brigade_destroy(bb);
500         }
501         else {
502             ctx->buffered_bb = bb;
503         }
504     }
505     else {
506         apr_brigade_destroy(bb);
507     }
508 }
509
510 #ifndef APR_MAX_IOVEC_SIZE
511 #define MAX_IOVEC_TO_WRITE 16
512 #else
513 #if APR_MAX_IOVEC_SIZE > 16
514 #define MAX_IOVEC_TO_WRITE 16
515 #else
516 #define MAX_IOVEC_TO_WRITE APR_MAX_IOVEC_SIZE
517 #endif
518 #endif
519
520 static apr_status_t send_brigade_nonblocking(apr_socket_t *s,
521                                              apr_bucket_brigade *bb,
522                                              apr_size_t *bytes_written,
523                                              conn_rec *c)
524 {
525     apr_bucket *bucket, *next;
526     apr_status_t rv;
527     struct iovec vec[MAX_IOVEC_TO_WRITE];
528     apr_size_t nvec = 0;
529
530     remove_empty_buckets(bb);
531
532     for (bucket = APR_BRIGADE_FIRST(bb);
533          bucket != APR_BRIGADE_SENTINEL(bb);
534          bucket = next) {
535         int did_sendfile = 0;
536         next = APR_BUCKET_NEXT(bucket);
537 #if APR_HAS_SENDFILE
538         if (APR_BUCKET_IS_FILE(bucket)) {
539             apr_bucket_file *file_bucket = (apr_bucket_file *)(bucket->data);
540             apr_file_t *fd = file_bucket->fd;
541             /* Use sendfile to send this file unless:
542              *   - the platform doesn't support sendfile,
543              *   - the file is too small for sendfile to be useful, or
544              *   - sendfile is disabled in the httpd config via "EnableSendfile off"
545              */
546
547             if ((apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) &&
548                 (bucket->length >= AP_MIN_SENDFILE_BYTES)) {
549                 did_sendfile = 1;
550                 if (nvec > 0) {
551                     (void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 1);
552                     rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
553                     nvec = 0;
554                     if (rv != APR_SUCCESS) {
555                         (void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 0);
556                         return rv;
557                     }
558                 }
559                 rv = sendfile_nonblocking(s, bb, bytes_written, c);
560                 if (nvec > 0) {
561                     (void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 0);
562                 }
563                 if (rv != APR_SUCCESS) {
564                     return rv;
565                 }
566                 break;
567             }
568         }
569 #endif /* APR_HAS_SENDFILE */
570         if (!did_sendfile && !APR_BUCKET_IS_METADATA(bucket)) {
571             const char *data;
572             apr_size_t length;
573             rv = apr_bucket_read(bucket, &data, &length, APR_BLOCK_READ);
574             if (rv != APR_SUCCESS) {
575                 return rv;
576             }
577             /* reading may have split the bucket, so recompute next: */
578             next = APR_BUCKET_NEXT(bucket);
579             vec[nvec].iov_base = (char *)data;
580             vec[nvec].iov_len = length;
581             nvec++;
582             if (nvec == MAX_IOVEC_TO_WRITE) {
583                 rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
584                 nvec = 0;
585                 if (rv != APR_SUCCESS) {
586                     return rv;
587                 }
588                 break;
589             }
590         }
591     }
592
593     if (nvec > 0) {
594         rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
595         if (rv != APR_SUCCESS) {
596             return rv;
597         }
598     }
599
600     remove_empty_buckets(bb);
601
602     return APR_SUCCESS;
603 }
604
605 static void remove_empty_buckets(apr_bucket_brigade *bb)
606 {
607     apr_bucket *bucket;
608     while (((bucket = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) &&
609            (APR_BUCKET_IS_METADATA(bucket) || (bucket->length == 0))) {
610         APR_BUCKET_REMOVE(bucket);
611         apr_bucket_destroy(bucket);
612     }
613 }
614
615 static apr_status_t send_brigade_blocking(apr_socket_t *s,
616                                           apr_bucket_brigade *bb,
617                                           apr_size_t *bytes_written,
618                                           conn_rec *c)
619 {
620     apr_status_t rv;
621
622     rv = APR_SUCCESS;
623     while (!APR_BRIGADE_EMPTY(bb)) {
624         rv = send_brigade_nonblocking(s, bb, bytes_written, c);
625         if (rv != APR_SUCCESS) {
626             if (APR_STATUS_IS_EAGAIN(rv)) {
627                 rv = apr_wait_for_io_or_timeout(NULL, s, 0);
628                 if (rv != APR_SUCCESS) {
629                     break;
630                 }
631             }
632             else {
633                 break;
634             }
635         }
636     }
637     return rv;
638 }
639
640 static apr_status_t writev_nonblocking(apr_socket_t *s,
641                                        struct iovec *vec, apr_size_t nvec,
642                                        apr_bucket_brigade *bb,
643                                        apr_size_t *cumulative_bytes_written,
644                                        conn_rec *c)
645 {
646     apr_status_t rv = APR_SUCCESS, arv;
647     apr_size_t bytes_written = 0, bytes_to_write = 0;
648     apr_size_t i, offset;
649     apr_interval_time_t old_timeout;
650
651     arv = apr_socket_timeout_get(s, &old_timeout);
652     if (arv != APR_SUCCESS) {
653         return arv;
654     }
655     arv = apr_socket_timeout_set(s, 0);
656     if (arv != APR_SUCCESS) {
657         return arv;
658     }
659
660     for (i = 0; i < nvec; i++) {
661         bytes_to_write += vec[i].iov_len;
662     }
663     offset = 0;
664     while (bytes_written < bytes_to_write) {
665         apr_size_t n = 0;
666         rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
667         if (n > 0) {
668             bytes_written += n;
669             for (i = offset; i < nvec; ) {
670                 apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
671                 if (APR_BUCKET_IS_METADATA(bucket)) {
672                     APR_BUCKET_REMOVE(bucket);
673                     apr_bucket_destroy(bucket);
674                 }
675                 else if (n >= vec[i].iov_len) {
676                     APR_BUCKET_REMOVE(bucket);
677                     apr_bucket_destroy(bucket);
678                     offset++;
679                     n -= vec[i++].iov_len;
680                 }
681                 else {
682                     apr_bucket_split(bucket, n);
683                     APR_BUCKET_REMOVE(bucket);
684                     apr_bucket_destroy(bucket);
685                     vec[i].iov_len -= n;
686                     vec[i].iov_base += n;
687                     break;
688                 }
689             }
690         }
691         if (rv != APR_SUCCESS) {
692             break;
693         }
694     }
695     if ((logio_add_bytes_out != NULL) && (bytes_written > 0)) {
696         logio_add_bytes_out(c, bytes_written);
697     }
698     *cumulative_bytes_written += bytes_written;
699
700     arv = apr_socket_timeout_set(s, old_timeout);
701     if ((arv != APR_SUCCESS) && (rv == APR_SUCCESS)) {
702         return arv;
703     }
704     else {
705         return rv;
706     }
707 }
708
709 static apr_status_t sendfile_nonblocking(apr_socket_t *s,
710                                          apr_bucket_brigade *bb,
711                                          apr_size_t *cumulative_bytes_written,
712                                          conn_rec *c)
713 {
714     apr_status_t rv = APR_SUCCESS;
715     apr_bucket *bucket;
716     apr_bucket_file *file_bucket;
717     apr_file_t *fd;
718     apr_size_t file_length;
719     apr_off_t file_offset;
720     apr_size_t bytes_written = 0;
721
722     bucket = APR_BRIGADE_FIRST(bb);
723     if (!APR_BUCKET_IS_FILE(bucket)) {
724         /* XXX log a "this should never happen" message */
725         return APR_EGENERAL;
726     }
727     file_bucket = (apr_bucket_file *)(bucket->data);
728     fd = file_bucket->fd;
729     file_length = bucket->length;
730     file_offset = bucket->start;
731
732     if (bytes_written < file_length) {
733         apr_size_t n = file_length - bytes_written;
734         apr_status_t arv;
735         apr_interval_time_t old_timeout;
736
737         arv = apr_socket_timeout_get(s, &old_timeout);
738         if (arv != APR_SUCCESS) {
739             return arv;
740         }
741         arv = apr_socket_timeout_set(s, 0);
742         if (arv != APR_SUCCESS) {
743             return arv;
744         }
745         rv = apr_socket_sendfile(s, fd, NULL, &file_offset, &n, 0);
746         if (rv == APR_SUCCESS) {
747             bytes_written += n;
748             file_offset += n;
749         }
750         arv = apr_socket_timeout_set(s, old_timeout);
751         if ((arv != APR_SUCCESS) && (rv == APR_SUCCESS)) {
752             rv = arv;
753         }
754     }
755     if ((logio_add_bytes_out != NULL) && (bytes_written > 0)) {
756         logio_add_bytes_out(c, bytes_written);
757     }
758     *cumulative_bytes_written += bytes_written;
759     if ((bytes_written < file_length) && (bytes_written > 0)) {
760         apr_bucket_split(bucket, bytes_written);
761         APR_BUCKET_REMOVE(bucket);
762         apr_bucket_destroy(bucket);
763     }
764     else if (bytes_written == file_length) {
765         APR_BUCKET_REMOVE(bucket);
766         apr_bucket_destroy(bucket);
767     }
768     return rv;
769 }
770