blob: 02af1cb95ad57af2d9e3eaebc68cb0dd0c56b9c5 [file] [log] [blame]
/*
** Copyright 2003-2004 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_PARAMS_H
#define APREQ_PARAMS_H
#include "apreq.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @file apreq_params.h
* @brief Request parsing and parameter API
* @ingroup libapreq2
*/
/** Common data structure for params and file uploads */
typedef struct apreq_param_t {
apr_table_t *info; /**< header table associated with the param */
apr_bucket_brigade *bb; /**< brigade to spool upload files */
apreq_value_t v; /**< underlying name/value/status info */
} apreq_param_t;
/* These structs are defined below */
typedef struct apreq_hook_t apreq_hook_t;
typedef struct apreq_parser_t apreq_parser_t;
/** accessor macros */
#define apreq_value_to_param(ptr) apreq_attr_to_type(apreq_param_t, v, ptr)
#define apreq_param_name(p) ((p)->v.name)
#define apreq_param_value(p) ((p)->v.data)
#define apreq_param_info(p) ((p)->info)
#define apreq_param_brigade(p) ((p)->bb ? apreq_copy_brigade((p)->bb) : NULL)
/** creates a param from name/value information */
APREQ_DECLARE(apreq_param_t *) apreq_make_param(apr_pool_t *p,
const char *name,
const apr_size_t nlen,
const char *val,
const apr_size_t vlen);
/** Structure which manages the request data. */
typedef struct apreq_request_t {
apr_table_t *args; /**< parsed query-string */
apr_table_t *body; /**< parsed post data */
apreq_parser_t *parser; /**< active parser for this request */
void *env; /**< request environment */
apr_status_t args_status; /**< status of query-string parse */
apr_status_t body_status; /**< status of post data parse */
} apreq_request_t;
/**
* Creates an apreq_request_t object.
* @param env The current request environment.
* @param qs The query string.
* @remark "qs = NULL" has special behavior. In this case,
* apreq_request(env,NULL) will attempt to fetch a cached object
* from the environment via apreq_env_request. Failing that, it will
* replace "qs" with the result of apreq_env_query_string(env),
* parse that, and store the resulting apreq_request_t object back
* within the environment. This maneuver is designed to both mimimize
* parsing work and allow the environent to place the parsed POST data in
* req->body (otherwise the caller may need to do this manually).
* For details on this, see the environment's documentation for
* the apreq_env_read function.
*/
APREQ_DECLARE(apreq_request_t *)apreq_request(void *env, const char *qs);
/**
* Returns the first parameter value with the desired name,
* NULL if none found. The name is case-insensitive.
* @param req The current apreq_request_t object.
* @param name Nul-terminated search key. Returns the first table value
* if NULL.
* @return First matching parameter.
* @remark Also parses the request as necessary.
*/
APREQ_DECLARE(apreq_param_t *) apreq_param(const apreq_request_t *req,
const char *name);
/**
* Returns a table containing key-value pairs for the full request
* (args + body).
* @param p Allocates the returned table.
* @param req The current apreq_request_t object.
* @remark Also parses the request if necessary.
*/
APREQ_DECLARE(apr_table_t *) apreq_params(apr_pool_t *p,
const apreq_request_t *req);
/**
* Returns an array of parameters (apreq_param_t *) matching the given key.
* The key is case-insensitive.
* @param p Allocates the returned array.
* @param req The current apreq_request_t object.
* @param key Null-terminated search key. key==NULL fetches all parameters.
* @remark Also parses the request if necessary.
*/
APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p,
apreq_request_t *req,
const char *key);
/**
* Returns a ", " -separated string containing all parameters
* for the requested key, NULL if none are found. The key is case-insensitive.
* @param p Allocates the return string.
* @param req The current apreq_request_t object.
* @param key Null-terminated parameter name. key==NULL fetches all values.
* @param mode Join type- see apreq_join().
* @return Returned string is the data attribute of an apreq_value_t,
* so it is safe to use in apreq_strlen() and apreq_strtoval().
* @remark Also parses the request if necessary.
*/
APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p,
apreq_request_t *req,
const char *key,
apreq_join_t mode);
/**
* Url-decodes a name=value pair into a param.
* @param pool Pool from which the param is allocated.
* @param word Start of the name=value pair.
* @param nlen Length of urlencoded name.
* @param vlen Length of urlencoded value.
* @remark Unless vlen == 0, this function assumes there is
* exactly one character ('=') which separates the pair.
*
*/
APREQ_DECLARE(apreq_param_t *) apreq_decode_param(apr_pool_t *pool,
const char *word,
const apr_size_t nlen,
const apr_size_t vlen);
/**
* Url-encodes the param into a name-value pair.
* @param pool Pool which allocates the returned string.
* @param param Param to encode.
* @return name-value pair representing the param.
*/
APREQ_DECLARE(char *) apreq_encode_param(apr_pool_t *pool,
const apreq_param_t *param);
/**
* Parse a url-encoded string into a param table.
* @param pool pool used to allocate the param data.
* @param t table to which the params are added.
* @param qs Query string to url-decode.
* @return APR_SUCCESS if successful, error otherwise.
* @remark This function uses [&;] as the set of tokens
* to delineate words, and will treat a word w/o '='
* as a name-value pair with value-length = 0.
*
*/
APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool,
apr_table_t *t,
const char *qs);
/**
* Parse a brigade as incoming POST data.
* @param req Current request.
* @param bb Brigade to parse. See remarks below.
* @return APR_INCOMPLETE if the parse is incomplete,
* APR_SUCCESS if the parser is finished (saw eos),
* APR_ENOTIMPL if no parser is available for this request
* (i.e. unrecognized Content-Type header),
* unrecoverable error value otherwise.
*/
APREQ_DECLARE(apr_status_t)apreq_parse_request(apreq_request_t *req,
apr_bucket_brigade *bb);
/**
* Returns a table of all params in req->body with non-NULL bucket brigades.
* @param pool Pool which allocates the table struct.
* @param req Current request.
* @return Upload table.
* @remark Will parse the request if necessary.
*/
APREQ_DECLARE(apr_table_t *) apreq_uploads(apr_pool_t *pool,
const apreq_request_t *req);
/**
* Returns the first param in req->body which has both param->v.name
* matching key and param->bb != NULL.
* @param req The current request.
* @param key Parameter name. key == NULL returns first upload.
* @return Corresponding upload, NULL if none found.
* @remark Will parse the request as necessary.
*/
APREQ_DECLARE(apreq_param_t *) apreq_upload(const apreq_request_t *req,
const char *key);
#include "apreq.h"
/** Parser arguments. */
#define APREQ_PARSER_ARGS apreq_parser_t *parser, \
void *env, \
apr_table_t *t, \
apr_bucket_brigade *bb
/** Hook arguments */
#define APREQ_HOOK_ARGS apreq_hook_t *hook, \
void *env, \
apreq_param_t *param, \
apr_bucket_brigade *bb
/**
* Declares a API parser.
*/
#define APREQ_DECLARE_PARSER(f) APREQ_DECLARE_NONSTD(apr_status_t) \
(f) (APREQ_PARSER_ARGS)
/**
* Declares an API hook.
*/
#define APREQ_DECLARE_HOOK(f) APREQ_DECLARE_NONSTD(apr_status_t) \
(f) (APREQ_HOOK_ARGS)
/**
* Singly linked list of hooks.
*
*/
struct apreq_hook_t {
apr_status_t (*hook) (APREQ_HOOK_ARGS);
apreq_hook_t *next;
void *ctx;
};
/**
* Request parser with associated enctype and hooks.
*
*/
struct apreq_parser_t {
apr_status_t (*parser) (APREQ_PARSER_ARGS);
const char *enctype;
apreq_hook_t *hook;
void *ctx;
};
/**
* Parse the incoming brigade into a table. Parsers normally
* consume all the buckets of the brigade during parsing. However
* parsers may leave "rejected" data in the brigade, even during a
* successful parse, so callers may need to clean up the brigade
* themselves (in particular, rejected buckets should not be
* passed back to the parser again).
* @remark bb == NULL is valid: the parser should return its
* public status: APR_INCOMPLETE, APR_SUCCESS, or an error code.
*/
#define APREQ_RUN_PARSER(psr,env,t,bb) (psr)->parser(psr,env,t,bb)
/**
* Run the hook with the current parameter and the incoming
* bucket brigade. The hook may modify the brigade if necessary.
* Once all hooks have completed, the contents of the brigade will
* be added to the parameter's bb attribute.
* @return APR_SUCCESS on success. All other values represent errors.
*/
#define APREQ_RUN_HOOK(h,env,param,bb) (h)->hook(h,env,param,bb)
/**
* Concatenates the brigades, spooling large brigades into
* a tempfile bucket according to the environment's max_brigade
* setting- see apreq_env_max_brigade().
* @param env Environment.
* @param out Resulting brigade.
* @param in Brigade to append.
* @return APR_SUCCESS on success, error code otherwise.
*/
APREQ_DECLARE(apr_status_t) apreq_brigade_concat(void *env,
apr_bucket_brigade *out,
apr_bucket_brigade *in);
/**
* Rfc822 Header parser. It will reject all data
* after the first CRLF CRLF sequence (an empty line).
* See #APREQ_RUN_PARSER for more info on rejected data.
*/
APREQ_DECLARE_PARSER(apreq_parse_headers);
/**
* Rfc2396 application/x-www-form-urlencoded parser.
*/
APREQ_DECLARE_PARSER(apreq_parse_urlencoded);
/**
* Rfc2388 multipart/form-data (and XForms 1.0 multipart/related)
* parser. It will reject any buckets representing preamble and
* postamble text (this is normal behavior, not an error condition).
* See #APREQ_RUN_PARSER for more info on rejected data.
*/
APREQ_DECLARE_PARSER(apreq_parse_multipart);
/**
* Generic parser. No table entries will be added to
* the req->body table by this parser. The parser creates
* a dummy apreq_param_t to pass to any configured hooks. If
* no hooks are configured, the dummy param's bb slot will
* contain a copy of the request body. It can be retrieved
* by casting the parser's ctx pointer to (apreq_param_t **).
*/
APREQ_DECLARE_PARSER(apreq_parse_generic);
/**
* apr_xml_parser hook. It will parse until EOS appears.
* The parsed document isn't available until parsing has
* completed successfully. The hook's ctx pointer may
* be cast as (apr_xml_doc **) to retrieve the
* parsed document.
*/
APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser);
/**
* Construct a parser.
*
* @param pool Pool used to allocate the parser.
* @param enctype Content-type that this parser can deal with.
* @param parser The parser function.
* @param hook Hooks to asssociate this parser with.
* @param ctx Parser's internal scratch pad.
* @return New parser.
*/
APREQ_DECLARE(apreq_parser_t *)
apreq_make_parser(apr_pool_t *pool,
const char *enctype,
apr_status_t (*parser) (APREQ_PARSER_ARGS),
apreq_hook_t *hook,
void *ctx);
/**
* Construct a hook.
*
* @param pool used to allocate the hook.
* @param hook The hook function.
* @param next List of other hooks for this hook to call on.
* @param ctx Hook's internal scratch pad.
* @return New hook.
*/
APREQ_DECLARE(apreq_hook_t *)
apreq_make_hook(apr_pool_t *pool,
apr_status_t (*hook) (APREQ_HOOK_ARGS),
apreq_hook_t *next,
void *ctx);
/**
* Add a new hook to the end of the parser's hook list.
*
* @param p Parser.
* @param h Hook to append.
*/
APREQ_DECLARE(void) apreq_add_hook(apreq_parser_t *p,
apreq_hook_t *h);
/**
* Create the default parser associated with the
* current request's Content-Type (if possible).
* @param env The current environment.
* @param hook Hook(s) to add to the parser.
* @return New parser, NULL if the Content-Type is
* unrecognized.
*
* @param env The current environment.
* @param hook Additional hooks to supply the parser with.
* @return The parser; NULL if the environment's
* Content-Type is unrecognized.
*/
APREQ_DECLARE(apreq_parser_t *)apreq_parser(void *env,
apreq_hook_t *hook);
/**
* Register a new parsing function with a MIME enctype.
* Registered parsers are added to apreq_parser()'s
* internal lookup table.
*
* @param enctype The MIME type.
* @param parser The function to use during parsing. Setting
* parser == NULL will remove an existing parser.
* @remark This is not a thread-safe operation, so applications
* should only call this during process startup,
* or within a request-thread mutex.
*/
APREQ_DECLARE(void) apreq_register_parser(const char *enctype,
apr_status_t (*parser) (APREQ_PARSER_ARGS));
/**
* Returns APR_EGENERAL. Effectively disables mfd parser
* if a file-upload field is present.
*
*/
APREQ_DECLARE_HOOK(apreq_hook_disable_uploads);
/**
* Calls apr_brigade_cleanup on the incoming brigade
* after passing the brigade to any subsequent hooks.
*/
APREQ_DECLARE_HOOK(apreq_hook_discard_brigade);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_PARAMS_H */