core_filters.c revision 231ca3b40df46af2a63d006ebde6b745f73c40b2
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync/* Licensed to the Apache Software Foundation (ASF) under one or more
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * contributor license agreements. See the NOTICE file distributed with
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * this work for additional information regarding copyright ownership.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * The ASF licenses this file to You under the Apache License, Version 2.0
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * (the "License"); you may not use this file except in compliance with
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * the License. You may obtain a copy of the License at
772269936494ffaddd0750ba9e28e805ba81398cvboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * http://www.apache.org/licenses/LICENSE-2.0
78f327ee942771169c65c91baf789fd10e72b01avboxsync *
78f327ee942771169c65c91baf789fd10e72b01avboxsync * Unless required by applicable law or agreed to in writing, software
78f327ee942771169c65c91baf789fd10e72b01avboxsync * distributed under the License is distributed on an "AS IS" BASIS,
78f327ee942771169c65c91baf789fd10e72b01avboxsync * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
78f327ee942771169c65c91baf789fd10e72b01avboxsync * See the License for the specific language governing permissions and
78f327ee942771169c65c91baf789fd10e72b01avboxsync * limitations under the License.
78f327ee942771169c65c91baf789fd10e72b01avboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync/**
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @file core_filters.c
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * @brief Core input/output network filters.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "apr.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "apr_strings.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "apr_lib.h"
dcd01485c22687cd874d69a566131b4a6a82e54bvboxsync#include "apr_fnmatch.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "apr_hash.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "apr_thread_proc.h" /* for RLIMIT stuff */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define APR_WANT_IOVEC
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define APR_WANT_STRFUNC
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define APR_WANT_MEMFUNC
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "apr_want.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "ap_config.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "httpd.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "http_config.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "http_core.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "http_protocol.h" /* For index_of_response(). Grump. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "http_request.h"
e24bfeec424d0e6481eccbe85ffde550384b6364vboxsync#include "http_vhost.h"
e24bfeec424d0e6481eccbe85ffde550384b6364vboxsync#include "http_main.h" /* For the default_handler below... */
e24bfeec424d0e6481eccbe85ffde550384b6364vboxsync#include "http_log.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "util_md5.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "http_connection.h"
dcd01485c22687cd874d69a566131b4a6a82e54bvboxsync#include "apr_buckets.h"
dcd01485c22687cd874d69a566131b4a6a82e54bvboxsync#include "util_filter.h"
dcd01485c22687cd874d69a566131b4a6a82e54bvboxsync#include "util_ebcdic.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "mpm_common.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "scoreboard.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "mod_core.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "mod_proxy.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "ap_listen.h"
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#include "mod_so.h" /* for ap_find_loaded_module_symbol */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define AP_MIN_SENDFILE_BYTES (256)
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync/**
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync * Remove all zero length buckets from the brigade.
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync */
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync#define BRIGADE_NORMALIZE(b) \
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsyncdo { \
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync apr_bucket *e = APR_BRIGADE_FIRST(b); \
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync do { \
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync if (e->length == 0 && !APR_BUCKET_IS_METADATA(e)) { \
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync apr_bucket *d; \
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync d = APR_BUCKET_NEXT(e); \
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_delete(e); \
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync e = d; \
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } \
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else { \
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync e = APR_BUCKET_NEXT(e); \
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } \
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync } while (!APR_BRIGADE_EMPTY(b) && (e != APR_BRIGADE_SENTINEL(b))); \
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync} while (0)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync/* we know core's module_index is 0 */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#undef APLOG_MODULE_INDEX
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncstruct core_output_filter_ctx {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_brigade *buffered_bb;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_brigade *tmp_flush_bb;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_pool_t *deferred_write_pool;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_size_t bytes_written;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync};
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncstruct core_filter_ctx {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_brigade *b;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_brigade *tmpbb;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync};
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncAP_DECLARE(core_ctx_t *) ap_create_core_ctx(conn_rec *c)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync{
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync core_ctx_t *ctx = apr_palloc(c->pool, sizeof(*ctx));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ctx->b = apr_brigade_create(c->pool, c->bucket_alloc);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ctx->tmpbb = apr_brigade_create(c->pool, c->bucket_alloc);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return ctx;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync}
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncAP_DECLARE(apr_bucket_brigade *) ap_core_ctx_get_bb(core_ctx_t *ctx)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync{
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return ctx->b;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync}
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncapr_status_t ap_core_input_filter(ap_filter_t *f, apr_bucket_brigade *b,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ap_input_mode_t mode, apr_read_type_e block,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_off_t readbytes)
d97357e2036109245c83ba553d0290212e28ea40vboxsync{
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket *e;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_status_t rv;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync core_net_rec *net = f->ctx;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync core_ctx_t *ctx = net->in_ctx;
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync const char *str;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_size_t len;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (mode == AP_MODE_INIT) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /*
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * this mode is for filters that might need to 'initialize'
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * a connection before reading request data from a client.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * NNTP over SSL for example needs to handshake before the
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * server sends the welcome message.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * such filters would have changed the mode before this point
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * is reached. however, protocol modules such as NNTP should
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * not need to know anything about SSL. given the example, if
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * SSL is not in the filter chain, AP_MODE_INIT is a noop.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (!ctx)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync net->in_ctx = ctx = ap_create_core_ctx(f->c);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* seed the brigade with the client socket. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync e = apr_bucket_socket_create(net->client_socket, f->c->bucket_alloc);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync APR_BRIGADE_INSERT_TAIL(ctx->b, e);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if (APR_BRIGADE_EMPTY(ctx->b)) {
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync return APR_EOF;
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* ### This is bad. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync BRIGADE_NORMALIZE(ctx->b);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* check for empty brigade again *AFTER* BRIGADE_NORMALIZE()
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * If we have lost our socket bucket (see above), we are EOF.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
d97357e2036109245c83ba553d0290212e28ea40vboxsync * Ideally, this should be returning SUCCESS with EOS bucket, but
d97357e2036109245c83ba553d0290212e28ea40vboxsync * some higher-up APIs (spec. read_request_line via ap_rgetline)
d97357e2036109245c83ba553d0290212e28ea40vboxsync * want an error code. */
d97357e2036109245c83ba553d0290212e28ea40vboxsync if (APR_BRIGADE_EMPTY(ctx->b)) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync return APR_EOF;
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (mode == AP_MODE_GETLINE) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* we are reading a single LF line, e.g. the HTTP headers */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = apr_brigade_split_line(b, ctx->b, block, HUGE_STRING_LEN);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* We should treat EAGAIN here the same as we do for EOF (brigade is
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * empty). We do this by returning whatever we have read. This may
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * or may not be bogus, but is consistent (for now) with EOF logic.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (APR_STATUS_IS_EAGAIN(rv) && block == APR_NONBLOCK_READ) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return rv;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* ### AP_MODE_PEEK is a horrific name for this mode because we also
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * eat any CRLFs that we see. That's not the obvious intention of
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * this mode. Determine whether anyone actually uses this or not. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (mode == AP_MODE_EATCRLF) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket *e;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync const char *c;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* The purpose of this loop is to ignore any CRLF (or LF) at the end
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * of a request. Many browsers send extra lines at the end of POST
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * requests. We use the PEEK method to determine if there is more
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * data on the socket, so that we know if we should delay sending the
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * end of one request until we have served the second request in a
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * pipelined situation. We don't want to actually delay sending a
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * response if the server finds a CRLF (or LF), becuause that doesn't
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * mean that there is another request, just a blank line.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync while (1) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (APR_BRIGADE_EMPTY(ctx->b))
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return APR_EOF;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
418b2ca36b57bba4727decfa2e9b93affca1dd43vboxsync e = APR_BRIGADE_FIRST(ctx->b);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = apr_bucket_read(e, &str, &len, APR_NONBLOCK_READ);
d97357e2036109245c83ba553d0290212e28ea40vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (rv != APR_SUCCESS)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return rv;
2868a4e01e366cc5b7228503675dbbf3ecdeba2cvboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync c = str;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync while (c < str + len) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (*c == APR_ASCII_LF)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync c++;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if (*c == APR_ASCII_CR && *(c + 1) == APR_ASCII_LF)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync c += 2;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* If we reach here, we were a bucket just full of CRLFs, so
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * just toss the bucket. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* FIXME: Is this the right thing to do in the core? */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_delete(e);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* If mode is EXHAUSTIVE, we want to just read everything until the end
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * of the brigade, which in this case means the end of the socket.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * To do this, we attach the brigade that has currently been setaside to
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * the brigade that was passed down, and send that brigade back.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * NOTE: This is VERY dangerous to use, and should only be done with
d97357e2036109245c83ba553d0290212e28ea40vboxsync * extreme caution. FWLIW, this would be needed by an MPM like Perchild;
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync * such an MPM can easily request the socket and all data that has been
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync * read, which means that it can pass it to the correct child process.
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync */
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync if (mode == AP_MODE_EXHAUSTIVE) {
1f2b5fc378de7ce78fee422ffb66635630f23016vboxsync apr_bucket *e;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Tack on any buckets that were set aside. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync APR_BRIGADE_CONCAT(b, ctx->b);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Since we've just added all potential buckets (which will most
d97357e2036109245c83ba553d0290212e28ea40vboxsync * likely simply be the socket bucket) we know this is the end,
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync * so tack on an EOS too. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* We have read until the brigade was empty, so we know that we
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * must be EOS. */
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync e = apr_bucket_eos_create(f->c->bucket_alloc);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync APR_BRIGADE_INSERT_TAIL(b, e);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* read up to the amount they specified. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (mode == AP_MODE_READBYTES || mode == AP_MODE_SPECULATIVE) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_bucket *e;
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsync AP_DEBUG_ASSERT(readbytes > 0);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsync e = APR_BRIGADE_FIRST(ctx->b);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = apr_bucket_read(e, &str, &len, block);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
3c3d0383bb6ce1db26a5d4ca83da998bbac6eeb5vboxsync if (APR_STATUS_IS_EAGAIN(rv) && block == APR_NONBLOCK_READ) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync /* getting EAGAIN for a blocking read is an error; for a
d97357e2036109245c83ba553d0290212e28ea40vboxsync * non-blocking read, return an empty brigade. */
d97357e2036109245c83ba553d0290212e28ea40vboxsync return APR_SUCCESS;
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync else if (rv != APR_SUCCESS) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync return rv;
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync else if (block == APR_BLOCK_READ && len == 0) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync /* We wanted to read some bytes in blocking mode. We read
ebc7c1b822f7cde4e2ed4c54da127eb7a3a28e7dvboxsync * 0 bytes. Hence, we now assume we are EOS.
d97357e2036109245c83ba553d0290212e28ea40vboxsync *
d97357e2036109245c83ba553d0290212e28ea40vboxsync * When we are in normal mode, return an EOS bucket to the
ebc7c1b822f7cde4e2ed4c54da127eb7a3a28e7dvboxsync * caller.
d97357e2036109245c83ba553d0290212e28ea40vboxsync * When we are in speculative mode, leave ctx->b empty, so
d97357e2036109245c83ba553d0290212e28ea40vboxsync * that the next call returns an EOS bucket.
26809165876a75147696a496b69185a6aecbb8b0vboxsync */
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_bucket_delete(e);
d97357e2036109245c83ba553d0290212e28ea40vboxsync
26809165876a75147696a496b69185a6aecbb8b0vboxsync if (mode == AP_MODE_READBYTES) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync e = apr_bucket_eos_create(f->c->bucket_alloc);
d97357e2036109245c83ba553d0290212e28ea40vboxsync APR_BRIGADE_INSERT_TAIL(b, e);
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync return APR_SUCCESS;
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsync /* Have we read as much data as we wanted (be greedy)? */
d97357e2036109245c83ba553d0290212e28ea40vboxsync if (len < readbytes) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_size_t bucket_len;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* We already registered the data in e in len */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync e = APR_BUCKET_NEXT(e);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync while ((len < readbytes) && (rv == APR_SUCCESS)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync && (e != APR_BRIGADE_SENTINEL(ctx->b))) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Check for the availability of buckets with known length */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (e->length != -1) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync len += e->length;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync e = APR_BUCKET_NEXT(e);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else {
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync /*
a6fc0ecba4e98bb619fc1d42bcdb4c37353ebf8evboxsync * Read from bucket, but non blocking. If there isn't any
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * more data, well than this is fine as well, we will
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * not wait for more since we already got some and we are
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * only checking if there isn't more.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = apr_bucket_read(e, &str, &bucket_len,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync APR_NONBLOCK_READ);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (rv == APR_SUCCESS) {
d97357e2036109245c83ba553d0290212e28ea40vboxsync len += bucket_len;
d97357e2036109245c83ba553d0290212e28ea40vboxsync e = APR_BUCKET_NEXT(e);
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsync /* We can only return at most what we read. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (len < readbytes) {
d314ffdac4d234c923b4b5273e78a2f4e3c894cevboxsync readbytes = len;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = apr_brigade_partition(ctx->b, readbytes, &e);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (rv != APR_SUCCESS) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return rv;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Must do move before CONCAT */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ctx->tmpbb = apr_brigade_split_ex(ctx->b, e, ctx->tmpbb);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (mode == AP_MODE_READBYTES) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync APR_BRIGADE_CONCAT(b, ctx->b);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if (mode == AP_MODE_SPECULATIVE) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket *copy_bucket;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync for (e = APR_BRIGADE_FIRST(ctx->b);
541ba632c438350cc8044d7ce2c8623dca446546vboxsync e != APR_BRIGADE_SENTINEL(ctx->b);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync e = APR_BUCKET_NEXT(e))
80a573ec1c224241824d55a4c1bdb1294618aa96vboxsync {
80a573ec1c224241824d55a4c1bdb1294618aa96vboxsync rv = apr_bucket_copy(e, &copy_bucket);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (rv != APR_SUCCESS) {
541ba632c438350cc8044d7ce2c8623dca446546vboxsync return rv;
80a573ec1c224241824d55a4c1bdb1294618aa96vboxsync }
541ba632c438350cc8044d7ce2c8623dca446546vboxsync APR_BRIGADE_INSERT_TAIL(b, copy_bucket);
541ba632c438350cc8044d7ce2c8623dca446546vboxsync }
80a573ec1c224241824d55a4c1bdb1294618aa96vboxsync }
80a573ec1c224241824d55a4c1bdb1294618aa96vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsync /* Take what was originally there and place it back on ctx->b */
d97357e2036109245c83ba553d0290212e28ea40vboxsync APR_BRIGADE_CONCAT(ctx->b, ctx->tmpbb);
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
d97357e2036109245c83ba553d0290212e28ea40vboxsync return APR_SUCCESS;
d97357e2036109245c83ba553d0290212e28ea40vboxsync}
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsyncstatic void setaside_remaining_output(ap_filter_t *f,
d97357e2036109245c83ba553d0290212e28ea40vboxsync core_output_filter_ctx_t *ctx,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_bucket_brigade *bb,
d97357e2036109245c83ba553d0290212e28ea40vboxsync conn_rec *c);
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsyncstatic apr_status_t send_brigade_nonblocking(apr_socket_t *s,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_bucket_brigade *bb,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_size_t *bytes_written,
d97357e2036109245c83ba553d0290212e28ea40vboxsync conn_rec *c);
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsyncstatic void remove_empty_buckets(apr_bucket_brigade *bb);
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsyncstatic apr_status_t send_brigade_blocking(apr_socket_t *s,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_bucket_brigade *bb,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_size_t *bytes_written,
d97357e2036109245c83ba553d0290212e28ea40vboxsync conn_rec *c);
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsyncstatic apr_status_t writev_nonblocking(apr_socket_t *s,
d97357e2036109245c83ba553d0290212e28ea40vboxsync struct iovec *vec, apr_size_t nvec,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_bucket_brigade *bb,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_size_t *cumulative_bytes_written,
d97357e2036109245c83ba553d0290212e28ea40vboxsync conn_rec *c);
d97357e2036109245c83ba553d0290212e28ea40vboxsync
d97357e2036109245c83ba553d0290212e28ea40vboxsync#if APR_HAS_SENDFILE
d97357e2036109245c83ba553d0290212e28ea40vboxsyncstatic apr_status_t sendfile_nonblocking(apr_socket_t *s,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_bucket *bucket,
d97357e2036109245c83ba553d0290212e28ea40vboxsync apr_size_t *cumulative_bytes_written,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync conn_rec *c);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#endif
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync/* XXX: Should these be configurable parameters? */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define THRESHOLD_MIN_WRITE 4096
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define THRESHOLD_MAX_BUFFER 65536
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define MAX_REQUESTS_IN_PIPELINE 5
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync/* Optional function coming from mod_logio, used for logging of output
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * traffic
e4e2d49b574b44c06b923b86fbfc12253d58e310vboxsync */
e4e2d49b574b44c06b923b86fbfc12253d58e310vboxsyncextern APR_OPTIONAL_FN_TYPE(ap_logio_add_bytes_out) *ap__logio_add_bytes_out;
e4e2d49b574b44c06b923b86fbfc12253d58e310vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncapr_status_t ap_core_output_filter(ap_filter_t *f, apr_bucket_brigade *new_bb)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync{
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync conn_rec *c = f->c;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync core_net_rec *net = f->ctx;
e4e2d49b574b44c06b923b86fbfc12253d58e310vboxsync core_output_filter_ctx_t *ctx = net->out_ctx;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_brigade *bb = NULL;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket *bucket, *next, *flush_upto = NULL;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_size_t bytes_in_brigade, non_file_bytes_in_brigade;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync int eor_buckets_in_brigade, morphing_bucket_in_brigade;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_status_t rv;
e4e2d49b574b44c06b923b86fbfc12253d58e310vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Fail quickly if the connection has already been aborted. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (c->aborted) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (new_bb != NULL) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_brigade_cleanup(new_bb);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return APR_ECONNABORTED;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (ctx == NULL) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ctx = apr_pcalloc(c->pool, sizeof(*ctx));
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync net->out_ctx = (core_output_filter_ctx_t *)ctx;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = apr_socket_opt_set(net->client_socket, APR_SO_NONBLOCK, 1);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (rv != APR_SUCCESS) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return rv;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /*
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Need to create tmp brigade with correct lifetime. Passing
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * NULL to apr_brigade_split_ex would result in a brigade
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * allocated from bb->pool which might be wrong.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ctx->tmp_flush_bb = apr_brigade_create(c->pool, c->bucket_alloc);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* same for buffered_bb and ap_save_brigade */
0da0539aeae9b2692f4967c4a8ef273018effb2evboxsync ctx->buffered_bb = apr_brigade_create(c->pool, c->bucket_alloc);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (new_bb != NULL)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync bb = new_bb;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if ((ctx->buffered_bb != NULL) &&
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync !APR_BRIGADE_EMPTY(ctx->buffered_bb)) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (new_bb != NULL) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync APR_BRIGADE_PREPEND(bb, ctx->buffered_bb);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
85668909c68b5d0e67c89d6042535b41c4bffeccvboxsync else {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync bb = ctx->buffered_bb;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync c->data_in_output_filters = 0;
945e2415c4f3b92c25b27f5568cd94e281353e5fvboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if (new_bb == NULL) {
945e2415c4f3b92c25b27f5568cd94e281353e5fvboxsync return APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
945e2415c4f3b92c25b27f5568cd94e281353e5fvboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* Scan through the brigade and decide whether to attempt a write,
945e2415c4f3b92c25b27f5568cd94e281353e5fvboxsync * and how much to write, based on the following rules:
f5dceedee19e251fca087d8efb960533a60c82e4vboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * 1) The new_bb is null: Do a nonblocking write of as much as
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * possible: do a nonblocking write of as much data as possible,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * then save the rest in ctx->buffered_bb. (If new_bb == NULL,
945e2415c4f3b92c25b27f5568cd94e281353e5fvboxsync * it probably means that the MPM is doing asynchronous write
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * completion and has just determined that this connection
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * is writable.)
e33e8ebf8162fdd25a8349e71d5891bdbd3bf17dvboxsync *
945e2415c4f3b92c25b27f5568cd94e281353e5fvboxsync * 2) Determine if and up to which bucket we need to do a blocking
225ca6d3ef738902dab207ecb9354b64430962bcvboxsync * write:
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
2bb528b255ed2d743bb36b48b400447012e8f6dbvboxsync * a) The brigade contains a flush bucket: Do a blocking write
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * of everything up that point.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * b) The request is in CONN_STATE_HANDLER state, and the brigade
930b964496e0f9341162fc31990a7a3a507f453evboxsync * contains at least THRESHOLD_MAX_BUFFER bytes in non-file
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * buckets: Do blocking writes until the amount of data in the
d97357e2036109245c83ba553d0290212e28ea40vboxsync * buffer is less than THRESHOLD_MAX_BUFFER. (The point of this
d97357e2036109245c83ba553d0290212e28ea40vboxsync * rule is to provide flow control, in case a handler is
d97357e2036109245c83ba553d0290212e28ea40vboxsync * streaming out lots of data faster than the data can be
d97357e2036109245c83ba553d0290212e28ea40vboxsync * sent to the client.)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * c) The request is in CONN_STATE_HANDLER state, and the brigade
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * contains at least MAX_REQUESTS_IN_PIPELINE EOR buckets:
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Do blocking writes until less than MAX_REQUESTS_IN_PIPELINE EOR
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * buckets are left. (The point of this rule is to prevent too many
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * FDs being kept open by pipelined requests, possibly allowing a
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * DoS).
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * d) The brigade contains a morphing bucket: If there was no other
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * reason to do a blocking write yet, try reading the bucket. If its
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * contents fit into memory before THRESHOLD_MAX_BUFFER is reached,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * everything is fine. Otherwise we need to do a blocking write the
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * up to and including the morphing bucket, because ap_save_brigade()
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * would read the whole bucket into memory later on.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * 3) Actually do the blocking write up to the last bucket determined
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * by rules 2a-d. The point of doing only one flush is to make as
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * few calls to writev() as possible.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync *
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * 4) If the brigade contains at least THRESHOLD_MIN_WRITE
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * bytes: Do a nonblocking write of as much data as possible,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * then save the rest in ctx->buffered_bb.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (new_bb == NULL) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = send_brigade_nonblocking(net->client_socket, bb,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync &(ctx->bytes_written), c);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (APR_STATUS_IS_EAGAIN(rv)) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if (rv != APR_SUCCESS) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* The client has aborted the connection */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync c->aborted = 1;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync setaside_remaining_output(f, ctx, bb, c);
d97357e2036109245c83ba553d0290212e28ea40vboxsync return rv;
d97357e2036109245c83ba553d0290212e28ea40vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync bytes_in_brigade = 0;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync non_file_bytes_in_brigade = 0;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync eor_buckets_in_brigade = 0;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync morphing_bucket_in_brigade = 0;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
85668909c68b5d0e67c89d6042535b41c4bffeccvboxsync for (bucket = APR_BRIGADE_FIRST(bb); bucket != APR_BRIGADE_SENTINEL(bb);
85668909c68b5d0e67c89d6042535b41c4bffeccvboxsync bucket = next) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync next = APR_BUCKET_NEXT(bucket);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (!APR_BUCKET_IS_METADATA(bucket)) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (bucket->length == (apr_size_t)-1) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /*
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * A setaside of morphing buckets would read everything into
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * memory. Instead, we will flush everything up to and
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * including this bucket.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync morphing_bucket_in_brigade = 1;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync bytes_in_brigade += bucket->length;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (!APR_BUCKET_IS_FILE(bucket))
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync non_file_bytes_in_brigade += bucket->length;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if (AP_BUCKET_IS_EOR(bucket)) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync eor_buckets_in_brigade++;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (APR_BUCKET_IS_FLUSH(bucket)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync || non_file_bytes_in_brigade >= THRESHOLD_MAX_BUFFER
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync || morphing_bucket_in_brigade
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync || eor_buckets_in_brigade > MAX_REQUESTS_IN_PIPELINE) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* this segment of the brigade MUST be sent before returning. */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (APLOGctrace6(c)) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync char *reason = APR_BUCKET_IS_FLUSH(bucket) ?
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "FLUSH bucket" :
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync (non_file_bytes_in_brigade >= THRESHOLD_MAX_BUFFER) ?
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "THRESHOLD_MAX_BUFFER" :
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync morphing_bucket_in_brigade ? "morphing bucket" :
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "MAX_REQUESTS_IN_PIPELINE";
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ap_log_cerror(APLOG_MARK, APLOG_TRACE6, 0, c,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync "core_output_filter: flushing because of %s",
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync reason);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /*
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * Defer the actual blocking write to avoid doing many writes.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync flush_upto = next;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync bytes_in_brigade = 0;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync non_file_bytes_in_brigade = 0;
3c3d0383bb6ce1db26a5d4ca83da998bbac6eeb5vboxsync eor_buckets_in_brigade = 0;
d97357e2036109245c83ba553d0290212e28ea40vboxsync morphing_bucket_in_brigade = 0;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
a6fc0ecba4e98bb619fc1d42bcdb4c37353ebf8evboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (flush_upto != NULL) {
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync ctx->tmp_flush_bb = apr_brigade_split_ex(bb, flush_upto,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync ctx->tmp_flush_bb);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync rv = send_brigade_blocking(net->client_socket, bb,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync &(ctx->bytes_written), c);
d314ffdac4d234c923b4b5273e78a2f4e3c894cevboxsync if (rv != APR_SUCCESS) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /* The client has aborted the connection */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync c->aborted = 1;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return rv;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync APR_BRIGADE_CONCAT(bb, ctx->tmp_flush_bb);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (bytes_in_brigade >= THRESHOLD_MIN_WRITE) {
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync rv = send_brigade_nonblocking(net->client_socket, bb,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync &(ctx->bytes_written), c);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if ((rv != APR_SUCCESS) && (!APR_STATUS_IS_EAGAIN(rv))) {
a6fc0ecba4e98bb619fc1d42bcdb4c37353ebf8evboxsync /* The client has aborted the connection */
a6fc0ecba4e98bb619fc1d42bcdb4c37353ebf8evboxsync c->aborted = 1;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync return rv;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync setaside_remaining_output(f, ctx, bb, c);
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync return APR_SUCCESS;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync}
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync/*
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * This function assumes that either ctx->buffered_bb == NULL, or
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * ctx->buffered_bb is empty, or ctx->buffered_bb == bb
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncstatic void setaside_remaining_output(ap_filter_t *f,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync core_output_filter_ctx_t *ctx,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_brigade *bb,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync conn_rec *c)
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync{
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync if (bb == NULL) {
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync return;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync remove_empty_buckets(bb);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (!APR_BRIGADE_EMPTY(bb)) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync c->data_in_output_filters = 1;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (bb != ctx->buffered_bb) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync if (!ctx->deferred_write_pool) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_pool_create(&ctx->deferred_write_pool, c->pool);
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync apr_pool_tag(ctx->deferred_write_pool, "deferred_write");
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync ap_save_brigade(f, &(ctx->buffered_bb), &bb,
3b3bc8a9383a065307e540b83fc3a3d6c548a082vboxsync ctx->deferred_write_pool);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_brigade_cleanup(bb);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync else if (ctx->deferred_write_pool) {
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync /*
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * There are no more requests in the pipeline. We can just clear the
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync * pool.
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync */
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_pool_clear(ctx->deferred_write_pool);
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync }
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync}
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#ifndef APR_MAX_IOVEC_SIZE
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define MAX_IOVEC_TO_WRITE 16
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#else
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#if APR_MAX_IOVEC_SIZE > 16
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define MAX_IOVEC_TO_WRITE 16
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#else
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#define MAX_IOVEC_TO_WRITE APR_MAX_IOVEC_SIZE
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#endif
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync#endif
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsyncstatic apr_status_t send_brigade_nonblocking(apr_socket_t *s,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket_brigade *bb,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_size_t *bytes_written,
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync conn_rec *c)
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync{
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_bucket *bucket, *next;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync apr_status_t rv;
dee9e52b1688c0617890cbbd8a8488f9f315d1b7vboxsync struct iovec vec[MAX_IOVEC_TO_WRITE];
772269936494ffaddd0750ba9e28e805ba81398cvboxsync apr_size_t nvec = 0;
remove_empty_buckets(bb);
for (bucket = APR_BRIGADE_FIRST(bb);
bucket != APR_BRIGADE_SENTINEL(bb);
bucket = next) {
next = APR_BUCKET_NEXT(bucket);
#if APR_HAS_SENDFILE
if (APR_BUCKET_IS_FILE(bucket)) {
apr_bucket_file *file_bucket = (apr_bucket_file *)(bucket->data);
apr_file_t *fd = file_bucket->fd;
/* Use sendfile to send this file unless:
* - the platform doesn't support sendfile,
* - the file is too small for sendfile to be useful, or
* - sendfile is disabled in the httpd config via "EnableSendfile off"
*/
if ((apr_file_flags_get(fd) & APR_SENDFILE_ENABLED) &&
(bucket->length >= AP_MIN_SENDFILE_BYTES)) {
if (nvec > 0) {
(void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 1);
rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
nvec = 0;
if (rv != APR_SUCCESS) {
(void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 0);
return rv;
}
}
rv = sendfile_nonblocking(s, bucket, bytes_written, c);
if (nvec > 0) {
(void)apr_socket_opt_set(s, APR_TCP_NOPUSH, 0);
}
if (rv != APR_SUCCESS) {
return rv;
}
break;
}
}
#endif /* APR_HAS_SENDFILE */
/* didn't sendfile */
if (!APR_BUCKET_IS_METADATA(bucket)) {
const char *data;
apr_size_t length;
/* Non-blocking read first, in case this is a morphing
* bucket type. */
rv = apr_bucket_read(bucket, &data, &length, APR_NONBLOCK_READ);
if (APR_STATUS_IS_EAGAIN(rv)) {
/* Read would block; flush any pending data and retry. */
if (nvec) {
rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
if (rv) {
return rv;
}
nvec = 0;
}
rv = apr_bucket_read(bucket, &data, &length, APR_BLOCK_READ);
}
if (rv != APR_SUCCESS) {
return rv;
}
/* reading may have split the bucket, so recompute next: */
next = APR_BUCKET_NEXT(bucket);
vec[nvec].iov_base = (char *)data;
vec[nvec].iov_len = length;
nvec++;
if (nvec == MAX_IOVEC_TO_WRITE) {
rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
nvec = 0;
if (rv != APR_SUCCESS) {
return rv;
}
break;
}
}
}
if (nvec > 0) {
rv = writev_nonblocking(s, vec, nvec, bb, bytes_written, c);
if (rv != APR_SUCCESS) {
return rv;
}
}
remove_empty_buckets(bb);
return APR_SUCCESS;
}
static void remove_empty_buckets(apr_bucket_brigade *bb)
{
apr_bucket *bucket;
while (((bucket = APR_BRIGADE_FIRST(bb)) != APR_BRIGADE_SENTINEL(bb)) &&
(APR_BUCKET_IS_METADATA(bucket) || (bucket->length == 0))) {
APR_BUCKET_REMOVE(bucket);
apr_bucket_destroy(bucket);
}
}
static apr_status_t send_brigade_blocking(apr_socket_t *s,
apr_bucket_brigade *bb,
apr_size_t *bytes_written,
conn_rec *c)
{
apr_status_t rv;
rv = APR_SUCCESS;
while (!APR_BRIGADE_EMPTY(bb)) {
rv = send_brigade_nonblocking(s, bb, bytes_written, c);
if (rv != APR_SUCCESS) {
if (APR_STATUS_IS_EAGAIN(rv)) {
/* Wait until we can send more data */
apr_int32_t nsds;
apr_interval_time_t timeout;
apr_pollfd_t pollset;
pollset.p = c->pool;
pollset.desc_type = APR_POLL_SOCKET;
pollset.reqevents = APR_POLLOUT;
pollset.desc.s = s;
apr_socket_timeout_get(s, &timeout);
rv = apr_poll(&pollset, 1, &nsds, timeout);
if (rv != APR_SUCCESS) {
break;
}
}
else {
break;
}
}
}
return rv;
}
static apr_status_t writev_nonblocking(apr_socket_t *s,
struct iovec *vec, apr_size_t nvec,
apr_bucket_brigade *bb,
apr_size_t *cumulative_bytes_written,
conn_rec *c)
{
apr_status_t rv = APR_SUCCESS, arv;
apr_size_t bytes_written = 0, bytes_to_write = 0;
apr_size_t i, offset;
apr_interval_time_t old_timeout;
arv = apr_socket_timeout_get(s, &old_timeout);
if (arv != APR_SUCCESS) {
return arv;
}
arv = apr_socket_timeout_set(s, 0);
if (arv != APR_SUCCESS) {
return arv;
}
for (i = 0; i < nvec; i++) {
bytes_to_write += vec[i].iov_len;
}
offset = 0;
while (bytes_written < bytes_to_write) {
apr_size_t n = 0;
rv = apr_socket_sendv(s, vec + offset, nvec - offset, &n);
if (n > 0) {
bytes_written += n;
for (i = offset; i < nvec; ) {
apr_bucket *bucket = APR_BRIGADE_FIRST(bb);
if (APR_BUCKET_IS_METADATA(bucket)) {
APR_BUCKET_REMOVE(bucket);
apr_bucket_destroy(bucket);
}
else if (n >= vec[i].iov_len) {
APR_BUCKET_REMOVE(bucket);
apr_bucket_destroy(bucket);
offset++;
n -= vec[i++].iov_len;
}
else {
apr_bucket_split(bucket, n);
APR_BUCKET_REMOVE(bucket);
apr_bucket_destroy(bucket);
vec[i].iov_len -= n;
vec[i].iov_base = (char *) vec[i].iov_base + n;
break;
}
}
}
if (rv != APR_SUCCESS) {
break;
}
}
if ((ap__logio_add_bytes_out != NULL) && (bytes_written > 0)) {
ap__logio_add_bytes_out(c, bytes_written);
}
*cumulative_bytes_written += bytes_written;
arv = apr_socket_timeout_set(s, old_timeout);
if ((arv != APR_SUCCESS) && (rv == APR_SUCCESS)) {
return arv;
}
else {
return rv;
}
}
#if APR_HAS_SENDFILE
static apr_status_t sendfile_nonblocking(apr_socket_t *s,
apr_bucket *bucket,
apr_size_t *cumulative_bytes_written,
conn_rec *c)
{
apr_status_t rv = APR_SUCCESS;
apr_bucket_file *file_bucket;
apr_file_t *fd;
apr_size_t file_length;
apr_off_t file_offset;
apr_size_t bytes_written = 0;
if (!APR_BUCKET_IS_FILE(bucket)) {
ap_log_error(APLOG_MARK, APLOG_ERR, rv, c->base_server, APLOGNO(00006)
"core_filter: sendfile_nonblocking: "
"this should never happen");
return APR_EGENERAL;
}
file_bucket = (apr_bucket_file *)(bucket->data);
fd = file_bucket->fd;
file_length = bucket->length;
file_offset = bucket->start;
if (bytes_written < file_length) {
apr_size_t n = file_length - bytes_written;
apr_status_t arv;
apr_interval_time_t old_timeout;
arv = apr_socket_timeout_get(s, &old_timeout);
if (arv != APR_SUCCESS) {
return arv;
}
arv = apr_socket_timeout_set(s, 0);
if (arv != APR_SUCCESS) {
return arv;
}
rv = apr_socket_sendfile(s, fd, NULL, &file_offset, &n, 0);
if (rv == APR_SUCCESS) {
bytes_written += n;
file_offset += n;
}
arv = apr_socket_timeout_set(s, old_timeout);
if ((arv != APR_SUCCESS) && (rv == APR_SUCCESS)) {
rv = arv;
}
}
if ((ap__logio_add_bytes_out != NULL) && (bytes_written > 0)) {
ap__logio_add_bytes_out(c, bytes_written);
}
*cumulative_bytes_written += bytes_written;
if ((bytes_written < file_length) && (bytes_written > 0)) {
apr_bucket_split(bucket, bytes_written);
APR_BUCKET_REMOVE(bucket);
apr_bucket_destroy(bucket);
}
else if (bytes_written == file_length) {
APR_BUCKET_REMOVE(bucket);
apr_bucket_destroy(bucket);
}
return rv;
}
#endif