Return-Path: Delivered-To: apmail-httpd-apreq-cvs-archive@www.apache.org Received: (qmail 73709 invoked from network); 24 Feb 2006 18:57:20 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 24 Feb 2006 18:57:20 -0000 Received: (qmail 80098 invoked by uid 500); 24 Feb 2006 18:57:18 -0000 Delivered-To: apmail-httpd-apreq-cvs-archive@httpd.apache.org Received: (qmail 80021 invoked by uid 500); 24 Feb 2006 18:57:17 -0000 Mailing-List: contact apreq-cvs-help@httpd.apache.org; run by ezmlm Precedence: bulk Reply-To: apreq-dev@httpd.apache.org List-Post: List-Help: List-Unsubscribe: List-Id: Delivered-To: mailing list apreq-cvs@httpd.apache.org Received: (qmail 79976 invoked by uid 99); 24 Feb 2006 18:57:17 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 24 Feb 2006 10:57:17 -0800 X-ASF-Spam-Status: No, hits=-9.4 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from [209.237.227.194] (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.29) with SMTP; Fri, 24 Feb 2006 10:57:13 -0800 Received: (qmail 73473 invoked by uid 65534); 24 Feb 2006 18:56:52 -0000 Message-ID: <20060224185652.73471.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r380784 [2/4] - in /httpd/apreq/branches/apr-build-system: ./ build/ include/ library/ module/ module/apache2/ Date: Fri, 24 Feb 2006 18:56:38 -0000 To: apreq-cvs@httpd.apache.org From: joes@apache.org X-Mailer: svnmailer-1.0.7 X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Added: httpd/apreq/branches/apr-build-system/include/apreq_parser.h URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/include/apreq_parser.h?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/include/apreq_parser.h (added) +++ httpd/apreq/branches/apr-build-system/include/apreq_parser.h Fri Feb 24 10:56:34 2006 @@ -0,0 +1,286 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef APREQ_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); + +/** + * Special purpose utility for locating a parameter + * during parsing. The hook's ctx shoud be initialized + * to a const char *, which is a pointer to the desired + * param name. The hook's ctx will be reassigned to the + * first param found. + * + * @remarks When used, this should always be the first hook + * invoked, so add it manually as parser->hook instead of + * using apreq_parser_add_hook. + */ +APREQ_DECLARE_HOOK(apreq_hook_find_param); + + +#ifdef __cplusplus +} + +#endif +#endif /* APREQ_PARSERS_H */ Propchange: httpd/apreq/branches/apr-build-system/include/apreq_parser.h ------------------------------------------------------------------------------ svn:eol-style = native Added: httpd/apreq/branches/apr-build-system/include/apreq_util.h URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/include/apreq_util.h?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/include/apreq_util.h (added) +++ httpd/apreq/branches/apr-build-system/include/apreq_util.h Fri Feb 24 10:56:34 2006 @@ -0,0 +1,442 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef APREQ_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 In the future, this function may do something + * intelligent with file buckets. + */ + +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 */ Propchange: httpd/apreq/branches/apr-build-system/include/apreq_util.h ------------------------------------------------------------------------------ svn:eol-style = native Added: httpd/apreq/branches/apr-build-system/include/apreq_version.h URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/include/apreq_version.h?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/include/apreq_version.h (added) +++ httpd/apreq/branches/apr-build-system/include/apreq_version.h Fri Feb 24 10:56:34 2006 @@ -0,0 +1,104 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#ifndef APREQ_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 5 + +/** patch level */ +#define APREQ_PATCH_VERSION 8 + +/** + * 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 */ Propchange: httpd/apreq/branches/apr-build-system/include/apreq_version.h ------------------------------------------------------------------------------ svn:eol-style = native Propchange: httpd/apreq/branches/apr-build-system/library/ ------------------------------------------------------------------------------ --- svn:ignore (added) +++ svn:ignore Fri Feb 24 10:56:34 2006 @@ -0,0 +1 @@ +.libs Added: httpd/apreq/branches/apr-build-system/library/cookie.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/cookie.c?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/library/cookie.c (added) +++ httpd/apreq/branches/apr-build-system/library/cookie.c Fri Feb 24 10:56:34 2006 @@ -0,0 +1,466 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#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; + + }; + + 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; + + hdr = *data; + + while (apr_isspace(*hdr) || *hdr == '=') + ++hdr; + + key = strchr(hdr, '='); + + if (key == NULL) + return APREQ_ERROR_NOTOKEN; + + val = key + 1; + + do --key; + while (key > hdr && apr_isspace(*key)); + + *n = key; + + while (key >= hdr && !apr_isspace(*key)) + --key; + + *nlen = *n - key; + *n = key + 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 */ + 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; + + parse_cookie_header: + + c = NULL; + version = NETSCAPE; + + while (apr_isspace(*hdr)) + ++hdr; + + + if (*hdr == '$') { + /* XXX cheat: assume "$..." => "$Version" => RFC Cookie header */ + version = RFC; + skip_version_string: + switch (*hdr++) { + case 0: + return APR_SUCCESS; + 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 APR_SUCCESS; + + case ',': + ++hdr; + if (c != NULL) { + ADD_COOKIE(j, c); + } + goto parse_cookie_header; + + case '$': + if (c == NULL) { + return APREQ_ERROR_BADCHAR; + } + else if (version == NETSCAPE) { + return APREQ_ERROR_MISMATCH; + } + + ++hdr; + status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 1); + if (status != APR_SUCCESS) + return status; + + status = apreq_cookie_attr(p, c, name, nlen, value, vlen); + + switch (status) { + case APR_ENOTIMPL: + /* XXX: skip unrecognized attr? Not really correct, + but for now, just fall through */ + + case APR_SUCCESS: + break; + default: + return status; + } + + break; + + default: + if (c != NULL) { + ADD_COOKIE(j, c); + } + + status = get_pair(p, &hdr, &name, &nlen, &value, &vlen, 0); + + if (status != APR_SUCCESS) + return status; + + c = apreq_cookie_make(p, name, nlen, value, vlen); + apreq_cookie_tainted_on(c); + if (version != NETSCAPE) + apreq_cookie_version_set(c, version); + } + } + + /* NOT REACHED */ + return APREQ_ERROR_GENERAL; +} + + +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"); + + 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"); + + 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; +} + Propchange: httpd/apreq/branches/apr-build-system/library/cookie.c ------------------------------------------------------------------------------ svn:eol-style = native Added: httpd/apreq/branches/apr-build-system/library/error.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/error.c?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/library/error.c (added) +++ httpd/apreq/branches/apr-build-system/library/error.c Fri Feb 24 10:56:34 2006 @@ -0,0 +1,104 @@ +/* Copyright 2000-2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#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)); +} + Propchange: httpd/apreq/branches/apr-build-system/library/error.c ------------------------------------------------------------------------------ svn:eol-style = native Added: httpd/apreq/branches/apr-build-system/library/module.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/module.c?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/library/module.c (added) +++ httpd/apreq/branches/apr-build-system/library/module.c Fri Feb 24 10:56:34 2006 @@ -0,0 +1,52 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#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; + +} + + +/** @} */ Propchange: httpd/apreq/branches/apr-build-system/library/module.c ------------------------------------------------------------------------------ svn:eol-style = native Added: httpd/apreq/branches/apr-build-system/library/module_cgi.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/module_cgi.c?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/library/module_cgi.c (added) +++ httpd/apreq/branches/apr-build-system/library/module_cgi.c Fri Feb 24 10:56:34 2006 @@ -0,0 +1,688 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +#include + +#include "apreq_module.h" +#include "apreq_error.h" +#include "apr_strings.h" +#include "apr_lib.h" +#include "apr_env.h" +#include "apreq_util.h" + +#define USER_DATA_KEY "apreq" + +/* Parroting APLOG_* ... */ + +#define CGILOG_EMERG 0 /* system is unusable */ +#define CGILOG_ALERT 1 /* action must be taken immediately */ +#define CGILOG_CRIT 2 /* critical conditions */ +#define CGILOG_ERR 3 /* error conditions */ +#define CGILOG_WARNING 4 /* warning conditions */ +#define CGILOG_NOTICE 5 /* normal but significant condition */ +#define CGILOG_INFO 6 /* informational */ +#define CGILOG_DEBUG 7 /* debug-level messages */ + +#define CGILOG_LEVELMASK 7 +#define CGILOG_MARK __FILE__, __LINE__ + + + + +struct cgi_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; + apreq_hook_t *hook_queue; + apreq_hook_t *find_param; + + const char *temp_dir; + apr_size_t brigade_limit; + apr_uint64_t read_limit; + apr_uint64_t bytes_read; + + apr_bucket_brigade *in; + apr_bucket_brigade *tmpbb; + +}; + +#define CRLF "\015\012" + +typedef struct { + const char *t_name; + int t_val; +} TRANS; + +static const TRANS priorities[] = { + {"emerg", CGILOG_EMERG}, + {"alert", CGILOG_ALERT}, + {"crit", CGILOG_CRIT}, + {"error", CGILOG_ERR}, + {"warn", CGILOG_WARNING}, + {"notice", CGILOG_NOTICE}, + {"info", CGILOG_INFO}, + {"debug", CGILOG_DEBUG}, + {NULL, -1}, +}; + +static const char *cgi_header_in(apreq_handle_t *handle, + const char *name) +{ + apr_pool_t *p = handle->pool; + char *key = apr_pstrcat(p, "HTTP_", name, NULL); + char *k, *value = NULL; + for (k = key; *k; ++k) { + if (*k == '-') + *k = '_'; + else + *k = apr_toupper(*k); + } + + if (!strcmp(key, "HTTP_CONTENT_TYPE") + || !strcmp(key, "HTTP_CONTENT_LENGTH")) + { + key += 5; /* strlen("HTTP_") */ + } + + apr_env_get(&value, key, p); + + return value; +} + + + + +static void cgi_log_error(const char *file, int line, int level, + apr_status_t status, apreq_handle_t *handle, + const char *fmt, ...) +{ + apr_pool_t *p = handle->pool; + char buf[256]; + char *log_level_string, *ra; + const char *remote_addr; + unsigned log_level = CGILOG_WARNING; + char date[APR_CTIME_LEN]; + va_list vp; +#ifndef WIN32 + apr_file_t *err; +#endif + + va_start(vp, fmt); + + if (apr_env_get(&log_level_string, "LOG_LEVEL", p) == APR_SUCCESS) + log_level = (log_level_string[0] - '0'); + + level &= CGILOG_LEVELMASK; + + if (level < (int)log_level) { + + if (apr_env_get(&ra, "REMOTE_ADDR", p) == APR_SUCCESS) + remote_addr = ra; + else + remote_addr = "address unavailable"; + + apr_ctime(date, apr_time_now()); + +#ifndef WIN32 + + apr_file_open_stderr(&err, p); + apr_file_printf(err, "[%s] [%s] [%s] %s(%d): %s: %s\n", + date, priorities[level].t_name, remote_addr, file, line, + apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp)); + apr_file_flush(err); + +#else + fprintf(stderr, "[%s] [%s] [%s] %s(%d): %s: %s\n", + date, priorities[level].t_name, remote_addr, file, line, + apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp)); +#endif + } + + va_end(vp); + +} + + +APR_INLINE +static const char *cgi_query_string(apreq_handle_t *handle) +{ + char *value = NULL, qs[] = "QUERY_STRING"; + apr_env_get(&value, qs, handle->pool); + return value; +} + + +static void init_body(apreq_handle_t *handle) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + const char *cl_header = cgi_header_in(handle, "Content-Length"); + apr_bucket_alloc_t *ba = handle->bucket_alloc; + apr_pool_t *pool = handle->pool; + apr_file_t *file; + apr_bucket *eos, *pipe; + + req->body = apr_table_make(pool, APREQ_DEFAULT_NELTS); + + if (cl_header != NULL) { + char *dummy; + apr_int64_t content_length = apr_strtoi64(cl_header, &dummy, 0); + + if (dummy == NULL || *dummy != 0) { + req->body_status = APREQ_ERROR_BADHEADER; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle, + "Invalid Content-Length header (%s)", cl_header); + return; + } + else if ((apr_uint64_t)content_length > req->read_limit) { + req->body_status = APREQ_ERROR_OVERLIMIT; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle, + "Content-Length header (%s) exceeds configured " + "max_body limit (%" APR_UINT64_T_FMT ")", + cl_header, req->read_limit); + return; + } + } + + if (req->parser == NULL) { + const char *ct_header = cgi_header_in(handle, "Content-Type"); + + if (ct_header != NULL) { + apreq_parser_function_t pf = apreq_parser(ct_header); + + if (pf != NULL) { + req->parser = apreq_parser_make(pool, + ba, + ct_header, + pf, + req->brigade_limit, + req->temp_dir, + req->hook_queue, + NULL); + } + else { + req->body_status = APREQ_ERROR_NOPARSER; + return; + } + } + else { + req->body_status = APREQ_ERROR_NOHEADER; + return; + } + } + else { + if (req->parser->brigade_limit > req->brigade_limit) + req->parser->brigade_limit = req->brigade_limit; + if (req->temp_dir != NULL) + req->parser->temp_dir = req->temp_dir; + if (req->hook_queue != NULL) + apreq_parser_add_hook(req->parser, req->hook_queue); + } + + req->hook_queue = NULL; + req->in = apr_brigade_create(pool, ba); + req->tmpbb = apr_brigade_create(pool, ba); + + apr_file_open_stdin(&file, pool); // error status? + pipe = apr_bucket_pipe_create(file, ba); + eos = apr_bucket_eos_create(ba); + APR_BRIGADE_INSERT_HEAD(req->in, pipe); + APR_BRIGADE_INSERT_TAIL(req->in, eos); + + req->body_status = APR_INCOMPLETE; + +} + +static apr_status_t cgi_read(apreq_handle_t *handle, + apr_off_t bytes) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + apr_bucket *e; + apr_status_t s; + + if (req->body_status == APR_EINIT) + init_body(handle); + + 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; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, + handle, "Bytes read (%" APR_UINT64_T_FMT + ") exceeds configured limit (%" APR_UINT64_T_FMT ")", + req->bytes_read, req->read_limit); + 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; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle, + "Bytes read (%" APR_UINT64_T_FMT + ") exceeds configured limit (%" APR_UINT64_T_FMT ")", + req->bytes_read, req->read_limit); + + 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 cgi_jar(apreq_handle_t *handle, + const apr_table_t **t) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + + if (req->jar_status == APR_EINIT) { + const char *cookies = cgi_header_in(handle, "Cookie"); + if (cookies != NULL) { + req->jar = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS); + req->jar_status = + apreq_parse_cookie_header(handle->pool, req->jar, cookies); + } + else + req->jar_status = APREQ_ERROR_NODATA; + } + + *t = req->jar; + return req->jar_status; +} + +static apr_status_t cgi_args(apreq_handle_t *handle, + const apr_table_t **t) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + + if (req->args_status == APR_EINIT) { + const char *qs = cgi_query_string(handle); + if (qs != NULL) { + req->args = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS); + req->args_status = + apreq_parse_query_string(handle->pool, req->args, qs); + } + else + req->args_status = APREQ_ERROR_NODATA; + } + + *t = req->args; + return req->args_status; +} + + + + +static apreq_cookie_t *cgi_jar_get(apreq_handle_t *handle, + const char *name) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + const apr_table_t *t; + const char *val; + + if (req->jar_status == APR_EINIT) + cgi_jar(handle, &t); + else + t = req->jar; + + if (t == NULL) + return NULL; + + val = apr_table_get(t, name); + if (val == NULL) + return NULL; + + return apreq_value_to_cookie(val); +} + +static apreq_param_t *cgi_args_get(apreq_handle_t *handle, + const char *name) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + const apr_table_t *t; + const char *val; + + if (req->args_status == APR_EINIT) + cgi_args(handle, &t); + else + t = req->args; + + if (t == NULL) + return NULL; + + val = apr_table_get(t, name); + if (val == NULL) + return NULL; + + return apreq_value_to_param(val); +} + + + +static apr_status_t cgi_body(apreq_handle_t *handle, + const apr_table_t **t) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + + switch (req->body_status) { + + case APR_EINIT: + init_body(handle); + if (req->body_status != APR_INCOMPLETE) + break; + + case APR_INCOMPLETE: + while (cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE) + == APR_INCOMPLETE) + ; /*loop*/ + } + + *t = req->body; + return req->body_status; +} + +static apreq_param_t *cgi_body_get(apreq_handle_t *handle, + const char *name) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + const char *val; + apreq_hook_t *h; + + switch (req->body_status) { + + case APR_SUCCESS: + + val = apr_table_get(req->body, name); + if (val != NULL) + return apreq_value_to_param(val); + return NULL; + + + case APR_EINIT: + + init_body(handle); + if (req->body_status != APR_INCOMPLETE) + return NULL; + cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE); + + + case APR_INCOMPLETE: + + val = apr_table_get(req->body, name); + if (val != NULL) + return apreq_value_to_param(val); + + /* Not seen yet, so we need to scan for + param while prefetching the body */ + + if (req->find_param == NULL) + req->find_param = apreq_hook_make(handle->pool, + apreq_hook_find_param, + NULL, NULL); + h = req->find_param; + h->next = req->parser->hook; + req->parser->hook = h; + *(const char **)&h->ctx = name; + + do { + cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE); + if (h->ctx != name) { + req->parser->hook = h->next; + return h->ctx; + } + } while (req->body_status == APR_INCOMPLETE); + + req->parser->hook = h->next; + return NULL; + + + default: + + if (req->body == NULL) + return NULL; + + val = apr_table_get(req->body, name); + if (val != NULL) + return apreq_value_to_param(val); + return NULL; + } + + /* not reached */ + return NULL; +} + +static apr_status_t cgi_parser_get(apreq_handle_t *handle, + const apreq_parser_t **parser) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + + *parser = req->parser; + return APR_SUCCESS; +} + +static apr_status_t cgi_parser_set(apreq_handle_t *handle, + apreq_parser_t *parser) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + + if (req->parser == NULL) { + + if (req->hook_queue != NULL) { + apr_status_t s = apreq_parser_add_hook(parser, req->hook_queue); + if (s != APR_SUCCESS) + return s; + } + if (req->temp_dir != NULL) { + parser->temp_dir = req->temp_dir; + } + if (req->brigade_limit < parser->brigade_limit) { + parser->brigade_limit = req->brigade_limit; + } + + req->hook_queue = NULL; + req->parser = parser; + return APR_SUCCESS; + } + else + return APREQ_ERROR_MISMATCH; +} + + +static apr_status_t cgi_hook_add(apreq_handle_t *handle, + apreq_hook_t *hook) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + + if (req->parser != NULL) { + return apreq_parser_add_hook(req->parser, hook); + } + else if (req->hook_queue != NULL) { + apreq_hook_t *h = req->hook_queue; + while (h->next != NULL) + h = h->next; + h->next = hook; + } + else { + req->hook_queue = hook; + } + return APR_SUCCESS; + +} + +static apr_status_t cgi_brigade_limit_set(apreq_handle_t *handle, + apr_size_t bytes) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + apr_size_t *limit = (req->parser == NULL) + ? &req->brigade_limit + : &req->parser->brigade_limit; + + if (*limit > bytes) { + *limit = bytes; + return APR_SUCCESS; + } + + return APREQ_ERROR_MISMATCH; +} + +static apr_status_t cgi_brigade_limit_get(apreq_handle_t *handle, + apr_size_t *bytes) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + *bytes = (req->parser == NULL) + ? req->brigade_limit + : req->parser->brigade_limit; + + return APR_SUCCESS; +} + +static apr_status_t cgi_read_limit_set(apreq_handle_t *handle, + apr_uint64_t bytes) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + + if (req->read_limit > bytes && req->bytes_read < bytes) { + req->read_limit = bytes; + return APR_SUCCESS; + } + + return APREQ_ERROR_MISMATCH; +} + + +static apr_status_t cgi_read_limit_get(apreq_handle_t *handle, + apr_uint64_t *bytes) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + *bytes = req->read_limit; + return APR_SUCCESS; +} + + +static apr_status_t cgi_temp_dir_set(apreq_handle_t *handle, + const char *path) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + const char **temp_dir = (req->parser == NULL) + ? &req->temp_dir + : &req->parser->temp_dir; + + + if (*temp_dir == NULL && req->bytes_read == 0) { + if (path != NULL) + *temp_dir = apr_pstrdup(handle->pool, path); + return APR_SUCCESS; + } + + return APREQ_ERROR_MISMATCH; +} + + +static apr_status_t cgi_temp_dir_get(apreq_handle_t *handle, + const char **path) +{ + struct cgi_handle *req = (struct cgi_handle *)handle; + *path = (req->parser == NULL) + ? req->temp_dir + : req->parser->temp_dir; + return APR_SUCCESS; +} + + + +#ifdef APR_POOL_DEBUG +static apr_status_t ba_cleanup(void *data) +{ + apr_bucket_alloc_t *ba = data; + apr_bucket_alloc_destroy(ba); + return APR_SUCCESS; +} +#endif + +static APREQ_MODULE(cgi, 20050425); + +APREQ_DECLARE(apreq_handle_t *)apreq_handle_cgi(apr_pool_t *pool) +{ + apr_bucket_alloc_t *ba; + struct cgi_handle *req; + void *data; + + apr_pool_userdata_get(&data, USER_DATA_KEY, pool); + + if (data != NULL) + return data; + + req = apr_pcalloc(pool, sizeof *req); + ba = apr_bucket_alloc_create(pool); + + /* check pool's userdata first. */ + + req->handle.module = &cgi_module; + req->handle.pool = pool; + req->handle.bucket_alloc = ba; + req->read_limit = (apr_uint64_t) -1; + req->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT; + + req->args_status = + req->jar_status = + req->body_status = APR_EINIT; + + apr_pool_userdata_setn(&req->handle, USER_DATA_KEY, NULL, pool); + +#ifdef APR_POOL_DEBUG + apr_pool_cleanup_register(pool, ba, ba_cleanup, ba_cleanup); +#endif + + return &req->handle; +} Propchange: httpd/apreq/branches/apr-build-system/library/module_cgi.c ------------------------------------------------------------------------------ svn:eol-style = native Added: httpd/apreq/branches/apr-build-system/library/module_custom.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/module_custom.c?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/library/module_custom.c (added) +++ httpd/apreq/branches/apr-build-system/library/module_custom.c Fri Feb 24 10:56:34 2006 @@ -0,0 +1,302 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#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, 20050516); + +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->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; +} + Propchange: httpd/apreq/branches/apr-build-system/library/module_custom.c ------------------------------------------------------------------------------ svn:eol-style = native Added: httpd/apreq/branches/apr-build-system/library/param.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/apr-build-system/library/param.c?rev=380784&view=auto ============================================================================== --- httpd/apreq/branches/apr-build-system/library/param.c (added) +++ httpd/apreq/branches/apr-build-system/library/param.c Fri Feb 24 10:56:34 2006 @@ -0,0 +1,271 @@ +/* +** Copyright 2003-2006 The Apache Software Foundation +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +#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; +} Propchange: httpd/apreq/branches/apr-build-system/library/param.c ------------------------------------------------------------------------------ svn:eol-style = native