As discussed at AC NA 2011

o relocate srclib/libapreq/library/*.c -> server/apreq_${f}.c
o relocate srclib/libapreq/include/*.h -> include/*.h
o remove apreq_version.[hc] related stuff since its nolonger its own lib
o connect modules/apreq to the build under 'most' default comment out in httpd.conf
o update make_exports.awk to handle APREQ marcos




git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1201372 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Philip M. Gollucci
2011-11-13 00:20:32 +00:00
parent 0d121a89f1
commit 4472a86146
25 changed files with 18 additions and 150 deletions

View File

@ -1,308 +0,0 @@
/*
** 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 */

View File

@ -1,237 +0,0 @@
/*
** 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*/

View File

@ -1,97 +0,0 @@
/*
** 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 */

View File

@ -1,457 +0,0 @@
/*
** 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 */

View File

@ -1,209 +0,0 @@
/*
** 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 */

View File

@ -1,300 +0,0 @@
/*
** 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 */

View File

@ -1,443 +0,0 @@
/*
** 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 */

View File

@ -1,105 +0,0 @@
/*
** 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 */

View File

@ -1,537 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_cookie.h"
#include "apreq_error.h"
#include "apreq_util.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "apr_date.h"
#define RFC 1
#define NETSCAPE 0
#define ADD_COOKIE(j,c) apreq_value_table_add(&c->v, j)
APREQ_DECLARE(void) apreq_cookie_expires(apreq_cookie_t *c,
const char *time_str)
{
if (time_str == NULL) {
c->max_age = -1;
return;
}
if (!strcasecmp(time_str, "now"))
c->max_age = 0;
else {
c->max_age = apr_date_parse_rfc(time_str);
if (c->max_age == APR_DATE_BAD)
c->max_age = apr_time_from_sec(apreq_atoi64t(time_str));
else
c->max_age -= apr_time_now();
}
}
static apr_status_t apreq_cookie_attr(apr_pool_t *p,
apreq_cookie_t *c,
const char *attr,
apr_size_t alen,
const char *val,
apr_size_t vlen)
{
if (alen < 2)
return APR_EBADARG;
if ( attr[0] == '-' || attr[0] == '$' ) {
++attr;
--alen;
}
switch (apr_tolower(*attr)) {
case 'n': /* name is not an attr */
return APR_ENOTIMPL;
case 'v': /* version; value is not an attr */
if (alen == 5 && strncasecmp(attr,"value", 5) == 0)
return APR_ENOTIMPL;
while (!apr_isdigit(*val)) {
if (vlen == 0)
return APREQ_ERROR_BADSEQ;
++val;
--vlen;
}
apreq_cookie_version_set(c, *val - '0');
return APR_SUCCESS;
case 'e': case 'm': /* expires, max-age */
apreq_cookie_expires(c, val);
return APR_SUCCESS;
case 'd':
c->domain = apr_pstrmemdup(p,val,vlen);
return APR_SUCCESS;
case 'p':
if (alen != 4)
break;
if (!strncasecmp("port", attr, 4)) {
c->port = apr_pstrmemdup(p,val,vlen);
return APR_SUCCESS;
}
else if (!strncasecmp("path", attr, 4)) {
c->path = apr_pstrmemdup(p,val,vlen);
return APR_SUCCESS;
}
break;
case 'c':
if (!strncasecmp("commentURL", attr, 10)) {
c->commentURL = apr_pstrmemdup(p,val,vlen);
return APR_SUCCESS;
}
else if (!strncasecmp("comment", attr, 7)) {
c->comment = apr_pstrmemdup(p,val,vlen);
return APR_SUCCESS;
}
break;
case 's':
if (vlen > 0 && *val != '0' && strncasecmp("off",val,vlen))
apreq_cookie_secure_on(c);
else
apreq_cookie_secure_off(c);
return APR_SUCCESS;
case 'h': /* httponly */
if (vlen > 0 && *val != '0' && strncasecmp("off",val,vlen))
apreq_cookie_httponly_on(c);
else
apreq_cookie_httponly_off(c);
return APR_SUCCESS;
};
return APR_ENOTIMPL;
}
APREQ_DECLARE(apreq_cookie_t *) apreq_cookie_make(apr_pool_t *p,
const char *name,
const apr_size_t nlen,
const char *value,
const apr_size_t vlen)
{
apreq_cookie_t *c;
apreq_value_t *v;
c = apr_palloc(p, nlen + vlen + 1 + sizeof *c);
if (c == NULL)
return NULL;
*(const apreq_value_t **)&v = &c->v;
if (vlen > 0 && value != NULL)
memcpy(v->data, value, vlen);
v->data[vlen] = 0;
v->dlen = vlen;
v->name = v->data + vlen + 1;
if (nlen && name != NULL)
memcpy(v->name, name, nlen);
v->name[nlen] = 0;
v->nlen = nlen;
c->path = NULL;
c->domain = NULL;
c->port = NULL;
c->comment = NULL;
c->commentURL = NULL;
c->max_age = -1; /* session cookie is the default */
c->flags = 0;
return c;
}
static APR_INLINE
apr_status_t get_pair(apr_pool_t *p, const char **data,
const char **n, apr_size_t *nlen,
const char **v, apr_size_t *vlen, unsigned unquote)
{
const char *hdr, *key, *val;
int nlen_set = 0;
hdr = *data;
while (apr_isspace(*hdr) || *hdr == '=')
++hdr;
key = hdr;
*n = hdr;
scan_name:
switch (*hdr) {
case 0:
case ';':
case ',':
if (!nlen_set)
*nlen = hdr - key;
*v = hdr;
*vlen = 0;
*data = hdr;
return *nlen ? APREQ_ERROR_NOTOKEN : APREQ_ERROR_BADCHAR;
case '=':
if (!nlen_set) {
*nlen = hdr - key;
nlen_set = 1;
}
break;
case ' ':
case '\t':
case '\r':
case '\n':
if (!nlen_set) {
*nlen = hdr - key;
nlen_set = 1;
}
/* fall thru */
default:
++hdr;
goto scan_name;
}
val = hdr + 1;
while (apr_isspace(*val))
++val;
if (*val == '"') {
unsigned saw_backslash = 0;
for (*v = (unquote) ? ++val : val++; *val; ++val) {
switch (*val) {
case '"':
*data = val + 1;
if (!unquote) {
*vlen = (val - *v) + 1;
}
else if (!saw_backslash) {
*vlen = val - *v;
}
else {
char *dest = apr_palloc(p, val - *v), *d = dest;
const char *s = *v;
while (s < val) {
if (*s == '\\')
++s;
*d++ = *s++;
}
*vlen = d - dest;
*v = dest;
}
return APR_SUCCESS;
case '\\':
saw_backslash = 1;
if (val[1] != 0)
++val;
default:
break;
}
}
/* bad sequence: no terminating quote found */
*data = val;
return APREQ_ERROR_BADSEQ;
}
else {
/* value is not wrapped in quotes */
for (*v = val; *val; ++val) {
switch (*val) {
case ';':
case ',':
case ' ':
case '\t':
case '\r':
case '\n':
*data = val;
*vlen = val - *v;
return APR_SUCCESS;
default:
break;
}
}
}
*data = val;
*vlen = val - *v;
return APR_SUCCESS;
}
APREQ_DECLARE(apr_status_t)apreq_parse_cookie_header(apr_pool_t *p,
apr_table_t *j,
const char *hdr)
{
apreq_cookie_t *c;
unsigned version;
apr_status_t rv = APR_SUCCESS;
parse_cookie_header:
c = NULL;
version = NETSCAPE;
while (apr_isspace(*hdr))
++hdr;
if (*hdr == '$' && strncasecmp(hdr, "$Version", 8) == 0) {
/* XXX cheat: assume "$Version" => RFC Cookie header */
version = RFC;
skip_version_string:
switch (*hdr++) {
case 0:
return rv;
case ',':
goto parse_cookie_header;
case ';':
break;
default:
goto skip_version_string;
}
}
for (;;) {
apr_status_t status;
const char *name, *value;
apr_size_t nlen, vlen;
while (*hdr == ';' || apr_isspace(*hdr))
++hdr;
switch (*hdr) {
case 0:
/* this is the normal exit point */
if (c != NULL) {
ADD_COOKIE(j, c);
}
return rv;
case ',':
++hdr;
if (c != NULL) {
ADD_COOKIE(j, c);
}
goto parse_cookie_header;
case '$':
++hdr;
if (c == NULL) {
rv = APREQ_ERROR_BADCHAR;
goto parse_cookie_error;
}
else if (version == NETSCAPE) {
rv = APREQ_ERROR_MISMATCH;
}
status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 1);
if (status != APR_SUCCESS) {
rv = status;
goto parse_cookie_error;
}
status = apreq_cookie_attr(p, c, name, nlen, value, vlen);
switch (status) {
case APR_ENOTIMPL:
rv = APREQ_ERROR_BADATTR;
/* fall thru */
case APR_SUCCESS:
break;
default:
rv = status;
goto parse_cookie_error;
}
break;
default:
if (c != NULL) {
ADD_COOKIE(j, c);
}
status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 0);
if (status != APR_SUCCESS) {
c = NULL;
rv = status;
goto parse_cookie_error;
}
c = apreq_cookie_make(p, name, nlen, value, vlen);
apreq_cookie_tainted_on(c);
if (version != NETSCAPE)
apreq_cookie_version_set(c, version);
}
}
parse_cookie_error:
switch (*hdr) {
case 0:
return rv;
case ',':
case ';':
if (c != NULL)
ADD_COOKIE(j, c);
++hdr;
goto parse_cookie_header;
default:
++hdr;
goto parse_cookie_error;
}
/* not reached */
return rv;
}
APREQ_DECLARE(int) apreq_cookie_serialize(const apreq_cookie_t *c,
char *buf, apr_size_t len)
{
/* The format string must be large enough to accomodate all
* of the cookie attributes. The current attributes sum to
* ~90 characters (w/ 6-8 padding chars per attr), so anything
* over 100 should be fine.
*/
unsigned version = apreq_cookie_version(c);
char format[128] = "%s=%s";
char *f = format + strlen(format);
/* XXX protocol enforcement (for debugging, anyway) ??? */
if (c->v.name == NULL)
return -1;
#define NULL2EMPTY(attr) (attr ? attr : "")
if (version == NETSCAPE) {
char expires[APR_RFC822_DATE_LEN] = {0};
#define ADD_NS_ATTR(name) do { \
if (c->name != NULL) \
strcpy(f, "; " #name "=%s"); \
else \
strcpy(f, "%0.s"); \
f += strlen(f); \
} while (0)
ADD_NS_ATTR(path);
ADD_NS_ATTR(domain);
if (c->max_age != -1) {
strcpy(f, "; expires=%s");
apr_rfc822_date(expires, c->max_age + apr_time_now());
expires[7] = '-';
expires[11] = '-';
}
else
strcpy(f, "");
f += strlen(f);
if (apreq_cookie_is_secure(c))
strcpy(f, "; secure");
f += strlen(f);
if (apreq_cookie_is_httponly(c))
strcpy(f, "; HttpOnly");
return apr_snprintf(buf, len, format, c->v.name, c->v.data,
NULL2EMPTY(c->path), NULL2EMPTY(c->domain), expires);
}
/* c->version == RFC */
strcpy(f,"; Version=%u");
f += strlen(f);
/* ensure RFC attributes are always quoted */
#define ADD_RFC_ATTR(name) do { \
if (c->name != NULL) \
if (*c->name == '"') \
strcpy(f, "; " #name "=%s"); \
else \
strcpy(f, "; " #name "=\"%s\""); \
else \
strcpy(f, "%0.s"); \
f += strlen (f); \
} while (0)
ADD_RFC_ATTR(path);
ADD_RFC_ATTR(domain);
ADD_RFC_ATTR(port);
ADD_RFC_ATTR(comment);
ADD_RFC_ATTR(commentURL);
strcpy(f, c->max_age != -1 ? "; max-age=%" APR_TIME_T_FMT : "");
f += strlen(f);
if (apreq_cookie_is_secure(c))
strcpy(f, "; secure");
f += strlen(f);
if (apreq_cookie_is_httponly(c))
strcpy(f, "; HttpOnly");
return apr_snprintf(buf, len, format, c->v.name, c->v.data, version,
NULL2EMPTY(c->path), NULL2EMPTY(c->domain),
NULL2EMPTY(c->port), NULL2EMPTY(c->comment),
NULL2EMPTY(c->commentURL), apr_time_sec(c->max_age));
}
APREQ_DECLARE(char*) apreq_cookie_as_string(const apreq_cookie_t *c,
apr_pool_t *p)
{
int n = apreq_cookie_serialize(c, NULL, 0);
char *s = apr_palloc(p, n + 1);
apreq_cookie_serialize(c, s, n + 1);
return s;
}

View File

@ -1,105 +0,0 @@
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "apreq_error.h"
#include "apr_strings.h"
/*
* stuffbuffer - like apr_cpystrn() but returns the address of the
* dest buffer instead of the address of the terminating '\0'
*/
static char *stuffbuffer(char *buf, apr_size_t bufsize, const char *s)
{
apr_cpystrn(buf,s,bufsize);
return buf;
}
static const char *apreq_error_string(apr_status_t statcode)
{
switch (statcode) {
/* 0's: generic error status codes */
case APREQ_ERROR_GENERAL:
return "Internal apreq error";
case APREQ_ERROR_TAINTED:
return "Attempt to perform unsafe action with tainted data";
/* 10's: malformed input */
case APREQ_ERROR_BADDATA:
return "Malformed input data";
case APREQ_ERROR_BADCHAR:
return "Invalid character";
case APREQ_ERROR_BADSEQ:
return "Invalid byte sequence";
case APREQ_ERROR_BADATTR:
return "Unrecognized attribute";
case APREQ_ERROR_BADHEADER:
return "Malformed header string";
/* 20's: missing input */
case APREQ_ERROR_NODATA:
return "Missing input data";
case APREQ_ERROR_NOTOKEN:
return "Expected token not present";
case APREQ_ERROR_NOATTR:
return "Missing attribute";
case APREQ_ERROR_NOHEADER:
return "Missing header";
case APREQ_ERROR_NOPARSER:
return "Missing parser";
/* 30's: configuration conflicts */
case APREQ_ERROR_MISMATCH:
return "Conflicting information";
case APREQ_ERROR_OVERLIMIT:
return "Exceeds configured maximum limit";
case APREQ_ERROR_NOTEMPTY:
return "Setting already configured";
default:
return "Error string not yet specified by apreq";
}
}
APREQ_DECLARE(char *) apreq_strerror(apr_status_t statcode, char *buf,
apr_size_t bufsize)
{
if (statcode < APR_OS_START_USERERR || statcode >= APR_OS_START_EAIERR)
return apr_strerror(statcode, buf, bufsize);
return stuffbuffer(buf, bufsize, apreq_error_string(statcode));
}

View File

@ -1,65 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_module.h"
#include "apreq_error.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "apr_file_io.h"
APREQ_DECLARE(apreq_param_t *)apreq_param(apreq_handle_t *req, const char *key)
{
apreq_param_t *param = apreq_args_get(req, key);
if (param == NULL)
return apreq_body_get(req, key);
else
return param;
}
APREQ_DECLARE(apr_table_t *)apreq_params(apreq_handle_t *req, apr_pool_t *p)
{
const apr_table_t *args, *body;
apreq_args(req, &args);
apreq_body(req, &body);
if (args != NULL)
if (body != NULL)
return apr_table_overlay(p, args, body);
else
return apr_table_copy(p, args);
else
if (body != NULL)
return apr_table_copy(p, body);
else
return NULL;
}
APREQ_DECLARE(apr_table_t *)apreq_cookies(apreq_handle_t *req, apr_pool_t *p)
{
const apr_table_t *jar;
apreq_jar(req, &jar);
if (jar != NULL)
return apr_table_copy(p, jar);
else
return NULL;
}
/** @} */

File diff suppressed because it is too large Load Diff

View File

@ -1,304 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apr_strings.h"
#include "apreq_module.h"
#include "apreq_error.h"
#include "apreq_util.h"
#define READ_BYTES (64 * 1024)
struct custom_handle {
struct apreq_handle_t handle;
apr_table_t *jar, *args, *body;
apr_status_t jar_status,
args_status,
body_status;
apreq_parser_t *parser;
apr_uint64_t read_limit;
apr_uint64_t bytes_read;
apr_bucket_brigade *in;
apr_bucket_brigade *tmpbb;
};
static apr_status_t custom_parse_brigade(apreq_handle_t *handle, apr_uint64_t bytes)
{
struct custom_handle *req = (struct custom_handle *)handle;
apr_status_t s;
apr_bucket *e;
if (req->body_status != APR_INCOMPLETE)
return req->body_status;
switch (s = apr_brigade_partition(req->in, bytes, &e)) {
apr_off_t len;
case APR_SUCCESS:
apreq_brigade_move(req->tmpbb, req->in, e);
req->bytes_read += bytes;
if (req->bytes_read > req->read_limit) {
req->body_status = APREQ_ERROR_OVERLIMIT;
break;
}
req->body_status =
apreq_parser_run(req->parser, req->body, req->tmpbb);
apr_brigade_cleanup(req->tmpbb);
break;
case APR_INCOMPLETE:
apreq_brigade_move(req->tmpbb, req->in, e);
s = apr_brigade_length(req->tmpbb, 1, &len);
if (s != APR_SUCCESS) {
req->body_status = s;
break;
}
req->bytes_read += len;
if (req->bytes_read > req->read_limit) {
req->body_status = APREQ_ERROR_OVERLIMIT;
break;
}
req->body_status =
apreq_parser_run(req->parser, req->body, req->tmpbb);
apr_brigade_cleanup(req->tmpbb);
break;
default:
req->body_status = s;
}
return req->body_status;
}
static apr_status_t custom_jar(apreq_handle_t *handle, const apr_table_t **t)
{
struct custom_handle *req = (struct custom_handle *)handle;
*t = req->jar;
return req->jar_status;
}
static apr_status_t custom_args(apreq_handle_t *handle, const apr_table_t **t)
{
struct custom_handle *req = (struct custom_handle*)handle;
*t = req->args;
return req->args_status;
}
static apr_status_t custom_body(apreq_handle_t *handle, const apr_table_t **t)
{
struct custom_handle *req = (struct custom_handle*)handle;
while (req->body_status == APR_INCOMPLETE)
custom_parse_brigade(handle, READ_BYTES);
*t = req->body;
return req->body_status;
}
static apreq_cookie_t *custom_jar_get(apreq_handle_t *handle, const char *name)
{
struct custom_handle *req = (struct custom_handle*)handle;
const char *val;
if (req->jar == NULL || name == NULL)
return NULL;
val = apr_table_get(req->jar, name);
if (val == NULL)
return NULL;
return apreq_value_to_cookie(val);
}
static apreq_param_t *custom_args_get(apreq_handle_t *handle, const char *name)
{
struct custom_handle *req = (struct custom_handle*)handle;
const char *val;
if (req->args == NULL || name == NULL)
return NULL;
val = apr_table_get(req->args, name);
if (val == NULL)
return NULL;
return apreq_value_to_param(val);
}
static apreq_param_t *custom_body_get(apreq_handle_t *handle, const char *name)
{
struct custom_handle *req = (struct custom_handle*)handle;
const char *val;
if (req->body == NULL || name == NULL)
return NULL;
while (1) {
*(const char **)&val = apr_table_get(req->body, name);
if (val != NULL)
break;
if (req->body_status == APR_INCOMPLETE)
custom_parse_brigade(handle, READ_BYTES);
else
return NULL;
}
return apreq_value_to_param(val);
}
static apr_status_t custom_parser_get(apreq_handle_t *handle,
const apreq_parser_t **parser)
{
struct custom_handle *req = (struct custom_handle*)handle;
*parser = req->parser;
return APR_SUCCESS;
}
static apr_status_t custom_parser_set(apreq_handle_t *handle,
apreq_parser_t *parser)
{
(void)handle;
(void)parser;
return APR_ENOTIMPL;
}
static apr_status_t custom_hook_add(apreq_handle_t *handle,
apreq_hook_t *hook)
{
struct custom_handle *req = (struct custom_handle*)handle;
apreq_parser_add_hook(req->parser, hook);
return APR_SUCCESS;
}
static apr_status_t custom_brigade_limit_get(apreq_handle_t *handle,
apr_size_t *bytes)
{
struct custom_handle *req = (struct custom_handle*)handle;
*bytes = req->parser->brigade_limit;
return APR_SUCCESS;
}
static apr_status_t custom_brigade_limit_set(apreq_handle_t *handle,
apr_size_t bytes)
{
(void)handle;
(void)bytes;
return APR_ENOTIMPL;
}
static apr_status_t custom_read_limit_get(apreq_handle_t *handle,
apr_uint64_t *bytes)
{
struct custom_handle *req = (struct custom_handle*)handle;
*bytes = req->read_limit;
return APR_SUCCESS;
}
static apr_status_t custom_read_limit_set(apreq_handle_t *handle,
apr_uint64_t bytes)
{
(void)handle;
(void)bytes;
return APR_ENOTIMPL;
}
static apr_status_t custom_temp_dir_get(apreq_handle_t *handle,
const char **path)
{
struct custom_handle *req = (struct custom_handle*)handle;
*path = req->parser->temp_dir;
return APR_SUCCESS;
}
static apr_status_t custom_temp_dir_set(apreq_handle_t *handle,
const char *path)
{
(void)handle;
(void)path;
return APR_ENOTIMPL;
}
static APREQ_MODULE(custom, 20070428);
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)
{
struct custom_handle *req;
req = apr_palloc(pool, sizeof(*req));
req->handle.module = &custom_module;
req->handle.pool = pool;
req->handle.bucket_alloc = in->bucket_alloc;
req->read_limit = read_limit;
req->bytes_read = 0;
req->parser = parser;
req->in = apr_brigade_create(pool, in->bucket_alloc);
req->tmpbb = apr_brigade_create(pool, in->bucket_alloc);
req->body = apr_table_make(pool, APREQ_DEFAULT_NELTS);
req->body_status = APR_INCOMPLETE;
APR_BRIGADE_CONCAT(req->in, in);
if (cookie != NULL) {
req->jar = apr_table_make(pool, APREQ_DEFAULT_NELTS);
req->jar_status =
apreq_parse_cookie_header(pool, req->jar, cookie);
}
else {
req->jar = NULL;
req->jar_status = APREQ_ERROR_NODATA;
}
if (query_string != NULL) {
req->args = apr_table_make(pool, APREQ_DEFAULT_NELTS);
req->args_status =
apreq_parse_query_string(pool, req->args, query_string);
}
else {
req->args = NULL;
req->args_status = APREQ_ERROR_NODATA;
}
if (!APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(req->in))) {
apr_bucket *eos = apr_bucket_eos_create(in->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(req->in, eos);
}
return &req->handle;
}

View File

@ -1,272 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_param.h"
#include "apreq_error.h"
#include "apreq_util.h"
#include "apr_strings.h"
#include "apr_lib.h"
#define MAX_LEN (1024 * 1024)
#define MAX_BRIGADE_LEN (1024 * 256)
#define MAX_READ_AHEAD (1024 * 64)
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)
{
apreq_param_t *param;
apreq_value_t *v;
param = apr_palloc(p, nlen + vlen + 1 + sizeof *param);
if (param == NULL)
return NULL;
param->info = NULL;
param->upload = NULL;
param->flags = 0;
*(const apreq_value_t **)&v = &param->v;
if (vlen && val != NULL)
memcpy(v->data, val, vlen);
v->data[vlen] = 0;
v->dlen = vlen;
v->name = v->data + vlen + 1;
if (nlen && name != NULL)
memcpy(v->name, name, nlen);
v->name[nlen] = 0;
v->nlen = nlen;
return param;
}
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)
{
apr_status_t status;
apreq_value_t *v;
apreq_param_t *p;
apreq_charset_t charset;
if (nlen == 0) {
*param = NULL;
return APR_EBADARG;
}
p = apr_palloc(pool, nlen + vlen + 1 + sizeof *p);
p->info = NULL;
p->upload = NULL;
p->flags = 0;
*(const apreq_value_t **)&v = &p->v;
if (vlen > 0) {
status = apreq_decode(v->data, &v->dlen, word + nlen + 1, vlen);
if (status != APR_SUCCESS) {
*param = NULL;
return status;
}
charset = apreq_charset_divine(v->data, v->dlen);
}
else {
v->data[0] = 0;
v->dlen = 0;
charset = APREQ_CHARSET_ASCII;
}
v->name = v->data + vlen + 1;
status = apreq_decode(v->name, &v->nlen, word, nlen);
if (status != APR_SUCCESS) {
*param = NULL;
return status;
}
switch (apreq_charset_divine(v->name, v->nlen)) {
case APREQ_CHARSET_UTF8:
if (charset == APREQ_CHARSET_ASCII)
charset = APREQ_CHARSET_UTF8;
case APREQ_CHARSET_ASCII:
break;
case APREQ_CHARSET_LATIN1:
if (charset != APREQ_CHARSET_CP1252)
charset = APREQ_CHARSET_LATIN1;
break;
case APREQ_CHARSET_CP1252:
charset = APREQ_CHARSET_CP1252;
}
apreq_param_charset_set(p, charset);
*param = p;
return APR_SUCCESS;
}
APREQ_DECLARE(char *) apreq_param_encode(apr_pool_t *pool,
const apreq_param_t *param)
{
apr_size_t dlen;
char *data;
data = apr_palloc(pool, 3 * (param->v.nlen + param->v.dlen) + 2);
dlen = apreq_encode(data, param->v.name, param->v.nlen);
data[dlen++] = '=';
dlen += apreq_encode(data + dlen, param->v.data, param->v.dlen);
return data;
}
APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool,
apr_table_t *t,
const char *qs)
{
const char *start = qs;
apr_size_t nlen = 0;
for (;;++qs) {
switch (*qs) {
case '=':
if (nlen == 0) {
nlen = qs - start;
}
break;
case '&':
case ';':
case 0:
if (qs > start) {
apr_size_t vlen = 0;
apreq_param_t *param;
apr_status_t s;
if (nlen == 0)
nlen = qs - start;
else
vlen = qs - start - nlen - 1;
s = apreq_param_decode(&param, pool, start, nlen, vlen);
if (s != APR_SUCCESS)
return s;
apreq_param_tainted_on(param);
apreq_value_table_add(&param->v, t);
}
if (*qs == 0)
return APR_SUCCESS;
nlen = 0;
start = qs + 1;
}
}
/* not reached */
return APR_INCOMPLETE;
}
static int param_push(void *data, const char *key, const char *val)
{
apr_array_header_t *arr = data;
*(apreq_param_t **)apr_array_push(arr) =
apreq_value_to_param(val);
return 1; /* keep going */
}
APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p,
const apr_table_t *t,
const char *key)
{
apr_array_header_t *arr;
arr = apr_array_make(p, apr_table_elts(t)->nelts,
sizeof(apreq_param_t *));
apr_table_do(param_push, arr, t, key, NULL);
return arr;
}
APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p,
const apr_table_t *t,
const char *key,
apreq_join_t mode)
{
apr_array_header_t *arr = apreq_params_as_array(p, t, key);
apreq_param_t **elt = (apreq_param_t **)arr->elts;
apreq_param_t **const end = elt + arr->nelts;
if (arr->nelts == 0)
return apr_pstrdup(p, "");
while (elt < end) {
*(const apreq_value_t **)elt = &(**elt).v;
++elt;
}
return apreq_join(p, ", ", arr, mode);
}
static int upload_push(void *data, const char *key, const char *val)
{
apr_table_t *t = data;
apreq_param_t *p = apreq_value_to_param(val);
if (p->upload != NULL)
apreq_value_table_add(&p->v, t);
return 1; /* keep going */
}
APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body,
apr_pool_t *pool)
{
apr_table_t *t = apr_table_make(pool, APREQ_DEFAULT_NELTS);
apr_table_do(upload_push, t, body, NULL);
return t;
}
static int upload_set(void *data, const char *key, const char *val)
{
const apreq_param_t **q = data;
apreq_param_t *p = apreq_value_to_param(val);
if (p->upload != NULL) {
*q = p;
return 0; /* upload found, stop */
}
else
return 1; /* keep searching */
}
APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body,
const char *name)
{
apreq_param_t *param = NULL;
apr_table_do(upload_set, &param, body, name, NULL);
return param;
}

View File

@ -1,356 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_error.h"
#include "apreq_parser.h"
#include "apreq_util.h"
#include "apr_strings.h"
#include "apr_xml.h"
#include "apr_hash.h"
#define PARSER_STATUS_CHECK(PREFIX) do { \
if (ctx->status == PREFIX##_ERROR) \
return APREQ_ERROR_GENERAL; \
else if (ctx->status == PREFIX##_COMPLETE) \
return APR_SUCCESS; \
else if (bb == NULL) \
return APR_INCOMPLETE; \
} while (0);
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)
{
apreq_parser_t *p = apr_palloc(pool, sizeof *p);
p->content_type = content_type;
p->parser = pfn;
p->hook = hook;
p->pool = pool;
p->bucket_alloc = ba;
p->brigade_limit = brigade_limit;
p->temp_dir = temp_dir;
p->ctx = ctx;
return p;
}
APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool,
apreq_hook_function_t hook,
apreq_hook_t *next,
void *ctx)
{
apreq_hook_t *h = apr_palloc(pool, sizeof *h);
h->hook = hook;
h->next = next;
h->pool = pool;
h->ctx = ctx;
return h;
}
/*XXX this may need to check the parser's state before modifying the hook list */
APREQ_DECLARE(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p,
apreq_hook_t *h)
{
apreq_hook_t *last = h;
while (last->next)
last = last->next;
last->next = p->hook;
p->hook = h;
return APR_SUCCESS;
}
static int default_parsers_lock = 0;
static apr_hash_t *default_parsers = NULL;
static apr_pool_t *default_parser_pool = NULL;
static apr_status_t apreq_parsers_cleanup(void *data)
{
default_parsers_lock = 0;
default_parsers = NULL;
default_parser_pool = NULL;
return APR_SUCCESS;
}
APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool)
{
apr_status_t status;
if (default_parser_pool != NULL)
return APR_SUCCESS;
if (default_parsers_lock)
return APREQ_ERROR_GENERAL;
status = apr_pool_create(&default_parser_pool, pool);
if (status != APR_SUCCESS)
return status;
apr_pool_cleanup_register(default_parser_pool, NULL,
apreq_parsers_cleanup,
apr_pool_cleanup_null);
default_parsers = apr_hash_make(default_parser_pool);
apreq_register_parser("application/x-www-form-urlencoded",
apreq_parse_urlencoded);
apreq_register_parser("multipart/form-data", apreq_parse_multipart);
apreq_register_parser("multipart/related", apreq_parse_multipart);
return APR_SUCCESS;
}
APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool)
{
(void)pool;
if (default_parser_pool == NULL)
return APREQ_ERROR_GENERAL;
default_parsers_lock = 1;
return APR_SUCCESS;
}
APREQ_DECLARE(apr_status_t) apreq_initialize(apr_pool_t *pool)
{
apr_status_t s = apreq_pre_initialize(pool);
if (s != APR_SUCCESS)
return s;
return apreq_post_initialize(pool);
}
APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype,
apreq_parser_function_t pfn)
{
apreq_parser_function_t *f = NULL;
if (default_parsers == NULL)
return APR_EINIT;
if (enctype == NULL)
return APR_EINVAL;
if (default_parsers_lock)
return APREQ_ERROR_GENERAL;
if (pfn != NULL) {
f = apr_palloc(default_parser_pool, sizeof *f);
*f = pfn;
}
apr_hash_set(default_parsers, apr_pstrdup(default_parser_pool, enctype),
APR_HASH_KEY_STRING, f);
return APR_SUCCESS;
}
APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype)
{
apreq_parser_function_t *f;
apr_size_t tlen = 0;
if (enctype == NULL || default_parsers_lock == 0)
return NULL;
while(enctype[tlen] && enctype[tlen] != ';')
++tlen;
f = apr_hash_get(default_parsers, enctype, tlen);
if (f != NULL)
return *f;
else
return NULL;
}
APREQ_DECLARE_HOOK(apreq_hook_disable_uploads)
{
return (bb == NULL) ? APR_SUCCESS : APREQ_ERROR_GENERAL;
}
APREQ_DECLARE_HOOK(apreq_hook_discard_brigade)
{
apr_status_t s = APR_SUCCESS;
if (hook->next)
s = apreq_hook_run(hook->next, param, bb);
if (bb != NULL)
apr_brigade_cleanup(bb);
return s;
}
/* generic parser */
struct gen_ctx {
apreq_param_t *param;
enum {
GEN_INCOMPLETE,
GEN_COMPLETE,
GEN_ERROR
} status;
};
APREQ_DECLARE_PARSER(apreq_parse_generic)
{
struct gen_ctx *ctx = parser->ctx;
apr_pool_t *pool = parser->pool;
apr_status_t s = APR_SUCCESS;
apr_bucket *e = APR_BRIGADE_LAST(bb);
unsigned saw_eos = 0;
if (ctx == NULL) {
parser->ctx = ctx = apr_palloc(pool, sizeof *ctx);
ctx->status = GEN_INCOMPLETE;
ctx->param = apreq_param_make(pool,
"_dummy_", strlen("_dummy_"), "", 0);
ctx->param->upload = apr_brigade_create(pool, parser->bucket_alloc);
ctx->param->info = apr_table_make(pool, APREQ_DEFAULT_NELTS);
}
PARSER_STATUS_CHECK(GEN);
while (e != APR_BRIGADE_SENTINEL(bb)) {
if (APR_BUCKET_IS_EOS(e)) {
saw_eos = 1;
break;
}
e = APR_BUCKET_PREV(e);
}
if (parser->hook != NULL) {
s = apreq_hook_run(parser->hook, ctx->param, bb);
if (s != APR_SUCCESS) {
ctx->status = GEN_ERROR;
return s;
}
}
apreq_brigade_setaside(bb, pool);
s = apreq_brigade_concat(pool, parser->temp_dir, parser->brigade_limit,
ctx->param->upload, bb);
if (s != APR_SUCCESS) {
ctx->status = GEN_ERROR;
return s;
}
if (saw_eos) {
ctx->status = GEN_COMPLETE;
return APR_SUCCESS;
}
else
return APR_INCOMPLETE;
}
struct xml_ctx {
apr_xml_doc *doc;
apr_xml_parser *xml_parser;
enum {
XML_INCOMPLETE,
XML_COMPLETE,
XML_ERROR
} status;
};
APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser)
{
apr_pool_t *pool = hook->pool;
struct xml_ctx *ctx = hook->ctx;
apr_status_t s = APR_SUCCESS;
apr_bucket *e;
if (ctx == NULL) {
hook->ctx = ctx = apr_palloc(pool, sizeof *ctx);
ctx->doc = NULL;
ctx->xml_parser = apr_xml_parser_create(pool);
ctx->status = XML_INCOMPLETE;
}
PARSER_STATUS_CHECK(XML);
for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
e = APR_BUCKET_NEXT(e))
{
const char *data;
apr_size_t dlen;
if (APR_BUCKET_IS_EOS(e)) {
s = apr_xml_parser_done(ctx->xml_parser, &ctx->doc);
if (s == APR_SUCCESS) {
ctx->status = XML_COMPLETE;
if (hook->next)
s = apreq_hook_run(hook->next, param, bb);
}
else {
ctx->status = XML_ERROR;
}
return s;
}
else if (APR_BUCKET_IS_METADATA(e)) {
continue;
}
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if (s != APR_SUCCESS) {
ctx->status = XML_ERROR;
return s;
}
s = apr_xml_parser_feed(ctx->xml_parser, data, dlen);
if (s != APR_SUCCESS) {
ctx->status = XML_ERROR;
return s;
}
}
if (hook->next)
return apreq_hook_run(hook->next, param, bb);
return APR_SUCCESS;
}
APREQ_DECLARE_HOOK(apreq_hook_find_param)
{
apreq_hook_find_param_ctx_t *ctx = hook->ctx;
int is_final = (bb == NULL) || APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(bb));
apr_status_t s = (hook->next == NULL)
? APR_SUCCESS : apreq_hook_run(hook->next, param, bb);
if (is_final && s == APR_SUCCESS
&& strcasecmp(ctx->name, param->v.name) == 0) {
ctx->param = param;
ctx->prev->next = hook->next;
}
return s;
}

View File

@ -1,365 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include <assert.h>
#include "apreq_parser.h"
#include "apreq_error.h"
#include "apreq_util.h"
#define PARSER_STATUS_CHECK(PREFIX) do { \
if (ctx->status == PREFIX##_ERROR) \
return APREQ_ERROR_GENERAL; \
else if (ctx->status == PREFIX##_COMPLETE) \
return APR_SUCCESS; \
else if (bb == NULL) \
return APR_INCOMPLETE; \
} while (0);
struct hdr_ctx {
apr_bucket_brigade *bb;
apr_size_t nlen;
apr_size_t glen;
apr_size_t vlen;
enum {
HDR_NAME,
HDR_GAP,
HDR_VALUE,
HDR_NEWLINE,
HDR_CONTINUE,
HDR_COMPLETE,
HDR_ERROR
} status;
};
/********************* header parsing utils ********************/
static apr_status_t split_header_line(apreq_param_t **p,
apr_pool_t *pool,
apr_bucket_brigade *bb,
apr_size_t nlen,
apr_size_t glen,
apr_size_t vlen)
{
apreq_param_t *param;
apreq_value_t *v;
apr_bucket *e, *f;
apr_status_t s;
struct iovec vec[APREQ_DEFAULT_NELTS], *iov, *end;
apr_array_header_t arr;
char *dest;
const char *data;
apr_size_t dlen;
if (nlen == 0)
return APR_EBADARG;
param = apreq_param_make(pool, NULL, nlen, NULL, vlen - 1); /*drop (CR)LF */
*(const apreq_value_t **)&v = &param->v;
arr.pool = pool;
arr.elt_size = sizeof(struct iovec);
arr.nelts = 0;
arr.nalloc = APREQ_DEFAULT_NELTS;
arr.elts = (char *)vec;
e = APR_BRIGADE_FIRST(bb);
/* store name in a temporary iovec array */
while (nlen > 0) {
apr_size_t len;
end = apr_array_push(&arr);
s = apr_bucket_read(e, (const char **)&end->iov_base,
&len, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
assert(nlen >= len);
end->iov_len = len;
nlen -= len;
e = APR_BUCKET_NEXT(e);
}
/* skip gap */
while (glen > 0) {
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
assert(glen >= dlen);
glen -= dlen;
e = APR_BUCKET_NEXT(e);
}
/* copy value */
assert(vlen > 0);
dest = v->data;
while (vlen > 0) {
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
memcpy(dest, data, dlen);
dest += dlen;
assert(vlen >= dlen);
vlen -= dlen;
e = APR_BUCKET_NEXT(e);
}
assert(dest[-1] == '\n');
if (dest[-2] == '\r')
--dest;
dest[-1] = 0;
v->dlen = (dest - v->data) - 1;
/* write name */
v->name = dest;
iov = (struct iovec *)arr.elts;
while (iov <= end) {
memcpy(dest, iov->iov_base, iov->iov_len);
dest += iov->iov_len;
++iov;
}
*dest = 0;
nlen = dest - v->name;
while ((f = APR_BRIGADE_FIRST(bb)) != e)
apr_bucket_delete(f);
apreq_param_tainted_on(param);
*p = param;
return APR_SUCCESS;
}
APREQ_DECLARE_PARSER(apreq_parse_headers)
{
apr_pool_t *pool = parser->pool;
apr_bucket *e;
struct hdr_ctx *ctx;
if (parser->ctx == NULL) {
ctx = apr_pcalloc(pool, sizeof *ctx);
ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
parser->ctx = ctx;
ctx->status = HDR_NAME;
}
else
ctx = parser->ctx;
PARSER_STATUS_CHECK(HDR);
e = APR_BRIGADE_LAST(ctx->bb);
APR_BRIGADE_CONCAT(ctx->bb, bb);
parse_hdr_brigade:
/* parse the brigade for CRLF_CRLF-terminated header block,
* each time starting from the front of the brigade.
*/
for (e = APR_BUCKET_NEXT(e);
e != APR_BRIGADE_SENTINEL(ctx->bb);
e = APR_BUCKET_NEXT(e))
{
apr_size_t off = 0, dlen;
const char *data;
apr_status_t s;
apreq_param_t *param = NULL; /* silences gcc-4.0 warning */
if (APR_BUCKET_IS_EOS(e)) {
ctx->status = HDR_COMPLETE;
APR_BRIGADE_CONCAT(bb, ctx->bb);
return APR_SUCCESS;
}
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if ( s != APR_SUCCESS ) {
ctx->status = HDR_ERROR;
return s;
}
if (dlen == 0)
continue;
parse_hdr_bucket:
/* gap nlen = 13
* vvv glen = 3
* Sample-Header: grape vlen = 5
* ^^^^^^^^^^^^^ ^^^^^
* name value
*/
switch (ctx->status) {
case HDR_NAME:
while (off < dlen) {
switch (data[off++]) {
case '\n':
if (off < dlen)
apr_bucket_split(e, off);
e = APR_BUCKET_NEXT(e);
do {
apr_bucket *f = APR_BRIGADE_FIRST(ctx->bb);
apr_bucket_delete(f);
} while (e != APR_BRIGADE_FIRST(ctx->bb));
APR_BRIGADE_CONCAT(bb, ctx->bb);
ctx->status = HDR_COMPLETE;
return APR_SUCCESS;
case ':':
if (off > 1) {
apr_bucket_split(e, off - 1);
dlen -= off - 1;
data += off - 1;
off = 1;
e = APR_BUCKET_NEXT(e);
}
++ctx->glen;
ctx->status = HDR_GAP;
goto parse_hdr_bucket;
default:
++ctx->nlen;
}
}
break;
case HDR_GAP:
while (off < dlen) {
switch (data[off++]) {
case ' ':
case '\t':
++ctx->glen;
break;
case '\n':
ctx->status = HDR_NEWLINE;
goto parse_hdr_bucket;
default:
ctx->status = HDR_VALUE;
if (off > 1) {
apr_bucket_split(e, off - 1);
dlen -= off - 1;
data += off - 1;
off = 1;
e = APR_BUCKET_NEXT(e);
}
++ctx->vlen;
goto parse_hdr_bucket;
}
}
break;
case HDR_VALUE:
while (off < dlen) {
++ctx->vlen;
if (data[off++] == '\n') {
ctx->status = HDR_NEWLINE;
goto parse_hdr_bucket;
}
}
break;
case HDR_NEWLINE:
if (off == dlen)
break;
else {
switch (data[off]) {
case ' ':
case '\t':
ctx->status = HDR_CONTINUE;
++off;
++ctx->vlen;
break;
default:
/* can parse brigade now */
if (off > 0)
apr_bucket_split(e, off);
s = split_header_line(&param, pool, ctx->bb, ctx->nlen, ctx->glen, ctx->vlen);
if (parser->hook != NULL && s == APR_SUCCESS)
s = apreq_hook_run(parser->hook, param, NULL);
if (s != APR_SUCCESS) {
ctx->status = HDR_ERROR;
return s;
}
apreq_value_table_add(&param->v, t);
e = APR_BRIGADE_SENTINEL(ctx->bb);
ctx->status = HDR_NAME;
ctx->nlen = 0;
ctx->vlen = 0;
ctx->glen = 0;
goto parse_hdr_brigade;
}
/* cases ' ', '\t' fall through to HDR_CONTINUE */
}
case HDR_CONTINUE:
while (off < dlen) {
switch (data[off++]) {
case ' ':
case '\t':
++ctx->vlen;
break;
case '\n':
ctx->status = HDR_NEWLINE;
goto parse_hdr_bucket;
default:
ctx->status = HDR_VALUE;
++ctx->vlen;
goto parse_hdr_bucket;
}
}
break;
default:
; /* not reached */
}
}
apreq_brigade_setaside(ctx->bb,pool);
return APR_INCOMPLETE;
}

View File

@ -1,661 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_parser.h"
#include "apreq_error.h"
#include "apreq_util.h"
#include "apr_strings.h"
#include "apr_strmatch.h"
#ifndef CRLF
#define CRLF "\015\012"
#endif
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define PARSER_STATUS_CHECK(PREFIX) do { \
if (ctx->status == PREFIX##_ERROR) \
return APREQ_ERROR_GENERAL; \
else if (ctx->status == PREFIX##_COMPLETE) \
return APR_SUCCESS; \
else if (bb == NULL) \
return APR_INCOMPLETE; \
} while (0);
/* maximum recursion level in the mfd parser */
#define MAX_LEVEL 8
struct mfd_ctx {
apr_table_t *info;
apr_bucket_brigade *in;
apr_bucket_brigade *bb;
apreq_parser_t *hdr_parser;
apreq_parser_t *next_parser;
const apr_strmatch_pattern *pattern;
char *bdry;
enum {
MFD_INIT,
MFD_NEXTLINE,
MFD_HEADER,
MFD_POST_HEADER,
MFD_PARAM,
MFD_UPLOAD,
MFD_MIXED,
MFD_COMPLETE,
MFD_ERROR
} status;
apr_bucket *eos;
const char *param_name;
apreq_param_t *upload;
unsigned level;
};
/********************* multipart/form-data *********************/
APR_INLINE
static apr_status_t brigade_start_string(apr_bucket_brigade *bb,
const char *start_string)
{
apr_bucket *e;
apr_size_t slen = strlen(start_string);
for (e = APR_BRIGADE_FIRST(bb); e != APR_BRIGADE_SENTINEL(bb);
e = APR_BUCKET_NEXT(e))
{
const char *buf;
apr_status_t s, bytes_to_check;
apr_size_t blen;
if (slen == 0)
return APR_SUCCESS;
if (APR_BUCKET_IS_EOS(e))
return APR_EOF;
s = apr_bucket_read(e, &buf, &blen, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
if (blen == 0)
continue;
bytes_to_check = MIN(slen,blen);
if (strncmp(buf,start_string,bytes_to_check) != 0)
return APREQ_ERROR_GENERAL;
slen -= bytes_to_check;
start_string += bytes_to_check;
}
/* slen > 0, so brigade isn't large enough yet */
return APR_INCOMPLETE;
}
static apr_status_t split_on_bdry(apr_bucket_brigade *out,
apr_bucket_brigade *in,
const apr_strmatch_pattern *pattern,
const char *bdry)
{
apr_bucket *e = APR_BRIGADE_FIRST(in);
apr_size_t blen = strlen(bdry), off = 0;
while ( e != APR_BRIGADE_SENTINEL(in) ) {
apr_ssize_t idx;
apr_size_t len;
const char *buf;
apr_status_t s;
if (APR_BUCKET_IS_EOS(e))
return APR_EOF;
s = apr_bucket_read(e, &buf, &len, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
if (len == 0) {
apr_bucket *f = e;
e = APR_BUCKET_NEXT(e);
apr_bucket_delete(f);
continue;
}
look_for_boundary_up_front:
if (strncmp(bdry + off, buf, MIN(len, blen - off)) == 0) {
if ( len >= blen - off ) {
/* complete match */
if (len > blen - off)
apr_bucket_split(e, blen - off);
e = APR_BUCKET_NEXT(e);
do {
apr_bucket *f = APR_BRIGADE_FIRST(in);
apr_bucket_delete(f);
} while (APR_BRIGADE_FIRST(in) != e);
return APR_SUCCESS;
}
/* partial match */
off += len;
e = APR_BUCKET_NEXT(e);
continue;
}
else if (off > 0) {
/* prior (partial) strncmp failed,
* so we can move previous buckets across
* and retest buf against the full bdry.
*/
/* give hints to GCC by making the brigade volatile, otherwise the
* loop below will end up being endless. See:
* https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=193740
*/
apr_bucket_brigade * volatile in_v = in;
do {
apr_bucket *f = APR_BRIGADE_FIRST(in_v);
APR_BUCKET_REMOVE(f);
APR_BRIGADE_INSERT_TAIL(out, f);
} while (e != APR_BRIGADE_FIRST(in_v));
off = 0;
goto look_for_boundary_up_front;
}
if (pattern != NULL && len >= blen) {
const char *match = apr_strmatch(pattern, buf, len);
if (match != NULL)
idx = match - buf;
else {
idx = apreq_index(buf + len-blen, blen, bdry, blen,
APREQ_MATCH_PARTIAL);
if (idx >= 0)
idx += len-blen;
}
}
else
idx = apreq_index(buf, len, bdry, blen, APREQ_MATCH_PARTIAL);
/* Theoretically idx should never be 0 here, because we
* already tested the front of the brigade for a potential match.
* However, it doesn't hurt to allow for the possibility,
* since this will just start the whole loop over again.
*/
if (idx >= 0)
apr_bucket_split(e, idx);
APR_BUCKET_REMOVE(e);
APR_BRIGADE_INSERT_TAIL(out, e);
e = APR_BRIGADE_FIRST(in);
}
return APR_INCOMPLETE;
}
static
struct mfd_ctx * create_multipart_context(const char *content_type,
apr_pool_t *pool,
apr_bucket_alloc_t *ba,
apr_size_t brigade_limit,
const char *temp_dir,
unsigned level)
{
apr_status_t s;
apr_size_t blen;
struct mfd_ctx *ctx = apr_palloc(pool, sizeof *ctx);
char *ct = apr_pstrdup(pool, content_type);
ct = strchr(ct, ';');
if (ct == NULL)
return NULL; /* missing semicolon */
*ct++ = 0;
s = apreq_header_attribute(ct, "boundary", 8,
(const char **)&ctx->bdry, &blen);
if (s != APR_SUCCESS)
return NULL; /* missing boundary */
ctx->bdry[blen] = 0;
*--ctx->bdry = '-';
*--ctx->bdry = '-';
*--ctx->bdry = '\n';
*--ctx->bdry = '\r';
ctx->status = MFD_INIT;
ctx->pattern = apr_strmatch_precompile(pool, ctx->bdry, 1);
ctx->hdr_parser = apreq_parser_make(pool, ba, "",
apreq_parse_headers,
brigade_limit,
temp_dir, NULL, NULL);
ctx->info = NULL;
ctx->bb = apr_brigade_create(pool, ba);
ctx->in = apr_brigade_create(pool, ba);
ctx->eos = apr_bucket_eos_create(ba);
ctx->next_parser = NULL;
ctx->param_name = NULL;
ctx->upload = NULL;
ctx->level = level;
return ctx;
}
APREQ_DECLARE_PARSER(apreq_parse_multipart)
{
apr_pool_t *pool = parser->pool;
apr_bucket_alloc_t *ba = parser->bucket_alloc;
struct mfd_ctx *ctx = parser->ctx;
apr_status_t s;
if (ctx == NULL) {
ctx = create_multipart_context(parser->content_type,
pool, ba,
parser->brigade_limit,
parser->temp_dir, 1);
if (ctx == NULL)
return APREQ_ERROR_GENERAL;
parser->ctx = ctx;
}
PARSER_STATUS_CHECK(MFD);
APR_BRIGADE_CONCAT(ctx->in, bb);
mfd_parse_brigade:
switch (ctx->status) {
case MFD_INIT:
{
s = split_on_bdry(ctx->bb, ctx->in, NULL, ctx->bdry + 2);
if (s != APR_SUCCESS) {
apreq_brigade_setaside(ctx->in, pool);
apreq_brigade_setaside(ctx->bb, pool);
return s;
}
ctx->status = MFD_NEXTLINE;
/* Be polite and return any preamble text to the caller. */
APR_BRIGADE_CONCAT(bb, ctx->bb);
}
/* fall through */
case MFD_NEXTLINE:
{
s = split_on_bdry(ctx->bb, ctx->in, NULL, CRLF);
if (s == APR_EOF) {
ctx->status = MFD_COMPLETE;
return APR_SUCCESS;
}
if (s != APR_SUCCESS) {
apreq_brigade_setaside(ctx->in, pool);
apreq_brigade_setaside(ctx->bb, pool);
return s;
}
if (!APR_BRIGADE_EMPTY(ctx->bb)) {
char *line;
apr_size_t len;
apr_brigade_pflatten(ctx->bb, &line, &len, pool);
if (len >= 2 && strncmp(line, "--", 2) == 0) {
APR_BRIGADE_CONCAT(bb, ctx->in);
ctx->status = MFD_COMPLETE;
return APR_SUCCESS;
}
apr_brigade_cleanup(ctx->bb);
}
ctx->status = MFD_HEADER;
ctx->info = NULL;
}
/* fall through */
case MFD_HEADER:
{
if (ctx->info == NULL) {
ctx->info = apr_table_make(pool, APREQ_DEFAULT_NELTS);
/* flush out header parser internal structs for reuse */
ctx->hdr_parser->ctx = NULL;
}
s = apreq_parser_run(ctx->hdr_parser, ctx->info, ctx->in);
switch (s) {
case APR_SUCCESS:
ctx->status = MFD_POST_HEADER;
break;
case APR_INCOMPLETE:
apreq_brigade_setaside(ctx->in, pool);
return APR_INCOMPLETE;
default:
ctx->status = MFD_ERROR;
return s;
}
}
/* fall through */
case MFD_POST_HEADER:
{
/* Must handle special case of missing CRLF (mainly
* coming from empty file uploads). See RFC2065 S5.1.1:
*
* body-part = MIME-part-header [CRLF *OCTET]
*
* So the CRLF we already matched in MFD_HEADER may have been
* part of the boundary string! Both Konqueror (v??) and
* Mozilla-0.97 are known to emit such blocks.
*
* Here we first check for this condition with
* brigade_start_string, and prefix the brigade with
* an additional CRLF bucket if necessary.
*/
const char *cd, *ct, *name, *filename;
apr_size_t nlen, flen;
apr_bucket *e;
switch (brigade_start_string(ctx->in, ctx->bdry + 2)) {
case APR_INCOMPLETE:
apreq_brigade_setaside(ctx->in, pool);
return APR_INCOMPLETE;
case APR_SUCCESS:
/* part has no body- return CRLF to front */
e = apr_bucket_immortal_create(CRLF, 2,
ctx->bb->bucket_alloc);
APR_BRIGADE_INSERT_HEAD(ctx->in, e);
break;
default:
; /* has body, ok */
}
cd = apr_table_get(ctx->info, "Content-Disposition");
/* First check to see if must descend into a new multipart
* block. If we do, create a new parser and pass control
* to it.
*/
ct = apr_table_get(ctx->info, "Content-Type");
if (ct != NULL && strncmp(ct, "multipart/", 10) == 0) {
struct mfd_ctx *next_ctx;
if (ctx->level >= MAX_LEVEL) {
ctx->status = MFD_ERROR;
goto mfd_parse_brigade;
}
next_ctx = create_multipart_context(ct, pool, ba,
parser->brigade_limit,
parser->temp_dir,
ctx->level + 1);
next_ctx->param_name = "";
if (cd != NULL) {
s = apreq_header_attribute(cd, "name", 4,
&name, &nlen);
if (s == APR_SUCCESS) {
next_ctx->param_name
= apr_pstrmemdup(pool, name, nlen);
}
else {
const char *cid = apr_table_get(ctx->info,
"Content-ID");
if (cid != NULL)
next_ctx->param_name = apr_pstrdup(pool, cid);
}
}
ctx->next_parser = apreq_parser_make(pool, ba, ct,
apreq_parse_multipart,
parser->brigade_limit,
parser->temp_dir,
parser->hook,
next_ctx);
ctx->status = MFD_MIXED;
goto mfd_parse_brigade;
}
/* Look for a normal form-data part. */
if (cd != NULL && strncmp(cd, "form-data", 9) == 0) {
s = apreq_header_attribute(cd, "name", 4, &name, &nlen);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
goto mfd_parse_brigade;
}
s = apreq_header_attribute(cd, "filename",
8, &filename, &flen);
if (s == APR_SUCCESS) {
apreq_param_t *param;
param = apreq_param_make(pool, name, nlen,
filename, flen);
apreq_param_tainted_on(param);
param->info = ctx->info;
param->upload
= apr_brigade_create(pool, ctx->bb->bucket_alloc);
ctx->upload = param;
ctx->status = MFD_UPLOAD;
goto mfd_parse_brigade;
}
else {
ctx->param_name = apr_pstrmemdup(pool, name, nlen);
ctx->status = MFD_PARAM;
/* fall thru */
}
}
/* else check for a file part in a multipart section */
else if (cd != NULL && strncmp(cd, "file", 4) == 0) {
apreq_param_t *param;
s = apreq_header_attribute(cd, "filename",
8, &filename, &flen);
if (s != APR_SUCCESS || ctx->param_name == NULL) {
ctx->status = MFD_ERROR;
goto mfd_parse_brigade;
}
name = ctx->param_name;
nlen = strlen(name);
param = apreq_param_make(pool, name, nlen,
filename, flen);
apreq_param_tainted_on(param);
param->info = ctx->info;
param->upload = apr_brigade_create(pool,
ctx->bb->bucket_alloc);
ctx->upload = param;
ctx->status = MFD_UPLOAD;
goto mfd_parse_brigade;
}
/* otherwise look for Content-ID in multipart/mixed case */
else {
const char *cid = apr_table_get(ctx->info, "Content-ID");
apreq_param_t *param;
if (cid != NULL) {
name = cid;
nlen = strlen(name);
}
else {
name = "";
nlen = 0;
}
filename = "";
flen = 0;
param = apreq_param_make(pool, name, nlen,
filename, flen);
apreq_param_tainted_on(param);
param->info = ctx->info;
param->upload = apr_brigade_create(pool,
ctx->bb->bucket_alloc);
ctx->upload = param;
ctx->status = MFD_UPLOAD;
goto mfd_parse_brigade;
}
}
/* fall through */
case MFD_PARAM:
{
apreq_param_t *param;
apreq_value_t *v;
apr_size_t len;
apr_off_t off;
s = split_on_bdry(ctx->bb, ctx->in, ctx->pattern, ctx->bdry);
switch (s) {
case APR_INCOMPLETE:
apreq_brigade_setaside(ctx->in, pool);
apreq_brigade_setaside(ctx->bb, pool);
return s;
case APR_SUCCESS:
s = apr_brigade_length(ctx->bb, 1, &off);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
return s;
}
len = off;
param = apreq_param_make(pool, ctx->param_name,
strlen(ctx->param_name),
NULL, len);
apreq_param_tainted_on(param);
param->info = ctx->info;
*(const apreq_value_t **)&v = &param->v;
apr_brigade_flatten(ctx->bb, v->data, &len);
v->data[len] = 0;
if (parser->hook != NULL) {
s = apreq_hook_run(parser->hook, param, NULL);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
return s;
}
}
apreq_param_charset_set(param,
apreq_charset_divine(v->data, len));
apreq_value_table_add(v, t);
ctx->status = MFD_NEXTLINE;
ctx->param_name = NULL;
apr_brigade_cleanup(ctx->bb);
goto mfd_parse_brigade;
default:
ctx->status = MFD_ERROR;
return s;
}
}
break; /* not reached */
case MFD_UPLOAD:
{
apreq_param_t *param = ctx->upload;
s = split_on_bdry(ctx->bb, ctx->in, ctx->pattern, ctx->bdry);
switch (s) {
case APR_INCOMPLETE:
if (parser->hook != NULL) {
s = apreq_hook_run(parser->hook, param, ctx->bb);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
return s;
}
}
apreq_brigade_setaside(ctx->bb, pool);
apreq_brigade_setaside(ctx->in, pool);
s = apreq_brigade_concat(pool, parser->temp_dir,
parser->brigade_limit,
param->upload, ctx->bb);
return (s == APR_SUCCESS) ? APR_INCOMPLETE : s;
case APR_SUCCESS:
if (parser->hook != NULL) {
APR_BRIGADE_INSERT_TAIL(ctx->bb, ctx->eos);
s = apreq_hook_run(parser->hook, param, ctx->bb);
APR_BUCKET_REMOVE(ctx->eos);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
return s;
}
}
apreq_value_table_add(&param->v, t);
apreq_brigade_setaside(ctx->bb, pool);
s = apreq_brigade_concat(pool, parser->temp_dir,
parser->brigade_limit,
param->upload, ctx->bb);
if (s != APR_SUCCESS)
return s;
ctx->status = MFD_NEXTLINE;
goto mfd_parse_brigade;
default:
ctx->status = MFD_ERROR;
return s;
}
}
break; /* not reached */
case MFD_MIXED:
{
s = apreq_parser_run(ctx->next_parser, t, ctx->in);
switch (s) {
case APR_SUCCESS:
ctx->status = MFD_INIT;
ctx->param_name = NULL;
goto mfd_parse_brigade;
case APR_INCOMPLETE:
APR_BRIGADE_CONCAT(bb, ctx->in);
return APR_INCOMPLETE;
default:
ctx->status = MFD_ERROR;
return s;
}
}
break; /* not reached */
default:
return APREQ_ERROR_GENERAL;
}
return APR_INCOMPLETE;
}

View File

@ -1,275 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_parser.h"
#include "apreq_util.h"
#include "apreq_error.h"
#define PARSER_STATUS_CHECK(PREFIX) do { \
if (ctx->status == PREFIX##_ERROR) \
return APREQ_ERROR_GENERAL; \
else if (ctx->status == PREFIX##_COMPLETE) \
return APR_SUCCESS; \
else if (bb == NULL) \
return APR_INCOMPLETE; \
} while (0);
struct url_ctx {
apr_bucket_brigade *bb;
apr_size_t nlen;
apr_size_t vlen;
enum {
URL_NAME,
URL_VALUE,
URL_COMPLETE,
URL_ERROR
} status;
};
/******************** application/x-www-form-urlencoded ********************/
static apr_status_t split_urlword(apreq_param_t **p, apr_pool_t *pool,
apr_bucket_brigade *bb,
apr_size_t nlen,
apr_size_t vlen)
{
apreq_param_t *param;
apreq_value_t *v;
apr_bucket *e, *f;
apr_status_t s;
struct iovec vec[APREQ_DEFAULT_NELTS];
apr_array_header_t arr;
apr_size_t mark;
apreq_charset_t charset;
if (nlen == 0)
return APR_EBADARG;
param = apreq_param_make(pool, NULL, nlen, NULL, vlen);
*(const apreq_value_t **)&v = &param->v;
arr.pool = pool;
arr.elt_size = sizeof(struct iovec);
arr.nelts = 0;
arr.nalloc = APREQ_DEFAULT_NELTS;
arr.elts = (char *)vec;
++nlen, ++vlen;
e = APR_BRIGADE_FIRST(bb);
while (!APR_BUCKET_IS_EOS(e)) {
struct iovec *iov = apr_array_push(&arr);
apr_size_t len;
s = apr_bucket_read(e, (const char **)&iov->iov_base,
&len, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
iov->iov_len = len;
nlen -= len;
e = APR_BUCKET_NEXT(e);
if (nlen == 0) {
iov->iov_len--;
break;
}
}
mark = arr.nelts;
while (!APR_BUCKET_IS_EOS(e)) {
struct iovec *iov = apr_array_push(&arr);
apr_size_t len;
s = apr_bucket_read(e, (const char **)&iov->iov_base,
&len, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
iov->iov_len = len;
vlen -= len;
e = APR_BUCKET_NEXT(e);
if (vlen == 0) {
iov->iov_len--;
break;
}
}
s = apreq_decodev(v->data, &vlen,
(struct iovec *)arr.elts + mark, arr.nelts - mark);
if (s != APR_SUCCESS)
return s;
charset = apreq_charset_divine(v->data, vlen);
v->name = v->data + vlen + 1;
v->dlen = vlen;
s = apreq_decodev(v->name, &nlen, (struct iovec *)arr.elts, mark);
if (s != APR_SUCCESS)
return s;
switch (apreq_charset_divine(v->name, nlen)) {
case APREQ_CHARSET_UTF8:
if (charset == APREQ_CHARSET_ASCII)
charset = APREQ_CHARSET_UTF8;
case APREQ_CHARSET_ASCII:
break;
case APREQ_CHARSET_LATIN1:
if (charset != APREQ_CHARSET_CP1252)
charset = APREQ_CHARSET_LATIN1;
break;
case APREQ_CHARSET_CP1252:
charset = APREQ_CHARSET_CP1252;
}
v->nlen = nlen;
while ((f = APR_BRIGADE_FIRST(bb)) != e)
apr_bucket_delete(f);
apreq_param_tainted_on(param);
apreq_param_charset_set(param, charset);
*p = param;
return APR_SUCCESS;
}
APREQ_DECLARE_PARSER(apreq_parse_urlencoded)
{
apr_pool_t *pool = parser->pool;
apr_bucket *e;
struct url_ctx *ctx;
if (parser->ctx == NULL) {
ctx = apr_pcalloc(pool, sizeof *ctx);
ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
parser->ctx = ctx;
ctx->status = URL_NAME;
}
else
ctx = parser->ctx;
PARSER_STATUS_CHECK(URL);
e = APR_BRIGADE_LAST(ctx->bb);
APR_BRIGADE_CONCAT(ctx->bb, bb);
parse_url_brigade:
for (e = APR_BUCKET_NEXT(e);
e != APR_BRIGADE_SENTINEL(ctx->bb);
e = APR_BUCKET_NEXT(e))
{
apreq_param_t *param;
apr_size_t off = 0, dlen;
const char *data;
apr_status_t s;
if (APR_BUCKET_IS_EOS(e)) {
if (ctx->status == URL_NAME) {
s = APR_SUCCESS;
}
else {
s = split_urlword(&param, pool, ctx->bb, ctx->nlen, ctx->vlen);
if (parser->hook != NULL && s == APR_SUCCESS)
s = apreq_hook_run(parser->hook, param, NULL);
if (s == APR_SUCCESS) {
apreq_value_table_add(&param->v, t);
ctx->status = URL_COMPLETE;
}
else {
ctx->status = URL_ERROR;
}
}
APR_BRIGADE_CONCAT(bb, ctx->bb);
return s;
}
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if ( s != APR_SUCCESS ) {
ctx->status = URL_ERROR;
return s;
}
parse_url_bucket:
switch (ctx->status) {
case URL_NAME:
while (off < dlen) {
switch (data[off++]) {
case '=':
apr_bucket_split(e, off);
dlen -= off;
data += off;
off = 0;
e = APR_BUCKET_NEXT(e);
ctx->status = URL_VALUE;
goto parse_url_bucket;
default:
++ctx->nlen;
}
}
break;
case URL_VALUE:
while (off < dlen) {
switch (data[off++]) {
case '&':
case ';':
apr_bucket_split(e, off);
s = split_urlword(&param, pool, ctx->bb,
ctx->nlen, ctx->vlen);
if (parser->hook != NULL && s == APR_SUCCESS)
s = apreq_hook_run(parser->hook, param, NULL);
if (s != APR_SUCCESS) {
ctx->status = URL_ERROR;
return s;
}
apreq_value_table_add(&param->v, t);
ctx->status = URL_NAME;
ctx->nlen = 0;
ctx->vlen = 0;
e = APR_BRIGADE_SENTINEL(ctx->bb);
goto parse_url_brigade;
default:
++ctx->vlen;
}
}
break;
default:
; /* not reached */
}
}
apreq_brigade_setaside(ctx->bb, pool);
return APR_INCOMPLETE;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,36 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#include "apreq_version.h"
#include "apr_general.h" /* for APR_STRINGIFY */
APREQ_DECLARE(void) apreq_version(apr_version_t *pvsn)
{
pvsn->major = APREQ_MAJOR_VERSION;
pvsn->minor = APREQ_MINOR_VERSION;
pvsn->patch = APREQ_PATCH_VERSION;
#ifdef APREQ_IS_DEV_VERSION
pvsn->is_dev = 1;
#else
pvsn->is_dev = 0;
#endif
}
APREQ_DECLARE(const char *) apreq_version_string(void)
{
return APREQ_VERSION_STRING;
}