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

📄 http_filters.c

📁 apache服务器源代码(版本号:2.2.2)
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Copyright 1999-2005 The Apache Software Foundation or its licensors, as * applicable. * * Licensed 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_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>#endifstatic 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    } state;    int eos_sent;} http_ctx_t;/* 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;    /* 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_palloc(f->r->pool, sizeof(*ctx));        ctx->state = BODY_NONE;        ctx->remaining = 0;        ctx->limit_used = 0;        ctx->eos_sent = 0;        /* 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;            }        }        else if (lenp) {            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) {                apr_bucket_brigade *bb;                ctx->remaining = 0;                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,                              "Invalid Content-Length");                bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);                e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, 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);            }            /* 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) {                apr_bucket_brigade *bb;                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);                bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);                e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, 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);            }        }        /* 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)) {            char *tmp;            apr_bucket_brigade *bb;            tmp = apr_pstrcat(f->r->pool, AP_SERVER_PROTOCOL, " ",                              ap_get_status_line(100), CRLF CRLF, NULL);            bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);            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) {            char line[30];            apr_bucket_brigade *bb;            apr_size_t len = 30;            apr_off_t brigade_length;            bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);            rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,                                APR_BLOCK_READ, 0);            if (rv == APR_SUCCESS) {                /* We have to check the length of the brigade we got back.                 * We will not accept partial or blank lines.                 */                rv = apr_brigade_length(bb, 1, &brigade_length);                if (rv == APR_SUCCESS                    && (!brigade_length ||                        brigade_length > f->r->server->limit_req_line)) {                    rv = APR_ENOSPC;                }                if (rv == APR_SUCCESS) {                    rv = apr_brigade_flatten(bb, line, &len);                    if (rv == APR_SUCCESS) {                        ctx->remaining = get_chunk_size(line);                    }                }            }            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 */                e = ap_bucket_error_create(HTTP_REQUEST_ENTITY_TOO_LARGE, 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);            }            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;            }        }    }    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);            ctx->eos_sent = 1;            return APR_SUCCESS;        case BODY_CHUNK:            {                char line[30];                apr_bucket_brigade *bb;                apr_size_t len = 30;                apr_status_t http_error = HTTP_REQUEST_ENTITY_TOO_LARGE;                bb = apr_brigade_create(f->r->pool, f->c->bucket_alloc);                /* We need to read the CRLF after the chunk.  */                rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,                                    APR_BLOCK_READ, 0);                apr_brigade_cleanup(bb);                if (rv == APR_SUCCESS) {                    /* Read the real chunk line. */                    rv = ap_get_brigade(f->next, bb, AP_MODE_GETLINE,                                        APR_BLOCK_READ, 0);                    if (rv == APR_SUCCESS) {                        rv = apr_brigade_flatten(bb, line, &len);                        if (rv == APR_SUCCESS) {                            /* Wait a sec, that's a blank line!  Oh no. */                            if (!len) {                                rv = APR_EGENERAL;                                http_error = HTTP_SERVICE_UNAVAILABLE;                            }                            else {                                ctx->remaining = get_chunk_size(line);                            }                        }                    }                    apr_brigade_cleanup(bb);                }                /* Detect chunksize error (such as overflow) */                if (rv != APR_SUCCESS || ctx->remaining < 0) {                    apr_status_t out_error;                    ctx->remaining = 0; /* Reset it in case we have to                                         * come back here later */                    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;                    out_error = ap_pass_brigade(f->r->output_filters, bb);                    return rv;                }                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;                }            }            break;        }    }    /* Ensure that the caller can not go over our boundary point. */    if (ctx->state == BODY_LENGTH || ctx->state == BODY_CHUNK) {        if (ctx->remaining < readbytes) {            readbytes = ctx->remaining;        }

⌨️ 快捷键说明

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