mod_request.c revision 7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5ed
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/* Licensed to the Apache Software Foundation (ASF) under one or more
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * contributor license agreements. See the NOTICE file distributed with
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * this work for additional information regarding copyright ownership.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * The ASF licenses this file to You under the Apache License, Version 2.0
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * (the "License"); you may not use this file except in compliance with
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * the License. You may obtain a copy of the License at
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * http://www.apache.org/licenses/LICENSE-2.0
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * Unless required by applicable law or agreed to in writing, software
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * distributed under the License is distributed on an "AS IS" BASIS,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * See the License for the specific language governing permissions and
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * limitations under the License.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/*
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * mod_request.c --- HTTP routines to set aside or process request bodies.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "apr.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "apr_strings.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "apr_buckets.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "apr_lib.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "ap_config.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "httpd.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "http_config.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "http_protocol.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "http_log.h" /* For errors detected in basic auth common
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * support code... */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "http_request.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin#include "mod_request.h"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/* Handles for core filters */
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowestatic ap_filter_rec_t *keep_body_input_filter_handle;
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowestatic ap_filter_rec_t *kept_body_input_filter_handle;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinstatic apr_status_t bail_out_on_error(apr_bucket_brigade *bb,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_filter_t *f,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin int http_error)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *e;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_cleanup(bb);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin e = ap_bucket_error_create(http_error,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin NULL, f->r->pool,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin f->c->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BRIGADE_INSERT_TAIL(bb, e);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin e = apr_bucket_eos_create(f->c->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BRIGADE_INSERT_TAIL(bb, e);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return ap_pass_brigade(f->r->output_filters, bb);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrintypedef struct keep_body_filter_ctx {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_off_t remaining;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_off_t keep_body;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin} keep_body_ctx_t;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/**
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * This is the KEEP_BODY_INPUT filter for HTTP requests, for times when the
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * body should be set aside for future use by other modules.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowestatic apr_status_t keep_body_filter(ap_filter_t *f, apr_bucket_brigade *b,
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe ap_input_mode_t mode,
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe apr_read_type_e block,
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe apr_off_t readbytes)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *e;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin keep_body_ctx_t *ctx = f->ctx;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_status_t rv;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *bucket;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_off_t len = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (!ctx) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *lenp;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin char *endstr = NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_dir_conf *dconf = ap_get_module_config(f->r->per_dir_config,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin &request_module);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* must we step out of the way? */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (!dconf->keep_body || f->r->kept_body) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_remove_input_filter(f);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return ap_get_brigade(f->next, b, mode, block, readbytes);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin f->ctx = ctx = apr_pcalloc(f->r->pool, sizeof(*ctx));
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* fail fast if the content length exceeds keep body */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin lenp = apr_table_get(f->r->headers_in, "Content-Length");
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (lenp) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* Protects against over/underflow, non-digit chars in the
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * string (excluding leading space) (the endstr checks)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * and a negative number. */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (apr_strtoff(&ctx->remaining, lenp, &endstr, 10)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin || endstr == lenp || *endstr || ctx->remaining < 0) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin "Invalid Content-Length");
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_remove_input_filter(f);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* If we have a limit in effect and we know the C-L ahead of
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * time, stop it here if it is invalid.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (dconf->keep_body < ctx->remaining) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin "Requested content-length of %" APR_OFF_T_FMT
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin " is larger than the configured limit"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin " of %" APR_OFF_T_FMT, ctx->remaining, dconf->keep_body);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_remove_input_filter(f);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin f->r->kept_body = apr_brigade_create(f->r->pool, f->r->connection->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ctx->remaining = dconf->keep_body;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* get the brigade from upstream, and read it in to get its length */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin rv = ap_get_brigade(f->next, b, mode, block, readbytes);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (rv == APR_SUCCESS) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin rv = apr_brigade_length(b, 1, &len);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* does the length take us over the limit? */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (APR_SUCCESS == rv && len > ctx->remaining) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (f->r->kept_body) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_cleanup(f->r->kept_body);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin f->r->kept_body = NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, f->r,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin "Requested content-length of %" APR_OFF_T_FMT
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin " is larger than the configured limit"
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin " of %" APR_OFF_T_FMT, len, ctx->keep_body);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return bail_out_on_error(b, f, HTTP_REQUEST_ENTITY_TOO_LARGE);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ctx->remaining -= len;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* pass any errors downstream */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (rv != APR_SUCCESS) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (f->r->kept_body) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_cleanup(f->r->kept_body);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin f->r->kept_body = NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return rv;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* all is well, set aside the buckets */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin for (bucket = APR_BRIGADE_FIRST(b);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin bucket != APR_BRIGADE_SENTINEL(b);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin bucket = APR_BUCKET_NEXT(bucket))
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket_copy(bucket, &e);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BRIGADE_INSERT_TAIL(f->r->kept_body, e);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return APR_SUCCESS;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrintypedef struct kept_body_filter_ctx {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_off_t offset;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_off_t remaining;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin} kept_body_ctx_t;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/**
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * Initialisation of filter to handle a kept body on subrequests.
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * If a body is to be reinserted into a subrequest, any chunking will have
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * been removed from the body during storage. We need to change the request
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * from Transfer-Encoding: chunked to an explicit Content-Length.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinstatic int kept_body_filter_init(ap_filter_t *f) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_off_t length = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_rec *r = f->r;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket_brigade *kept_body = r->kept_body;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (kept_body) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_table_unset(r->headers_in, "Transfer-Encoding");
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_length(kept_body, 1, &length);
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin apr_table_setn(r->headers_in, "Content-Length", apr_off_t_toa(r->pool, length));
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return OK;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/**
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * Filter to handle a kept body on subrequests.
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * If a body has been previously kept by the request, and if a subrequest wants
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * to re-insert the body into the request, this input filter makes it happen.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowestatic apr_status_t kept_body_filter(ap_filter_t *f, apr_bucket_brigade *b,
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin ap_input_mode_t mode,
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe apr_read_type_e block,
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe apr_off_t readbytes)
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe{
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_rec *r = f->r;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket_brigade *kept_body = r->kept_body;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin kept_body_ctx_t *ctx = f->ctx;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *ec, *e2;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_status_t rv;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* just get out of the way of things we don't want. */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (!kept_body || (mode != AP_MODE_READBYTES && mode != AP_MODE_GETLINE)) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return ap_get_brigade(f->next, b, mode, block, readbytes);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* set up the context if it does not already exist */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (!ctx) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin f->ctx = ctx = apr_palloc(f->r->pool, sizeof(*ctx));
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ctx->offset = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_length(kept_body, 1, &ctx->remaining);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* kept_body is finished, send next filter */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (ctx->remaining <= 0) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return ap_get_brigade(f->next, b, mode, block, readbytes);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* send all of the kept_body, but no more */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (readbytes > ctx->remaining) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin readbytes = ctx->remaining;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* send part of the kept_body */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if ((rv = apr_brigade_partition(kept_body, ctx->offset, &ec)) != APR_SUCCESS) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin "apr_brigade_partition() failed on kept_body at %" APR_OFF_T_FMT, ctx->offset);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return rv;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if ((rv = apr_brigade_partition(kept_body, ctx->offset + readbytes, &e2)) != APR_SUCCESS) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin "apr_brigade_partition() failed on kept_body at %" APR_OFF_T_FMT, ctx->offset + readbytes);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return rv;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin do {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *foo;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *str;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_size_t len;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (apr_bucket_copy(ec, &foo) != APR_SUCCESS) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* As above; this should not fail since the bucket has
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * a known length, but just to be sure, this takes
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * care of uncopyable buckets that do somehow manage
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * to slip through. */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* XXX: check for failure? */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket_read(ec, &str, &len, APR_BLOCK_READ);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket_copy(ec, &foo);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BRIGADE_INSERT_TAIL(b, foo);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ec = APR_BUCKET_NEXT(ec);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin } while (ec != e2);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ctx->remaining -= readbytes;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ctx->offset += readbytes;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return APR_SUCCESS;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/* form parsing stuff */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrintypedef enum {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin FORM_NORMAL,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin FORM_AMP,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin FORM_NAME,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin FORM_VALUE,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin FORM_PERCENTA,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin FORM_PERCENTB,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin FORM_ABORT
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin} ap_form_type_t;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/**
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * Read the body and parse any form found, which must be of the
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * type application/x-www-form-urlencoded.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * Name/value pairs are returned in an array, with the names as
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * strings with a maximum length of HUGE_STRING_LEN, and the
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * values as bucket brigades. This allows values to be arbitrarily
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * large.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * All url-encoding is removed from both the names and the values
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * on the fly. The names are interpreted as strings, while the
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * values are interpreted as blocks of binary data, that may
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * contain the 0 character.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * In order to ensure that resource limits are not exceeded, a
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * maximum size must be provided. If the sum of the lengths of
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * the names and the values exceed this size, this function
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * will return HTTP_REQUEST_ENTITY_TOO_LARGE.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * An optional number of parameters can be provided, if the number
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * of parameters provided exceeds this amount, this function will
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * no limit is imposed, and the number of parameters is in turn
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * constrained by the size parameter above.
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * This function honours any kept_body configuration, and the
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * original raw request body will be saved to the kept_body brigade
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * if so configured, just as ap_discard_request_body does.
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * NOTE: File upload is not yet supported, but can be without change
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * to the function call.
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrinstatic int ap_parse_request_form(request_rec * r, ap_filter_t * f,
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe apr_array_header_t ** ptr,
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe apr_size_t num, apr_size_t size)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin apr_bucket_brigade *bb = NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin int seen_eos = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin char buffer[HUGE_STRING_LEN + 1];
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *ct;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_size_t offset = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ap_form_pair_t *pair = NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin char hi = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin char low = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin *ptr = pairs;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin /* sanity check - we only support forms for now */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin ct = apr_table_get(r->headers_in, "Content-Type");
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (!ct || strcmp("application/x-www-form-urlencoded", ct)) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return ap_discard_request_body(r);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin if (!f) {
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin f = r->input_filters;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin do {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *bucket = NULL, *last = NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BLOCK_READ, HUGE_STRING_LEN);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (rv != APR_SUCCESS) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_destroy(bb);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return (rv == AP_FILTER_ERROR) ? rv : HTTP_BAD_REQUEST;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin for (bucket = APR_BRIGADE_FIRST(bb);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin bucket != APR_BRIGADE_SENTINEL(bb);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *data;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_size_t len, slide;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (last) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket_delete(last);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (APR_BUCKET_IS_EOS(bucket)) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin seen_eos = 1;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin break;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (bucket->length == 0) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin continue;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (rv != APR_SUCCESS) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_destroy(bb);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return HTTP_BAD_REQUEST;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin slide = len;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin char c = *data++;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if ('+' == c) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin c = ' ';
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else if ('&' == c) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin state = FORM_AMP;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if ('%' == c) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin percent = FORM_PERCENTA;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin continue;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (FORM_PERCENTA == percent) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (c >= 'a') {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin hi = c - 'a' + 10;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else if (c >= 'A') {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin hi = c - 'A' + 10;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else if (c >= '0') {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin hi = c - '0';
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin hi = hi << 4;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin percent = FORM_PERCENTB;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin continue;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (FORM_PERCENTB == percent) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (c >= 'a') {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin low = c - 'a' + 10;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else if (c >= 'A') {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin low = c - 'A' + 10;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else if (c >= '0') {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin low = c - '0';
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
4c480a1fdd90e06da4688876c371b83268feff40rpluem c = low | hi;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin percent = FORM_NORMAL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin switch (state) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin case FORM_AMP:
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (pair) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *tmp = apr_pmemdup(r->pool, buffer, offset);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BRIGADE_INSERT_TAIL(pair->value, b);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin state = FORM_NAME;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin pair = NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin offset = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin num--;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin break;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin case FORM_NAME:
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (offset < HUGE_STRING_LEN) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if ('=' == c) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin buffer[offset] = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin offset = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin pair = (ap_form_pair_t *) apr_array_push(pairs);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin pair->name = apr_pstrdup(r->pool, buffer);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin state = FORM_VALUE;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin buffer[offset++] = c;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin size--;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin state = FORM_ABORT;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin break;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin case FORM_VALUE:
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (offset >= HUGE_STRING_LEN) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *tmp = apr_pmemdup(r->pool, buffer, offset);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BRIGADE_INSERT_TAIL(pair->value, b);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin offset = 0;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin buffer[offset++] = c;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin size--;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin break;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin default:
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin break;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_brigade_cleanup(bb);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin } while (!seen_eos);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (FORM_ABORT == state || size < 0 || num == 0) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return HTTP_REQUEST_ENTITY_TOO_LARGE;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin else if (FORM_VALUE == state && pair && offset > 0) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *tmp = apr_pmemdup(r->pool, buffer, offset);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin APR_BRIGADE_INSERT_TAIL(pair->value, b);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return OK;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin/**
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin * Check whether this filter is not already present.
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin */
e02cb8f5090d904c054633ff33dfd1111e16e404minfrinstatic int request_is_filter_present(request_rec * r, ap_filter_rec_t *fn)
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin{
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin ap_filter_t * f = r->input_filters;
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin while (f) {
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin if (f->frec == fn) {
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin return 1;
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin }
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin f = f->next;
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin }
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin return 0;
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin}
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin/**
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin * Insert filter hook.
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * Add the KEEP_BODY filter to the request, if the admin wants to keep
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * the body using the KeptBodySize directive.
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin *
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin * As a precaution, any pre-existing instances of either the kept_body or
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin * keep_body filters will be removed before the filter is added.
7f5b3f0f3b0c35f6c1a8e3dee83e68aa7a78e5edminfrin *
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin * @param r The request
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin */
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowestatic void ap_request_insert_filter(request_rec * r)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_dir_conf *conf = ap_get_module_config(r->per_dir_config,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin &request_module);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin if (r->kept_body) {
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe if (!request_is_filter_present(r, kept_body_input_filter_handle)) {
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe ap_add_input_filter_handle(kept_body_input_filter_handle,
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin NULL, r, r->connection);
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin }
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin }
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin else if (conf->keep_body) {
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe if (!request_is_filter_present(r, kept_body_input_filter_handle)) {
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe ap_add_input_filter_handle(keep_body_input_filter_handle,
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin NULL, r, r->connection);
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin/**
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin * Remove the kept_body and keep body filters from this specific request.
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin */
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowestatic void ap_request_remove_filter(request_rec * r)
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin{
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin ap_filter_t * f = r->input_filters;
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin while (f) {
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe if (f->frec->filter_func.in_func == kept_body_filter ||
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe f->frec->filter_func.in_func == keep_body_filter) {
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin ap_remove_input_filter(f);
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin }
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin f = f->next;
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinstatic void *create_request_dir_config(apr_pool_t *p, char *dummy)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_dir_conf *new =
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin (request_dir_conf *) apr_pcalloc(p, sizeof(request_dir_conf));
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin new->keep_body_set = 0; /* unset */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin new->keep_body = 0; /* don't by default */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return (void *) new;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinstatic void *merge_request_dir_config(apr_pool_t *p, void *basev, void *addv)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_dir_conf *new = (request_dir_conf *) apr_pcalloc(p, sizeof(request_dir_conf));
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_dir_conf *add = (request_dir_conf *) addv;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_dir_conf *base = (request_dir_conf *) basev;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin new->keep_body = (add->keep_body_set == 0) ? base->keep_body : add->keep_body;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin new->keep_body_set = add->keep_body_set || base->keep_body_set;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return new;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinstatic const char *set_kept_body_size(cmd_parms *cmd, void *dconf,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin const char *arg)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_dir_conf *conf = dconf;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin if (APR_SUCCESS != apr_strtoff(&(conf->keep_body), arg, NULL, 0)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin || conf->keep_body < 0) {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return "KeptBodySize must be a size in bytes, or zero.";
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin conf->keep_body_set = 1;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin return NULL;
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinstatic const command_rec request_cmds[] = {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin AP_INIT_TAKE1("KeptBodySize", set_kept_body_size, NULL, ACCESS_CONF,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin "Maximum size of request bodies kept aside for use by filters"),
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin { NULL }
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin};
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinstatic void register_hooks(apr_pool_t *p)
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin{
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe keep_body_input_filter_handle =
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe ap_register_input_filter(KEEP_BODY_FILTER, keep_body_filter,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin NULL, AP_FTYPE_RESOURCE);
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe kept_body_input_filter_handle =
c033603eabef0ba88287fa7f0e22c5e1c6564f90wrowe ap_register_input_filter(KEPT_BODY_FILTER, kept_body_filter,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin kept_body_filter_init, AP_FTYPE_RESOURCE);
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin ap_hook_insert_filter(ap_request_insert_filter, NULL, NULL, APR_HOOK_LAST);
becf0c14669eadd259c4be0655342f7dff073003minfrin APR_REGISTER_OPTIONAL_FN(ap_parse_request_form);
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin APR_REGISTER_OPTIONAL_FN(ap_request_insert_filter);
e02cb8f5090d904c054633ff33dfd1111e16e404minfrin APR_REGISTER_OPTIONAL_FN(ap_request_remove_filter);
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin}
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin
82632a19f2f9c346fee2b28a65920ba9737b3973minfrinmodule AP_MODULE_DECLARE_DATA request_module = {
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin STANDARD20_MODULE_STUFF,
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin create_request_dir_config, /* create per-directory config structure */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin merge_request_dir_config, /* merge per-directory config structures */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin NULL, /* create per-server config structure */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin NULL, /* merge per-server config structures */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin request_cmds, /* command apr_table_t */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin register_hooks /* register hooks */
82632a19f2f9c346fee2b28a65920ba9737b3973minfrin};