import apreq include files

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1200458 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Philip M. Gollucci
2011-11-10 18:08:04 +00:00
parent 008ccc8212
commit e9806ab9d9
8 changed files with 2156 additions and 0 deletions

308
include/apreq.h Normal file
View File

@ -0,0 +1,308 @@
/*
** 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.
*/
#ifndef APREQ_H
#define APREQ_H
#ifdef APREQ_DEBUG
#include <assert.h>
#endif
#include "apr_tables.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file apreq.h
* @brief Main header file...
* @ingroup libapreq2
*
* Define the generic APREQ_ macros and common data structures.
*/
#ifndef WIN32
/**
* The public APREQ functions are declared with APREQ_DECLARE(), so they may
* use the most appropriate calling convention. Public APR functions with
* variable arguments must use APR_DECLARE_NONSTD().
*
* @remark Both the declaration and implementations must use the same macro.
*/
/** APREQ_DECLARE(rettype) apeq_func(args)
*/
#define APREQ_DECLARE(d) APR_DECLARE(d)
/**
* The public APEQ functions using variable arguments are declared with
* APEQ_DECLARE_NONSTD(), as they must follow the C language calling convention.
* @see APEQ_DECLARE @see APEQ_DECLARE_DATA
* @remark Both the declaration and implementations must use the same macro.
* @example
*/
/** APEQ_DECLARE_NONSTD(rettype) apr_func(args, ...);
*/
#define APREQ_DECLARE_NONSTD(d) APR_DECLARE_NONSTD(d)
/**
* The public APREQ variables are declared with APREQ_DECLARE_DATA.
* This assures the appropriate indirection is invoked at compile time.
* @see APREQ_DECLARE @see APREQ_DECLARE_NONSTD
* @remark Note that the declaration and implementations use different forms,
* but both must include the macro.
*/
/** extern APREQ_DECLARE_DATA type apr_variable;\n
* APREQ_DECLARE_DATA type apr_variable = value;
*/
#define APREQ_DECLARE_DATA
#elif defined (APREQ_DECLARE_STATIC)
#define APREQ_DECLARE(type) type __stdcall
#define APREQ_DECLARE_NONSTD(type) type
#define APREQ_DECLARE_DATA
#elif defined (APREQ_DECLARE_EXPORT)
#define APREQ_DECLARE(type) __declspec(dllexport) type __stdcall
#define APREQ_DECLARE_NONSTD(type) __declspec(dllexport) type
#define APREQ_DECLARE_DATA __declspec(dllexport)
#else
#define APREQ_DECLARE(type) __declspec(dllimport) type __stdcall
#define APREQ_DECLARE_NONSTD(type) __declspec(dllimport) type
#define APREQ_DECLARE_DATA __declspec(dllimport)
#endif
/**
* Read chucks of data in 64k blocks from the request
*/
#define APREQ_DEFAULT_READ_BLOCK_SIZE (64 * 1024)
/**
* Maximum number of bytes mod_apreq2 will send off to libapreq2 for parsing.
* mod_apreq2 will log this event and subsequently remove itself
* from the filter chain.
* @see ap_set_read_limit
*/
#define APREQ_DEFAULT_READ_LIMIT (64 * 1024 * 1024)
/**
* Maximum number of bytes mod_apreq2 will let accumulate within the
* heap-buckets in a brigade. Excess data will be spooled to an
* appended file bucket
* @see ap_set_brigade_read_limit
*/
#define APREQ_DEFAULT_BRIGADE_LIMIT (256 * 1024)
/**
* Number of elements in the initial apr_table
* @see apr_table_make
*/
#define APREQ_DEFAULT_NELTS 8
/**
* Check to see if specified bit f is off in bitfield name
*/
#define APREQ_FLAGS_OFF(f, name) ((f) &= ~(name##_MASK << name##_BIT))
/**
* Check to see if specified bit f is on in bitfield name
*/
#define APREQ_FLAGS_ON(f, name) ((f) |= (name##_MASK << name##_BIT))
/**
* Get specified bit f in bitfield name
*/
#define APREQ_FLAGS_GET(f, name) (((f) >> name##_BIT) & name##_MASK)
/**
* Set specified bit f in bitfield name to value
* Note the below BIT/Mask defines are used sans the
* _BIT, _MASK because of the this define's \#\#_MASK, \#\#_BIT usage.
* Each come in a pair
*/
#define APREQ_FLAGS_SET(f, name, value) \
((f) = (((f) & ~(name##_MASK << name##_BIT)) \
| ((name##_MASK & (value)) << name##_BIT)))
/**
* Charset Bit
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_CHARSET_BIT 0
/**
* Charset Mask
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_CHARSET_MASK 255
/**
* Tainted Bit
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_TAINTED_BIT 8
/**
* Tainted Mask
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_TAINTED_MASK 1
/**
* Cookier Version Bit
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_COOKIE_VERSION_BIT 11
/**
* Cookie Version Mask
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_COOKIE_VERSION_MASK 3
/**
* Cookie's Secure Bit
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_COOKIE_SECURE_BIT 13
/**
* Cookie's Secure Mask
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_COOKIE_SECURE_MASK 1
/**
* Cookie's HttpOnly Bit
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_COOKIE_HTTPONLY_BIT 14
/**
* Cookie's HttpOnly Mask
* @see APREQ_FLAGS_OFF @see APREQ_FLAGS_ON
* @see APREQ_FLAGS_GET @see APREQ_FLAGS_SET
*/
#define APREQ_COOKIE_HTTPONLY_MASK 1
/** Character encodings. */
typedef enum {
APREQ_CHARSET_ASCII =0,
APREQ_CHARSET_LATIN1 =1, /* ISO-8859-1 */
APREQ_CHARSET_CP1252 =2, /* Windows-1252 */
APREQ_CHARSET_UTF8 =8
} apreq_charset_t;
/** @enum apreq_join_t Join type */
typedef enum {
APREQ_JOIN_AS_IS, /**< Join the strings without modification */
APREQ_JOIN_ENCODE, /**< Url-encode the strings before joining them */
APREQ_JOIN_DECODE, /**< Url-decode the strings before joining them */
APREQ_JOIN_QUOTE /**< Quote the strings, backslashing existing quote marks. */
} apreq_join_t;
/** @enum apreq_match_t Match type */
typedef enum {
APREQ_MATCH_FULL, /**< Full match only. */
APREQ_MATCH_PARTIAL /**< Partial matches are ok. */
} apreq_match_t;
/** @enum apreq_expires_t Expiration date format */
typedef enum {
APREQ_EXPIRES_HTTP, /**< Use date formatting consistent with RFC 2616 */
APREQ_EXPIRES_NSCOOKIE /**< Use format consistent with Netscape's Cookie Spec */
} apreq_expires_t;
/** @brief libapreq's pre-extensible string type */
typedef struct apreq_value_t {
char *name; /**< value name */
apr_size_t nlen; /**< length of name */
apr_size_t dlen; /**< length of data */
char data[1]; /**< value data */
} apreq_value_t;
/**
* Adds the specified apreq_value_t to the apr_table_t.
*
* @param v value to add
* @param t add v to this table
*
* @return void
*
* @ see apr_table_t @see apr_value_t
*/
static APR_INLINE
void apreq_value_table_add(const apreq_value_t *v, apr_table_t *t) {
apr_table_addn(t, v->name, v->data);
}
/**
* @param T type
* @param A attribute
* @param P
*
* XXX
*/
#define apreq_attr_to_type(T,A,P) ( (T*) ((char*)(P)-offsetof(T,A)) )
/**
* Initialize libapreq2. Applications (except apache modules using
* mod_apreq) should call this exactly once before they use any
* libapreq2 modules. If you want to modify the list of default parsers
* with apreq_register_parser(), please use apreq_pre_initialize()
* and apreq_post_initialize() instead.
*
* @param pool a base pool persisting while libapreq2 is used
* @remarks after you detroy the pool, you have to call this function again
* with a new pool if you still plan to use libapreq2
*/
APREQ_DECLARE(apr_status_t) apreq_initialize(apr_pool_t *pool);
/**
* Pre-initialize libapreq2. Applications (except apache modules using
* mod_apreq2) should call this exactly once before they register custom
* parsers with libapreq2. mod_apreq2 does this automatically during the
* post-config phase, so modules that need call apreq_register_parser should
* create a post-config hook using APR_HOOK_MIDDLE.
*
* @param pool a base pool persisting while libapreq2 is used
* @remarks after you detroyed the pool, you have to call this function again
* with a new pool if you still plan to use libapreq2
*/
APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool);
/**
* Post-initialize libapreq2. Applications (except apache modules using
* mod_apreq2) should this exactly once before they use any
* libapreq2 modules for parsing.
*
* @param pool the same pool that was used in apreq_pre_initialize().
*/
APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_H */

237
include/apreq_cookie.h Normal file
View File

@ -0,0 +1,237 @@
/*
** 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.
*/
#ifndef APREQ_COOKIE_H
#define APREQ_COOKIE_H
#include "apreq.h"
#include "apr_time.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file apreq_cookie.h
* @brief Cookies and Jars.
* @ingroup libapreq2
*
* apreq_cookie.h describes a common server-side API for request (incoming)
* and response (outgoing) cookies. It aims towards compliance with the
* standard cookie specifications listed below.
*
* @see http://wp.netscape.com/newsref/std/cookie_spec.html
* @see http://www.ietf.org/rfc/rfc2109.txt
* @see http://www.ietf.org/rfc/rfc2964.txt
* @see http://www.ietf.org/rfc/rfc2965.txt
*
*/
/** This macro is deprecated.
*
* Maximum length of a single Set-Cookie(2) header.
*/
#define APREQ_COOKIE_MAX_LENGTH 4096
/** @brief Cookie type, supporting both Netscape and RFC cookie specifications.
*/
typedef struct apreq_cookie_t {
char *path; /**< Restricts url path */
char *domain; /**< Restricts server domain */
char *port; /**< Restricts server port */
char *comment; /**< RFC cookies may send a comment */
char *commentURL; /**< RFC cookies may place an URL here */
apr_time_t max_age; /**< total duration of cookie: -1 == session */
unsigned flags; /**< charsets, taint marks, app-specific bits */
const apreq_value_t v; /**< "raw" cookie value */
} apreq_cookie_t;
/** Upgrades a jar's table values to apreq_cookie_t structs. */
static APR_INLINE
apreq_cookie_t *apreq_value_to_cookie(const char *val)
{
union { const char *in; char *out; } deconst;
deconst.in = val;
return apreq_attr_to_type(apreq_cookie_t, v,
apreq_attr_to_type(apreq_value_t, data, deconst.out));
}
/**@return 1 if this is an RFC cookie, 0 if its a Netscape cookie. */
static APR_INLINE
unsigned apreq_cookie_version(const apreq_cookie_t *c) {
return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_VERSION);
}
/** Sets the cookie's protocol version. */
static APR_INLINE
void apreq_cookie_version_set(apreq_cookie_t *c, unsigned v) {
APREQ_FLAGS_SET(c->flags, APREQ_COOKIE_VERSION, v);
}
/** @return 1 if the secure flag is set, 0 otherwise. */
static APR_INLINE
unsigned apreq_cookie_is_secure(const apreq_cookie_t *c) {
return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_SECURE);
}
/** Sets the cookie's secure flag, meaning it only
* comes back over an SSL-encrypted connction.
*/
static APR_INLINE
void apreq_cookie_secure_on(apreq_cookie_t *c) {
APREQ_FLAGS_ON(c->flags, APREQ_COOKIE_SECURE);
}
/** Turns off the cookie's secure flag. */
static APR_INLINE
void apreq_cookie_secure_off(apreq_cookie_t *c) {
APREQ_FLAGS_OFF(c->flags, APREQ_COOKIE_SECURE);
}
/** @return 1 if the HttpOnly flag is set, 0 otherwise. */
static APR_INLINE
unsigned apreq_cookie_is_httponly(const apreq_cookie_t *c) {
return APREQ_FLAGS_GET(c->flags, APREQ_COOKIE_HTTPONLY);
}
/** Sets the cookie's HttpOnly flag, meaning it is not
* accessible through client-side script in supported
* browsers.
*/
static APR_INLINE
void apreq_cookie_httponly_on(apreq_cookie_t *c) {
APREQ_FLAGS_ON(c->flags, APREQ_COOKIE_HTTPONLY);
}
/** Turns off the cookie's HttpOnly flag. */
static APR_INLINE
void apreq_cookie_httponly_off(apreq_cookie_t *c) {
APREQ_FLAGS_OFF(c->flags, APREQ_COOKIE_HTTPONLY);
}
/** @return 1 if the taint flag is set, 0 otherwise. */
static APR_INLINE
unsigned apreq_cookie_is_tainted(const apreq_cookie_t *c) {
return APREQ_FLAGS_GET(c->flags, APREQ_TAINTED);
}
/** Sets the cookie's tainted flag. */
static APR_INLINE
void apreq_cookie_tainted_on(apreq_cookie_t *c) {
APREQ_FLAGS_ON(c->flags, APREQ_TAINTED);
}
/** Turns off the cookie's tainted flag. */
static APR_INLINE
void apreq_cookie_tainted_off(apreq_cookie_t *c) {
APREQ_FLAGS_OFF(c->flags, APREQ_TAINTED);
}
/**
* Parse a cookie header and store the cookies in an apr_table_t.
*
* @param pool pool which allocates the cookies
* @param jar table where parsed cookies are stored
* @param header the header value
*
* @return APR_SUCCESS.
* @return ::APREQ_ERROR_BADSEQ if an unparseable character sequence appears.
* @return ::APREQ_ERROR_MISMATCH if an rfc-cookie attribute appears in a
* netscape cookie header.
* @return ::APR_ENOTIMPL if an unrecognized rfc-cookie attribute appears.
* @return ::APREQ_ERROR_NOTOKEN if a required token was not present.
* @return ::APREQ_ERROR_BADCHAR if an unexpected token was present.
*/
APREQ_DECLARE(apr_status_t) apreq_parse_cookie_header(apr_pool_t *pool,
apr_table_t *jar,
const char *header);
/**
* Returns a new cookie, made from the argument list.
*
* @param pool Pool which allocates the cookie.
* @param name The cookie's name.
* @param nlen Length of name.
* @param value The cookie's value.
* @param vlen Length of value.
*
* @return the new cookie
*/
APREQ_DECLARE(apreq_cookie_t *) apreq_cookie_make(apr_pool_t *pool,
const char *name,
const apr_size_t nlen,
const char *value,
const apr_size_t vlen);
/**
* Returns a string that represents the cookie as it would appear
* in a valid "Set-Cookie*" header.
*
* @param c cookie.
* @param p pool which allocates the returned string.
*
* @return header string.
*/
APREQ_DECLARE(char*) apreq_cookie_as_string(const apreq_cookie_t *c,
apr_pool_t *p);
/**
* Same functionality as apreq_cookie_as_string. Stores the string
* representation in buf, using up to len bytes in buf as storage.
* The return value has the same semantics as that of apr_snprintf,
* including the special behavior for a "len = 0" argument.
*
* @param c cookie.
* @param buf storage location for the result.
* @param len size of buf's storage area.
*
* @return size of resulting header string.
*/
APREQ_DECLARE(int) apreq_cookie_serialize(const apreq_cookie_t *c,
char *buf, apr_size_t len);
/**
* Set the Cookie's expiration date.
*
* @param c The cookie.
* @param time_str If NULL, the Cookie's expiration date is unset,
* making it a session cookie. This means no "expires" or "max-age"
* attribute will appear in the cookie's serialized form. If time_str
* is not NULL, the expiration date will be reset to the offset (from now)
* represented by time_str. The time_str should be in a format that
* apreq_atoi64t() can understand, namely /[+-]?\\d+\\s*[YMDhms]/.
*
* @remarks Now time_str may also be a fixed date; see apr_date_parse_rfc()
* for admissible formats.
*/
APREQ_DECLARE(void) apreq_cookie_expires(apreq_cookie_t *c,
const char *time_str);
#ifdef __cplusplus
}
#endif
#endif /*APREQ_COOKIE_H*/

97
include/apreq_error.h Normal file
View File

@ -0,0 +1,97 @@
/*
** 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.
*/
#ifndef APREQ_ERROR_H
#define APREQ_ERROR_H
#include "apr_errno.h"
#include "apreq.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* apreq's wrapper around apr_strerror();
* recognizes APREQ_ERROR_* status codes.
*/
APREQ_DECLARE(char *)
apreq_strerror(apr_status_t s, char *buf, apr_size_t bufsize);
/**
* @file apreq_error.h
* @brief Error status codes.
* @ingroup libapreq2
*
* Define the APREQ_ error codes.
*/
#ifndef APR_EBADARG
/**
* Bad Arguments return value
* @see APR_BADARG
*/
#define APR_EBADARG APR_BADARG /* XXX: don't use APR_BADARG */
#endif
/** Internal apreq error. */
#define APREQ_ERROR_GENERAL APR_OS_START_USERERR
/** Attempted to perform unsafe action with tainted data. */
#define APREQ_ERROR_TAINTED (APREQ_ERROR_GENERAL + 1)
/** Parsing interrupted. */
#define APREQ_ERROR_INTERRUPT (APREQ_ERROR_GENERAL + 2)
/** Invalid input data. */
#define APREQ_ERROR_BADDATA (APREQ_ERROR_GENERAL + 10)
/** Invalid character. */
#define APREQ_ERROR_BADCHAR (APREQ_ERROR_BADDATA + 1)
/** Invalid byte sequence. */
#define APREQ_ERROR_BADSEQ (APREQ_ERROR_BADDATA + 2)
/** Invalid attribute. */
#define APREQ_ERROR_BADATTR (APREQ_ERROR_BADDATA + 3)
/** Invalid header. */
#define APREQ_ERROR_BADHEADER (APREQ_ERROR_BADDATA + 4)
/** Invalid utf8 encoding. */
#define APREQ_ERROR_BADUTF8 (APREQ_ERROR_BADDATA + 5)
/** Missing input data. */
#define APREQ_ERROR_NODATA (APREQ_ERROR_GENERAL + 20)
/** Missing required token. */
#define APREQ_ERROR_NOTOKEN (APREQ_ERROR_NODATA + 1)
/** Missing attribute. */
#define APREQ_ERROR_NOATTR (APREQ_ERROR_NODATA + 2)
/** Missing header. */
#define APREQ_ERROR_NOHEADER (APREQ_ERROR_NODATA + 3)
/** Missing parser. */
#define APREQ_ERROR_NOPARSER (APREQ_ERROR_NODATA + 4)
/** Conflicting information. */
#define APREQ_ERROR_MISMATCH (APREQ_ERROR_GENERAL + 30)
/** Exceeds configured maximum limit. */
#define APREQ_ERROR_OVERLIMIT (APREQ_ERROR_MISMATCH + 1)
/** Below configured minimum limit. */
#define APREQ_ERROR_UNDERLIMIT (APREQ_ERROR_MISMATCH + 2)
/** Setting already configured. */
#define APREQ_ERROR_NOTEMPTY (APREQ_ERROR_MISMATCH + 3)
#ifdef __cplusplus
}
#endif
#endif /* APREQ_ERROR_H */

457
include/apreq_module.h Normal file
View File

@ -0,0 +1,457 @@
/*
** 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.
*/
#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;
/** the pool which defines the lifetime of the parsed data */
apr_pool_t *pool;
/** the allocator, which persists at least as long as the pool */
apr_bucket_alloc_t *bucket_alloc;
} apreq_handle_t;
/**
* @brief Vtable describing the necessary module 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 *);
} 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);
}
/**
* 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 module. All attributes of
* the apreq_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 module.
*/
#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, \
}
/**
* 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 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,
apreq_parser_t *parser,
apr_uint64_t read_limit,
apr_bucket_brigade *in);
/**
* 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 name desired cookie name
*
* @return The first matching cookie 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);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_MODULE_H */

209
include/apreq_param.h Normal file
View File

@ -0,0 +1,209 @@
/*
** 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.
*/
#ifndef APREQ_PARAM_H
#define APREQ_PARAM_H
#include "apreq.h"
#include "apr_buckets.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file apreq_param.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 *upload; /**< brigade used to spool upload files */
unsigned flags; /**< charsets, taint marks, app-specific bits */
const apreq_value_t v; /**< underlying name/value info */
} apreq_param_t;
/** @return 1 if the taint flag is set, 0 otherwise. */
static APR_INLINE
unsigned apreq_param_is_tainted(const apreq_param_t *p) {
return APREQ_FLAGS_GET(p->flags, APREQ_TAINTED);
}
/** Sets the tainted flag. */
static APR_INLINE
void apreq_param_tainted_on(apreq_param_t *p) {
APREQ_FLAGS_ON(p->flags, APREQ_TAINTED);
}
/** Turns off the taint flag. */
static APR_INLINE
void apreq_param_tainted_off(apreq_param_t *p) {
APREQ_FLAGS_OFF(p->flags, APREQ_TAINTED);
}
/** Sets the character encoding for this parameter. */
static APR_INLINE
apreq_charset_t apreq_param_charset_set(apreq_param_t *p, apreq_charset_t c) {
apreq_charset_t old = (apreq_charset_t)
APREQ_FLAGS_GET(p->flags, APREQ_CHARSET);
APREQ_FLAGS_SET(p->flags, APREQ_CHARSET, c);
return old;
}
/** Gets the character encoding for this parameter. */
static APR_INLINE
apreq_charset_t apreq_param_charset_get(apreq_param_t *p) {
return (apreq_charset_t)APREQ_FLAGS_GET(p->flags, APREQ_CHARSET);
}
/** Upgrades args and body table values to apreq_param_t structs. */
static APR_INLINE
apreq_param_t *apreq_value_to_param(const char *val)
{
union { const char *in; char *out; } deconst;
deconst.in = val;
return apreq_attr_to_type(apreq_param_t, v,
apreq_attr_to_type(apreq_value_t, data, deconst.out));
}
/** creates a param from name/value information */
APREQ_DECLARE(apreq_param_t *) apreq_param_make(apr_pool_t *p,
const char *name,
const apr_size_t nlen,
const char *val,
const apr_size_t vlen);
/**
* Url-decodes a name=value pair into a param.
*
* @param param points to the decoded parameter on success
* @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.
*
* @return APR_SUCCESS on success.
* @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
*
* @remarks Unless vlen == 0, this function assumes there is
* exactly one character ('=') which separates the pair.
*
*/
APREQ_DECLARE(apr_status_t) apreq_param_decode(apreq_param_t **param,
apr_pool_t *pool,
const char *word,
apr_size_t nlen,
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_param_encode(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);
/**
* Returns an array of parameters (apreq_param_t *) matching the given key.
* The key is case-insensitive.
* @param p Allocates the returned array.
* @param t the parameter table returned by apreq_args(), apreq_body()
* or apreq_params()
* @param key Null-terminated search key, case insensitive.
* key==NULL fetches all parameters.
* @return an array of apreq_param_t* (pointers)
* @remark Also parses the request if necessary.
*/
APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p,
const apr_table_t *t,
const char *key);
/**
* Returns a ", " -joined string containing all parameters
* for the requested key, an empty string if none are found.
* The key is case-insensitive.
*
* @param p Allocates the return string.
* @param t the parameter table returned by apreq_args(), apreq_body()
* or apreq_params()
* @param key Null-terminated parameter name, case insensitive.
* key==NULL fetches all values.
* @param mode Join type- see apreq_join().
* @return the joined string or NULL on error
* @remark Also parses the request if necessary.
*/
APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p,
const apr_table_t *t,
const char *key,
apreq_join_t mode);
/**
* Returns a table of all params in req->body with non-NULL upload brigades.
* @param body parameter table returned by apreq_body() or apreq_params()
* @param pool Pool which allocates the table struct.
* @return Upload table.
* @remark Will parse the request if necessary.
*/
APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body,
apr_pool_t *pool);
/**
* Returns the first param in req->body which has both param->v.name
* matching key (case insensitive) and param->upload != NULL.
* @param body parameter table returned by apreq_body() or apreq_params()
* @param name Parameter name. key == NULL returns first upload.
* @return Corresponding upload, NULL if none found.
* @remark Will parse the request as necessary.
*/
APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body,
const char *name);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_PARAM_H */

300
include/apreq_parser.h Normal file
View File

@ -0,0 +1,300 @@
/*
** 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.
*/
#ifndef APREQ_PARSERS_H
#define APREQ_PARSERS_H
/* These structs are defined below */
#include "apreq_param.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @file apreq_parser.h
* @brief Request body parser API
* @ingroup libapreq2
*/
/**
* A hook is called by the parser whenever data arrives in a file
* upload parameter of the request body. You may associate any number
* of hooks with a parser instance with apreq_parser_add_hook().
*/
typedef struct apreq_hook_t apreq_hook_t;
/**
* A request body parser instance.
*/
typedef struct apreq_parser_t apreq_parser_t;
/** Parser arguments. */
#define APREQ_PARSER_ARGS apreq_parser_t *parser, \
apr_table_t *t, \
apr_bucket_brigade *bb
/** Hook arguments */
#define APREQ_HOOK_ARGS apreq_hook_t *hook, \
apreq_param_t *param, \
apr_bucket_brigade *bb
/**
* The callback function implementing a request body parser.
*/
typedef apr_status_t (*apreq_parser_function_t)(APREQ_PARSER_ARGS);
/**
* The callback function of a hook. See apreq_hook_t.
*/
typedef apr_status_t (*apreq_hook_function_t)(APREQ_HOOK_ARGS);
/**
* 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)
/**
* A hook is called by the parser whenever data arrives in a file
* upload parameter of the request body. You may associate any number
* of hooks with a parser instance with apreq_parser_add_hook().
*/
struct apreq_hook_t {
apreq_hook_function_t hook; /**< the hook function */
apreq_hook_t *next; /**< next item in the linked list */
apr_pool_t *pool; /**< pool which allocated this hook */
void *ctx; /**< a user defined pointer passed to the hook function */
};
/**
* A request body parser instance.
*/
struct apreq_parser_t {
/** the function which parses chunks of body data */
apreq_parser_function_t parser;
/** the Content-Type request header */
const char *content_type;
/** a pool which outlasts the bucket_alloc. */
apr_pool_t *pool;
/** bucket allocator used to create bucket brigades */
apr_bucket_alloc_t *bucket_alloc;
/** the maximum in-memory bytes a brigade may use */
apr_size_t brigade_limit;
/** the directory for generating temporary files */
const char *temp_dir;
/** linked list of hooks */
apreq_hook_t *hook;
/** internal context pointer used by the parser function */
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.
*/
static APR_INLINE
apr_status_t apreq_parser_run(struct apreq_parser_t *psr, apr_table_t *t,
apr_bucket_brigade *bb)
{
return psr->parser(psr, 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.
*/
static APR_INLINE
apr_status_t apreq_hook_run(struct apreq_hook_t *h, apreq_param_t *param,
apr_bucket_brigade *bb)
{
return h->hook(h, param, bb);
}
/**
* RFC 822 Header parser. It will reject all data
* after the first CRLF CRLF sequence (an empty line).
* See apreq_parser_run() for more info on rejected data.
*/
APREQ_DECLARE_PARSER(apreq_parse_headers);
/**
* RFC 2396 application/x-www-form-urlencoded parser.
*/
APREQ_DECLARE_PARSER(apreq_parse_urlencoded);
/**
* RFC 2388 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_parser_run() 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 ba bucket allocator used to create bucket brigades
* @param content_type Content-type that this parser can deal with.
* @param pfn The parser function.
* @param brigade_limit the maximum in-memory bytes a brigade may use
* @param temp_dir the directory used by the parser for temporary files
* @param hook Hooks to associate this parser with.
* @param ctx Parser's internal scratch pad.
* @return New parser.
*/
APREQ_DECLARE(apreq_parser_t *) apreq_parser_make(apr_pool_t *pool,
apr_bucket_alloc_t *ba,
const char *content_type,
apreq_parser_function_t pfn,
apr_size_t brigade_limit,
const char *temp_dir,
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_hook_make(apr_pool_t *pool,
apreq_hook_function_t hook,
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(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p,
apreq_hook_t *h);
/**
* Fetch the default parser function associated with the given MIME type.
* @param enctype The desired enctype (can also be a full "Content-Type"
* header).
* @return The parser function, or NULL if the enctype is unrecognized.
*/
APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype);
/**
* 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 pfn The function to use during parsing. Setting
* parser == NULL will remove an existing parser.
*
* @return APR_SUCCESS or error.
*/
APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype,
apreq_parser_function_t pfn);
/**
* Returns APREQ_ERROR_GENERAL. 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);
/**
* Context struct for the apreq_hook_find_param hook.
*/
typedef struct apreq_hook_find_param_ctx_t {
const char *name;
apreq_param_t *param;
apreq_hook_t *prev;
} apreq_hook_find_param_ctx_t;
/**
* Special purpose utility for locating a parameter
* during parsing. The hook's ctx shoud be initialized
* to an apreq_hook_find_param_ctx_t *, with the name
* attribute set to the sought parameter name, the param
* attribute set to NULL, and the prev attribute set to
* the address of the previous hook. The param attribute
* will be reassigned to the first param found, and once
* that happens this hook is immediately removed from the chain.
*
* @remarks When used, this should always be the first hook
* invoked, so add it manually with ctx->prev = &parser->hook
* instead of using apreq_parser_add_hook.
*/
APREQ_DECLARE_HOOK(apreq_hook_find_param);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_PARSERS_H */

443
include/apreq_util.h Normal file
View File

@ -0,0 +1,443 @@
/*
** 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.
*/
#ifndef APREQ_UTIL_H
#define APREQ_UTIL_H
#include "apr_file_io.h"
#include "apr_buckets.h"
#include "apreq.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* This header contains useful functions for creating new
* parsers, hooks or modules. It includes
*
* - string <-> array converters
* - substring search functions
* - simple encoders & decoders for urlencoded strings
* - simple time, date, & file-size converters
* @file apreq_util.h
* @brief Utility functions for apreq.
* @ingroup libapreq2
*/
/**
* Join an array of values. The result is an empty string if there are
* no values.
*
* @param p Pool to allocate return value.
* @param sep String that is inserted between the joined values.
* @param arr Array of apreq_value_t entries.
* @param mode Join type- see apreq_join_t.
*
* @return Joined string, or NULL on error
*/
APREQ_DECLARE(char *) apreq_join(apr_pool_t *p,
const char *sep,
const apr_array_header_t *arr,
apreq_join_t mode);
/**
* Returns offset of match string's location, or -1 if no match is found.
*
* @param hay Location of bytes to scan.
* @param hlen Number of bytes available for scanning.
* @param ndl Search string
* @param nlen Length of search string.
* @param type Match type.
*
* @return Offset of match string, or -1 if no match is found.
*
*/
APREQ_DECLARE(apr_ssize_t) apreq_index(const char* hay, apr_size_t hlen,
const char* ndl, apr_size_t nlen,
const apreq_match_t type);
/**
* Places a quoted copy of src into dest. Embedded quotes are escaped with a
* backslash ('\').
*
* @param dest Location of quoted copy. Must be large enough to hold the copy
* and trailing null byte.
* @param src Original string.
* @param slen Length of original string.
* @param dest Destination string.
*
* @return length of quoted copy in dest.
*/
APREQ_DECLARE(apr_size_t) apreq_quote(char *dest, const char *src,
const apr_size_t slen);
/**
*
* Same as apreq_quote() except when src begins and ends in quote marks. In
* that case it assumes src is quoted correctly, and just copies src to dest.
*
* @param dest Location of quoted copy. Must be large enough to hold the copy
* and trailing null byte.
* @param src Original string.
* @param slen Length of original string.
* @param dest Destination string.
*
* @return length of quoted copy in dest.
*/
APREQ_DECLARE(apr_size_t) apreq_quote_once(char *dest, const char *src,
const apr_size_t slen);
/**
* Url-encodes a string.
*
* @param dest Location of url-encoded result string. Caller must ensure it
* is large enough to hold the encoded string and trailing '\\0'.
* @param src Original string.
* @param slen Length of original string.
*
* @return length of url-encoded string in dest; does not exceed 3 * slen.
*/
APREQ_DECLARE(apr_size_t) apreq_encode(char *dest, const char *src,
const apr_size_t slen);
/**
* Convert a string from cp1252 to utf8. Caller must ensure it is large enough
* to hold the encoded string and trailing '\\0'.
*
* @param dest Location of utf8-encoded result string. Caller must ensure it
* is large enough to hold the encoded string and trailing '\\0'.
* @param src Original string.
* @param slen Length of original string.
*
* @return length of utf8-encoded string in dest; does not exceed 3 * slen.
*/
APREQ_DECLARE(apr_size_t) apreq_cp1252_to_utf8(char *dest,
const char *src, apr_size_t slen);
/**
* Heuristically determine the charset of a string.
*
* @param src String to scan.
* @param slen Length of string.
*
* @return APREQ_CHARSET_ASCII if the string contains only 7-bit chars;
* @return APREQ_CHARSET_UTF8 if the string is a valid utf8 byte sequence;
* @return APREQ_CHARSET_LATIN1 if the string has no control chars;
* @return APREQ_CHARSET_CP1252 if the string has control chars.
*/
APREQ_DECLARE(apreq_charset_t) apreq_charset_divine(const char *src,
apr_size_t slen);
/**
* Url-decodes a string.
*
* @param dest Location of url-encoded result string. Caller must ensure dest is
* large enough to hold the encoded string and trailing null character.
* @param dlen points to resultant length of url-decoded string in dest
* @param src Original string.
* @param slen Length of original string.
*
* @return APR_SUCCESS.
* @return APR_INCOMPLETE if the string
* ends in the middle of an escape sequence.
* @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
*
* @remarks In the non-success case, dlen will be set to include
* the last succesfully decoded value. This function decodes
* \%uXXXX into a utf8 (wide) character, following ECMA-262
* (the Javascript spec) Section B.2.1.
*/
APREQ_DECLARE(apr_status_t) apreq_decode(char *dest, apr_size_t *dlen,
const char *src, apr_size_t slen);
/**
* Url-decodes an iovec array.
*
* @param dest Location of url-encoded result string. Caller must ensure dest is
* large enough to hold the encoded string and trailing null character.
* @param dlen Resultant length of dest.
* @param v Array of iovecs that represent the source string
* @param nelts Number of iovecs in the array.
*
* @return APR_SUCCESS.
* @return APR_INCOMPLETE if the iovec
* ends in the middle of an escape sequence.
* @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
*
* @remarks In the non-APR_SUCCESS case, dlen will be set to include
* the last succesfully decoded value. This function decodes
* \%uXXXX into a utf8 (wide) character, following ECMA-262
* (the Javascript spec) Section B.2.1.
*/
APREQ_DECLARE(apr_status_t) apreq_decodev(char *dest, apr_size_t *dlen,
struct iovec *v, int nelts);
/**
* Returns an url-encoded copy of a string.
*
* @param p Pool used to allocate the return value.
* @param src Original string.
* @param slen Length of original string.
*
* @return The url-encoded string.
*
* @remarks Use this function insead of apreq_encode if its
* caller might otherwise overflow dest.
*/
static APR_INLINE
char *apreq_escape(apr_pool_t *p, const char *src, const apr_size_t slen)
{
char *rv;
if (src == NULL)
return NULL;
rv = (char *)apr_palloc(p, 3 * slen + 1);
apreq_encode(rv, src, slen);
return rv;
}
/**
* An \e in-situ url-decoder.
*
* @param str The string to decode
*
* @return Length of decoded string, or < 0 on error.
*/
static APR_INLINE apr_ssize_t apreq_unescape(char *str)
{
apr_size_t len;
apr_status_t rv = apreq_decode(str, &len, str, strlen(str));
if (rv == APR_SUCCESS)
return (apr_ssize_t)len;
else
return -1;
}
/**
* Converts file sizes (KMG) to bytes
*
* @param s file size matching m/^\\d+[KMG]b?$/i
*
* @return 64-bit integer representation of s.
*
* @todo What happens when s is malformed? Should this return
* an unsigned value instead?
*/
APREQ_DECLARE(apr_int64_t) apreq_atoi64f(const char *s);
/**
* Converts time strings (YMDhms) to seconds
*
* @param s time string matching m/^\\+?\\d+[YMDhms]$/
*
* @return 64-bit integer representation of s as seconds.
*
* @todo What happens when s is malformed? Should this return
* an unsigned value instead?
*/
APREQ_DECLARE(apr_int64_t) apreq_atoi64t(const char *s);
/**
* Writes brigade to a file.
*
* @param f File that gets the brigade.
* @param wlen On a successful return, wlen holds the length of
* the brigade, which is the amount of data written to
* the file.
* @param bb Bucket brigade.
*
* @return APR_SUCCESS.
* @return Error status code from either an unsuccessful apr_bucket_read(),
* or a failed apr_file_writev().
*
* @remarks This function leaks a bucket brigade into bb->p whenever
* the final bucket in bb is a spool bucket.
*/
APREQ_DECLARE(apr_status_t) apreq_brigade_fwrite(apr_file_t *f,
apr_off_t *wlen,
apr_bucket_brigade *bb);
/**
* Makes a temporary file.
*
* @param fp Points to the temporary apr_file_t on success.
* @param pool Pool to associate with the temp file. When the
* pool is destroyed, the temp file will be closed
* and deleted.
* @param path The base directory which will contain the temp file.
* If param == NULL, the directory will be selected via
* tempnam(). See the tempnam manpage for details.
*
* @return APR_SUCCESS.
* @return Error status code from unsuccessful apr_filepath_merge(),
* or a failed apr_file_mktemp().
*/
APREQ_DECLARE(apr_status_t) apreq_file_mktemp(apr_file_t **fp,
apr_pool_t *pool,
const char *path);
/**
* Set aside all buckets in the brigade.
*
* @param bb Brigade.
* @param p Setaside buckets into this pool.
* @return APR_SUCCESS.
* @return Error status code from an unsuccessful apr_bucket_setaside().
*/
static APR_INLINE
apr_status_t apreq_brigade_setaside(apr_bucket_brigade *bb, apr_pool_t *p)
{
apr_bucket *e;
for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
e = APR_BUCKET_NEXT(e))
{
apr_status_t rv = apr_bucket_setaside(e, p);
if (rv != APR_SUCCESS)
return rv;
}
return APR_SUCCESS;
}
/**
* Copy a brigade.
*
* @param d (destination) Copied buckets are appended to this brigade.
* @param s (source) Brigade to copy from.
*
* @return APR_SUCCESS.
* @return Error status code from an unsuccessful apr_bucket_copy().
*
* @remarks s == d produces Undefined Behavior.
*/
static APR_INLINE
apr_status_t apreq_brigade_copy(apr_bucket_brigade *d, apr_bucket_brigade *s) {
apr_bucket *e;
for (e = APR_BRIGADE_FIRST(s); e != APR_BRIGADE_SENTINEL(s);
e = APR_BUCKET_NEXT(e))
{
apr_bucket *c;
apr_status_t rv = apr_bucket_copy(e, &c);
if (rv != APR_SUCCESS)
return rv;
APR_BRIGADE_INSERT_TAIL(d, c);
}
return APR_SUCCESS;
}
/**
* Move the front of a brigade.
*
* @param d (destination) Append buckets to this brigade.
* @param s (source) Brigade to take buckets from.
* @param e First bucket of s after the move. All buckets
* before e are appended to d.
*
* @remarks This moves all buckets when e == APR_BRIGADE_SENTINEL(s).
*/
static APR_INLINE
void apreq_brigade_move(apr_bucket_brigade *d, apr_bucket_brigade *s,
apr_bucket *e)
{
apr_bucket *f;
if (e != APR_BRIGADE_SENTINEL(s)) {
f = APR_RING_FIRST(&s->list);
if (f == e) /* zero buckets to be moved */
return;
/* obtain the last bucket to be moved */
e = APR_RING_PREV(e, link);
APR_RING_UNSPLICE(f, e, link);
APR_RING_SPLICE_HEAD(&d->list, f, e, apr_bucket, link);
}
else {
APR_BRIGADE_CONCAT(d, s);
}
}
/**
* Search a header string for the value of a particular named attribute.
*
* @param hdr Header string to scan.
* @param name Name of attribute to search for.
* @param nlen Length of name.
* @param val Location of (first) matching value.
* @param vlen Length of matching value.
*
* @return APR_SUCCESS.
* @return ::APREQ_ERROR_NOATTR if the attribute is not found.
* @return ::APREQ_ERROR_BADSEQ if an unpaired quote mark was detected.
*/
APREQ_DECLARE(apr_status_t) apreq_header_attribute(const char *hdr,
const char *name,
const apr_size_t nlen,
const char **val,
apr_size_t *vlen);
/**
* Concatenates the brigades, spooling large brigades into
* a tempfile (APREQ_SPOOL) bucket.
*
* @param pool Pool for creating a tempfile bucket.
* @param temp_dir Directory for tempfile creation.
* @param brigade_limit If out's length would exceed this value,
* the appended buckets get written to a tempfile.
* @param out Resulting brigade.
* @param in Brigade to append.
*
* @return APR_SUCCESS.
* @return Error status code resulting from either apr_brigade_length(),
* apreq_file_mktemp(), apreq_brigade_fwrite(), or apr_file_seek().
*
* @todo Flesh out these error codes, making them as explicit as possible.
*/
APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apr_pool_t *pool,
const char *temp_dir,
apr_size_t brigade_limit,
apr_bucket_brigade *out,
apr_bucket_brigade *in);
/**
* Determines the spool file used by the brigade. Returns NULL if the
* brigade is not spooled in a file (does not use an APREQ_SPOOL
* bucket).
*
* @param bb the bucket brigade
* @return the spool file, or NULL.
*/
APREQ_DECLARE(apr_file_t *)apreq_brigade_spoolfile(apr_bucket_brigade *bb);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_UTIL_H */

105
include/apreq_version.h Normal file
View File

@ -0,0 +1,105 @@
/*
** 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.
*/
#ifndef APREQ_VERSION_H
#define APREQ_VERSION_H
#ifdef __cplusplus
extern "C" {
#endif
#include "apr_version.h"
#include "apreq.h"
/**
* @file apreq_version.h
* @brief Versioning API for libapreq
* @ingroup libapreq2
*
* There are several different mechanisms for accessing the version. There
* is a string form, and a set of numbers; in addition, there are constants
* which can be compiled into your application, and you can query the library
* being used for its actual version.
*
* Note that it is possible for an application to detect that it has been
* compiled against a different version of libapreq by use of the compile-time
* constants and the use of the run-time query function.
*
* libapreq version numbering follows the guidelines specified in:
*
* http://apr.apache.org/versioning.html
*/
/* The numeric compile-time version constants. These constants are the
* authoritative version numbers for libapreq.
*/
/** major version
* Major API changes that could cause compatibility problems for older
* programs such as structure size changes. No binary compatibility is
* possible across a change in the major version.
*/
#define APREQ_MAJOR_VERSION 2
/**
* Minor API changes that do not cause binary compatibility problems.
* Should be reset to 0 when upgrading APREQ_MAJOR_VERSION
*/
#define APREQ_MINOR_VERSION 8
/** patch level */
#define APREQ_PATCH_VERSION 0
/**
* This symbol is defined for internal, "development" copies of libapreq.
* This symbol will be \#undef'd for releases.
*/
#define APREQ_IS_DEV_VERSION
/** The formatted string of libapreq's version */
#define APREQ_VERSION_STRING \
APR_STRINGIFY(APREQ_MAJOR_VERSION) "." \
APR_STRINGIFY(APREQ_MINOR_VERSION) "." \
APR_STRINGIFY(APREQ_PATCH_VERSION) \
APREQ_IS_DEV_STRING
/**
* Return libapreq's version information information in a numeric form.
*
* @param pvsn Pointer to a version structure for returning the version
* information.
*/
APREQ_DECLARE(void) apreq_version(apr_version_t *pvsn);
/** Return libapreq's version information as a string. */
APREQ_DECLARE(const char *) apreq_version_string(void);
/** Internal: string form of the "is dev" flag */
#ifdef APREQ_IS_DEV_VERSION
#define APREQ_IS_DEV_STRING "-dev"
#else
#define APREQ_IS_DEV_STRING ""
#endif
#ifdef __cplusplus
}
#endif
#endif /* APREQ_VERSION_H */