blob: 44921fa34739059300a6f05132d966d480fc1831 [file]
/*
** Copyright 2003-2005 The Apache Software Foundation
**
** 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.
*/
#include "assert.h"
#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 *env)
{
struct apache2_handle *handle = (struct apache2_handle *)env;
if (handle->f == NULL) {
handle->f = ap_add_input_filter(APREQ_FILTER_NAME, NULL,
handle->r,
handle->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(handle->f);
}
return handle->f;
}
static apr_status_t apache2_jar(apreq_handle_t *env, const apr_table_t **t)
{
struct apache2_handle *handle = (struct apache2_handle*)env;
request_rec *r = handle->r;
if (handle->jar_status == APR_EINIT) {
const char *cookies = apr_table_get(r->headers_in, "Cookie");
if (cookies != NULL) {
handle->jar = apr_table_make(handle->r->pool, APREQ_DEFAULT_NELTS);
handle->jar_status =
apreq_parse_cookie_header(r->pool, handle->jar, cookies);
}
else
handle->jar_status = APREQ_ERROR_NODATA;
}
*t = handle->jar;
return handle->jar_status;
}
static apr_status_t apache2_args(apreq_handle_t *env, const apr_table_t **t)
{
struct apache2_handle *handle = (struct apache2_handle*)env;
request_rec *r = handle->r;
if (handle->args_status == APR_EINIT) {
if (r->args != NULL) {
handle->args = apr_table_make(handle->r->pool, APREQ_DEFAULT_NELTS);
handle->args_status =
apreq_parse_query_string(r->pool, handle->args, r->args);
}
else
handle->args_status = APREQ_ERROR_NODATA;
}
*t = handle->args;
return handle->args_status;
}
static apreq_cookie_t *apache2_jar_get(apreq_handle_t *env, const char *name)
{
struct apache2_handle *handle = (struct apache2_handle *)env;
const apr_table_t *t;
const char *val;
if (handle->jar_status == APR_EINIT)
apache2_jar(env, &t);
else
t = handle->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 *env, const char *name)
{
struct apache2_handle *handle = (struct apache2_handle *)env;
const apr_table_t *t;
const char *val;
if (handle->args_status == APR_EINIT)
apache2_args(env, &t);
else
t = handle->args;
if (t == NULL)
return NULL;
val = apr_table_get(t, name);
if (val == NULL)
return NULL;
return apreq_value_to_param(val);
}
static const char *apache2_header_in(apreq_handle_t *env, const char *name)
{
struct apache2_handle *handle = (struct apache2_handle *)env;
return apr_table_get(handle->r->headers_in, name);
}
static apr_status_t apache2_header_out(apreq_handle_t *env,
const char *name, char *value)
{
struct apache2_handle *handle = (struct apache2_handle *)env;
apr_table_add(handle->r->err_headers_out, name, value);
return APR_SUCCESS;
}
static apr_status_t apache2_body(apreq_handle_t *req, const apr_table_t **t)
{
ap_filter_t *f = get_apreq_filter(req);
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 *env, const char *name)
{
ap_filter_t *f = get_apreq_filter(env);
struct filter_ctx *ctx;
const char *val;
apreq_hook_t *h;
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 */
if (ctx->find_param == NULL)
ctx->find_param = apreq_hook_make(f->r->pool,
apreq_hook_find_param,
NULL, NULL);
h = ctx->find_param;
h->next = ctx->parser->hook;
ctx->parser->hook = h;
*(const char **)&h->ctx = name;
do {
apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
if (h->ctx != name) {
ctx->parser->hook = h->next;
return h->ctx;
}
} 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 *env,
const apreq_parser_t **parser)
{
ap_filter_t *f = get_apreq_filter(env);
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 *env,
apreq_parser_t *parser)
{
ap_filter_t *f = get_apreq_filter(env);
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 *env,
apreq_hook_t *hook)
{
ap_filter_t *f = get_apreq_filter(env);
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 *env,
apr_size_t bytes)
{
ap_filter_t *f = get_apreq_filter(env);
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 *env,
apr_size_t *bytes)
{
ap_filter_t *f = get_apreq_filter(env);
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 *env,
apr_uint64_t bytes)
{
ap_filter_t *f = get_apreq_filter(env);
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 *env,
apr_uint64_t *bytes)
{
ap_filter_t *f = get_apreq_filter(env);
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 *env,
const char *path)
{
ap_filter_t *f = get_apreq_filter(env);
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(f->r->pool, path);
return APR_SUCCESS;
}
return APREQ_ERROR_NOTEMPTY;
}
static
apr_status_t apache2_temp_dir_get(apreq_handle_t *env,
const char **path)
{
ap_filter_t *f = get_apreq_filter(env);
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, 20050315);
APREQ_DECLARE(apreq_handle_t *) apreq_handle_apache2(request_rec *r)
{
struct apache2_handle *handle =
ap_get_module_config(r->request_config, &apreq_module);
if (handle != NULL) {
get_apreq_filter(&handle->env);
return &handle->env;
}
handle = apr_palloc(r->pool, sizeof *handle);
ap_set_module_config(r->request_config, &apreq_module, handle);
handle->env.module = &apache2_module;
handle->r = r;
handle->args_status = handle->jar_status = APR_EINIT;
handle->args = handle->jar = NULL;
handle->f = NULL;
get_apreq_filter(&handle->env);
return &handle->env;
}