httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Bill Stoddard" <stodd...@raleigh.ibm.com>
Subject Re: cvs commit: apache-2.0/src/main http_core.c
Date Fri, 22 Sep 2000 20:49:13 GMT
Just noticed that this breaks platforms not using apr_sendfile.  Will probably
be tomorrow before I can fix it.

Bill
----- Original Message -----
From: <stoddard@locus.apache.org>
To: <apache-2.0-cvs@apache.org>
Sent: Friday, September 22, 2000 4:36 PM
Subject: cvs commit: apache-2.0/src/main http_core.c


> stoddard    00/09/22 13:36:21
>
>   Modified:    src/main http_core.c
>   Log:
>   Make the core_filter use apr_sendv and apr_sendfile as appropriate. This is
still a bit crufty
>   but it is an improvement over the previous implementation.
>
>   Revision  Changes    Path
>   1.129     +154 -87   apache-2.0/src/main/http_core.c
>
>   Index: http_core.c
>   ===================================================================
>   RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
>   retrieving revision 1.128
>   retrieving revision 1.129
>   diff -u -r1.128 -r1.129
>   --- http_core.c 2000/09/21 22:44:51 1.128
>   +++ http_core.c 2000/09/22 20:36:20 1.129
>   @@ -2526,60 +2526,69 @@
>    #endif
>
>    #if APR_HAS_SENDFILE
>   -static apr_status_t send_the_file(apr_file_t *fd, apr_off_t offset,
apr_size_t length,
>   -                                  request_rec *r, apr_size_t *nbytes)
>   +/* XXX handle partial writes */
>   +static apr_status_t send_the_file(request_rec *r, apr_file_t *fd,
>   +                                  apr_hdtr_t *hdtr, apr_off_t offset,
>   +                                  apr_size_t length, apr_size_t *nbytes)
>    {
>        apr_int32_t flags = 0;
>        apr_status_t rv;
>   -    struct iovec iov;
>   -    apr_hdtr_t hdtr;
>   +    apr_size_t n = length;
>
>   -#if 0
>   -    ap_bsetopt(r->connection->client, BO_TIMEOUT,
>   -               r->connection->keptalive
>   -               ? &r->server->keep_alive_timeout
>   -               : &r->server->timeout);
>   -#endif
>   -    /*
>   -     * We want to send any data held in the client buffer on the
>   -     * call to apr_sendfile. So hijack it then set outcnt to 0
>   -     * to prevent the data from being sent to the client again
>   -     * when the buffer is flushed to the client at the end of the
>   -     * request.
>   -     */
>   -    iov.iov_base = r->connection->client->outbase;
>   -    iov.iov_len =  r->connection->client->outcnt;
>   -    r->connection->client->outcnt = 0;
>   -
>   -    /* initialize the apr_hdtr_t struct */
>   -    hdtr.headers = &iov;
>   -    hdtr.numheaders = 1;
>   -    hdtr.trailers = NULL;
>   -    hdtr.numtrailers = 0;
>   -
>        if (!r->connection->keepalive) {
>            /* Prepare the socket to be reused */
>   -        /* XXX fix me - byteranges? */
>            flags |= APR_SENDFILE_DISCONNECT_SOCKET;
>        }
>
>        rv = apr_sendfile(r->connection->client->bsock,
>                          fd,      /* The file to send */
>   -                      &hdtr,   /* Header and trailer iovecs */
>   +                      hdtr,    /* Header and trailer iovecs */
>                          &offset, /* Offset in file to begin sending from */
>   -                      &length,
>   +                      &n,
>                          flags);
>   -#if 0
>   -    if (r->connection->keptalive) {
>   -        ap_bsetopt(r->connection->client, BO_TIMEOUT,
>   -                   &r->server->timeout);
>   -    }
>   -#endif
>   -    *nbytes = length;
>   +    *nbytes = n;
>
>        return rv;
>    }
>    #endif
>   +static apr_status_t writev_it_all(apr_socket_t *s, struct iovec *vec, int
nvec,
>   +                                  apr_size_t len, apr_ssize_t *nbytes)
>   +{
>   +    apr_size_t bytes_written = 0;
>   +    apr_status_t rv;
>   +    apr_ssize_t n = len;
>   +    apr_ssize_t i = 0;
>   +
>   +    /* XXX handle checking for non-blocking socket */
>   +    while (bytes_written != len) {
>   +        rv = apr_sendv(s, vec + i, nvec - i, &n);
>   +        bytes_written += n;
>   +        if (rv != APR_SUCCESS)
>   +            return rv;
>   +
>   +        /* If the write did not complete, adjust the iovecs and issue
>   +         * apr_sendv again
>   +         */
>   +        if (bytes_written < len) {
>   +            /* Skip over the vectors that have already been written */
>   +            apr_size_t cnt = vec[i].iov_len;
>   +            while (n >= cnt) {
>   +                i++;
>   +                cnt += vec[i].iov_len;
>   +            }
>   +
>   +            if (n < cnt) {
>   +                /* Handle partial write of vec i */
>   +                vec[i].iov_base = (char *) vec[i].iov_base +
>   +                    (vec[i].iov_len - (cnt - n));
>   +                vec[i].iov_len = cnt -n;
>   +            }
>   +        }
>   +        n = len - bytes_written;
>   +    }
>   +
>   +    return APR_SUCCESS;
>   +}
>    /* Note --- ErrorDocument will now work from .htaccess files.
>     * The AllowOverride of Fileinfo allows webmasters to turn it off
>     */
>   @@ -3102,22 +3111,16 @@
>
>    /* Default filter.  This filter should almost always be used.  Its only job
>     * is to send the headers if they haven't already been sent, and then send
>   - * the actual data.  To send the data, we create an iovec out of the bucket
>   - * brigade and then call the sendv function.  On platforms that don't
>   - * have writev, we have the problem of creating a lot of potentially small
>   - * packets that we are sending to the network.
>   - *
>   - * This can be solved later by making the buckets buffer everything into a
>   - * single memory block that can be written using write (on those systems
>   - * without writev only !)
>   + * the actual data.
>     */
>    static int core_filter(ap_filter_t *f, ap_bucket_brigade *b)
>    {
>        request_rec *r = f->r;
>   +    apr_pool_t *p = r->pool;
>        apr_status_t rv;
>        apr_ssize_t bytes_sent = 0, len = 0, written;
>        ap_bucket *e;
>   -    const char *str;
>   +
>
>    #if 0 /* XXX: bit rot! */
>        /* This will all be needed once BUFF is removed from the code */
>   @@ -3140,56 +3143,120 @@
>        }
>        else {
>    #endif
>   +    struct iovec *iov;
>   +    apr_array_header_t *vec_trailers = NULL;
>   +    int  nvec_trailers= 0;
>   +    apr_array_header_t *vec;
>   +    int nvec = 0;
>
>   -     AP_BRIGADE_FOREACH(e, b) {
>   -         if (e->type == AP_BUCKET_EOS) {
>   -             /* there shouldn't be anything after the eos */
>   -             break;
>   -         }
>   -         else if (e->type == AP_BUCKET_FILE) {
>   +    apr_file_t *fd = NULL;
>   +    apr_ssize_t flen = 0;
>   +    apr_off_t foffset = 0;
>   +
>   +    vec = apr_make_array(p, 1, sizeof(struct iovec));
>   +
>   +    /* Hijack the data in BUFF to send on apr_sendv */
>   +    iov = (struct iovec *) apr_push_array(vec);
>   +    iov->iov_base = r->connection->client->outbase;
>   +    iov->iov_len =  r->connection->client->outcnt;
>   +    r->connection->client->outcnt = 0;
>   +    len = iov->iov_len;
>   +    nvec++;
>   +
>   +    /* Iterate across the buckets and build an iovec array.
>   +     * XXX The chunk filter gives us some very small chunks to send.
>   +     * Consider buffering some of these chunks into a contiguous piece
>   +     * of memory
>   +     */
>   +    AP_BRIGADE_FOREACH(e, b) {
>   +        switch (e->type) {
>   +        case AP_BUCKET_EOS:
>   +            break;
>   +        case AP_BUCKET_FILE:
>   +            /* Assume there is at most one AP_BUCKET_FILE in the brigade */
>   +            fd = e->data;
>   +            flen = e->length;
>   +            foffset = e->offset;
>   +            break;
>   +        default:
>   +        {
>   +            char *str;
>   +            apr_size_t n;
>   +            rv = e->read(e, &str, &n, 0);
>   +            if (n) {
>   +                len += n;
>   +
>   +                if (!fd) {
>   +                    nvec++;
>   +                    iov = (struct iovec *) apr_push_array(vec);
>   +                }
>   +                else {
>   +                    /* The bucket is a trailer to a file bucket */
>   +                    nvec_trailers++;
>   +                    if (vec_trailers == NULL) {
>   +                        vec_trailers = apr_make_array(p, 1, sizeof(struct
iovec));
>   +                    }
>   +                    iov = (struct iovec *) apr_push_array(vec_trailers);
>   +                }
>   +                iov->iov_base = str;
>   +                iov->iov_len = n;
>   +            }
>   +            break;
>   +        }
>   +        }
>   +
>   +        /* there shouldn't be anything after the eos */
>   +        if (e->type == AP_BUCKET_EOS) {
>   +            break;
>   +        }
>   +    }
>   +
>   +    /* We're done iterating across the buckets. Time to do network i/o.
>   +     * XXX Set socket i/o timeout and blocking characteristics.
>   +     * XXX We should consider eliminating ap_send_mmap and using ap_send_fd
>   +     * instead. Defer the decision on whether to use sendfile, mmap, or
>   +     * buffered file reads to the core filter.
>   +     */
>   +
>    #if APR_HAS_SENDFILE
>   -             /* If a file bucket gets all the way down to the core filter,
>   -              * the bucket by definition represents the unfiltered contents
>   -              * of a file. Thus it is acceptable to use apr_sendfile().
>   -              */
>   -             rv = send_the_file(e->data, e->offset, e->length, r,
&written);
>   -
>   -             /* Returning on APR_SUCCESS is not the correct behaviour as
there
>   -              * may be other buckets... Need to think about this awhile
before
>   -              * I change it. wgs
>   -              */
>   -             if (rv == APR_SUCCESS) {
>   -                 ap_brigade_destroy(b);
>   -                 return APR_SUCCESS;
>   -             }
>   -
>   -             /* If apr_sendfile is not implemented (e.g. Win95/98), then
>   -              * continue to the read/write loop.
>   -              */
>   -             if (rv != APR_ENOTIMPL) {
>   -                 /* check_first_conn_error(r, "send_fd", rv); */
>   -                 return rv;
>   -             }
>   -#endif
>   +     if (fd) {
>   +         apr_hdtr_t *hdtr =  apr_pcalloc(r->pool, sizeof(*hdtr));
>   +         if (nvec) {
>   +             hdtr->numheaders = nvec;
>   +             hdtr->headers = (struct iovec *) vec->elts;
>             }
>   -         rv = e->read(e, &str, &len, 0);
>   -         if (rv != APR_SUCCESS) {
>   -             return rv;
>   +         if (nvec_trailers) {
>   +             hdtr->numtrailers = nvec_trailers;
>   +             hdtr->trailers = (struct iovec *) vec_trailers->elts;
>             }
>   -         rv = ap_bwrite(r->connection->client, str, len, &written);
>   -         if (rv != APR_SUCCESS) {
>   +
>   +         rv = send_the_file(r, fd, hdtr, foffset, flen, &bytes_sent);
>   +
>   +         if (rv == APR_SUCCESS) {
>   +             ap_brigade_destroy(b);
>   +             return APR_SUCCESS;
>   +         }
>   +         /* If apr_sendfile is not implemented (e.g. Win95/98), then
>   +          * use apr_senv() to send the content.
>   +          */
>   +         if (rv != APR_ENOTIMPL) {
>   +             ap_brigade_destroy(b);
>   +             /* check_first_conn_error(r, "send_fd", rv); */
>                 return rv;
>             }
>   -         bytes_sent += written;
>   +         /* XXX: If we made it this far, sendfile must have failed with
>   +          * APR_ENOTIMPL. Read the file into an iovec array to prepare
>   +          * for a writev.
>   +          */
>         }
>   +#endif
>   +     rv = writev_it_all(r->connection->client->bsock,
>   +                        (struct iovec*) vec->elts, nvec,
>   +                        len, &bytes_sent);
>
>   -    ap_brigade_destroy(b);
>   -    /* This line will go away as soon as the BUFFs are removed */
>   -    if (len == AP_END_OF_BRIGADE) {
>   -        ap_bflush(r->connection->client);
>   -    }
>   +     ap_brigade_destroy(b);
>
>   -    return APR_SUCCESS;
>   +     return rv;
>    #if 0
>        }
>    #endif
>
>
>


Mime
View raw message