Blame buckets/buckets.c

Packit 3adb1e
/* ====================================================================
Packit 3adb1e
 *    Licensed to the Apache Software Foundation (ASF) under one
Packit 3adb1e
 *    or more contributor license agreements.  See the NOTICE file
Packit 3adb1e
 *    distributed with this work for additional information
Packit 3adb1e
 *    regarding copyright ownership.  The ASF licenses this file
Packit 3adb1e
 *    to you under the Apache License, Version 2.0 (the
Packit 3adb1e
 *    "License"); you may not use this file except in compliance
Packit 3adb1e
 *    with the License.  You may obtain a copy of the License at
Packit 3adb1e
 *
Packit 3adb1e
 *      http://www.apache.org/licenses/LICENSE-2.0
Packit 3adb1e
 *
Packit 3adb1e
 *    Unless required by applicable law or agreed to in writing,
Packit 3adb1e
 *    software distributed under the License is distributed on an
Packit 3adb1e
 *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
Packit 3adb1e
 *    KIND, either express or implied.  See the License for the
Packit 3adb1e
 *    specific language governing permissions and limitations
Packit 3adb1e
 *    under the License.
Packit 3adb1e
 * ====================================================================
Packit 3adb1e
 */
Packit 3adb1e
Packit 3adb1e
#include <apr_pools.h>
Packit 3adb1e
Packit 3adb1e
#include "serf.h"
Packit 3adb1e
#include "serf_bucket_util.h"
Packit 3adb1e
#include "serf_private.h"
Packit 3adb1e
Packit 3adb1e
serf_bucket_t *serf_bucket_create(
Packit 3adb1e
    const serf_bucket_type_t *type,
Packit 3adb1e
    serf_bucket_alloc_t *allocator,
Packit 3adb1e
    void *data)
Packit 3adb1e
{
Packit 3adb1e
    serf_bucket_t *bkt = serf_bucket_mem_alloc(allocator, sizeof(*bkt));
Packit 3adb1e
Packit 3adb1e
    bkt->type = type;
Packit 3adb1e
    bkt->data = data;
Packit 3adb1e
    bkt->allocator = allocator;
Packit 3adb1e
Packit 3adb1e
    return bkt;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_default_read_iovec(
Packit 3adb1e
    serf_bucket_t *bucket,
Packit 3adb1e
    apr_size_t requested,
Packit 3adb1e
    int vecs_size,
Packit 3adb1e
    struct iovec *vecs,
Packit 3adb1e
    int *vecs_used)
Packit 3adb1e
{
Packit 3adb1e
    const char *data;
Packit 3adb1e
    apr_size_t len;
Packit 3adb1e
Packit 3adb1e
    /* Read some data from the bucket.
Packit 3adb1e
     *
Packit 3adb1e
     * Because we're an internal 'helper' to the bucket, we can't call the
Packit 3adb1e
     * normal serf_bucket_read() call because the debug allocator tracker will
Packit 3adb1e
     * end up marking the bucket as read *twice* - once for us and once for
Packit 3adb1e
     * our caller - which is reading the same bucket.  This leads to premature
Packit 3adb1e
     * abort()s if we ever see EAGAIN.  Instead, we'll go directly to the
Packit 3adb1e
     * vtable and bypass the debug tracker.
Packit 3adb1e
     */
Packit 3adb1e
    apr_status_t status = bucket->type->read(bucket, requested, &data, &len;;
Packit 3adb1e
Packit 3adb1e
    /* assert that vecs_size >= 1 ? */
Packit 3adb1e
Packit 3adb1e
    /* Return that data as a single iovec. */
Packit 3adb1e
    if (len) {
Packit 3adb1e
        vecs[0].iov_base = (void *)data; /* loses the 'const' */
Packit 3adb1e
        vecs[0].iov_len = len;
Packit 3adb1e
        *vecs_used = 1;
Packit 3adb1e
    }
Packit 3adb1e
    else {
Packit 3adb1e
        *vecs_used = 0;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return status;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_default_read_for_sendfile(
Packit 3adb1e
    serf_bucket_t *bucket,
Packit 3adb1e
    apr_size_t requested,
Packit 3adb1e
    apr_hdtr_t *hdtr,
Packit 3adb1e
    apr_file_t **file,
Packit 3adb1e
    apr_off_t *offset,
Packit 3adb1e
    apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    /* Read a bunch of stuff into the headers.
Packit 3adb1e
     *
Packit 3adb1e
     * See serf_default_read_iovec as to why we call into the vtable
Packit 3adb1e
     * directly.
Packit 3adb1e
     */
Packit 3adb1e
    apr_status_t status = bucket->type->read_iovec(bucket, requested,
Packit 3adb1e
                                                   hdtr->numheaders,
Packit 3adb1e
                                                   hdtr->headers,
Packit 3adb1e
                                                   &hdtr->numheaders);
Packit 3adb1e
Packit 3adb1e
    /* There isn't a file, and there are no trailers. */
Packit 3adb1e
    *file = NULL;
Packit 3adb1e
    hdtr->numtrailers = 0;
Packit 3adb1e
Packit 3adb1e
    return status;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
serf_bucket_t *serf_default_read_bucket(
Packit 3adb1e
    serf_bucket_t *bucket,
Packit 3adb1e
    const serf_bucket_type_t *type)
Packit 3adb1e
{
Packit 3adb1e
    return NULL;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_default_destroy(serf_bucket_t *bucket)
Packit 3adb1e
{
Packit 3adb1e
#ifdef SERF_DEBUG_BUCKET_USE
Packit 3adb1e
    serf_debug__bucket_destroy(bucket);
Packit 3adb1e
#endif
Packit 3adb1e
Packit 3adb1e
    serf_bucket_mem_free(bucket->allocator, bucket);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_default_destroy_and_data(serf_bucket_t *bucket)
Packit 3adb1e
{
Packit 3adb1e
    serf_bucket_mem_free(bucket->allocator, bucket->data);
Packit 3adb1e
    serf_default_destroy(bucket);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
/* ==================================================================== */
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
char *serf_bstrmemdup(serf_bucket_alloc_t *allocator,
Packit 3adb1e
                      const char *str,
Packit 3adb1e
                      apr_size_t size)
Packit 3adb1e
{
Packit 3adb1e
    char *newstr = serf_bucket_mem_alloc(allocator, size + 1);
Packit 3adb1e
    memcpy(newstr, str, size);
Packit 3adb1e
    newstr[size] = '\0';
Packit 3adb1e
    return newstr;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void *serf_bmemdup(serf_bucket_alloc_t *allocator,
Packit 3adb1e
                   const void *mem,
Packit 3adb1e
                   apr_size_t size)
Packit 3adb1e
{
Packit 3adb1e
    void *newmem = serf_bucket_mem_alloc(allocator, size);
Packit 3adb1e
    memcpy(newmem, mem, size);
Packit 3adb1e
    return newmem;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
char *serf_bstrdup(serf_bucket_alloc_t *allocator,
Packit 3adb1e
                   const char *str)
Packit 3adb1e
{
Packit 3adb1e
    apr_size_t size = strlen(str) + 1;
Packit 3adb1e
    char *newstr = serf_bucket_mem_alloc(allocator, size);
Packit 3adb1e
    memcpy(newstr, str, size);
Packit 3adb1e
    return newstr;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
char *serf_bstrcatv(serf_bucket_alloc_t *allocator, struct iovec *vec,
Packit 3adb1e
                    int vecs, apr_size_t *bytes_written)
Packit 3adb1e
{
Packit 3adb1e
    int i;
Packit 3adb1e
    apr_size_t new_len = 0;
Packit 3adb1e
    char *c, *newstr;
Packit 3adb1e
Packit 3adb1e
    for (i = 0; i < vecs; i++) {
Packit 3adb1e
        new_len += vec[i].iov_len;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* It's up to the caller to free this memory later. */
Packit 3adb1e
    newstr = serf_bucket_mem_alloc(allocator, new_len);
Packit 3adb1e
Packit 3adb1e
    c = newstr;
Packit 3adb1e
    for (i = 0; i < vecs; i++) {
Packit 3adb1e
        memcpy(c, vec[i].iov_base, vec[i].iov_len);
Packit 3adb1e
        c += vec[i].iov_len;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    if (bytes_written) {
Packit 3adb1e
        *bytes_written = c - newstr;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    return newstr;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* ==================================================================== */
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
static void find_crlf(const char **data, apr_size_t *len, int *found)
Packit 3adb1e
{
Packit 3adb1e
    const char *start = *data;
Packit 3adb1e
    const char *end = start + *len;
Packit 3adb1e
Packit 3adb1e
    while (start < end) {
Packit 3adb1e
        const char *cr = memchr(start, '\r', *len);
Packit 3adb1e
Packit 3adb1e
        if (cr == NULL) {
Packit 3adb1e
            break;
Packit 3adb1e
        }
Packit 3adb1e
        ++cr;
Packit 3adb1e
Packit 3adb1e
        if (cr < end && cr[0] == '\n') {
Packit 3adb1e
            *len -= cr + 1 - start;
Packit 3adb1e
            *data = cr + 1;
Packit 3adb1e
            *found = SERF_NEWLINE_CRLF;
Packit 3adb1e
            return;
Packit 3adb1e
        }
Packit 3adb1e
        if (cr == end) {
Packit 3adb1e
            *len = 0;
Packit 3adb1e
            *data = end;
Packit 3adb1e
            *found = SERF_NEWLINE_CRLF_SPLIT;
Packit 3adb1e
            return;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        /* It was a bare CR without an LF. Just move past it. */
Packit 3adb1e
        *len -= cr - start;
Packit 3adb1e
        start = cr;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    *data = start + *len;
Packit 3adb1e
    *len -= *data - start;
Packit 3adb1e
    *found = SERF_NEWLINE_NONE;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_util_readline(
Packit 3adb1e
    const char **data,
Packit 3adb1e
    apr_size_t *len,
Packit 3adb1e
    int acceptable,
Packit 3adb1e
    int *found)
Packit 3adb1e
{
Packit 3adb1e
    const char *start;
Packit 3adb1e
    const char *cr;
Packit 3adb1e
    const char *lf;
Packit 3adb1e
    int want_cr;
Packit 3adb1e
    int want_crlf;
Packit 3adb1e
    int want_lf;
Packit 3adb1e
Packit 3adb1e
    /* If _only_ CRLF is acceptable, then the scanning needs a loop to
Packit 3adb1e
     * skip false hits on CR characters. Use a separate function.
Packit 3adb1e
     */
Packit 3adb1e
    if (acceptable == SERF_NEWLINE_CRLF) {
Packit 3adb1e
        find_crlf(data, len, found);
Packit 3adb1e
        return;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    start = *data;
Packit 3adb1e
    cr = lf = NULL;
Packit 3adb1e
    want_cr = acceptable & SERF_NEWLINE_CR;
Packit 3adb1e
    want_crlf = acceptable & SERF_NEWLINE_CRLF;
Packit 3adb1e
    want_lf = acceptable & SERF_NEWLINE_LF;
Packit 3adb1e
Packit 3adb1e
    if (want_cr || want_crlf) {
Packit 3adb1e
        cr = memchr(start, '\r', *len);
Packit 3adb1e
    }
Packit 3adb1e
    if (want_lf) {
Packit 3adb1e
        lf = memchr(start, '\n', *len);
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    if (cr != NULL) {
Packit 3adb1e
        if (lf != NULL) {
Packit 3adb1e
            if (cr + 1 == lf)
Packit 3adb1e
                *found = want_crlf ? SERF_NEWLINE_CRLF : SERF_NEWLINE_CR;
Packit 3adb1e
            else if (want_cr && cr < lf)
Packit 3adb1e
                *found = SERF_NEWLINE_CR;
Packit 3adb1e
            else
Packit 3adb1e
                *found = SERF_NEWLINE_LF;
Packit 3adb1e
        }
Packit 3adb1e
        else if (cr == start + *len - 1) {
Packit 3adb1e
            /* the CR occurred in the last byte of the buffer. this could be
Packit 3adb1e
             * a CRLF split across the data boundary.
Packit 3adb1e
             * ### FIX THIS LOGIC? does caller need to detect?
Packit 3adb1e
             */
Packit 3adb1e
            *found = want_crlf ? SERF_NEWLINE_CRLF_SPLIT : SERF_NEWLINE_CR;
Packit 3adb1e
        }
Packit 3adb1e
        else if (want_cr)
Packit 3adb1e
            *found = SERF_NEWLINE_CR;
Packit 3adb1e
        else /* want_crlf */
Packit 3adb1e
            *found = SERF_NEWLINE_NONE;
Packit 3adb1e
    }
Packit 3adb1e
    else if (lf != NULL)
Packit 3adb1e
        *found = SERF_NEWLINE_LF;
Packit 3adb1e
    else
Packit 3adb1e
        *found = SERF_NEWLINE_NONE;
Packit 3adb1e
Packit 3adb1e
    switch (*found) {
Packit 3adb1e
      case SERF_NEWLINE_LF:
Packit 3adb1e
        *data = lf + 1;
Packit 3adb1e
        break;
Packit 3adb1e
      case SERF_NEWLINE_CR:
Packit 3adb1e
      case SERF_NEWLINE_CRLF:
Packit 3adb1e
      case SERF_NEWLINE_CRLF_SPLIT:
Packit 3adb1e
        *data = cr + 1 + (*found == SERF_NEWLINE_CRLF);
Packit 3adb1e
        break;
Packit 3adb1e
      case SERF_NEWLINE_NONE:
Packit 3adb1e
        *data += *len;
Packit 3adb1e
        break;
Packit 3adb1e
      default:
Packit 3adb1e
        /* Not reachable */
Packit 3adb1e
        return;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    *len -= *data - start;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
/* ==================================================================== */
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_databuf_init(serf_databuf_t *databuf)
Packit 3adb1e
{
Packit 3adb1e
    /* nothing is sitting in the buffer */
Packit 3adb1e
    databuf->remaining = 0;
Packit 3adb1e
Packit 3adb1e
    /* avoid thinking we have hit EOF */
Packit 3adb1e
    databuf->status = APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Ensure the buffer is prepared for reading. Will return APR_SUCCESS,
Packit 3adb1e
 * APR_EOF, or some failure code. *len is only set for EOF. */
Packit 3adb1e
static apr_status_t common_databuf_prep(serf_databuf_t *databuf,
Packit 3adb1e
                                        apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    apr_size_t readlen;
Packit 3adb1e
    apr_status_t status;
Packit 3adb1e
Packit 3adb1e
    /* if there is data in the buffer, then we're happy. */
Packit 3adb1e
    if (databuf->remaining > 0)
Packit 3adb1e
        return APR_SUCCESS;
Packit 3adb1e
Packit 3adb1e
    /* if we already hit EOF, then keep returning that. */
Packit 3adb1e
    if (APR_STATUS_IS_EOF(databuf->status)) {
Packit 3adb1e
        /* *data = NULL;   ?? */
Packit 3adb1e
        *len = 0;
Packit 3adb1e
        return APR_EOF;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    /* refill the buffer */
Packit 3adb1e
    status = (*databuf->read)(databuf->read_baton, sizeof(databuf->buf),
Packit 3adb1e
                              databuf->buf, &readlen);
Packit 3adb1e
    if (SERF_BUCKET_READ_ERROR(status)) {
Packit 3adb1e
        return status;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    databuf->current = databuf->buf;
Packit 3adb1e
    databuf->remaining = readlen;
Packit 3adb1e
    databuf->status = status;
Packit 3adb1e
Packit 3adb1e
    return APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_databuf_read(
Packit 3adb1e
    serf_databuf_t *databuf,
Packit 3adb1e
    apr_size_t requested,
Packit 3adb1e
    const char **data,
Packit 3adb1e
    apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    apr_status_t status = common_databuf_prep(databuf, len);
Packit 3adb1e
    if (status)
Packit 3adb1e
        return status;
Packit 3adb1e
Packit 3adb1e
    /* peg the requested amount to what we have remaining */
Packit 3adb1e
    if (requested == SERF_READ_ALL_AVAIL || requested > databuf->remaining)
Packit 3adb1e
        requested = databuf->remaining;
Packit 3adb1e
Packit 3adb1e
    /* return the values */
Packit 3adb1e
    *data = databuf->current;
Packit 3adb1e
    *len = requested;
Packit 3adb1e
Packit 3adb1e
    /* adjust our internal state to note we've consumed some data */
Packit 3adb1e
    databuf->current += requested;
Packit 3adb1e
    databuf->remaining -= requested;
Packit 3adb1e
Packit 3adb1e
    /* If we read everything, then we need to return whatever the data
Packit 3adb1e
     * read returned to us. This is going to be APR_EOF or APR_EGAIN.
Packit 3adb1e
     * If we have NOT read everything, then return APR_SUCCESS to indicate
Packit 3adb1e
     * that we're ready to return some more if asked.
Packit 3adb1e
     */
Packit 3adb1e
    return databuf->remaining ? APR_SUCCESS : databuf->status;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_databuf_readline(
Packit 3adb1e
    serf_databuf_t *databuf,
Packit 3adb1e
    int acceptable,
Packit 3adb1e
    int *found,
Packit 3adb1e
    const char **data,
Packit 3adb1e
    apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    apr_status_t status = common_databuf_prep(databuf, len);
Packit 3adb1e
    if (status)
Packit 3adb1e
        return status;
Packit 3adb1e
Packit 3adb1e
    /* the returned line will start at the current position. */
Packit 3adb1e
    *data = databuf->current;
Packit 3adb1e
Packit 3adb1e
    /* read a line from the buffer, and adjust the various pointers. */
Packit 3adb1e
    serf_util_readline(&databuf->current, &databuf->remaining, acceptable,
Packit 3adb1e
                       found);
Packit 3adb1e
Packit 3adb1e
    /* the length matches the amount consumed by the readline */
Packit 3adb1e
    *len = databuf->current - *data;
Packit 3adb1e
Packit 3adb1e
    /* see serf_databuf_read's return condition */
Packit 3adb1e
    return databuf->remaining ? APR_SUCCESS : databuf->status;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_databuf_peek(
Packit 3adb1e
    serf_databuf_t *databuf,
Packit 3adb1e
    const char **data,
Packit 3adb1e
    apr_size_t *len)
Packit 3adb1e
{
Packit 3adb1e
    apr_status_t status = common_databuf_prep(databuf, len);
Packit 3adb1e
    if (status)
Packit 3adb1e
        return status;
Packit 3adb1e
Packit 3adb1e
    /* return everything we have */
Packit 3adb1e
    *data = databuf->current;
Packit 3adb1e
    *len = databuf->remaining;
Packit 3adb1e
Packit 3adb1e
    /* If the last read returned EOF, then the peek should return the same.
Packit 3adb1e
     * The other possibility in databuf->status is APR_EAGAIN, which we
Packit 3adb1e
     * should never return. Thus, just return APR_SUCCESS for non-EOF cases.
Packit 3adb1e
     */
Packit 3adb1e
    if (APR_STATUS_IS_EOF(databuf->status))
Packit 3adb1e
        return APR_EOF;
Packit 3adb1e
    return APR_SUCCESS;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
/* ==================================================================== */
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
void serf_linebuf_init(serf_linebuf_t *linebuf)
Packit 3adb1e
{
Packit 3adb1e
    linebuf->state = SERF_LINEBUF_EMPTY;
Packit 3adb1e
    linebuf->used = 0;
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
Packit 3adb1e
apr_status_t serf_linebuf_fetch(
Packit 3adb1e
    serf_linebuf_t *linebuf,
Packit 3adb1e
    serf_bucket_t *bucket,
Packit 3adb1e
    int acceptable)
Packit 3adb1e
{
Packit 3adb1e
    /* If we had a complete line, then assume the caller has used it, so
Packit 3adb1e
     * we can now reset the state.
Packit 3adb1e
     */
Packit 3adb1e
    if (linebuf->state == SERF_LINEBUF_READY) {
Packit 3adb1e
        linebuf->state = SERF_LINEBUF_EMPTY;
Packit 3adb1e
Packit 3adb1e
        /* Reset the line_used, too, so we don't have to test the state
Packit 3adb1e
         * before using this value.
Packit 3adb1e
         */
Packit 3adb1e
        linebuf->used = 0;
Packit 3adb1e
    }
Packit 3adb1e
Packit 3adb1e
    while (1) {
Packit 3adb1e
        apr_status_t status;
Packit 3adb1e
        const char *data;
Packit 3adb1e
        apr_size_t len;
Packit 3adb1e
Packit 3adb1e
        if (linebuf->state == SERF_LINEBUF_CRLF_SPLIT) {
Packit 3adb1e
            /* On the previous read, we received just a CR. The LF might
Packit 3adb1e
             * be present, but the bucket couldn't see it. We need to
Packit 3adb1e
             * examine a single character to determine how to handle the
Packit 3adb1e
             * split CRLF.
Packit 3adb1e
             */
Packit 3adb1e
Packit 3adb1e
            status = serf_bucket_peek(bucket, &data, &len;;
Packit 3adb1e
            if (SERF_BUCKET_READ_ERROR(status))
Packit 3adb1e
                return status;
Packit 3adb1e
Packit 3adb1e
            if (len > 0) {
Packit 3adb1e
                if (*data == '\n') {
Packit 3adb1e
                    /* We saw the second part of CRLF. We don't need to
Packit 3adb1e
                     * save that character, so do an actual read to suck
Packit 3adb1e
                     * up that character.
Packit 3adb1e
                     */
Packit 3adb1e
                    /* ### check status */
Packit 3adb1e
                    (void) serf_bucket_read(bucket, 1, &data, &len;;
Packit 3adb1e
                }
Packit 3adb1e
                /* else:
Packit 3adb1e
                 *   We saw the first character of the next line. Thus,
Packit 3adb1e
                 *   the current line is terminated by the CR. Just
Packit 3adb1e
                 *   ignore whatever we peeked at. The next reader will
Packit 3adb1e
                 *   see it and handle it as appropriate.
Packit 3adb1e
                 */
Packit 3adb1e
Packit 3adb1e
                /* Whatever was read, the line is now ready for use. */
Packit 3adb1e
                linebuf->state = SERF_LINEBUF_READY;
Packit 3adb1e
            } else {
Packit 3adb1e
                /* no data available, try again later. */
Packit 3adb1e
                return APR_EAGAIN;
Packit 3adb1e
            }
Packit 3adb1e
        }
Packit 3adb1e
        else {
Packit 3adb1e
            int found;
Packit 3adb1e
Packit 3adb1e
            status = serf_bucket_readline(bucket, acceptable, &found,
Packit 3adb1e
                                          &data, &len;;
Packit 3adb1e
            if (SERF_BUCKET_READ_ERROR(status)) {
Packit 3adb1e
                return status;
Packit 3adb1e
            }
Packit 3adb1e
            /* Some bucket types (socket) might need an extra read to find
Packit 3adb1e
               out EOF state, so they'll return no data in that read. This
Packit 3adb1e
               means we're done reading, return what we got. */
Packit 3adb1e
            if (APR_STATUS_IS_EOF(status) && len == 0) {
Packit 3adb1e
	        return status;
Packit 3adb1e
            }
Packit 3adb1e
            if (linebuf->used + len > sizeof(linebuf->line)) {
Packit 3adb1e
                /* ### need a "line too long" error */
Packit 3adb1e
                return APR_EGENERAL;
Packit 3adb1e
            }
Packit 3adb1e
Packit 3adb1e
            /* Note: our logic doesn't change for SERF_LINEBUF_PARTIAL. That
Packit 3adb1e
             * only affects how we fill the buffer. It is a communication to
Packit 3adb1e
             * our caller on whether the line is ready or not.
Packit 3adb1e
             */
Packit 3adb1e
Packit 3adb1e
            /* If we didn't see a newline, then we should mark the line
Packit 3adb1e
             * buffer as partially complete.
Packit 3adb1e
             */
Packit 3adb1e
            if (found == SERF_NEWLINE_NONE) {
Packit 3adb1e
                linebuf->state = SERF_LINEBUF_PARTIAL;
Packit 3adb1e
            }
Packit 3adb1e
            else if (found == SERF_NEWLINE_CRLF_SPLIT) {
Packit 3adb1e
                linebuf->state = SERF_LINEBUF_CRLF_SPLIT;
Packit 3adb1e
Packit 3adb1e
                /* Toss the partial CR. We won't ever need it. */
Packit 3adb1e
                --len;
Packit 3adb1e
            }
Packit 3adb1e
            else {
Packit 3adb1e
                /* We got a newline (of some form). We don't need it
Packit 3adb1e
                 * in the line buffer, so back up the length. Then
Packit 3adb1e
                 * mark the line as ready.
Packit 3adb1e
                 */
Packit 3adb1e
                len -= 1 + (found == SERF_NEWLINE_CRLF);
Packit 3adb1e
Packit 3adb1e
                linebuf->state = SERF_LINEBUF_READY;
Packit 3adb1e
            }
Packit 3adb1e
Packit 3adb1e
            /* ### it would be nice to avoid this copy if at all possible,
Packit 3adb1e
               ### and just return the a data/len pair to the caller. we're
Packit 3adb1e
               ### keeping it simple for now. */
Packit 3adb1e
            memcpy(&linebuf->line[linebuf->used], data, len);
Packit 3adb1e
            linebuf->used += len;
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        /* If we saw anything besides "success. please read again", then
Packit 3adb1e
         * we should return that status. If the line was completed, then
Packit 3adb1e
         * we should also return.
Packit 3adb1e
         */
Packit 3adb1e
        if (status || linebuf->state == SERF_LINEBUF_READY)
Packit 3adb1e
            return status;
Packit 3adb1e
Packit 3adb1e
        /* We got APR_SUCCESS and the line buffer is not complete. Let's
Packit 3adb1e
         * loop to read some more data.
Packit 3adb1e
         */
Packit 3adb1e
    }
Packit 3adb1e
    /* NOTREACHED */
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
/* Logging functions.
Packit 3adb1e
   Use with one of the [COMP]_VERBOSE defines so that the compiler knows to
Packit 3adb1e
   optimize this code out when no logging is needed. */
Packit 3adb1e
static void log_time()
Packit 3adb1e
{
Packit 3adb1e
    apr_time_exp_t tm;
Packit 3adb1e
Packit 3adb1e
    apr_time_exp_lt(&tm, apr_time_now());
Packit 3adb1e
    fprintf(stderr, "[%d-%02d-%02dT%02d:%02d:%02d.%06d%+03d] ",
Packit 3adb1e
            1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday,
Packit 3adb1e
            tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
Packit 3adb1e
            tm.tm_gmtoff/3600);
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
void serf__log(int verbose_flag, const char *filename, const char *fmt, ...)
Packit 3adb1e
{
Packit 3adb1e
    va_list argp;
Packit 3adb1e
Packit 3adb1e
    if (verbose_flag) {
Packit 3adb1e
        log_time();
Packit 3adb1e
Packit 3adb1e
        if (filename)
Packit 3adb1e
            fprintf(stderr, "%s: ", filename);
Packit 3adb1e
Packit 3adb1e
        va_start(argp, fmt);
Packit 3adb1e
        vfprintf(stderr, fmt, argp);
Packit 3adb1e
        va_end(argp);
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
void serf__log_nopref(int verbose_flag, const char *fmt, ...)
Packit 3adb1e
{
Packit 3adb1e
    va_list argp;
Packit 3adb1e
Packit 3adb1e
    if (verbose_flag) {
Packit 3adb1e
        va_start(argp, fmt);
Packit 3adb1e
        vfprintf(stderr, fmt, argp);
Packit 3adb1e
        va_end(argp);
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e
Packit 3adb1e
void serf__log_skt(int verbose_flag, const char *filename, apr_socket_t *skt,
Packit 3adb1e
                   const char *fmt, ...)
Packit 3adb1e
{
Packit 3adb1e
    va_list argp;
Packit 3adb1e
Packit 3adb1e
    if (verbose_flag) {
Packit 3adb1e
        apr_sockaddr_t *sa;
Packit 3adb1e
        log_time();
Packit 3adb1e
Packit 3adb1e
        if (skt) {
Packit 3adb1e
            /* Log local and remote ip address:port */
Packit 3adb1e
            fprintf(stderr, "[l:");
Packit 3adb1e
            if (apr_socket_addr_get(&sa, APR_LOCAL, skt) == APR_SUCCESS) {
Packit 3adb1e
                char buf[32];
Packit 3adb1e
                apr_sockaddr_ip_getbuf(buf, 32, sa);
Packit 3adb1e
                fprintf(stderr, "%s:%d", buf, sa->port);
Packit 3adb1e
            }
Packit 3adb1e
            fprintf(stderr, " r:");
Packit 3adb1e
            if (apr_socket_addr_get(&sa, APR_REMOTE, skt) == APR_SUCCESS) {
Packit 3adb1e
                char buf[32];
Packit 3adb1e
                apr_sockaddr_ip_getbuf(buf, 32, sa);
Packit 3adb1e
                fprintf(stderr, "%s:%d", buf, sa->port);
Packit 3adb1e
            }
Packit 3adb1e
            fprintf(stderr, "] ");
Packit 3adb1e
        }
Packit 3adb1e
Packit 3adb1e
        if (filename)
Packit 3adb1e
            fprintf(stderr, "%s: ", filename);
Packit 3adb1e
Packit 3adb1e
        va_start(argp, fmt);
Packit 3adb1e
        vfprintf(stderr, fmt, argp);
Packit 3adb1e
        va_end(argp);
Packit 3adb1e
    }
Packit 3adb1e
}
Packit 3adb1e