blob: 0452bc7c9c27acac6ec5a568f051df60e9009662 [file] [log] [blame]
/*
** 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.
*/
#ifndef APREQ_MODULE_H
#define APREQ_MODULE_H
#include "apreq_cookie.h"
#include "apreq_parser.h"
#include "apreq_error.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file apreq_module.h
* @brief Module API
* @ingroup libapreq2
*/
/**
* An apreq handle associated with a module. The structure
* may have variable size, because the module may append its own data
* structures after it.
*/
typedef struct apreq_handle_t {
/** the apreq module which implements this handle */
const struct apreq_module_t *module;
} apreq_handle_t;
/**
* @brief Vtable describing the necessary environment functions.
*/
typedef struct apreq_module_t {
/** name of this apreq module */
const char *name;
/** magic number identifying the module and version */
apr_uint32_t magic_number;
/** get a table with all cookies */
apr_status_t (*jar)(apreq_handle_t *, const apr_table_t **);
/** get a table with all query string parameters */
apr_status_t (*args)(apreq_handle_t *, const apr_table_t **);
/** get a table with all body parameters */
apr_status_t (*body)(apreq_handle_t *, const apr_table_t **);
/** get a cookie by its name */
apreq_cookie_t *(*jar_get)(apreq_handle_t *, const char *);
/** get a query string parameter by its name */
apreq_param_t *(*args_get)(apreq_handle_t *, const char *);
/** get a body parameter by its name */
apreq_param_t *(*body_get)(apreq_handle_t *, const char *);
/** gets the parser associated with the request body */
apr_status_t (*parser_get)(apreq_handle_t *, const apreq_parser_t **);
/** manually set a parser for the request body */
apr_status_t (*parser_set)(apreq_handle_t *, apreq_parser_t *);
/** add a hook function */
apr_status_t (*hook_add)(apreq_handle_t *, apreq_hook_t *);
/** determine the maximum in-memory bytes a brigade may use */
apr_status_t (*brigade_limit_get)(apreq_handle_t *, apr_size_t *);
/** set the maximum in-memory bytes a brigade may use */
apr_status_t (*brigade_limit_set)(apreq_handle_t *, apr_size_t);
/** determine the maximum amount of data that will be fed into a parser */
apr_status_t (*read_limit_get)(apreq_handle_t *, apr_uint64_t *);
/** set the maximum amount of data that will be fed into a parser */
apr_status_t (*read_limit_set)(apreq_handle_t *, apr_uint64_t);
/** determine the directory used by the parser for temporary files */
apr_status_t (*temp_dir_get)(apreq_handle_t *, const char **);
/** set the directory used by the parser for temporary files */
apr_status_t (*temp_dir_set)(apreq_handle_t *, const char *);
/** get the value of a request header */
const char *(*header_in)(apreq_handle_t *,const char *);
/** send a response header */
apr_status_t (*header_out)(apreq_handle_t *, const char *,char *);
} apreq_module_t;
/**
* Defines the module-specific status codes which
* are commonly considered to be non-fatal.
*
* @param s status code returned by an apreq_module_t method.
*
* @return 1 if s is fatal, 0 otherwise.
*/
static APR_INLINE
unsigned apreq_module_status_is_error(apr_status_t s) {
switch (s) {
case APR_SUCCESS:
case APR_INCOMPLETE:
case APR_EINIT:
case APREQ_ERROR_NODATA:
case APREQ_ERROR_NOPARSER:
case APREQ_ERROR_NOHEADER:
return 0;
default:
return 1;
}
}
/**
* Expose the parsed "cookie" header associated to this handle.
*
* @param req The request handle
* @param t The resulting table, which will either be NULL or a
* valid table object on return.
*
* @return APR_SUCCESS or a module-specific error status code.
*/
static APR_INLINE
apr_status_t apreq_jar(apreq_handle_t *req, const apr_table_t **t)
{
return req->module->jar(req,t);
}
/**
* Expose the parsed "query string" associated to this handle.
*
* @param req The request handle
* @param t The resulting table, which will either be NULL or a
* valid table object on return.
*
* @return APR_SUCCESS or a module-specific error status code.
*/
static APR_INLINE
apr_status_t apreq_args(apreq_handle_t *req, const apr_table_t **t)
{
return req->module->args(req,t);
}
/**
* Expose the parsed "request body" associated to this handle.
*
* @param req The request handle
* @param t The resulting table, which will either be NULL or a
* valid table object on return.
*
* @return APR_SUCCESS or a module-specific error status code.
*/
static APR_INLINE
apr_status_t apreq_body(apreq_handle_t *req, const apr_table_t **t)
{
return req->module->body(req, t);
}
/**
* Fetch the first cookie with the given name.
*
* @param req The request handle
* @param name Case-insensitive cookie name.
*
* @return First matching cookie, or NULL if none match.
*/
static APR_INLINE
apreq_cookie_t *apreq_jar_get(apreq_handle_t *req, const char *name)
{
return req->module->jar_get(req, name);
}
/**
* Fetch the first query string param with the given name.
*
* @param req The request handle
* @param name Case-insensitive param name.
*
* @return First matching param, or NULL if none match.
*/
static APR_INLINE
apreq_param_t *apreq_args_get(apreq_handle_t *req, const char *name)
{
return req->module->args_get(req, name);
}
/**
* Fetch the first body param with the given name.
*
* @param req The request handle
* @param name Case-insensitive cookie name.
*
* @return First matching param, or NULL if none match.
*/
static APR_INLINE
apreq_param_t *apreq_body_get(apreq_handle_t *req, const char *name)
{
return req->module->body_get(req, name);
}
/**
* Fetch the active body parser.
*
* @param req The request handle
* @param parser Points to the active parser on return.
*
* @return APR_SUCCESS or module-specific error.
*
*/
static APR_INLINE
apr_status_t apreq_parser_get(apreq_handle_t *req,
const apreq_parser_t **parser)
{
return req->module->parser_get(req, parser);
}
/**
* Set the body parser for this request.
*
* @param req The request handle
* @param parser New parser to use.
*
* @return APR_SUCCESS or module-specific error.
*/
static APR_INLINE
apr_status_t apreq_parser_set(apreq_handle_t *req,
apreq_parser_t *parser)
{
return req->module->parser_set(req, parser);
}
/**
* Add a parser hook for this request.
*
* @param req The request handle
* @param hook Hook to add.
*
* @return APR_SUCCESS or module-specific error.
*/
static APR_INLINE
apr_status_t apreq_hook_add(apreq_handle_t *req, apreq_hook_t *hook)
{
return req->module->hook_add(req, hook);
}
/**
* Fetch the header value (joined by ", " if there are multiple headers)
* for a given header name.
*
* @param req The request handle.
* @param name The header name.
*
* @return The value of the header, or NULL if not found.
*/
static APR_INLINE
const char *apreq_header_in(apreq_handle_t *req, const char *name)
{
return req->module->header_in(req, name);
}
/**
* Add a header field to the environment's outgoing response headers
*
* @param req The request handle
* @param name The name of the outgoing header.
* @param val Value of the outgoing header.
*
* @return APR_SUCCESS or module-specific error code.
*/
static APR_INLINE
apr_status_t apreq_header_out(apreq_handle_t *req,
const char *name, char *val)
{
return req->module->header_out(req, name, val);
}
/**
* Set the active brigade limit.
*
* @param req The handle.
* @param bytes New limit to use.
*
* @return APR_SUCCESS or module-specific error.
*
*/
static APR_INLINE
apr_status_t apreq_brigade_limit_set(apreq_handle_t *req,
apr_size_t bytes)
{
return req->module->brigade_limit_set(req, bytes);
}
/**
* Get the active brigade limit.
*
* @param req The handle.
* @param bytes Pointer to resulting (current) limit.
*
* @return APR_SUCCESS or a module-specific error,
* which may leave bytes undefined.
*/
static APR_INLINE
apr_status_t apreq_brigade_limit_get(apreq_handle_t *req,
apr_size_t *bytes)
{
return req->module->brigade_limit_get(req, bytes);
}
/**
* Set the active read limit.
*
* @param req The handle.
* @param bytes New limit to use.
*
* @return APR_SUCCESS or a module-specific error.
*
*/
static APR_INLINE
apr_status_t apreq_read_limit_set(apreq_handle_t *req,
apr_uint64_t bytes)
{
return req->module->read_limit_set(req, bytes);
}
/**
* Get the active read limit.
*
* @param req The request handle.
* @param bytes Pointer to resulting (current) limit.
*
* @return APR_SUCCESS or a module-specific error,
* which may leave bytes undefined.
*/
static APR_INLINE
apr_status_t apreq_read_limit_get(apreq_handle_t *req,
apr_uint64_t *bytes)
{
return req->module->read_limit_get(req, bytes);
}
/**
* Set the active temp directory.
*
* @param req The handle.
* @param path New path to use; may be NULL.
*
* @return APR_SUCCESS or a module-specific error .
*/
static APR_INLINE
apr_status_t apreq_temp_dir_set(apreq_handle_t *req, const char *path)
{
return req->module->temp_dir_set(req, path);
}
/**
* Get the active temp directory.
*
* @param req The handle.
* @param path Resulting path to temp dir.
*
* @return APR_SUCCESS implies path is valid, but may also be NULL.
* Any other return value is module-specific, and may leave
* path undefined.
*/
static APR_INLINE
apr_status_t apreq_temp_dir_get(apreq_handle_t *req, const char **path)
{
return req->module->temp_dir_get(req, path);
}
/**
* Convenience macro for defining a module by mapping
* a function prefix to an associated apreq_module_t structure.
*
* @param pre Prefix to define new environment. All attributes of
* the apreq_env_module_t struct are defined with this as their
* prefix. The generated struct is named by appending "_module" to
* the prefix.
* @param mmn Magic number (i.e. version number) of this environment.
*/
#define APREQ_MODULE(pre, mmn) const apreq_module_t \
pre##_module = { #pre, mmn, \
pre##_jar, pre##_args, pre##_body, \
pre##_jar_get, pre##_args_get, pre##_body_get, \
pre##_parser_get, pre##_parser_set, pre##_hook_add, \
pre##_brigade_limit_get, pre##_brigade_limit_set, \
pre##_read_limit_get, pre##_read_limit_set, \
pre##_temp_dir_get, pre##_temp_dir_set, \
pre##_header_in, pre##_header_out }
/**
* Create an apreq handle which is suitable for a CGI program. It
* reads input from stdin and writes output to stdout.
*
* @param pool Pool associated to this handle.
*
* @return New handle; can only be NULL if the pool allocation failed.
*
* @remarks The handle gets cached in the pool's userdata, so subsequent
* calls will retrieve the original cached handle.
*/
APREQ_DECLARE(apreq_handle_t*) apreq_handle_cgi(apr_pool_t *pool);
/**
* Create a custom apreq handle which knows only some static
* values. Useful if you want to test the parser code or if you have
* got data from a custom source (neither Apache 2 nor CGI).
*
* @param pool allocates the parse data,
* @param query_string parsed into args table
* @param cookie value of the request "Cookie" header
* @param cookie2 value of the request "Cookie2" header
* @param parser parses the request body
* @param read_limit maximum bytes to read from the body
* @param in brigade containing the request body
*
* @return new handle; can only be NULL if the pool allocation failed.
*/
APREQ_DECLARE(apreq_handle_t*) apreq_handle_custom(apr_pool_t *pool,
const char *query_string,
const char *cookie,
const char *cookie2,
apreq_parser_t *parser,
apr_uint64_t read_limit,
apr_bucket_brigade *in);
/**
* Add the cookie to the outgoing "Set-Cookie" headers.
*
* @param c The cookie.
* @param req The request handle which set the outgoing header.
*
* @return APR_SUCCESS or error.
*/
APREQ_DECLARE(apr_status_t) apreq_cookie_bake(const apreq_cookie_t *c,
apreq_handle_t *req);
/**
* Add the cookie to the outgoing "Set-Cookie2" headers.
*
* @param c cookie
* @param req request handle
*
* @return APR_SUCCESS or error.
*/
APREQ_DECLARE(apr_status_t) apreq_cookie_bake2(const apreq_cookie_t *c,
apreq_handle_t *req);
/**
* Looks for the presence of a "Cookie2" header to determine whether
* or not the current User-Agent responsible for this request supports
* rfc2965.
*
* @param req the apreq request handle
*
* @return ::APREQ_COOKIE_VERSION_RFC if rfc2965 is supported
* by the user-agent, ::APREQ_COOKIE_VERSION_NETSCAPE otherwise.
*/
APREQ_DECLARE(unsigned)apreq_ua_cookie_version(apreq_handle_t *req);
/**
* Find the first query string parameter or body parameter with the
* specified name. The match is case-insensitive.
*
* @param req request handle.
* @param key desired parameter name
*
* @return The first matching parameter (with args searched first) or NULL.
*/
APREQ_DECLARE(apreq_param_t *)apreq_param(apreq_handle_t *req, const char *key);
/**
* Find the first cookie with the specified name.
* The match is case-insensitive.
*
* @param req request handle.
* @param key desired cookie name
*
* @return The first matching parameter (with args searched first) or NULL.
*/
#define apreq_cookie(req, name) apreq_jar_get(req, name)
/**
* Returns a table containing key-value pairs for the full request
* (args + body).
*
* @param req request handle
* @param p allocates the returned table.
*
* @return table representing all available params; is never NULL.
*/
APREQ_DECLARE(apr_table_t *) apreq_params(apreq_handle_t *req, apr_pool_t *p);
/**
* Returns a table containing all request cookies.
*
* @param req the apreq request handle
* @param p Allocates the returned table.
*/
APREQ_DECLARE(apr_table_t *)apreq_cookies(apreq_handle_t *req, apr_pool_t *p);
/**
* Force a complete parse of everything.
*
* @param req The request handle
*
* @return APR_SUCCESS on an error-free parse of the request data.
* Any other status code indicates a potential problem somewhere.
*/
static APR_INLINE
apr_status_t apreq_parse(apreq_handle_t *req)
{
const apr_table_t *dummy;
apr_status_t jar_status, args_status, body_status;
jar_status = apreq_jar(req, &dummy);
args_status = apreq_args(req, &dummy);
body_status = apreq_body(req, &dummy);
/* XXX: punt to APREQ_ERROR_GENERAL; need to improve this
* for valid requests where certain data/headers are
* unavailable.
*/
if (jar_status || args_status || body_status)
return APREQ_ERROR_GENERAL;
return APR_SUCCESS;
}
#ifdef __cplusplus
}
#endif
#endif /* APREQ_MODULE_H */