⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 http_filters.c

📁 Apache官方在今天放出产品系列2.2的最新版本2.2.11的源码包 最流行的HTTP服务器软件之一
💻 C
📖 第 1 页 / 共 4 页
字号:
/* 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. *//* * http_filter.c --- HTTP routines which either filters or deal with filters. */#include "apr.h"#include "apr_strings.h"#include "apr_buckets.h"#include "apr_lib.h"#include "apr_signal.h"#define APR_WANT_STDIO          /* for sscanf */#define APR_WANT_STRFUNC#define APR_WANT_MEMFUNC#include "apr_want.h"#define CORE_PRIVATE#include "util_filter.h"#include "ap_config.h"#include "httpd.h"#include "http_config.h"#include "http_core.h"#include "http_protocol.h"#include "http_main.h"#include "http_request.h"#include "http_vhost.h"#include "http_connection.h"#include "http_log.h"           /* For errors detected in basic auth common                                 * support code... */#include "apr_date.h"           /* For apr_date_parse_http and APR_DATE_BAD */#include "util_charset.h"#include "util_ebcdic.h"#include "util_time.h"#include "mod_core.h"#if APR_HAVE_STDARG_H#include <stdarg.h>#endif#if APR_HAVE_UNISTD_H#include <unistd.h>#endif#define INVALID_CHAR -2static long get_chunk_size(char *);typedef struct http_filter_ctx {    apr_off_t remaining;    apr_off_t limit;    apr_off_t limit_used;    enum {        BODY_NONE,        BODY_LENGTH,        BODY_CHUNK,        BODY_CHUNK_PART    } state;    int eos_sent;    char chunk_ln[32];    char *pos;    apr_off_t linesize;    apr_bucket_brigade *bb;} http_ctx_t;static apr_status_t bail_out_on_error(http_ctx_t *ctx,                                      ap_filter_t *f,                                      int http_error){    apr_bucket *e;    apr_bucket_brigade *bb = ctx->bb;    apr_brigade_cleanup(bb);    e = ap_bucket_error_create(http_error,                               NULL, f->r->pool,                               f->c->bucket_alloc);    APR_BRIGADE_INSERT_TAIL(bb, e);    e = apr_bucket_eos_create(f->c->bucket_alloc);    APR_BRIGADE_INSERT_TAIL(bb, e);    ctx->eos_sent = 1;    return ap_pass_brigade(f->r->output_filters, bb);}static apr_status_t get_remaining_chunk_line(http_ctx_t *ctx,                                             apr_bucket_brigade *b,                                             int linelimit){    apr_status_t rv;    apr_off_t brigade_length;    apr_bucket *e;    const char *lineend;    apr_size_t len;    /*     * As the brigade b should have been requested in mode AP_MODE_GETLINE     * all buckets in this brigade are already some type of memory     * buckets (due to the needed scanning for LF in mode AP_MODE_GETLINE)     * or META buckets.     */    rv = apr_brigade_length(b, 0, &brigade_length);    if (rv != APR_SUCCESS) {        return rv;    }    /* Sanity check. Should never happen. See above. */    if (brigade_length == -1) {        return APR_EGENERAL;    }    if (!brigade_length) {        return APR_EAGAIN;    }    ctx->linesize += brigade_length;    if (ctx->linesize > linelimit) {        return APR_ENOSPC;    }    /*     * As all buckets are already some type of memory buckets or META buckets     * (see above), we only need to check the last byte in the last data bucket.     */    for (e = APR_BRIGADE_LAST(b);         e != APR_BRIGADE_SENTINEL(b);         e = APR_BUCKET_PREV(e)) {        if (APR_BUCKET_IS_METADATA(e)) {            continue;        }        rv = apr_bucket_read(e, &lineend, &len, APR_BLOCK_READ);        if (rv != APR_SUCCESS) {            return rv;        }        if (len > 0) {            break;  /* we got the data we want */        }        /* If we got a zero-length data bucket, we try the next one */    }    /* We had no data in this brigade */    if (!len || e == APR_BRIGADE_SENTINEL(b)) {        return APR_EAGAIN;    }    if (lineend[len - 1] != APR_ASCII_LF) {        return APR_EAGAIN;    }    /* Line is complete. So reset ctx->linesize for next round. */    ctx->linesize = 0;    return APR_SUCCESS;}static apr_status_t get_chunk_line(http_ctx_t *ctx, apr_bucket_brigade *b,                                   int linelimit){    apr_size_t len;    int tmp_len;    apr_status_t rv;    tmp_len = sizeof(ctx->chunk_ln) - (ctx->pos - ctx->chunk_ln) - 1;    /* Saveguard ourselves against underflows */    if (tmp_len < 0) {        len = 0;    }    else {        len = (apr_size_t) tmp_len;    }    /*     * Check if there is space left in ctx->chunk_ln. If not, then either     * the chunk size is insane or we have chunk-extensions. Ignore both     * by discarding the remaining part of the line via     * get_remaining_chunk_line. Only bail out if the line is too long.     */    if (len > 0) {        rv = apr_brigade_flatten(b, ctx->pos, &len);        if (rv != APR_SUCCESS) {            return rv;        }        ctx->pos += len;        ctx->linesize += len;        *(ctx->pos) = '\0';        /*         * Check if we really got a full line. If yes the         * last char in the just read buffer must be LF.         * If not advance the buffer and return APR_EAGAIN.         * We do not start processing until we have the         * full line.         */        if (ctx->pos[-1] != APR_ASCII_LF) {            /* Check if the remaining data in the brigade has the LF */            return get_remaining_chunk_line(ctx, b, linelimit);        }        /* Line is complete. So reset ctx->pos for next round. */        ctx->pos = ctx->chunk_ln;        return APR_SUCCESS;    }    return get_remaining_chunk_line(ctx, b, linelimit);}/* This is the HTTP_INPUT filter for HTTP requests and responses from * proxied servers (mod_proxy).  It handles chunked and content-length * bodies.  This can only be inserted/used after the headers * are successfully parsed. */apr_status_t ap_http_filter(ap_filter_t *f, apr_bucket_brigade *b,                            ap_input_mode_t mode, apr_read_type_e block,                            apr_off_t readbytes){    apr_bucket *e;    http_ctx_t *ctx = f->ctx;    apr_status_t rv;    apr_off_t totalread;    int http_error = HTTP_REQUEST_ENTITY_TOO_LARGE;    apr_bucket_brigade *bb;    /* just get out of the way of things we don't want. */    if (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE) {        return ap_get_brigade(f->next, b, mode, block, readbytes);    }    if (!ctx) {        const char *tenc, *lenp;        f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));        ctx->state = BODY_NONE;        ctx->pos = ctx->chunk_ln;        ctx->bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);        bb = ctx->bb;        /* LimitRequestBody does not apply to proxied responses.         * Consider implementing this check in its own filter.         * Would adding a directive to limit the size of proxied         * responses be useful?         */        if (!f->r->proxyreq) {            ctx->limit = ap_get_limit_req_body(f->r);        }        else {            ctx->limit = 0;        }        tenc = apr_table_get(f->r->headers_in, "Transfer-Encoding");        lenp = apr_table_get(f->r->headers_in, "Content-Length");        if (tenc) {            if (!strcasecmp(tenc, "chunked")) {                ctx->state = BODY_CHUNK;            }            /* test lenp, because it gives another case we can handle */            else if (!lenp) {                /* Something that isn't in HTTP, unless some future                 * edition defines new transfer ecodings, is unsupported.                 */                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,                              "Unknown Transfer-Encoding: %s", tenc);                return bail_out_on_error(ctx, f, HTTP_NOT_IMPLEMENTED);            }            else {                ap_log_rerror(APLOG_MARK, APLOG_WARNING, 0, f->r,                  "Unknown Transfer-Encoding: %s; using Content-Length", tenc);                tenc = NULL;            }        }        if (lenp && !tenc) {            char *endstr;            ctx->state = BODY_LENGTH;            errno = 0;            /* Protects against over/underflow, non-digit chars in the             * string (excluding leading space) (the endstr checks)             * and a negative number. */            if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10)                || endstr == lenp || *endstr || ctx->remaining < 0) {                ctx->remaining = 0;                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,                              "Invalid Content-Length");                return bail_out_on_error(ctx, f, HTTP_REQUEST_ENTITY_TOO_LARGE);            }            /* If we have a limit in effect and we know the C-L ahead of             * time, stop it here if it is invalid.             */            if (ctx->limit && ctx->limit < ctx->remaining) {                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,                          "Requested content-length of %" APR_OFF_T_FMT                          " is larger than the configured limit"                          " of %" APR_OFF_T_FMT, ctx->remaining, ctx->limit);                return bail_out_on_error(ctx, f, HTTP_REQUEST_ENTITY_TOO_LARGE);            }        }        /* If we don't have a request entity indicated by the headers, EOS.         * (BODY_NONE is a valid intermediate state due to trailers,         *  but it isn't a valid starting state.)         *         * RFC 2616 Section 4.4 note 5 states that connection-close         * is invalid for a request entity - request bodies must be         * denoted by C-L or T-E: chunked.         *         * Note that since the proxy uses this filter to handle the         * proxied *response*, proxy responses MUST be exempt.         */        if (ctx->state == BODY_NONE && f->r->proxyreq != PROXYREQ_RESPONSE) {            e = apr_bucket_eos_create(f->c->bucket_alloc);            APR_BRIGADE_INSERT_TAIL(b, e);            ctx->eos_sent = 1;            return APR_SUCCESS;        }        /* Since we're about to read data, send 100-Continue if needed.         * Only valid on chunked and C-L bodies where the C-L is > 0. */        if ((ctx->state == BODY_CHUNK ||            (ctx->state == BODY_LENGTH && ctx->remaining > 0)) &&            f->r->expecting_100 && f->r->proto_num >= HTTP_VERSION(1,1) &&            !(f->r->eos_sent || f->r->bytes_sent)) {            if (!ap_is_HTTP_SUCCESS(f->r->status)) {                ctx->state = BODY_NONE;                ctx->eos_sent = 1;            } else {                char *tmp;                tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ",                                  ap_get_status_line(100), CRLF CRLF, NULL);                apr_brigade_cleanup(bb);                e = apr_bucket_pool_create(tmp, strlen(tmp), f->r->pool,                                           f->c->bucket_alloc);                APR_BRIGADE_INSERT_HEAD(bb, e);                e = apr_bucket_flush_create(f->c->bucket_alloc);                APR_BRIGADE_INSERT_TAIL(bb, e);                ap_pass_brigade(f->c->output_filters, bb);            }        }        /* We can't read the chunk until after sending 100 if required. */        if (ctx->state == BODY_CHUNK) {            apr_brigade_cleanup(bb);            rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,                                block, 0);            /* for timeout */            if (block == APR_NONBLOCK_READ &&                ( (rv == APR_SUCCESS && APR_BRIGADE_EMPTY(bb)) ||                  (APR_STATUS_IS_EAGAIN(rv)) )) {                ctx->state = BODY_CHUNK_PART;                return APR_EAGAIN;            }            if (rv == APR_SUCCESS) {                rv = get_chunk_line(ctx, bb, f->r->server->limit_req_line);                if (APR_STATUS_IS_EAGAIN(rv)) {                    apr_brigade_cleanup(bb);                    ctx->state = BODY_CHUNK_PART;                    return rv;                }                if (rv == APR_SUCCESS) {                    ctx->remaining = get_chunk_size(ctx->chunk_ln);                    if (ctx->remaining == INVALID_CHAR) {                        rv = APR_EGENERAL;                        http_error = HTTP_SERVICE_UNAVAILABLE;                    }                }            }            apr_brigade_cleanup(bb);            /* Detect chunksize error (such as overflow) */            if (rv != APR_SUCCESS || ctx->remaining < 0) {                ctx->remaining = 0; /* Reset it in case we have to                                     * come back here later */                return bail_out_on_error(ctx, f, http_error);            }            if (!ctx->remaining) {                /* Handle trailers by calling ap_get_mime_headers again! */                ctx->state = BODY_NONE;                ap_get_mime_headers(f->r);                e = apr_bucket_eos_create(f->c->bucket_alloc);                APR_BRIGADE_INSERT_TAIL(b, e);                ctx->eos_sent = 1;                return APR_SUCCESS;            }        }    }    else {        bb = ctx->bb;    }    if (ctx->eos_sent) {        e = apr_bucket_eos_create(f->c->bucket_alloc);        APR_BRIGADE_INSERT_TAIL(b, e);        return APR_SUCCESS;    }    if (!ctx->remaining) {        switch (ctx->state) {        case BODY_NONE:            break;        case BODY_LENGTH:            e = apr_bucket_eos_create(f->c->bucket_alloc);            APR_BRIGADE_INSERT_TAIL(b, e);

⌨️ 快捷键说明

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