apr_brigade.c

来自「linux网络服务器工具」· C语言 代码 · 共 732 行 · 第 1/2 页

C
732
字号
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *     http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include "apr.h"#include "apr_lib.h"#include "apr_strings.h"#include "apr_pools.h"#include "apr_tables.h"#include "apr_buckets.h"#include "apr_errno.h"#define APR_WANT_MEMFUNC#define APR_WANT_STRFUNC#include "apr_want.h"#if APR_HAVE_SYS_UIO_H#include <sys/uio.h>#endifstatic apr_status_t brigade_cleanup(void *data) {    return apr_brigade_cleanup(data);}APU_DECLARE(apr_status_t) apr_brigade_cleanup(void *data){    apr_bucket_brigade *b = data;    apr_bucket *e;    while (!APR_BRIGADE_EMPTY(b)) {        e = APR_BRIGADE_FIRST(b);        apr_bucket_delete(e);    }    /* We don't need to free(bb) because it's allocated from a pool. */    return APR_SUCCESS;}APU_DECLARE(apr_status_t) apr_brigade_destroy(apr_bucket_brigade *b){    apr_pool_cleanup_kill(b->p, b, brigade_cleanup);    return apr_brigade_cleanup(b);}APU_DECLARE(apr_bucket_brigade *) apr_brigade_create(apr_pool_t *p,                                                     apr_bucket_alloc_t *list){    apr_bucket_brigade *b;    b = apr_palloc(p, sizeof(*b));    b->p = p;    b->bucket_alloc = list;    APR_RING_INIT(&b->list, apr_bucket, link);    apr_pool_cleanup_register(b->p, b, brigade_cleanup, apr_pool_cleanup_null);    return b;}APU_DECLARE(apr_bucket_brigade *) apr_brigade_split_ex(apr_bucket_brigade *b,                                                       apr_bucket *e,                                                       apr_bucket_brigade *a){    apr_bucket *f;    if (!a) {        a = apr_brigade_create(b->p, b->bucket_alloc);    }    else if (!APR_BRIGADE_EMPTY(a)) {        apr_brigade_cleanup(a);    }    /* Return an empty brigade if there is nothing left in      * the first brigade to split off      */    if (e != APR_BRIGADE_SENTINEL(b)) {        f = APR_RING_LAST(&b->list);        APR_RING_UNSPLICE(e, f, link);        APR_RING_SPLICE_HEAD(&a->list, e, f, apr_bucket, link);    }    APR_BRIGADE_CHECK_CONSISTENCY(a);    APR_BRIGADE_CHECK_CONSISTENCY(b);    return a;}APU_DECLARE(apr_bucket_brigade *) apr_brigade_split(apr_bucket_brigade *b,                                                    apr_bucket *e){    return apr_brigade_split_ex(b, e, NULL);}APU_DECLARE(apr_status_t) apr_brigade_partition(apr_bucket_brigade *b,                                                apr_off_t point,                                                apr_bucket **after_point){    apr_bucket *e;    const char *s;    apr_size_t len;    apr_uint64_t point64;    apr_status_t rv;    if (point < 0) {        /* this could cause weird (not necessarily SEGV) things to happen */        return APR_EINVAL;    }    if (point == 0) {        *after_point = APR_BRIGADE_FIRST(b);        return APR_SUCCESS;    }    /*     * Try to reduce the following casting mess: We know that point will be     * larger equal 0 now and forever and thus that point (apr_off_t) and     * apr_size_t will fit into apr_uint64_t in any case.     */    point64 = (apr_uint64_t)point;    APR_BRIGADE_CHECK_CONSISTENCY(b);    for (e = APR_BRIGADE_FIRST(b);         e != APR_BRIGADE_SENTINEL(b);         e = APR_BUCKET_NEXT(e))    {        /* For an unknown length bucket, while 'point64' is beyond the possible         * size contained in apr_size_t, read and continue...         */        if ((e->length == (apr_size_t)(-1))            && (point64 > (apr_uint64_t)APR_SIZE_MAX)) {            /* point64 is too far out to simply split this bucket,             * we must fix this bucket's size and keep going... */            rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);            if (rv != APR_SUCCESS) {                *after_point = e;                return rv;            }        }        else if ((point64 < (apr_uint64_t)e->length)                 || (e->length == (apr_size_t)(-1))) {            /* We already consumed buckets where point64 is beyond             * our interest ( point64 > APR_SIZE_MAX ), above.             * Here point falls between 0 and APR_SIZE_MAX             * and is within this bucket, or this bucket's len             * is undefined, so now we are ready to split it.             * First try to split the bucket natively... */            if ((rv = apr_bucket_split(e, (apr_size_t)point64))                     != APR_ENOTIMPL) {                *after_point = APR_BUCKET_NEXT(e);                return rv;            }            /* if the bucket cannot be split, we must read from it,             * changing its type to one that can be split */            rv = apr_bucket_read(e, &s, &len, APR_BLOCK_READ);            if (rv != APR_SUCCESS) {                *after_point = e;                return rv;            }            /* this assumes that len == e->length, which is okay because e             * might have been morphed by the apr_bucket_read() above, but             * if it was, the length would have been adjusted appropriately */            if (point64 < (apr_uint64_t)e->length) {                rv = apr_bucket_split(e, (apr_size_t)point64);                *after_point = APR_BUCKET_NEXT(e);                return rv;            }        }        if (point64 == (apr_uint64_t)e->length) {            *after_point = APR_BUCKET_NEXT(e);            return APR_SUCCESS;        }        point64 -= (apr_uint64_t)e->length;    }    *after_point = APR_BRIGADE_SENTINEL(b);     return APR_INCOMPLETE;}APU_DECLARE(apr_status_t) apr_brigade_length(apr_bucket_brigade *bb,                                             int read_all, apr_off_t *length){    apr_off_t total = 0;    apr_bucket *bkt;    apr_status_t status = APR_SUCCESS;    for (bkt = APR_BRIGADE_FIRST(bb);         bkt != APR_BRIGADE_SENTINEL(bb);         bkt = APR_BUCKET_NEXT(bkt))    {        if (bkt->length == (apr_size_t)(-1)) {            const char *ignore;            apr_size_t len;            if (!read_all) {                total = -1;                break;            }            if ((status = apr_bucket_read(bkt, &ignore, &len,                                          APR_BLOCK_READ)) != APR_SUCCESS) {                break;            }        }        total += bkt->length;    }    *length = total;    return status;}APU_DECLARE(apr_status_t) apr_brigade_flatten(apr_bucket_brigade *bb,                                              char *c, apr_size_t *len){    apr_size_t actual = 0;    apr_bucket *b;     for (b = APR_BRIGADE_FIRST(bb);         b != APR_BRIGADE_SENTINEL(bb);         b = APR_BUCKET_NEXT(b))    {        const char *str;        apr_size_t str_len;        apr_status_t status;        status = apr_bucket_read(b, &str, &str_len, APR_BLOCK_READ);        if (status != APR_SUCCESS) {            return status;        }        /* If we would overflow. */        if (str_len + actual > *len) {            str_len = *len - actual;        }        /* XXX: It appears that overflow of the final bucket         * is DISCARDED without any warning to the caller.         *         * No, we only copy the data up to their requested size.  -- jre         */        memcpy(c, str, str_len);        c += str_len;        actual += str_len;        /* This could probably be actual == *len, but be safe from stray         * photons. */        if (actual >= *len) {            break;        }    }    *len = actual;    return APR_SUCCESS;}APU_DECLARE(apr_status_t) apr_brigade_pflatten(apr_bucket_brigade *bb,                                               char **c,                                               apr_size_t *len,                                               apr_pool_t *pool){    apr_off_t actual;    apr_size_t total;    apr_status_t rv;    apr_brigade_length(bb, 1, &actual);        /* XXX: This is dangerous beyond belief.  At least in the     * apr_brigade_flatten case, the user explicitly stated their     * buffer length - so we don't up and palloc 4GB for a single     * file bucket.  This API must grow a useful max boundry,     * either compiled-in or preset via the *len value.     *     * Shouldn't both fn's grow an additional return value for      * the case that the brigade couldn't be flattened into the     * provided or allocated buffer (such as APR_EMOREDATA?)     * Not a failure, simply an advisory result.     */    total = (apr_size_t)actual;    *c = apr_palloc(pool, total);        rv = apr_brigade_flatten(bb, *c, &total);    if (rv != APR_SUCCESS) {        return rv;    }    *len = total;    return APR_SUCCESS;}APU_DECLARE(apr_status_t) apr_brigade_split_line(apr_bucket_brigade *bbOut,                                                 apr_bucket_brigade *bbIn,                                                 apr_read_type_e block,                                                 apr_off_t maxbytes){    apr_off_t readbytes = 0;    while (!APR_BRIGADE_EMPTY(bbIn)) {        const char *pos;        const char *str;        apr_size_t len;        apr_status_t rv;        apr_bucket *e;        e = APR_BRIGADE_FIRST(bbIn);        rv = apr_bucket_read(e, &str, &len, block);        if (rv != APR_SUCCESS) {            return rv;        }        pos = memchr(str, APR_ASCII_LF, len);        /* We found a match. */        if (pos != NULL) {            apr_bucket_split(e, pos - str + 1);            APR_BUCKET_REMOVE(e);            APR_BRIGADE_INSERT_TAIL(bbOut, e);            return APR_SUCCESS;        }        APR_BUCKET_REMOVE(e);        APR_BRIGADE_INSERT_TAIL(bbOut, e);        readbytes += len;        /* We didn't find an APR_ASCII_LF within the maximum line length. */        if (readbytes >= maxbytes) {            break;        }    }    return APR_SUCCESS;}APU_DECLARE(apr_status_t) apr_brigade_to_iovec(apr_bucket_brigade *b,                                                struct iovec *vec, int *nvec){    int left = *nvec;    apr_bucket *e;    struct iovec *orig;    apr_size_t iov_len;    const char *iov_base;    apr_status_t rv;    orig = vec;    for (e = APR_BRIGADE_FIRST(b);         e != APR_BRIGADE_SENTINEL(b);         e = APR_BUCKET_NEXT(e))    {        if (left-- == 0)            break;        rv = apr_bucket_read(e, &iov_base, &iov_len, APR_NONBLOCK_READ);        if (rv != APR_SUCCESS)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?