mirror of
https://github.com/apache/httpd.git
synced 2025-07-29 12:37:06 +00:00
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:
@ -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 */
|
@ -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*/
|
||||
|
||||
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
@ -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;
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
@ -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;
|
||||
}
|
||||
|
@ -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 = ¶m->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(¶m, pool, start, nlen, vlen);
|
||||
if (s != APR_SUCCESS)
|
||||
return s;
|
||||
|
||||
apreq_param_tainted_on(param);
|
||||
apreq_value_table_add(¶m->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, ¶m, body, name, NULL);
|
||||
return param;
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 = ¶m->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(¶m, 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(¶m->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;
|
||||
}
|
@ -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 = ¶m->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(¶m->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;
|
||||
}
|
@ -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 = ¶m->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(¶m, 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(¶m->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(¶m, 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(¶m->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
@ -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;
|
||||
}
|
Reference in New Issue
Block a user