mirror of
https://github.com/apache/httpd.git
synced 2025-08-05 16:55:50 +03:00
git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1534997 13f79535-47bb-0310-9956-ffa450edef68
441 lines
11 KiB
C
441 lines
11 KiB
C
/*
|
|
** 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 "httpd.h"
|
|
#include "http_config.h"
|
|
#include "http_log.h"
|
|
#include "util_filter.h"
|
|
#include "apr_tables.h"
|
|
#include "apr_buckets.h"
|
|
#include "http_request.h"
|
|
#include "apr_strings.h"
|
|
|
|
#include "apreq_module_apache2.h"
|
|
#include "apreq_private_apache2.h"
|
|
#include "apreq_error.h"
|
|
|
|
|
|
APR_INLINE
|
|
static ap_filter_t *get_apreq_filter(apreq_handle_t *handle)
|
|
{
|
|
struct apache2_handle *req = (struct apache2_handle *)handle;
|
|
|
|
if (req->f == NULL) {
|
|
req->f = ap_add_input_filter(APREQ_FILTER_NAME, NULL,
|
|
req->r,
|
|
req->r->connection);
|
|
/* ap_add_input_filter does not guarantee cfg->f == r->input_filters,
|
|
* so we reposition the new filter there as necessary.
|
|
*/
|
|
apreq_filter_relocate(req->f);
|
|
}
|
|
|
|
return req->f;
|
|
}
|
|
|
|
|
|
static apr_status_t apache2_jar(apreq_handle_t *handle, const apr_table_t **t)
|
|
{
|
|
struct apache2_handle *req = (struct apache2_handle*)handle;
|
|
request_rec *r = req->r;
|
|
|
|
if (req->jar_status == APR_EINIT) {
|
|
const char *cookies = apr_table_get(r->headers_in, "Cookie");
|
|
if (cookies != NULL) {
|
|
req->jar = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS);
|
|
req->jar_status =
|
|
apreq_parse_cookie_header(handle->pool, req->jar, cookies);
|
|
}
|
|
else
|
|
req->jar_status = APREQ_ERROR_NODATA;
|
|
}
|
|
|
|
*t = req->jar;
|
|
return req->jar_status;
|
|
}
|
|
|
|
static apr_status_t apache2_args(apreq_handle_t *handle, const apr_table_t **t)
|
|
{
|
|
struct apache2_handle *req = (struct apache2_handle*)handle;
|
|
request_rec *r = req->r;
|
|
|
|
if (req->args_status == APR_EINIT) {
|
|
if (r->args != NULL) {
|
|
req->args = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS);
|
|
req->args_status =
|
|
apreq_parse_query_string(handle->pool, req->args, r->args);
|
|
}
|
|
else
|
|
req->args_status = APREQ_ERROR_NODATA;
|
|
}
|
|
|
|
*t = req->args;
|
|
return req->args_status;
|
|
}
|
|
|
|
|
|
|
|
|
|
static apreq_cookie_t *apache2_jar_get(apreq_handle_t *handle, const char *name)
|
|
{
|
|
struct apache2_handle *req = (struct apache2_handle *)handle;
|
|
const apr_table_t *t;
|
|
const char *val;
|
|
|
|
if (req->jar_status == APR_EINIT)
|
|
apache2_jar(handle, &t);
|
|
else
|
|
t = req->jar;
|
|
|
|
if (t == NULL)
|
|
return NULL;
|
|
|
|
val = apr_table_get(t, name);
|
|
if (val == NULL)
|
|
return NULL;
|
|
|
|
return apreq_value_to_cookie(val);
|
|
}
|
|
|
|
static apreq_param_t *apache2_args_get(apreq_handle_t *handle, const char *name)
|
|
{
|
|
struct apache2_handle *req = (struct apache2_handle *)handle;
|
|
const apr_table_t *t;
|
|
const char *val;
|
|
|
|
if (req->args_status == APR_EINIT)
|
|
apache2_args(handle, &t);
|
|
else
|
|
t = req->args;
|
|
|
|
if (t == NULL)
|
|
return NULL;
|
|
|
|
val = apr_table_get(t, name);
|
|
if (val == NULL)
|
|
return NULL;
|
|
|
|
return apreq_value_to_param(val);
|
|
}
|
|
|
|
|
|
static apr_status_t apache2_body(apreq_handle_t *handle, const apr_table_t **t)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
|
|
switch (ctx->body_status) {
|
|
|
|
case APR_EINIT:
|
|
apreq_filter_init_context(f);
|
|
if (ctx->body_status != APR_INCOMPLETE)
|
|
break;
|
|
|
|
case APR_INCOMPLETE:
|
|
while (apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE) == APR_INCOMPLETE)
|
|
; /*loop*/
|
|
}
|
|
|
|
*t = ctx->body;
|
|
return ctx->body_status;
|
|
}
|
|
|
|
static apreq_param_t *apache2_body_get(apreq_handle_t *handle, const char *name)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
const char *val;
|
|
apreq_hook_t *h;
|
|
apreq_hook_find_param_ctx_t *hook_ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
|
|
switch (ctx->body_status) {
|
|
|
|
case APR_SUCCESS:
|
|
|
|
val = apr_table_get(ctx->body, name);
|
|
if (val != NULL)
|
|
return apreq_value_to_param(val);
|
|
return NULL;
|
|
|
|
|
|
case APR_EINIT:
|
|
|
|
apreq_filter_init_context(f);
|
|
if (ctx->body_status != APR_INCOMPLETE)
|
|
return NULL;
|
|
apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
|
|
|
|
|
|
case APR_INCOMPLETE:
|
|
|
|
val = apr_table_get(ctx->body, name);
|
|
if (val != NULL)
|
|
return apreq_value_to_param(val);
|
|
|
|
/* Not seen yet, so we need to scan for
|
|
param while prefetching the body */
|
|
hook_ctx = apr_palloc(handle->pool, sizeof *hook_ctx);
|
|
|
|
if (ctx->find_param == NULL)
|
|
ctx->find_param = apreq_hook_make(handle->pool,
|
|
apreq_hook_find_param,
|
|
NULL, NULL);
|
|
h = ctx->find_param;
|
|
h->next = ctx->parser->hook;
|
|
h->ctx = hook_ctx;
|
|
ctx->parser->hook = h;
|
|
hook_ctx->name = name;
|
|
hook_ctx->param = NULL;
|
|
hook_ctx->prev = ctx->parser->hook;
|
|
|
|
do {
|
|
apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
|
|
if (hook_ctx->param != NULL)
|
|
return hook_ctx->param;
|
|
} while (ctx->body_status == APR_INCOMPLETE);
|
|
|
|
ctx->parser->hook = h->next;
|
|
return NULL;
|
|
|
|
|
|
default:
|
|
|
|
if (ctx->body == NULL)
|
|
return NULL;
|
|
|
|
val = apr_table_get(ctx->body, name);
|
|
if (val != NULL)
|
|
return apreq_value_to_param(val);
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* not reached */
|
|
return NULL;
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_parser_get(apreq_handle_t *handle,
|
|
const apreq_parser_t **parser)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx = f->ctx;
|
|
|
|
if (ctx == NULL) {
|
|
*parser = NULL;
|
|
return APR_EINIT;
|
|
}
|
|
*parser = ctx->parser;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_parser_set(apreq_handle_t *handle,
|
|
apreq_parser_t *parser)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
|
|
if (ctx->parser == NULL) {
|
|
ctx->parser = parser;
|
|
return APR_SUCCESS;
|
|
}
|
|
else
|
|
return APREQ_ERROR_NOTEMPTY;
|
|
}
|
|
|
|
|
|
|
|
static
|
|
apr_status_t apache2_hook_add(apreq_handle_t *handle,
|
|
apreq_hook_t *hook)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
|
|
if (ctx->parser != NULL) {
|
|
return apreq_parser_add_hook(ctx->parser, hook);
|
|
}
|
|
else if (ctx->hook_queue != NULL) {
|
|
apreq_hook_t *h = ctx->hook_queue;
|
|
while (h->next != NULL)
|
|
h = h->next;
|
|
h->next = hook;
|
|
}
|
|
else {
|
|
ctx->hook_queue = hook;
|
|
}
|
|
return APR_SUCCESS;
|
|
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_brigade_limit_set(apreq_handle_t *handle,
|
|
apr_size_t bytes)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
|
|
if (ctx->body_status == APR_EINIT || ctx->brigade_limit > bytes) {
|
|
ctx->brigade_limit = bytes;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
return APREQ_ERROR_MISMATCH;
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_brigade_limit_get(apreq_handle_t *handle,
|
|
apr_size_t *bytes)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
*bytes = ctx->brigade_limit;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_read_limit_set(apreq_handle_t *handle,
|
|
apr_uint64_t bytes)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
|
|
if (ctx->read_limit > bytes && ctx->bytes_read < bytes) {
|
|
ctx->read_limit = bytes;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
return APREQ_ERROR_MISMATCH;
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_read_limit_get(apreq_handle_t *handle,
|
|
apr_uint64_t *bytes)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
*bytes = ctx->read_limit;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_temp_dir_set(apreq_handle_t *handle,
|
|
const char *path)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
/* init vs incomplete state? */
|
|
if (ctx->temp_dir == NULL && ctx->bytes_read == 0) {
|
|
if (path != NULL)
|
|
ctx->temp_dir = apr_pstrdup(handle->pool, path);
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
return APREQ_ERROR_NOTEMPTY;
|
|
}
|
|
|
|
static
|
|
apr_status_t apache2_temp_dir_get(apreq_handle_t *handle,
|
|
const char **path)
|
|
{
|
|
ap_filter_t *f = get_apreq_filter(handle);
|
|
struct filter_ctx *ctx;
|
|
|
|
if (f->ctx == NULL)
|
|
apreq_filter_make_context(f);
|
|
|
|
ctx = f->ctx;
|
|
*path = ctx->parser ? ctx->parser->temp_dir : ctx->temp_dir;
|
|
return APR_SUCCESS;
|
|
}
|
|
|
|
static APREQ_MODULE(apache2, APREQ_APACHE2_MMN);
|
|
|
|
APREQ_DECLARE(apreq_handle_t *) apreq_handle_apache2(request_rec *r)
|
|
{
|
|
struct apache2_handle *req =
|
|
ap_get_module_config(r->request_config, &apreq_module);
|
|
|
|
if (req != NULL) {
|
|
get_apreq_filter(&req->handle);
|
|
return &req->handle;
|
|
}
|
|
|
|
req = apr_palloc(r->pool, sizeof *req);
|
|
ap_set_module_config(r->request_config, &apreq_module, req);
|
|
|
|
req->handle.module = &apache2_module;
|
|
req->handle.pool = r->pool;
|
|
req->handle.bucket_alloc = r->connection->bucket_alloc;
|
|
req->r = r;
|
|
|
|
req->args_status = req->jar_status = APR_EINIT;
|
|
req->args = req->jar = NULL;
|
|
|
|
req->f = NULL;
|
|
|
|
get_apreq_filter(&req->handle);
|
|
return &req->handle;
|
|
|
|
}
|