1
0
mirror of https://github.com/apache/httpd.git synced 2026-10-23 22:49:01 +03:00

Remove apreq from trunk per PMC vote:

https://lists.apache.org/thread/hlvtnmg8qq1m10xlmgvyn12wrw4z3gp3

Revert \"Added apreq to NetWare build.\" r1201918

Revert \"add apreq in Win32\" r1825396

Remove references to apreq from CHANGES, httpd.spec.in.

Partial revert of r1825400.

Revert apreq support from cmake.

GitHub: closes #637


git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1933271 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Joe Orton
2026-04-23 16:08:21 +00:00
parent d6d9801149
commit 48e9e82540
40 changed files with 4 additions and 9238 deletions

View File

@@ -87,9 +87,6 @@ Package=<4>
Project_Dep_Name httpd
End Project Dependency
Begin Project Dependency
Project_Dep_Name mod_apreq
End Project Dependency
Begin Project Dependency
Project_Dep_Name ApacheMonitor
End Project Dependency
Begin Project Dependency
@@ -744,27 +741,6 @@ Package=<4>
###############################################################################
Project: "libapreq"=.\libapreq.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name libapr
End Project Dependency
Begin Project Dependency
Project_Dep_Name libapriconv
End Project Dependency
Begin Project Dependency
Project_Dep_Name libhttpd
End Project Dependency
}}}
###############################################################################
Project: "libhttpd"=.\libhttpd.dsp - Package Owner=<4>
Package=<5>

View File

@@ -90,9 +90,6 @@ Package=<4>
Project_Dep_Name httpd
End Project Dependency
Begin Project Dependency
Project_Dep_Name mod_apreq
End Project Dependency
Begin Project Dependency
Project_Dep_Name ApacheMonitor
End Project Dependency
Begin Project Dependency
@@ -906,30 +903,6 @@ Package=<4>
###############################################################################
Project: "libapreq"=.\libapreq.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name libapr
End Project Dependency
Begin Project Dependency
Project_Dep_Name libapriconv
End Project Dependency
Begin Project Dependency
Project_Dep_Name libaprutil
End Project Dependency
Begin Project Dependency
Project_Dep_Name libhttpd
End Project Dependency
}}}
###############################################################################
Project: "libhttpd"=.\libhttpd.dsp - Package Owner=<4>
Package=<5>
@@ -1056,30 +1029,6 @@ Package=<4>
###############################################################################
Project: "mod_apreq"=.\modules\apreq\mod_apreq.dsp - Package Owner=<4>
Package=<5>
{{{
}}}
Package=<4>
{{{
Begin Project Dependency
Project_Dep_Name libapr
End Project Dependency
Begin Project Dependency
Project_Dep_Name libaprutil
End Project Dependency
Begin Project Dependency
Project_Dep_Name libhttpd
End Project Dependency
Begin Project Dependency
Project_Dep_Name libapreq
End Project Dependency
}}}
###############################################################################
Project: "mod_asis"=.\modules\generators\mod_asis.dsp - Package Owner=<4>
Package=<5>
@@ -1099,6 +1048,7 @@ Package=<4>
End Project Dependency
}}}
###############################################################################
Project: "mod_access_compat"=.\modules\aaa\mod_access_compat.dsp - Package Owner=<4>

View File

@@ -2005,10 +2005,6 @@ Changes with Apache 2.5.0-alpha
*) mod_authnz_ldap: Resolve crashes with LDAP authz and non-LDAP authn since
r1608202. [Eric Covener]
*) apreq: Content-Length header should be always interpreted as a decimal.
Leading 0 could be erroneously considered as an octal value. PR 56598.
[Chris Card <ctcard hotmail com>]
*) mod_proxy: Now allow for 191 character worker names, with non-fatal
errors if name is truncated. PR53218. [Jim Jagielski]
@@ -2229,8 +2225,6 @@ Changes with Apache 2.5.0-alpha
*) mod_noloris
*) APREQ
*) Simple MPM
*) mod_serf

View File

@@ -321,7 +321,6 @@ SET(MODULE_LIST
"modules/aaa/mod_authz_host+A+host-based authorization control"
"modules/aaa/mod_authz_owner+I+'require file-owner' authorization control"
"modules/aaa/mod_authz_user+A+'require user' authorization control"
"modules/apreq/mod_apreq+i+Apache Request Filter"
"modules/arch/win32/mod_isapi+I+isapi extension support"
"modules/cache/mod_cache+I+dynamic file caching. At least one storage management module (e.g. mod_cache_disk) is also necessary."
"modules/cache/mod_cache_disk+I+disk caching module"
@@ -437,9 +436,6 @@ SET(installed_mod_libs_exps)
# Define extra definitions, sources, headers, etc. required by some modules.
# This could be included in the master list of modules above, though it
# certainly would get a lot more unreadable.
SET(mod_apreq_extra_defines APREQ_DECLARE_EXPORT)
SET(mod_apreq_extra_sources modules/apreq/handle.c)
SET(mod_apreq_main_source modules/apreq/filter.c)
SET(mod_authz_dbd_extra_defines AUTHZ_DBD_DECLARE_EXPORT)
SET(mod_authnz_ldap_requires APR_HAS_LDAP)
SET(mod_authnz_ldap_extra_libs mod_ldap)
@@ -684,17 +680,6 @@ SET(HTTPD_MAIN_SOURCES
SET(LIBHTTPD_SOURCES
${extra_builtin_modules}
${PROJECT_BINARY_DIR}/modules.c
server/apreq_cookie.c
server/apreq_error.c
server/apreq_module.c
server/apreq_module_cgi.c
server/apreq_module_custom.c
server/apreq_param.c
server/apreq_parser.c
server/apreq_parser_header.c
server/apreq_parser_multipart.c
server/apreq_parser_urlencoded.c
server/apreq_util.c
modules/arch/win32/mod_win32.c
modules/core/mod_so.c
modules/http/byterange_filter.c
@@ -921,7 +906,6 @@ TARGET_COMPILE_DEFINITIONS(libhttpd PRIVATE
"LONG_NAME=Apache HTTP Server Core"
"BIN_NAME=libhttpd.dll"
"AP_DECLARE_EXPORT"
"APREQ_DECLARE_EXPORT"
)
TARGET_COMPILE_OPTIONS(libhttpd PRIVATE ${PCRE_CFLAGS} ${EXTRA_COMPILE_FLAGS})
ADD_DEPENDENCIES(libhttpd test_char_header)

View File

@@ -508,7 +508,6 @@ _build:
$(MAKE) $(MAKEOPT) -f gen_test_char.mak CFG="gen_test_char - Win32 $(LONG)" RECURSE=0 $(CTARGET)
cd ..
$(MAKE) $(MAKEOPT) -f libhttpd.mak CFG="libhttpd - Win32 $(LONG)" RECURSE=0 $(CTARGET)
$(MAKE) $(MAKEOPT) -f libapreq.mak CFG="libapreq - Win32 $(LONG)" RECURSE=0 $(CTARGET)
$(MAKE) $(MAKEOPT) -f httpd.mak CFG="httpd - Win32 $(LONG)" RECURSE=0 $(CTARGET)
# build ldap prior to authnz_ldap
cd modules\ldap
@@ -540,9 +539,6 @@ _build:
$(MAKE) $(MAKEOPT) -f mod_authz_owner.mak CFG="mod_authz_owner - Win32 $(LONG)" RECURSE=0 $(CTARGET)
$(MAKE) $(MAKEOPT) -f mod_authz_user.mak CFG="mod_authz_user - Win32 $(LONG)" RECURSE=0 $(CTARGET)
cd ..\..
cd modules\apreq
$(MAKE) $(MAKEOPT) -f mod_apreq.mak CFG="mod_apreq - Win32 $(LONG)" RECURSE=0 $(CTARGET)
cd ..\..
cd modules\arch\win32
$(MAKE) $(MAKEOPT) -f mod_isapi.mak CFG="mod_isapi - Win32 $(LONG)" RECURSE=0 $(CTARGET)
cd ..\..\..
@@ -828,7 +824,6 @@ _build:
_copybin:
copy $(LONG)\httpd.$(src_exe) "$(inst_exe)" <.y
copy $(LONG)\libapreq.$(src_dll) "$(inst_dll)" <.y
copy $(LONG)\libhttpd.$(src_dll) "$(inst_dll)" <.y
copy srclib\apr\$(LONG)\libapr-1.$(src_dll) "$(inst_dll)" <.y
!IF EXIST("srclib\apr-util")
@@ -872,7 +867,6 @@ _copybin:
copy modules\aaa\$(LONG)\mod_authz_host.$(src_so) "$(inst_so)" <.y
copy modules\aaa\$(LONG)\mod_authz_owner.$(src_so) "$(inst_so)" <.y
copy modules\aaa\$(LONG)\mod_authz_user.$(src_so) "$(inst_so)" <.y
copy modules\apreq\$(LONG)\mod_apreq.$(src_so) "$(inst_so)" <.y
copy modules\arch\win32\$(LONG)\mod_isapi.$(src_so) "$(inst_so)" <.y
copy modules\cache\$(LONG)\mod_cache.$(src_so) "$(inst_so)" <.y
copy modules\cache\$(LONG)\mod_cache_disk.$(src_so) "$(inst_so)" <.y

View File

@@ -218,17 +218,6 @@ TARGET_lib = \
# Paths must all use the '/' character
#
FILES_nlm_objs = \
$(OBJDIR)/apreq_cookie.o \
$(OBJDIR)/apreq_error.o \
$(OBJDIR)/apreq_module.o \
$(OBJDIR)/apreq_module_cgi.o \
$(OBJDIR)/apreq_module_custom.o \
$(OBJDIR)/apreq_param.o \
$(OBJDIR)/apreq_parser.o \
$(OBJDIR)/apreq_parser_header.o \
$(OBJDIR)/apreq_parser_multipart.o \
$(OBJDIR)/apreq_parser_urlencoded.o \
$(OBJDIR)/apreq_util.o \
$(OBJDIR)/buildmark.o \
$(OBJDIR)/config.o \
$(OBJDIR)/connection.o \

View File

@@ -99,7 +99,6 @@ BEGIN {
print "LoadModule alias_module modules/mod_alias.so" > dstfl;
print "#LoadModule allowhandlers_module modules/mod_allowhandlers.so" > dstfl;
print "#LoadModule allowmethods_module modules/mod_allowmethods.so" > dstfl;
print "#LoadModule apreq_module modules/mod_apreq.so" > dstfl;
print "LoadModule asis_module modules/mod_asis.so" > dstfl;
print "LoadModule auth_basic_module modules/mod_auth_basic.so" > dstfl;
print "#LoadModule auth_digest_module modules/mod_auth_digest.so" > dstfl;

View File

@@ -28,8 +28,8 @@ function add_symbol(sym_name) {
# List of functions that we don't support, yet??
#/ap_some_name/{next}
/^[ \t]*(AP|DAV|CACHE|PROXY)([RU]|REQ|_CORE)?_DECLARE[^(]*[(][^)]*[)]([^ ]* )*[^(]+[(]/ {
sub("[ \t]*(AP|DAV|CACHE|PROXY)([RU]|REQ|_CORE)?_DECLARE[^(]*[(][^)]*[)][ \t]*", "")
/^[ \t]*(AP|DAV|CACHE|PROXY)([RU]|_CORE)?_DECLARE[^(]*[(][^)]*[)]([^ ]* )*[^(]+[(]/ {
sub("[ \t]*(AP|DAV|CACHE|PROXY)([RU]|_CORE)?_DECLARE[^(]*[(][^)]*[)][ \t]*", "")
sub("[(].*", "")
sub("([^ ]* (^([ \t]*[(])))+", "")
add_symbol($0)

View File

@@ -23,12 +23,6 @@
#define APR_DECLARE_OPTIONAL_FN APR_DECLARE_OPTIONAL_FN
#undef APR_DECLARE_EXTERNAL_HOOK
#define APR_DECLARE_EXTERNAL_HOOK APR_DECLARE_EXTERNAL_HOOK
#undef APREQ_DECLARE
#define APREQ_DECLARE APREQ_DECLARE
#undef APREQ_DECLARE_NONSTD
#define APREQ_DECLARE_NONSTD APREQ_DECLARE_NONSTD
#undef APREQ_DECLARE_DATA
#define APREQ_DECLARE_DATA APREQ_DECLARE_DATA
#undef APACHE_OS_H
#include "httpd.h"
@@ -41,12 +35,6 @@
#include "ap_provider.h"
#include "ap_release.h"
#include "ap_expr.h"
#include "apreq_cookie.h"
#include "apreq_error.h"
#include "apreq_module.h"
#include "apreq_param.h"
#include "apreq_parser.h"
#include "apreq_util.h"
#include "http_config.h"
#include "http_connection.h"
#include "http_core.h"

View File

@@ -306,7 +306,6 @@ rm -rf $RPM_BUILD_ROOT
%{_libdir}/httpd/modules/mod_alias.so
%{_libdir}/httpd/modules/mod_allowhandlers.so
%{_libdir}/httpd/modules/mod_allowmethods.so
%{_libdir}/httpd/modules/mod_apreq.so
%{_libdir}/httpd/modules/mod_asis.so
%{_libdir}/httpd/modules/mod_auth_basic.so
%{_libdir}/httpd/modules/mod_auth_digest.so

View File

@@ -1,263 +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 "ap_config.h"
#include "apr_tables.h"
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file apreq.h
* @brief Main header file...
* @ingroup libapreq2
*
* Define the common data structures.
*/
/**
* 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 destroy 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 destroyed the pool, you have to call this function again
* with a new pool if you still plan to use libapreq2
*/
APREQ_DECLARE(apr_status_t) apreq_pre_initialize(apr_pool_t *pool);
/**
* Post-initialize libapreq2. Applications (except apache modules using
* mod_apreq2) should this exactly once before they use any
* libapreq2 modules for parsing.
*
* @param pool the same pool that was used in apreq_pre_initialize().
*/
APREQ_DECLARE(apr_status_t) apreq_post_initialize(apr_pool_t *pool);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_H */

View File

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

View File

@@ -1,98 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef APREQ_ERROR_H
#define APREQ_ERROR_H
#include "apr_errno.h"
#include "apreq.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* apreq's wrapper around apr_strerror();
* recognizes APREQ_ERROR_* status codes.
*/
APREQ_DECLARE(char *) apreq_strerror(apr_status_t s,
char *buf,
apr_size_t bufsize);
/**
* @file apreq_error.h
* @brief Error status codes.
* @ingroup libapreq2
*
* Define the APREQ_ error codes.
*/
#ifndef APR_EBADARG
/**
* Bad Arguments return value
* @see APR_BADARG
*/
#define APR_EBADARG APR_BADARG /* XXX: don't use APR_BADARG */
#endif
/** Internal apreq error. */
#define APREQ_ERROR_GENERAL APR_OS_START_USERERR
/** Attempted to perform unsafe action with tainted data. */
#define APREQ_ERROR_TAINTED (APREQ_ERROR_GENERAL + 1)
/** Parsing interrupted. */
#define APREQ_ERROR_INTERRUPT (APREQ_ERROR_GENERAL + 2)
/** Invalid input data. */
#define APREQ_ERROR_BADDATA (APREQ_ERROR_GENERAL + 10)
/** Invalid character. */
#define APREQ_ERROR_BADCHAR (APREQ_ERROR_BADDATA + 1)
/** Invalid byte sequence. */
#define APREQ_ERROR_BADSEQ (APREQ_ERROR_BADDATA + 2)
/** Invalid attribute. */
#define APREQ_ERROR_BADATTR (APREQ_ERROR_BADDATA + 3)
/** Invalid header. */
#define APREQ_ERROR_BADHEADER (APREQ_ERROR_BADDATA + 4)
/** Invalid utf8 encoding. */
#define APREQ_ERROR_BADUTF8 (APREQ_ERROR_BADDATA + 5)
/** Missing input data. */
#define APREQ_ERROR_NODATA (APREQ_ERROR_GENERAL + 20)
/** Missing required token. */
#define APREQ_ERROR_NOTOKEN (APREQ_ERROR_NODATA + 1)
/** Missing attribute. */
#define APREQ_ERROR_NOATTR (APREQ_ERROR_NODATA + 2)
/** Missing header. */
#define APREQ_ERROR_NOHEADER (APREQ_ERROR_NODATA + 3)
/** Missing parser. */
#define APREQ_ERROR_NOPARSER (APREQ_ERROR_NODATA + 4)
/** Conflicting information. */
#define APREQ_ERROR_MISMATCH (APREQ_ERROR_GENERAL + 30)
/** Exceeds configured maximum limit. */
#define APREQ_ERROR_OVERLIMIT (APREQ_ERROR_MISMATCH + 1)
/** Below configured minimum limit. */
#define APREQ_ERROR_UNDERLIMIT (APREQ_ERROR_MISMATCH + 2)
/** Setting already configured. */
#define APREQ_ERROR_NOTEMPTY (APREQ_ERROR_MISMATCH + 3)
#ifdef __cplusplus
}
#endif
#endif /* APREQ_ERROR_H */

View File

@@ -1,457 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef APREQ_MODULE_H
#define APREQ_MODULE_H
#include "apreq_cookie.h"
#include "apreq_parser.h"
#include "apreq_error.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file apreq_module.h
* @brief Module API
* @ingroup libapreq2
*/
/**
* An apreq handle associated with a module. The structure
* may have variable size, because the module may append its own data
* structures after it.
*/
typedef struct apreq_handle_t {
/** the apreq module which implements this handle */
const struct apreq_module_t *module;
/** the pool which defines the lifetime of the parsed data */
apr_pool_t *pool;
/** the allocator, which persists at least as long as the pool */
apr_bucket_alloc_t *bucket_alloc;
} apreq_handle_t;
/**
* @brief Vtable describing the necessary module functions.
*/
typedef struct apreq_module_t {
/** name of this apreq module */
const char *name;
/** magic number identifying the module and version */
apr_uint32_t magic_number;
/** get a table with all cookies */
apr_status_t (*jar)(apreq_handle_t *, const apr_table_t **);
/** get a table with all query string parameters */
apr_status_t (*args)(apreq_handle_t *, const apr_table_t **);
/** get a table with all body parameters */
apr_status_t (*body)(apreq_handle_t *, const apr_table_t **);
/** get a cookie by its name */
apreq_cookie_t *(*jar_get)(apreq_handle_t *, const char *);
/** get a query string parameter by its name */
apreq_param_t *(*args_get)(apreq_handle_t *, const char *);
/** get a body parameter by its name */
apreq_param_t *(*body_get)(apreq_handle_t *, const char *);
/** gets the parser associated with the request body */
apr_status_t (*parser_get)(apreq_handle_t *, const apreq_parser_t **);
/** manually set a parser for the request body */
apr_status_t (*parser_set)(apreq_handle_t *, apreq_parser_t *);
/** add a hook function */
apr_status_t (*hook_add)(apreq_handle_t *, apreq_hook_t *);
/** determine the maximum in-memory bytes a brigade may use */
apr_status_t (*brigade_limit_get)(apreq_handle_t *, apr_size_t *);
/** set the maximum in-memory bytes a brigade may use */
apr_status_t (*brigade_limit_set)(apreq_handle_t *, apr_size_t);
/** determine the maximum amount of data that will be fed into a parser */
apr_status_t (*read_limit_get)(apreq_handle_t *, apr_uint64_t *);
/** set the maximum amount of data that will be fed into a parser */
apr_status_t (*read_limit_set)(apreq_handle_t *, apr_uint64_t);
/** determine the directory used by the parser for temporary files */
apr_status_t (*temp_dir_get)(apreq_handle_t *, const char **);
/** set the directory used by the parser for temporary files */
apr_status_t (*temp_dir_set)(apreq_handle_t *, const char *);
} apreq_module_t;
/**
* Defines the module-specific status codes which
* are commonly considered to be non-fatal.
*
* @param s status code returned by an apreq_module_t method.
*
* @return 1 if s is fatal, 0 otherwise.
*/
static APR_INLINE
unsigned apreq_module_status_is_error(apr_status_t s) {
switch (s) {
case APR_SUCCESS:
case APR_INCOMPLETE:
case APR_EINIT:
case APREQ_ERROR_NODATA:
case APREQ_ERROR_NOPARSER:
case APREQ_ERROR_NOHEADER:
return 0;
default:
return 1;
}
}
/**
* Expose the parsed "cookie" header associated to this handle.
*
* @param req The request handle
* @param t The resulting table, which will either be NULL or a
* valid table object on return.
*
* @return APR_SUCCESS or a module-specific error status code.
*/
static APR_INLINE
apr_status_t apreq_jar(apreq_handle_t *req, const apr_table_t **t)
{
return req->module->jar(req,t);
}
/**
* Expose the parsed "query string" associated to this handle.
*
* @param req The request handle
* @param t The resulting table, which will either be NULL or a
* valid table object on return.
*
* @return APR_SUCCESS or a module-specific error status code.
*/
static APR_INLINE
apr_status_t apreq_args(apreq_handle_t *req, const apr_table_t **t)
{
return req->module->args(req,t);
}
/**
* Expose the parsed "request body" associated to this handle.
*
* @param req The request handle
* @param t The resulting table, which will either be NULL or a
* valid table object on return.
*
* @return APR_SUCCESS or a module-specific error status code.
*/
static APR_INLINE
apr_status_t apreq_body(apreq_handle_t *req, const apr_table_t **t)
{
return req->module->body(req, t);
}
/**
* Fetch the first cookie with the given name.
*
* @param req The request handle
* @param name Case-insensitive cookie name.
*
* @return First matching cookie, or NULL if none match.
*/
static APR_INLINE
apreq_cookie_t *apreq_jar_get(apreq_handle_t *req, const char *name)
{
return req->module->jar_get(req, name);
}
/**
* Fetch the first query string param with the given name.
*
* @param req The request handle
* @param name Case-insensitive param name.
*
* @return First matching param, or NULL if none match.
*/
static APR_INLINE
apreq_param_t *apreq_args_get(apreq_handle_t *req, const char *name)
{
return req->module->args_get(req, name);
}
/**
* Fetch the first body param with the given name.
*
* @param req The request handle
* @param name Case-insensitive cookie name.
*
* @return First matching param, or NULL if none match.
*/
static APR_INLINE
apreq_param_t *apreq_body_get(apreq_handle_t *req, const char *name)
{
return req->module->body_get(req, name);
}
/**
* Fetch the active body parser.
*
* @param req The request handle
* @param parser Points to the active parser on return.
*
* @return APR_SUCCESS or module-specific error.
*
*/
static APR_INLINE
apr_status_t apreq_parser_get(apreq_handle_t *req,
const apreq_parser_t **parser)
{
return req->module->parser_get(req, parser);
}
/**
* Set the body parser for this request.
*
* @param req The request handle
* @param parser New parser to use.
*
* @return APR_SUCCESS or module-specific error.
*/
static APR_INLINE
apr_status_t apreq_parser_set(apreq_handle_t *req,
apreq_parser_t *parser)
{
return req->module->parser_set(req, parser);
}
/**
* Add a parser hook for this request.
*
* @param req The request handle
* @param hook Hook to add.
*
* @return APR_SUCCESS or module-specific error.
*/
static APR_INLINE
apr_status_t apreq_hook_add(apreq_handle_t *req, apreq_hook_t *hook)
{
return req->module->hook_add(req, hook);
}
/**
* Set the active brigade limit.
*
* @param req The handle.
* @param bytes New limit to use.
*
* @return APR_SUCCESS or module-specific error.
*
*/
static APR_INLINE
apr_status_t apreq_brigade_limit_set(apreq_handle_t *req,
apr_size_t bytes)
{
return req->module->brigade_limit_set(req, bytes);
}
/**
* Get the active brigade limit.
*
* @param req The handle.
* @param bytes Pointer to resulting (current) limit.
*
* @return APR_SUCCESS or a module-specific error,
* which may leave bytes undefined.
*/
static APR_INLINE
apr_status_t apreq_brigade_limit_get(apreq_handle_t *req,
apr_size_t *bytes)
{
return req->module->brigade_limit_get(req, bytes);
}
/**
* Set the active read limit.
*
* @param req The handle.
* @param bytes New limit to use.
*
* @return APR_SUCCESS or a module-specific error.
*
*/
static APR_INLINE
apr_status_t apreq_read_limit_set(apreq_handle_t *req,
apr_uint64_t bytes)
{
return req->module->read_limit_set(req, bytes);
}
/**
* Get the active read limit.
*
* @param req The request handle.
* @param bytes Pointer to resulting (current) limit.
*
* @return APR_SUCCESS or a module-specific error,
* which may leave bytes undefined.
*/
static APR_INLINE
apr_status_t apreq_read_limit_get(apreq_handle_t *req,
apr_uint64_t *bytes)
{
return req->module->read_limit_get(req, bytes);
}
/**
* Set the active temp directory.
*
* @param req The handle.
* @param path New path to use; may be NULL.
*
* @return APR_SUCCESS or a module-specific error .
*/
static APR_INLINE
apr_status_t apreq_temp_dir_set(apreq_handle_t *req, const char *path)
{
return req->module->temp_dir_set(req, path);
}
/**
* Get the active temp directory.
*
* @param req The handle.
* @param path Resulting path to temp dir.
*
* @return APR_SUCCESS implies path is valid, but may also be NULL.
* Any other return value is module-specific, and may leave
* path undefined.
*/
static APR_INLINE
apr_status_t apreq_temp_dir_get(apreq_handle_t *req, const char **path)
{
return req->module->temp_dir_get(req, path);
}
/**
* Convenience macro for defining a module by mapping
* a function prefix to an associated apreq_module_t structure.
*
* @param pre Prefix to define new module. All attributes of
* the apreq_module_t struct are defined with this as their
* prefix. The generated struct is named by appending "_module" to
* the prefix.
* @param mmn Magic number (i.e. version number) of this module.
*/
#define APREQ_MODULE(pre, mmn) const apreq_module_t \
pre##_module = { #pre, mmn, \
pre##_jar, pre##_args, pre##_body, \
pre##_jar_get, pre##_args_get, pre##_body_get, \
pre##_parser_get, pre##_parser_set, pre##_hook_add, \
pre##_brigade_limit_get, pre##_brigade_limit_set, \
pre##_read_limit_get, pre##_read_limit_set, \
pre##_temp_dir_get, pre##_temp_dir_set, \
}
/**
* Create an apreq handle which is suitable for a CGI program. It
* reads input from stdin and writes output to stdout.
*
* @param pool Pool associated to this handle.
*
* @return New handle; can only be NULL if the pool allocation failed.
*
* @remarks The handle gets cached in the pool's userdata, so subsequent
* calls will retrieve the original cached handle.
*/
APREQ_DECLARE(apreq_handle_t*) apreq_handle_cgi(apr_pool_t *pool);
/**
* Create a custom apreq handle which knows only some static
* values. Useful if you want to test the parser code or if you have
* got data from a custom source (neither Apache 2 nor CGI).
*
* @param pool allocates the parse data,
* @param query_string parsed into args table
* @param cookie value of the request "Cookie" header
* @param parser parses the request body
* @param read_limit maximum bytes to read from the body
* @param in brigade containing the request body
*
* @return new handle; can only be NULL if the pool allocation failed.
*/
APREQ_DECLARE(apreq_handle_t*) apreq_handle_custom(apr_pool_t *pool,
const char *query_string,
const char *cookie,
apreq_parser_t *parser,
apr_uint64_t read_limit,
apr_bucket_brigade *in);
/**
* Find the first query string parameter or body parameter with the
* specified name. The match is case-insensitive.
*
* @param req request handle.
* @param key desired parameter name
*
* @return The first matching parameter (with args searched first) or NULL.
*/
APREQ_DECLARE(apreq_param_t *)apreq_param(apreq_handle_t *req, const char *key);
/**
* Find the first cookie with the specified name.
* The match is case-insensitive.
*
* @param req request handle.
* @param name desired cookie name
*
* @return The first matching cookie or NULL.
*/
#define apreq_cookie(req, name) apreq_jar_get(req, name)
/**
* Returns a table containing key-value pairs for the full request
* (args + body).
*
* @param req request handle
* @param p allocates the returned table.
*
* @return table representing all available params; is never NULL.
*/
APREQ_DECLARE(apr_table_t *) apreq_params(apreq_handle_t *req, apr_pool_t *p);
/**
* Returns a table containing all request cookies.
*
* @param req the apreq request handle
* @param p Allocates the returned table.
*/
APREQ_DECLARE(apr_table_t *)apreq_cookies(apreq_handle_t *req, apr_pool_t *p);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_MODULE_H */

View File

@@ -1,209 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef APREQ_PARAM_H
#define APREQ_PARAM_H
#include "apreq.h"
#include "apr_buckets.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file apreq_param.h
* @brief Request parsing and parameter API
* @ingroup libapreq2
*/
/** Common data structure for params and file uploads */
typedef struct apreq_param_t {
apr_table_t *info; /**< header table associated with the param */
apr_bucket_brigade *upload; /**< brigade used to spool upload files */
unsigned flags; /**< charsets, taint marks, app-specific bits */
const apreq_value_t v; /**< underlying name/value info */
} apreq_param_t;
/** @return 1 if the taint flag is set, 0 otherwise. */
static APR_INLINE
unsigned apreq_param_is_tainted(const apreq_param_t *p) {
return APREQ_FLAGS_GET(p->flags, APREQ_TAINTED);
}
/** Sets the tainted flag. */
static APR_INLINE
void apreq_param_tainted_on(apreq_param_t *p) {
APREQ_FLAGS_ON(p->flags, APREQ_TAINTED);
}
/** Turns off the taint flag. */
static APR_INLINE
void apreq_param_tainted_off(apreq_param_t *p) {
APREQ_FLAGS_OFF(p->flags, APREQ_TAINTED);
}
/** Sets the character encoding for this parameter. */
static APR_INLINE
apreq_charset_t apreq_param_charset_set(apreq_param_t *p, apreq_charset_t c) {
apreq_charset_t old = (apreq_charset_t)
APREQ_FLAGS_GET(p->flags, APREQ_CHARSET);
APREQ_FLAGS_SET(p->flags, APREQ_CHARSET, c);
return old;
}
/** Gets the character encoding for this parameter. */
static APR_INLINE
apreq_charset_t apreq_param_charset_get(apreq_param_t *p) {
return (apreq_charset_t)APREQ_FLAGS_GET(p->flags, APREQ_CHARSET);
}
/** Upgrades args and body table values to apreq_param_t structs. */
static APR_INLINE
apreq_param_t *apreq_value_to_param(const char *val)
{
union { const char *in; char *out; } deconst;
deconst.in = val;
return apreq_attr_to_type(apreq_param_t, v,
apreq_attr_to_type(apreq_value_t, data, deconst.out));
}
/** creates a param from name/value information */
APREQ_DECLARE(apreq_param_t *) apreq_param_make(apr_pool_t *p,
const char *name,
const apr_size_t nlen,
const char *val,
const apr_size_t vlen);
/**
* Url-decodes a name=value pair into a param.
*
* @param param points to the decoded parameter on success
* @param pool Pool from which the param is allocated.
* @param word Start of the name=value pair.
* @param nlen Length of urlencoded name.
* @param vlen Length of urlencoded value.
*
* @return APR_SUCCESS on success.
* @return ::APREQ_ERROR_BADSEQ or ::APREQ_ERROR_BADCHAR on malformed input.
*
* @remarks Unless vlen == 0, this function assumes there is
* exactly one character ('=') which separates the pair.
*
*/
APREQ_DECLARE(apr_status_t) apreq_param_decode(apreq_param_t **param,
apr_pool_t *pool,
const char *word,
apr_size_t nlen,
apr_size_t vlen);
/**
* Url-encodes the param into a name-value pair.
* @param pool Pool which allocates the returned string.
* @param param Param to encode.
* @return name-value pair representing the param.
*/
APREQ_DECLARE(char *) apreq_param_encode(apr_pool_t *pool,
const apreq_param_t *param);
/**
* Parse a url-encoded string into a param table.
* @param pool pool used to allocate the param data.
* @param t table to which the params are added.
* @param qs Query string to url-decode.
* @return APR_SUCCESS if successful, error otherwise.
* @remark This function uses [&;] as the set of tokens
* to delineate words, and will treat a word w/o '='
* as a name-value pair with value-length = 0.
*
*/
APREQ_DECLARE(apr_status_t) apreq_parse_query_string(apr_pool_t *pool,
apr_table_t *t,
const char *qs);
/**
* Returns an array of parameters (apreq_param_t *) matching the given key.
* The key is case-insensitive.
* @param p Allocates the returned array.
* @param t the parameter table returned by apreq_args(), apreq_body()
* or apreq_params()
* @param key Null-terminated search key, case insensitive.
* key==NULL fetches all parameters.
* @return an array of apreq_param_t* (pointers)
* @remark Also parses the request if necessary.
*/
APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p,
const apr_table_t *t,
const char *key);
/**
* Returns a ", " -joined string containing all parameters
* for the requested key, an empty string if none are found.
* The key is case-insensitive.
*
* @param p Allocates the return string.
* @param t the parameter table returned by apreq_args(), apreq_body()
* or apreq_params()
* @param key Null-terminated parameter name, case insensitive.
* key==NULL fetches all values.
* @param mode Join type- see apreq_join().
* @return the joined string or NULL on error
* @remark Also parses the request if necessary.
*/
APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p,
const apr_table_t *t,
const char *key,
apreq_join_t mode);
/**
* Returns a table of all params in req->body with non-NULL upload brigades.
* @param body parameter table returned by apreq_body() or apreq_params()
* @param pool Pool which allocates the table struct.
* @return Upload table.
* @remark Will parse the request if necessary.
*/
APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body,
apr_pool_t *pool);
/**
* Returns the first param in req->body which has both param->v.name
* matching key (case insensitive) and param->upload != NULL.
* @param body parameter table returned by apreq_body() or apreq_params()
* @param name Parameter name. key == NULL returns first upload.
* @return Corresponding upload, NULL if none found.
* @remark Will parse the request as necessary.
*/
APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body,
const char *name);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_PARAM_H */

View File

@@ -1,300 +0,0 @@
/*
** Licensed to the Apache Software Foundation (ASF) under one or more
** contributor license agreements. See the NOTICE file distributed with
** this work for additional information regarding copyright ownership.
** The ASF licenses this file to You under the Apache License, Version 2.0
** (the "License"); you may not use this file except in compliance with
** the License. You may obtain a copy of the License at
**
** http://www.apache.org/licenses/LICENSE-2.0
**
** Unless required by applicable law or agreed to in writing, software
** distributed under the License is distributed on an "AS IS" BASIS,
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
** See the License for the specific language governing permissions and
** limitations under the License.
*/
#ifndef APREQ_PARSERS_H
#define APREQ_PARSERS_H
/* These structs are defined below */
#include "apreq_param.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @file apreq_parser.h
* @brief Request body parser API
* @ingroup libapreq2
*/
/**
* A hook is called by the parser whenever data arrives in a file
* upload parameter of the request body. You may associate any number
* of hooks with a parser instance with apreq_parser_add_hook().
*/
typedef struct apreq_hook_t apreq_hook_t;
/**
* A request body parser instance.
*/
typedef struct apreq_parser_t apreq_parser_t;
/** Parser arguments. */
#define APREQ_PARSER_ARGS apreq_parser_t *parser, \
apr_table_t *t, \
apr_bucket_brigade *bb
/** Hook arguments */
#define APREQ_HOOK_ARGS apreq_hook_t *hook, \
apreq_param_t *param, \
apr_bucket_brigade *bb
/**
* The callback function implementing a request body parser.
*/
typedef apr_status_t (*apreq_parser_function_t)(APREQ_PARSER_ARGS);
/**
* The callback function of a hook. See apreq_hook_t.
*/
typedef apr_status_t (*apreq_hook_function_t)(APREQ_HOOK_ARGS);
/**
* Declares a API parser.
*/
#define APREQ_DECLARE_PARSER(f) APREQ_DECLARE_NONSTD(apr_status_t) \
f (APREQ_PARSER_ARGS)
/**
* Declares an API hook.
*/
#define APREQ_DECLARE_HOOK(f) APREQ_DECLARE_NONSTD(apr_status_t) \
f (APREQ_HOOK_ARGS)
/**
* A hook is called by the parser whenever data arrives in a file
* upload parameter of the request body. You may associate any number
* of hooks with a parser instance with apreq_parser_add_hook().
*/
struct apreq_hook_t {
apreq_hook_function_t hook; /**< the hook function */
apreq_hook_t *next; /**< next item in the linked list */
apr_pool_t *pool; /**< pool which allocated this hook */
void *ctx; /**< a user defined pointer passed to the hook function */
};
/**
* A request body parser instance.
*/
struct apreq_parser_t {
/** the function which parses chunks of body data */
apreq_parser_function_t parser;
/** the Content-Type request header */
const char *content_type;
/** a pool which outlasts the bucket_alloc. */
apr_pool_t *pool;
/** bucket allocator used to create bucket brigades */
apr_bucket_alloc_t *bucket_alloc;
/** the maximum in-memory bytes a brigade may use */
apr_size_t brigade_limit;
/** the directory for generating temporary files */
const char *temp_dir;
/** linked list of hooks */
apreq_hook_t *hook;
/** internal context pointer used by the parser function */
void *ctx;
};
/**
* Parse the incoming brigade into a table. Parsers normally
* consume all the buckets of the brigade during parsing. However
* parsers may leave "rejected" data in the brigade, even during a
* successful parse, so callers may need to clean up the brigade
* themselves (in particular, rejected buckets should not be
* passed back to the parser again).
* @remark bb == NULL is valid: the parser should return its
* public status: APR_INCOMPLETE, APR_SUCCESS, or an error code.
*/
static APR_INLINE
apr_status_t apreq_parser_run(struct apreq_parser_t *psr, apr_table_t *t,
apr_bucket_brigade *bb)
{
return psr->parser(psr, t, bb);
}
/**
* Run the hook with the current parameter and the incoming
* bucket brigade. The hook may modify the brigade if necessary.
* Once all hooks have completed, the contents of the brigade will
* be added to the parameter's bb attribute.
* @return APR_SUCCESS on success. All other values represent errors.
*/
static APR_INLINE
apr_status_t apreq_hook_run(struct apreq_hook_t *h, apreq_param_t *param,
apr_bucket_brigade *bb)
{
return h->hook(h, param, bb);
}
/**
* RFC 822 Header parser. It will reject all data
* after the first CRLF CRLF sequence (an empty line).
* See apreq_parser_run() for more info on rejected data.
*/
APREQ_DECLARE_PARSER(apreq_parse_headers);
/**
* RFC 2396 application/x-www-form-urlencoded parser.
*/
APREQ_DECLARE_PARSER(apreq_parse_urlencoded);
/**
* RFC 2388 multipart/form-data (and XForms 1.0 multipart/related)
* parser. It will reject any buckets representing preamble and
* postamble text (this is normal behavior, not an error condition).
* See apreq_parser_run() for more info on rejected data.
*/
APREQ_DECLARE_PARSER(apreq_parse_multipart);
/**
* Generic parser. No table entries will be added to
* the req->body table by this parser. The parser creates
* a dummy apreq_param_t to pass to any configured hooks. If
* no hooks are configured, the dummy param's bb slot will
* contain a copy of the request body. It can be retrieved
* by casting the parser's ctx pointer to (apreq_param_t **).
*/
APREQ_DECLARE_PARSER(apreq_parse_generic);
/**
* apr_xml_parser hook. It will parse until EOS appears.
* The parsed document isn't available until parsing has
* completed successfully. The hook's ctx pointer may
* be cast as (apr_xml_doc **) to retrieve the
* parsed document.
*/
APREQ_DECLARE_HOOK(apreq_hook_apr_xml_parser);
/**
* Construct a parser.
*
* @param pool Pool used to allocate the parser.
* @param ba bucket allocator used to create bucket brigades
* @param content_type Content-type that this parser can deal with.
* @param pfn The parser function.
* @param brigade_limit the maximum in-memory bytes a brigade may use
* @param temp_dir the directory used by the parser for temporary files
* @param hook Hooks to associate this parser with.
* @param ctx Parser's internal scratch pad.
* @return New parser.
*/
APREQ_DECLARE(apreq_parser_t *) apreq_parser_make(apr_pool_t *pool,
apr_bucket_alloc_t *ba,
const char *content_type,
apreq_parser_function_t pfn,
apr_size_t brigade_limit,
const char *temp_dir,
apreq_hook_t *hook,
void *ctx);
/**
* Construct a hook.
*
* @param pool used to allocate the hook.
* @param hook The hook function.
* @param next List of other hooks for this hook to call on.
* @param ctx Hook's internal scratch pad.
* @return New hook.
*/
APREQ_DECLARE(apreq_hook_t *) apreq_hook_make(apr_pool_t *pool,
apreq_hook_function_t hook,
apreq_hook_t *next,
void *ctx);
/**
* Add a new hook to the end of the parser's hook list.
*
* @param p Parser.
* @param h Hook to append.
*/
APREQ_DECLARE(apr_status_t) apreq_parser_add_hook(apreq_parser_t *p,
apreq_hook_t *h);
/**
* Fetch the default parser function associated with the given MIME type.
* @param enctype The desired enctype (can also be a full "Content-Type"
* header).
* @return The parser function, or NULL if the enctype is unrecognized.
*/
APREQ_DECLARE(apreq_parser_function_t)apreq_parser(const char *enctype);
/**
* Register a new parsing function with a MIME enctype.
* Registered parsers are added to apreq_parser()'s
* internal lookup table.
*
* @param enctype The MIME type.
* @param pfn The function to use during parsing. Setting
* parser == NULL will remove an existing parser.
*
* @return APR_SUCCESS or error.
*/
APREQ_DECLARE(apr_status_t) apreq_register_parser(const char *enctype,
apreq_parser_function_t pfn);
/**
* Returns APREQ_ERROR_GENERAL. Effectively disables mfd parser
* if a file-upload field is present.
*
*/
APREQ_DECLARE_HOOK(apreq_hook_disable_uploads);
/**
* Calls apr_brigade_cleanup on the incoming brigade
* after passing the brigade to any subsequent hooks.
*/
APREQ_DECLARE_HOOK(apreq_hook_discard_brigade);
/**
* Context struct for the apreq_hook_find_param hook.
*/
typedef struct apreq_hook_find_param_ctx_t {
const char *name;
apreq_param_t *param;
apreq_hook_t *prev;
} apreq_hook_find_param_ctx_t;
/**
* Special purpose utility for locating a parameter
* during parsing. The hook's ctx should be initialized
* to an apreq_hook_find_param_ctx_t *, with the name
* attribute set to the sought parameter name, the param
* attribute set to NULL, and the prev attribute set to
* the address of the previous hook. The param attribute
* will be reassigned to the first param found, and once
* that happens this hook is immediately removed from the chain.
*
* @remarks When used, this should always be the first hook
* invoked, so add it manually with ctx->prev = &parser->hook
* instead of using apreq_parser_add_hook.
*/
APREQ_DECLARE_HOOK(apreq_hook_find_param);
#ifdef __cplusplus
}
#endif
#endif /* APREQ_PARSERS_H */

View File

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

View File

@@ -1,200 +0,0 @@
# Microsoft Developer Studio Project File - Name="libapreq" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=libapreq - Win32 Release
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "libapreq.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "libapreq.mak" CFG="libapreq - Win32 Release"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "libapreq - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "libapreq - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "libapreq - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_DECLARE_EXPORT" /D "APREQ_DECLARE_EXPORT" /FD /c
# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "./srclib/apr/include" /I "./srclib/apr-util/include" /I "./srclib/pcre" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_DECLARE_EXPORT" /D "APREQ_DECLARE_EXPORT" /Fd"Release\libapreq_cl" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /fo"Release/libapreq.res" /i "./include" /i "./srclib/apr/include" /d "NDEBUG" /d BIN_NAME="libapreq.dll" /d LONG_NAME="libapreq"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /machine:IX86
# ADD LINK32 pcre.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /debug /machine:IX86 /libpath:"./srclib/pcre" /base:@"os\win32\BaseAddr.ref",libapreq.dll /opt:ref
# Begin Special Build Tool
TargetPath=.\Release\libapreq.dll
SOURCE="$(InputPath)"
PostBuild_Desc=Embed .manifest
PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
# End Special Build Tool
!ELSEIF "$(CFG)" == "libapreq - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS"/D "AP_DECLARE_EXPORT" /D "APREQ_DECLARE_EXPORT" /FD /EHsc /c
# ADD CPP /nologo /MDd /W3 /Zi /Od /I "./include" /I "./srclib/apr/include" /I "./srclib/apr-util/include" /I "./srclib/pcre" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "AP_DECLARE_EXPORT" /D "APREQ_DECLARE_EXPORT" /Fd"Debug\libapreq_cl" /FD /EHsc /c
# ADD BASE MTL /nologo /D "_DEBUG" /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /fo"Debug/libapreq.res" /i "./include" /i "./srclib/apr/include" /d "_DEBUG" /d BIN_NAME="libapreq.dll" /d LONG_NAME="libapreq"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:IX86
# ADD LINK32 pcred.lib kernel32.lib user32.lib advapi32.lib ws2_32.lib mswsock.lib /nologo /subsystem:windows /dll /incremental:no /debug /machine:IX86 /libpath:"./srclib/pcre" /base:@"os\win32\BaseAddr.ref",libapreq.dll
# Begin Special Build Tool
TargetPath=.\Debug\libapreq.dll
SOURCE="$(InputPath)"
PostBuild_Desc=Embed .manifest
PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
# End Special Build Tool
!ENDIF
# Begin Target
# Name "libapreq - Win32 Release"
# Name "libapreq - Win32 Debug"
# Begin Group "headers"
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
# Begin Source File
SOURCE=.\include\ap_config.h
# End Source File
# Begin Source File
SOURCE=.\include\ap_release.h
# End Source File
# Begin Source File
SOURCE=.\include\apreq.h
# End Source File
# Begin Source File
SOURCE=.\include\apreq_cookie.h
# End Source File
# Begin Source File
SOURCE=.\include\apreq_error.h
# End Source File
# Begin Source File
SOURCE=.\include\apreq_module.h
# End Source File
# Begin Source File
SOURCE=.\include\apreq_param.h
# End Source File
# Begin Source File
SOURCE=.\include\apreq_parser.h
# End Source File
# Begin Source File
SOURCE=.\include\apreq_util.h
# End Source File
# End Group
# Begin Group "libapreq"
# PROP Default_Filter ""
# Begin Source File
SOURCE=.\server\apreq_cookie.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_error.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_module.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_module_cgi.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_module_custom.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_param.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_parser.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_parser_header.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_parser_multipart.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_parser_urlencoded.c
# End Source File
# Begin Source File
SOURCE=.\server\apreq_util.c
# End Source File
# Begin Source File
SOURCE=.\server\buildmark.c
# PROP Exclude_From_Build 1
# End Source File
# End Group
# Begin Source File
SOURCE=.\build\win32\httpd.rc
# End Source File
# End Target
# End Project

View File

@@ -33,7 +33,6 @@ endif
SUBDIRS = \
aaa \
apreq \
cache \
cluster \
core \

View File

@@ -1 +0,0 @@
include $(top_srcdir)/build/special.mk

View File

@@ -1,250 +0,0 @@
#
# Make sure all needed macro's are defined
#
#
# Get the 'head' of the build environment if necessary. This includes default
# targets and paths to tools
#
ifndef EnvironmentDefined
include $(AP_WORK)/build/NWGNUhead.inc
endif
#
# These directories will be at the beginning of the include list, followed by
# INCDIRS
#
XINCDIRS += \
$(APR)/include \
$(APRUTIL)/include \
$(SRC)/include \
$(NWOS) \
$(EOLIST)
#
# These flags will come after CFLAGS
#
XCFLAGS += \
$(EOLIST)
#
# These defines will come after DEFINES
#
XDEFINES += \
$(EOLIST)
#
# These flags will be added to the link.opt file
#
XLFLAGS += \
$(EOLIST)
#
# These values will be appended to the correct variables based on the value of
# RELEASE
#
ifeq "$(RELEASE)" "debug"
XINCDIRS += \
$(EOLIST)
XCFLAGS += \
$(EOLIST)
XDEFINES += \
$(EOLIST)
XLFLAGS += \
$(EOLIST)
endif
ifeq "$(RELEASE)" "noopt"
XINCDIRS += \
$(EOLIST)
XCFLAGS += \
$(EOLIST)
XDEFINES += \
$(EOLIST)
XLFLAGS += \
$(EOLIST)
endif
ifeq "$(RELEASE)" "release"
XINCDIRS += \
$(EOLIST)
XCFLAGS += \
$(EOLIST)
XDEFINES += \
$(EOLIST)
XLFLAGS += \
$(EOLIST)
endif
#
# These are used by the link target if an NLM is being generated
# This is used by the link 'name' directive to name the nlm. If left blank
# TARGET_nlm (see below) will be used.
#
NLM_NAME = mod_apreq
#
# This is used by the link '-desc ' directive.
# If left blank, NLM_NAME will be used.
#
NLM_DESCRIPTION = Apache $(VERSION_STR) Request Filter Module
#
# This is used by the '-threadname' directive. If left blank,
# NLM_NAME Thread will be used.
#
NLM_THREAD_NAME = apreq Module
#
# If this is specified, it will override VERSION value in
# $(AP_WORK)/build/NWGNUenvironment.inc
#
NLM_VERSION =
#
# If this is specified, it will override the default of 64K
#
NLM_STACK_SIZE = 8192
#
# If this is specified it will be used by the link '-entry' directive
#
NLM_ENTRY_SYM =
#
# If this is specified it will be used by the link '-exit' directive
#
NLM_EXIT_SYM =
#
# If this is specified it will be used by the link '-check' directive
#
NLM_CHECK_SYM =
#
# If these are specified it will be used by the link '-flags' directive
#
NLM_FLAGS =
#
# If this is specified it will be linked in with the XDCData option in the def
# file instead of the default of $(NWOS)/apache.xdc. XDCData can be disabled
# by setting APACHE_UNIPROC in the environment
#
XDCDATA =
#
# If there is an NLM target, put it here
#
TARGET_nlm = \
$(OBJDIR)/$(NLM_NAME).nlm \
$(EOLIST)
#
# If there is an LIB target, put it here
#
TARGET_lib = \
$(EOLIST)
#
# These are the OBJ files needed to create the NLM target above.
# Paths must all use the '/' character
#
FILES_nlm_objs = \
$(OBJDIR)/filter.o \
$(OBJDIR)/handle.o \
$(EOLIST)
#
# These are the LIB files needed to create the NLM target above.
# These will be added as a library command in the link.opt file.
#
FILES_nlm_libs = \
$(PRELUDE) \
$(EOLIST)
#
# These are the modules that the above NLM target depends on to load.
# These will be added as a module command in the link.opt file.
#
FILES_nlm_modules = \
aprlib \
libc \
$(EOLIST)
#
# If the nlm has a msg file, put it's path here
#
FILE_nlm_msg =
#
# If the nlm has a hlp file put it's path here
#
FILE_nlm_hlp =
#
# If this is specified, it will override $(NWOS)\copyright.txt.
#
FILE_nlm_copyright =
#
# Any additional imports go here
#
FILES_nlm_Ximports = \
@aprlib.imp \
@httpd.imp \
@libc.imp \
$(EOLIST)
#
# Any symbols exported to here
#
FILES_nlm_exports = \
apreq_module \
$(EOLIST)
#
# These are the OBJ files needed to create the LIB target above.
# Paths must all use the '/' character
#
FILES_lib_objs = \
$(EOLIST)
#
# implement targets and dependencies (leave this section alone)
#
libs :: $(OBJDIR) $(TARGET_lib)
nlms :: libs $(TARGET_nlm)
#
# Updated this target to create necessary directories and copy files to the
# correct place. (See $(AP_WORK)/build/NWGNUhead.inc for examples)
#
install :: nlms FORCE
$(call COPY,$(OBJDIR)/*.nlm, $(INSTALLBASE)/modules/)
#
# Any specialized rules here
#
#
# Include the 'tail' makefile that has targets that depend on variables defined
# in this makefile
#
include $(APBUILD)/NWGNUtail.inc

View File

@@ -1,182 +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_APACHE2_H
#define APREQ_APACHE2_H
#include "apreq_module.h"
#include "apr_optional.h"
#include <httpd.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup mod_apreq2 Apache 2.X Filter Module
* @ingroup APACHE_MODS
* @brief mod_apreq2 - DSO that ties libapreq2 to Apache HTTPD 2.X.
*
* mod_apreq2 provides the "APREQ2" input filter for using libapreq2
* (and allow its parsed data structures to be shared) within
* the Apache 2.X webserver. Using it, libapreq2 works properly
* in every phase of the HTTP request, from translation handlers
* to output filters, and even for subrequests / internal redirects.
*
* <hr>
*
* <h2>Activating mod_apreq2 in Apache 2.X</h2>
*
* The installation process triggered by
* <code>% make install</code>
* <em>will not modify your webserver's config file</em>. Hence,
* be sure you activate it on startup by adding a LoadModule directive
* to your webserver config; e.g.
*
* @code
*
* LoadModule apreq_module modules/mod_apreq2.so
*
* @endcode
*
* The mod_apreq2 filter is named "apreq2", and may be used in Apache's
* input filter directives, e.g.
* @code
*
* AddInputFilter apreq2 # or
* SetInputFilter apreq2
*
* @endcode
*
* However, this is not required because libapreq2 will add the filter (only)
* if it's necessary. You just need to ensure that your module invokes
* apreq_handle_apache2() <em>before the content handler ultimately reads
* from the input filter chain</em>. It is important to realize that no
* matter how the input filters are initially arranged, the APREQ2 filter
* will attempt to reposition itself to be the last input filter to read the
* data.
*
* If you want to use other input filters to transform the incoming HTTP
* request data, is important to register those filters with Apache
* as having type AP_FTYPE_CONTENT_SET or AP_FTYPE_RESOURCE. Due to the
* limitations of Apache's current input filter design, types higher than
* AP_FTYPE_CONTENT_SET may not work properly whenever the apreq filter is
* active.
*
* This is especially true when a content handler uses libapreq2 to parse
* some of the post data before doing an internal redirect. Any input
* filter subsequently added to the redirected request will bypass the
* original apreq filter (and therefore lose access to some of the original
* post data), unless its type is less than the type of the apreq filter
* (currently AP_FTYPE_PROTOCOL-1).
*
*
* <H2>Server Configuration Directives</H2>
*
* <TABLE class="qref">
* <CAPTION>Per-directory commands for mod_apreq2</CAPTION>
* <TR>
* <TH>Directive</TH>
* <TH>Context</TH>
* <TH>Default</TH><TH>Description</TH>
* </TR>
* <TR class="odd">
* <TD>APREQ2_ReadLimit</TD>
* <TD>directory</TD>
* <TD> #APREQ_DEFAULT_READ_LIMIT </TD>
* <TD> 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.
* </TD>
* </TR>
* <TR>
* <TD>APREQ2_BrigadeLimit</TD>
* <TD>directory</TD>
* <TD>#APREQ_DEFAULT_BRIGADE_LIMIT</TD>
* <TD> 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.
* </TD>
* </TR>
* <TR class="odd">
* <TD>APREQ2_TempDir</TD>
* <TD>directory</TD>
* <TD>NULL</TD>
* <TD> Sets the location of the temporary directory apreq will use to spool
* overflow brigade data (based on the APREQ2_BrigadeLimit setting).
* If left unset, libapreq2 will select a platform-specific location
* via apr_temp_dir_get().
* </TD>
* </TR>
* </TABLE>
*
* <H2>Implementation Details</H2>
* <PRE>
* XXX apreq as a normal input filter
* XXX apreq as a "virtual" content handler.
* XXX apreq as a transparent "tee".
* XXX apreq parser registration in post_config
* </PRE>
*
* @{
*/
/**
* Create an apreq handle which communicates with an Apache 2.X
* request_rec.
*/
APREQ_DECLARE(apreq_handle_t *) apreq_handle_apache2(request_rec *r);
/**
*
*
*/
#ifdef WIN32
typedef __declspec(dllexport) apreq_handle_t *
(__stdcall apr_OFN_apreq_handle_apache2_t) (request_rec *r);
#else
APR_DECLARE_OPTIONAL_FN(APREQ_DECLARE(apreq_handle_t *),
apreq_handle_apache2, (request_rec *r));
#endif
/**
* The mod_apreq2 filter is named "apreq2", and may be used in Apache's
* input filter directives, e.g.
* @code
*
* AddInputFilter apreq2 # or
* SetInputFilter apreq2
* @endcode
* See above
*/
#define APREQ_FILTER_NAME "apreq2"
/**
* The Apache2 Module Magic Number for use in the Apache 2.x module structures
* This gets bumped if changes in th4e API will break third party applications
* using this apache2 module
* @see APREQ_MODULE
*/
#define APREQ_APACHE2_MMN 20101207
/** @} */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,56 +0,0 @@
extern module AP_MODULE_DECLARE_DATA apreq_module;
struct dir_config {
const char *temp_dir;
apr_uint64_t read_limit;
apr_size_t brigade_limit;
};
/* The "warehouse", stored in r->request_config */
struct apache2_handle {
apreq_handle_t handle;
request_rec *r;
apr_table_t *jar, *args;
apr_status_t jar_status, args_status;
ap_filter_t *f;
};
/* Tracks the apreq filter state */
struct filter_ctx {
apr_bucket_brigade *bb; /* input brigade that's passed to the parser */
apr_bucket_brigade *bbtmp; /* temporary copy of bb, destined for the spool */
apr_bucket_brigade *spool; /* copied prefetch data for downstream filters */
apreq_parser_t *parser;
apreq_hook_t *hook_queue;
apreq_hook_t *find_param;
apr_table_t *body;
apr_status_t body_status;
apr_status_t filter_error;
apr_uint64_t bytes_read; /* Total bytes read into this filter. */
apr_uint64_t read_limit; /* Max bytes the filter may show to parser */
apr_size_t brigade_limit;
const char *temp_dir;
};
apr_status_t apreq_filter_prefetch(ap_filter_t *f, apr_off_t readbytes);
apr_status_t apreq_filter(ap_filter_t *f,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
apr_read_type_e block,
apr_off_t readbytes);
void apreq_filter_make_context(ap_filter_t *f);
void apreq_filter_init_context(ap_filter_t *f);
APR_INLINE
static void apreq_filter_relocate(ap_filter_t *f)
{
request_rec *r = f->r;
if (f != r->input_filters) {
ap_filter_t *top = r->input_filters;
ap_remove_input_filter(f);
r->input_filters = f;
f->next = top;
}
}

View File

@@ -1,9 +0,0 @@
dnl modules enabled in this directory by default
dnl APACHE_MODULE(name, helptext[, objects[, structname[, default[, config]]]])
APACHE_MODPATH_INIT(apreq)
APACHE_MODULE(apreq, Apache Request Filter, filter.lo handle.lo, , most)
APACHE_MODPATH_FINISH

View File

@@ -1,532 +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 "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "util_filter.h"
#include "apr_tables.h"
#include "apr_buckets.h"
#include "http_request.h"
#include "apr_strings.h"
#include "apreq_module_apache2.h"
#include "apreq_private_apache2.h"
#include "apreq_error.h"
#include "apreq_util.h"
static void *apreq_create_dir_config(apr_pool_t *p, char *d)
{
/* d == OR_ALL */
struct dir_config *dc = apr_palloc(p, sizeof *dc);
dc->temp_dir = NULL;
dc->read_limit = -1;
dc->brigade_limit = -1;
return dc;
}
static void *apreq_merge_dir_config(apr_pool_t *p, void *a_, void *b_)
{
struct dir_config *a = a_, *b = b_, *c = apr_palloc(p, sizeof *c);
c->temp_dir = (b->temp_dir != NULL) /* overrides ok */
? b->temp_dir : a->temp_dir;
c->brigade_limit = (b->brigade_limit == (apr_size_t)-1) /* overrides ok */
? a->brigade_limit : b->brigade_limit;
c->read_limit = (b->read_limit < a->read_limit) /* yes, min */
? b->read_limit : a->read_limit;
return c;
}
static const char *apreq_set_temp_dir(cmd_parms *cmd, void *data,
const char *arg)
{
struct dir_config *conf = data;
const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
if (err != NULL)
return err;
conf->temp_dir = arg;
return NULL;
}
static const char *apreq_set_read_limit(cmd_parms *cmd, void *data,
const char *arg)
{
struct dir_config *conf = data;
const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
if (err != NULL)
return err;
conf->read_limit = apreq_atoi64f(arg);
return NULL;
}
static const char *apreq_set_brigade_limit(cmd_parms *cmd, void *data,
const char *arg)
{
struct dir_config *conf = data;
const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
if (err != NULL)
return err;
conf->brigade_limit = apreq_atoi64f(arg);
return NULL;
}
static const command_rec apreq_cmds[] =
{
AP_INIT_TAKE1("APREQ2_TempDir", apreq_set_temp_dir, NULL, OR_ALL,
"Default location of temporary directory"),
AP_INIT_TAKE1("APREQ2_ReadLimit", apreq_set_read_limit, NULL, OR_ALL,
"Maximum amount of data that will be fed into a parser."),
AP_INIT_TAKE1("APREQ2_BrigadeLimit", apreq_set_brigade_limit, NULL, OR_ALL,
"Maximum in-memory bytes a brigade may use."),
{ NULL }
};
void apreq_filter_init_context(ap_filter_t *f)
{
request_rec *r = f->r;
struct filter_ctx *ctx = f->ctx;
apr_bucket_alloc_t *ba = r->connection->bucket_alloc;
const char *cl_header;
if (r->method_number == M_GET) {
/* Don't parse GET (this protects against subrequest body parsing). */
ctx->body_status = APREQ_ERROR_NODATA;
return;
}
cl_header = apr_table_get(r->headers_in, "Content-Length");
if (cl_header != NULL) {
apr_off_t cl;
if (!ap_parse_strict_length(&cl, cl_header)) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, APLOGNO(02045)
"Invalid Content-Length header (%s)", cl_header);
ctx->body_status = APREQ_ERROR_BADHEADER;
return;
}
if ((apr_uint64_t)cl > ctx->read_limit) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, APR_EGENERAL, r, APLOGNO(02046)
"Content-Length header (%s) exceeds configured "
"max_body limit (%" APR_UINT64_T_FMT ")",
cl_header, ctx->read_limit);
ctx->body_status = APREQ_ERROR_OVERLIMIT;
return;
}
}
if (ctx->parser == NULL) {
const char *ct_header = apr_table_get(r->headers_in, "Content-Type");
if (ct_header != NULL) {
apreq_parser_function_t pf = apreq_parser(ct_header);
if (pf != NULL) {
ctx->parser = apreq_parser_make(r->pool, ba, ct_header, pf,
ctx->brigade_limit,
ctx->temp_dir,
ctx->hook_queue,
NULL);
}
else {
ctx->body_status = APREQ_ERROR_NOPARSER;
return;
}
}
else {
ctx->body_status = APREQ_ERROR_NOHEADER;
return;
}
}
else {
if (ctx->parser->brigade_limit > ctx->brigade_limit)
ctx->parser->brigade_limit = ctx->brigade_limit;
if (ctx->temp_dir != NULL)
ctx->parser->temp_dir = ctx->temp_dir;
if (ctx->hook_queue != NULL)
apreq_parser_add_hook(ctx->parser, ctx->hook_queue);
}
ctx->hook_queue = NULL;
ctx->bb = apr_brigade_create(r->pool, ba);
ctx->bbtmp = apr_brigade_create(r->pool, ba);
ctx->spool = apr_brigade_create(r->pool, ba);
ctx->body = apr_table_make(r->pool, APREQ_DEFAULT_NELTS);
ctx->body_status = APR_INCOMPLETE;
}
/*
* Situations to contend with:
*
* 1) Often the filter will be added by the content handler itself,
* so the apreq_filter_init hook will not be run.
* 2) If an auth handler uses apreq, the apreq_filter will ensure
* it's part of the protocol filters. apreq_filter_init does NOT need
* to notify the protocol filter that it must not continue parsing,
* the apreq filter can perform this check itself. apreq_filter_init
* just needs to ensure cfg->f does not point at it.
* 3) If req->proto_input_filters and req->input_filters are apreq
* filters, and req->input_filters->next == req->proto_input_filters,
* it is safe for apreq_filter to "steal" the proto filter's context
* and subsequently drop it from the chain.
*/
/* Examines the input_filter chain and moves the apreq filter(s) around
* before the filter chain is stacked by ap_get_brigade.
*/
static apr_status_t apreq_filter_init(ap_filter_t *f)
{
request_rec *r = f->r;
struct filter_ctx *ctx = f->ctx;
struct apache2_handle *handle =
(struct apache2_handle *)apreq_handle_apache2(r);
/* Don't parse GET (this protects against subrequest body parsing). */
if (f->r->method_number == M_GET)
return APR_SUCCESS;
if (ctx == NULL || ctx->body_status == APR_EINIT) {
if (f == r->input_filters) {
handle->f = f;
}
else if (r->input_filters->frec->filter_func.in_func == apreq_filter) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02047)
"removing intermediate apreq filter");
if (handle->f == f)
handle->f = r->input_filters;
ap_remove_input_filter(f);
}
else {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02048)
"relocating intermediate apreq filter");
apreq_filter_relocate(f);
handle->f = f;
}
return APR_SUCCESS;
}
/* else this is a protocol filter which may still be active.
* if it is, we must deregister it now.
*/
if (handle->f == f) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02049)
"disabling stale protocol filter");
if (ctx->body_status == APR_INCOMPLETE)
ctx->body_status = APREQ_ERROR_INTERRUPT;
handle->f = NULL;
}
return APR_SUCCESS;
}
apr_status_t apreq_filter_prefetch(ap_filter_t *f, apr_off_t readbytes)
{
struct filter_ctx *ctx = f->ctx;
request_rec *r = f->r;
apr_status_t rv;
apr_off_t len;
if (ctx->body_status == APR_EINIT)
apreq_filter_init_context(f);
if (ctx->body_status != APR_INCOMPLETE || readbytes == 0)
return ctx->body_status;
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02050)
"prefetching %" APR_OFF_T_FMT " bytes", readbytes);
rv = ap_get_brigade(f->next, ctx->bb, AP_MODE_READBYTES,
APR_BLOCK_READ, readbytes);
if (rv != APR_SUCCESS) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02051)
"ap_get_brigade failed during prefetch");
ctx->filter_error = rv;
return ctx->body_status = APREQ_ERROR_GENERAL;
}
apreq_brigade_setaside(ctx->bb, r->pool);
apreq_brigade_copy(ctx->bbtmp, ctx->bb);
rv = apreq_brigade_concat(r->pool, ctx->temp_dir, ctx->brigade_limit,
ctx->spool, ctx->bbtmp);
if (rv != APR_SUCCESS && rv != APR_EOF) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r, APLOGNO(02052)
"apreq_brigade_concat failed; TempDir problem?");
ctx->filter_error = APR_EGENERAL;
return ctx->body_status = rv;
}
/* Adding "f" to the protocol filter chain ensures the
* spooled data is preserved across internal redirects.
*/
if (f != r->proto_input_filters) {
ap_filter_t *in;
for (in = r->input_filters; in != r->proto_input_filters;
in = in->next)
{
if (f == in) {
r->proto_input_filters = f;
break;
}
}
}
apr_brigade_length(ctx->bb, 1, &len);
ctx->bytes_read += len;
if (ctx->bytes_read > ctx->read_limit) {
ctx->body_status = APREQ_ERROR_OVERLIMIT;
ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r, APLOGNO(02053)
"Bytes read (%" APR_UINT64_T_FMT
") exceeds configured read limit (%" APR_UINT64_T_FMT ")",
ctx->bytes_read, ctx->read_limit);
return ctx->body_status;
}
ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb);
apr_brigade_cleanup(ctx->bb);
return ctx->body_status;
}
apr_status_t apreq_filter(ap_filter_t *f,
apr_bucket_brigade *bb,
ap_input_mode_t mode,
apr_read_type_e block,
apr_off_t readbytes)
{
request_rec *r = f->r;
struct filter_ctx *ctx;
apr_status_t rv;
apr_off_t len;
switch (mode) {
case AP_MODE_READBYTES:
/* only the modes above are supported */
break;
case AP_MODE_EXHAUSTIVE: /* not worth supporting at this level */
case AP_MODE_GETLINE: /* chunked trailers are b0rked in ap_http_filter */
return ap_get_brigade(f->next, bb, mode, block, readbytes);
default:
return APR_ENOTIMPL;
}
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
if (ctx->body_status == APR_EINIT)
apreq_filter_init_context(f);
if (ctx->spool && !APR_BRIGADE_EMPTY(ctx->spool)) {
apr_bucket *e;
rv = apr_brigade_partition(ctx->spool, readbytes, &e);
if (rv != APR_SUCCESS && rv != APR_INCOMPLETE)
return rv;
if (APR_BUCKET_IS_EOS(e))
e = APR_BUCKET_NEXT(e);
apreq_brigade_move(bb, ctx->spool, e);
return APR_SUCCESS;
}
else if (ctx->body_status != APR_INCOMPLETE) {
if (ctx->filter_error)
return ctx->filter_error;
rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
ap_remove_input_filter(f);
return rv;
}
rv = ap_get_brigade(f->next, bb, mode, block, readbytes);
if (rv != APR_SUCCESS)
return rv;
apreq_brigade_copy(ctx->bb, bb);
apr_brigade_length(bb, 1, &len);
ctx->bytes_read += len;
if (ctx->bytes_read > ctx->read_limit) {
ctx->body_status = APREQ_ERROR_OVERLIMIT;
ap_log_rerror(APLOG_MARK, APLOG_ERR, ctx->body_status, r, APLOGNO(02054)
"Bytes read (%" APR_UINT64_T_FMT
") exceeds configured max_body limit (%"
APR_UINT64_T_FMT ")",
ctx->bytes_read, ctx->read_limit);
}
else {
ctx->body_status = apreq_parser_run(ctx->parser, ctx->body, ctx->bb);
apr_brigade_cleanup(ctx->bb);
}
return APR_SUCCESS;
}
static int apreq_pre_init(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *base_server)
{
apr_status_t status;
status = apreq_pre_initialize(p);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, base_server, APLOGNO(02055)
"Failed to pre-initialize libapreq2");
return HTTP_INTERNAL_SERVER_ERROR;
}
APR_REGISTER_OPTIONAL_FN(apreq_handle_apache2);
return OK;
}
static int apreq_post_init(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *base_server)
{
apr_status_t status;
status = apreq_post_initialize(p);
if (status != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, base_server, APLOGNO(02056)
"Failed to post-initialize libapreq2");
return HTTP_INTERNAL_SERVER_ERROR;
}
return OK;
}
static void register_hooks (apr_pool_t *p)
{
/* APR_HOOK_FIRST because we want other modules to be able to
* register parsers in their post_config hook via APR_HOOK_MIDDLE.
*/
ap_hook_post_config(apreq_pre_init, NULL, NULL, APR_HOOK_FIRST);
/* APR_HOOK_LAST because we need to lock the default_parsers hash
* (to prevent further modifications) before the server forks.
*/
ap_hook_post_config(apreq_post_init, NULL, NULL, APR_HOOK_LAST);
ap_register_input_filter(APREQ_FILTER_NAME, apreq_filter, apreq_filter_init,
AP_FTYPE_PROTOCOL-1);
}
/** @} */
module AP_MODULE_DECLARE_DATA apreq_module = {
#line __LINE__ "mod_apreq2.c"
STANDARD20_MODULE_STUFF,
apreq_create_dir_config,
apreq_merge_dir_config,
NULL,
NULL,
apreq_cmds,
register_hooks,
};
void apreq_filter_make_context(ap_filter_t *f)
{
request_rec *r;
struct filter_ctx *ctx;
struct dir_config *d;
r = f->r;
d = ap_get_module_config(r->per_dir_config, &apreq_module);
if (f == r->input_filters
&& r->proto_input_filters == f->next
&& f->next->frec->filter_func.in_func == apreq_filter
&& f->r->method_number != M_GET)
{
ctx = f->next->ctx;
switch (ctx->body_status) {
case APREQ_ERROR_INTERRUPT:
ctx->body_status = APR_INCOMPLETE;
/* fall thru */
case APR_SUCCESS:
if (d != NULL) {
ctx->temp_dir = d->temp_dir;
ctx->read_limit = d->read_limit;
ctx->brigade_limit = d->brigade_limit;
if (ctx->parser != NULL) {
ctx->parser->temp_dir = d->temp_dir;
ctx->parser->brigade_limit = d->brigade_limit;
}
}
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, APLOGNO(02057)
"stealing filter context");
f->ctx = ctx;
r->proto_input_filters = f;
ap_remove_input_filter(f->next);
return;
default:
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, ctx->body_status, r, APLOGNO(02058)
"cannot steal context: bad filter status");
}
}
ctx = apr_pcalloc(r->pool, sizeof *ctx);
ctx->body_status = APR_EINIT;
if (d == NULL) {
ctx->read_limit = (apr_uint64_t)-1;
ctx->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT;
} else {
ctx->temp_dir = d->temp_dir;
ctx->read_limit = (d->read_limit == (apr_uint64_t)-1)
? APREQ_DEFAULT_READ_LIMIT : d->read_limit;
ctx->brigade_limit = (d->brigade_limit == (apr_size_t)-1)
? APREQ_DEFAULT_BRIGADE_LIMIT : d->brigade_limit;
}
f->ctx = ctx;
}

View File

@@ -1,440 +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 "httpd.h"
#include "http_config.h"
#include "http_log.h"
#include "util_filter.h"
#include "apr_tables.h"
#include "apr_buckets.h"
#include "http_request.h"
#include "apr_strings.h"
#include "apreq_module_apache2.h"
#include "apreq_private_apache2.h"
#include "apreq_error.h"
APR_INLINE
static ap_filter_t *get_apreq_filter(apreq_handle_t *handle)
{
struct apache2_handle *req = (struct apache2_handle *)handle;
if (req->f == NULL) {
req->f = ap_add_input_filter(APREQ_FILTER_NAME, NULL,
req->r,
req->r->connection);
/* ap_add_input_filter does not guarantee cfg->f == r->input_filters,
* so we reposition the new filter there as necessary.
*/
apreq_filter_relocate(req->f);
}
return req->f;
}
static apr_status_t apache2_jar(apreq_handle_t *handle, const apr_table_t **t)
{
struct apache2_handle *req = (struct apache2_handle*)handle;
request_rec *r = req->r;
if (req->jar_status == APR_EINIT) {
const char *cookies = apr_table_get(r->headers_in, "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 apache2_args(apreq_handle_t *handle, const apr_table_t **t)
{
struct apache2_handle *req = (struct apache2_handle*)handle;
request_rec *r = req->r;
if (req->args_status == APR_EINIT) {
if (r->args != NULL) {
req->args = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS);
req->args_status =
apreq_parse_query_string(handle->pool, req->args, r->args);
}
else
req->args_status = APREQ_ERROR_NODATA;
}
*t = req->args;
return req->args_status;
}
static apreq_cookie_t *apache2_jar_get(apreq_handle_t *handle, const char *name)
{
struct apache2_handle *req = (struct apache2_handle *)handle;
const apr_table_t *t;
const char *val;
if (req->jar_status == APR_EINIT)
apache2_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 *apache2_args_get(apreq_handle_t *handle, const char *name)
{
struct apache2_handle *req = (struct apache2_handle *)handle;
const apr_table_t *t;
const char *val;
if (req->args_status == APR_EINIT)
apache2_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 apache2_body(apreq_handle_t *handle, const apr_table_t **t)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
switch (ctx->body_status) {
case APR_EINIT:
apreq_filter_init_context(f);
if (ctx->body_status != APR_INCOMPLETE)
break;
case APR_INCOMPLETE:
while (apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE) == APR_INCOMPLETE)
; /*loop*/
}
*t = ctx->body;
return ctx->body_status;
}
static apreq_param_t *apache2_body_get(apreq_handle_t *handle, const char *name)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
const char *val;
apreq_hook_t *h;
apreq_hook_find_param_ctx_t *hook_ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
switch (ctx->body_status) {
case APR_SUCCESS:
val = apr_table_get(ctx->body, name);
if (val != NULL)
return apreq_value_to_param(val);
return NULL;
case APR_EINIT:
apreq_filter_init_context(f);
if (ctx->body_status != APR_INCOMPLETE)
return NULL;
apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
case APR_INCOMPLETE:
val = apr_table_get(ctx->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 */
hook_ctx = apr_palloc(handle->pool, sizeof *hook_ctx);
if (ctx->find_param == NULL)
ctx->find_param = apreq_hook_make(handle->pool,
apreq_hook_find_param,
NULL, NULL);
h = ctx->find_param;
h->next = ctx->parser->hook;
h->ctx = hook_ctx;
ctx->parser->hook = h;
hook_ctx->name = name;
hook_ctx->param = NULL;
hook_ctx->prev = ctx->parser->hook;
do {
apreq_filter_prefetch(f, APREQ_DEFAULT_READ_BLOCK_SIZE);
if (hook_ctx->param != NULL)
return hook_ctx->param;
} while (ctx->body_status == APR_INCOMPLETE);
ctx->parser->hook = h->next;
return NULL;
default:
if (ctx->body == NULL)
return NULL;
val = apr_table_get(ctx->body, name);
if (val != NULL)
return apreq_value_to_param(val);
return NULL;
}
/* not reached */
return NULL;
}
static
apr_status_t apache2_parser_get(apreq_handle_t *handle,
const apreq_parser_t **parser)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx = f->ctx;
if (ctx == NULL) {
*parser = NULL;
return APR_EINIT;
}
*parser = ctx->parser;
return APR_SUCCESS;
}
static
apr_status_t apache2_parser_set(apreq_handle_t *handle,
apreq_parser_t *parser)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
if (ctx->parser == NULL) {
ctx->parser = parser;
return APR_SUCCESS;
}
else
return APREQ_ERROR_NOTEMPTY;
}
static
apr_status_t apache2_hook_add(apreq_handle_t *handle,
apreq_hook_t *hook)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
if (ctx->parser != NULL) {
return apreq_parser_add_hook(ctx->parser, hook);
}
else if (ctx->hook_queue != NULL) {
apreq_hook_t *h = ctx->hook_queue;
while (h->next != NULL)
h = h->next;
h->next = hook;
}
else {
ctx->hook_queue = hook;
}
return APR_SUCCESS;
}
static
apr_status_t apache2_brigade_limit_set(apreq_handle_t *handle,
apr_size_t bytes)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
if (ctx->body_status == APR_EINIT || ctx->brigade_limit > bytes) {
ctx->brigade_limit = bytes;
return APR_SUCCESS;
}
return APREQ_ERROR_MISMATCH;
}
static
apr_status_t apache2_brigade_limit_get(apreq_handle_t *handle,
apr_size_t *bytes)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
*bytes = ctx->brigade_limit;
return APR_SUCCESS;
}
static
apr_status_t apache2_read_limit_set(apreq_handle_t *handle,
apr_uint64_t bytes)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
if (ctx->read_limit > bytes && ctx->bytes_read < bytes) {
ctx->read_limit = bytes;
return APR_SUCCESS;
}
return APREQ_ERROR_MISMATCH;
}
static
apr_status_t apache2_read_limit_get(apreq_handle_t *handle,
apr_uint64_t *bytes)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
*bytes = ctx->read_limit;
return APR_SUCCESS;
}
static
apr_status_t apache2_temp_dir_set(apreq_handle_t *handle,
const char *path)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
/* init vs incomplete state? */
if (ctx->temp_dir == NULL && ctx->bytes_read == 0) {
if (path != NULL)
ctx->temp_dir = apr_pstrdup(handle->pool, path);
return APR_SUCCESS;
}
return APREQ_ERROR_NOTEMPTY;
}
static
apr_status_t apache2_temp_dir_get(apreq_handle_t *handle,
const char **path)
{
ap_filter_t *f = get_apreq_filter(handle);
struct filter_ctx *ctx;
if (f->ctx == NULL)
apreq_filter_make_context(f);
ctx = f->ctx;
*path = ctx->parser ? ctx->parser->temp_dir : ctx->temp_dir;
return APR_SUCCESS;
}
static APREQ_MODULE(apache2, APREQ_APACHE2_MMN);
APREQ_DECLARE(apreq_handle_t *) apreq_handle_apache2(request_rec *r)
{
struct apache2_handle *req =
ap_get_module_config(r->request_config, &apreq_module);
if (req != NULL) {
get_apreq_filter(&req->handle);
return &req->handle;
}
req = apr_palloc(r->pool, sizeof *req);
ap_set_module_config(r->request_config, &apreq_module, req);
req->handle.module = &apache2_module;
req->handle.pool = r->pool;
req->handle.bucket_alloc = r->connection->bucket_alloc;
req->r = r;
req->args_status = req->jar_status = APR_EINIT;
req->args = req->jar = NULL;
req->f = NULL;
get_apreq_filter(&req->handle);
return &req->handle;
}

View File

@@ -1,115 +0,0 @@
# Microsoft Developer Studio Project File - Name="mod_apreq" - Package Owner=<4>
# Microsoft Developer Studio Generated Build File, Format Version 6.00
# ** DO NOT EDIT **
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
CFG=mod_apreq - Win32 Debug
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
!MESSAGE use the Export Makefile command and run
!MESSAGE
!MESSAGE NMAKE /f "mod_apreq.mak".
!MESSAGE
!MESSAGE You can specify a configuration when running NMAKE
!MESSAGE by defining the macro CFG on the command line. For example:
!MESSAGE
!MESSAGE NMAKE /f "mod_apreq.mak" CFG="mod_apreq - Win32 Debug"
!MESSAGE
!MESSAGE Possible choices for configuration are:
!MESSAGE
!MESSAGE "mod_apreq - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE "mod_apreq - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
!MESSAGE
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""
# PROP Scc_LocalPath ""
CPP=cl.exe
MTL=midl.exe
RSC=rc.exe
!IF "$(CFG)" == "mod_apreq - Win32 Release"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 0
# PROP BASE Output_Dir "Release"
# PROP BASE Intermediate_Dir "Release"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 0
# PROP Output_Dir "Release"
# PROP Intermediate_Dir "Release"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MD /W3 /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "APREQ_DECLARE_EXPORT" /FD /c
# ADD CPP /nologo /MD /W3 /O2 /Oy- /Zi /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "APREQ_DECLARE_EXPORT" /Fd"Release\mod_apreq_src" /FD /c
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
# ADD BASE RSC /l 0x409 /d "NDEBUG"
# ADD RSC /l 0x409 /fo"Release/mod_apreq.res" /i "../../include" /i "../../srclib/apr/include" /d "NDEBUG" /d BIN_NAME="mod_apreq.so" /d LONG_NAME="apreq_module for Apache"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /out:".\Release\mod_apreq.so" /base:@..\..\os\win32\BaseAddr.ref,mod_apreq.so
# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Release\mod_apreq.so" /base:@..\..\os\win32\BaseAddr.ref,mod_apreq.so /opt:ref
# Begin Special Build Tool
TargetPath=.\Release\mod_apreq.so
SOURCE="$(InputPath)"
PostBuild_Desc=Embed .manifest
PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
# End Special Build Tool
!ELSEIF "$(CFG)" == "mod_apreq - Win32 Debug"
# PROP BASE Use_MFC 0
# PROP BASE Use_Debug_Libraries 1
# PROP BASE Output_Dir "Debug"
# PROP BASE Intermediate_Dir "Debug"
# PROP BASE Target_Dir ""
# PROP Use_MFC 0
# PROP Use_Debug_Libraries 1
# PROP Output_Dir "Debug"
# PROP Intermediate_Dir "Debug"
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MDd /W3 /EHsc /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "APREQ_DECLARE_EXPORT" /FD /c
# ADD CPP /nologo /MDd /W3 /EHsc /Zi /Od /I "../../include" /I "../../srclib/apr/include" /I "../../srclib/apr-util/include" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "APREQ_DECLARE_EXPORT" /Fd"Debug\mod_apreq_src" /FD /c
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
# ADD BASE RSC /l 0x409 /d "_DEBUG"
# ADD RSC /l 0x409 /fo"Debug/mod_apreq.res" /i "../../include" /i "../../srclib/apr/include" /d "_DEBUG" /d BIN_NAME="mod_apreq.so" /d LONG_NAME="apreq_module for Apache"
BSC32=bscmake.exe
# ADD BASE BSC32 /nologo
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_apreq.so" /base:@..\..\os\win32\BaseAddr.ref,mod_apreq.so
# ADD LINK32 kernel32.lib /nologo /subsystem:windows /dll /incremental:no /debug /out:".\Debug\mod_apreq.so" /base:@..\..\os\win32\BaseAddr.ref,mod_apreq.so
# Begin Special Build Tool
TargetPath=.\Debug\mod_apreq.so
SOURCE="$(InputPath)"
PostBuild_Desc=Embed .manifest
PostBuild_Cmds=if exist $(TargetPath).manifest mt.exe -manifest $(TargetPath).manifest -outputresource:$(TargetPath);2
# End Special Build Tool
!ENDIF
# Begin Target
# Name "mod_apreq - Win32 Release"
# Name "mod_apreq - Win32 Debug"
# Begin Source File
SOURCE=.\filter.c
# End Source File
# Begin Source File
SOURCE=.\handle.c
# End Source File
# Begin Source File
SOURCE=..\..\build\win32\httpd.rc
# End Source File
# End Target
# End Project

View File

@@ -123,7 +123,6 @@ mod_cache_socache.so 0x70B60000 0x00020000
mod_allowhandlers.so 0x70B80000 0x00010000
mod_macro.so 0x70B90000 0x00020000
mod_proxy_wstunnel.so 0x70BB0000 0x00020000
mod_apreq.so 0x70BD0000 0x00020000
mod_authnz_fcgi.so 0x70BF0000 0x00020000
mod_dialup.so 0x70C10000 0x00010000
mod_optional_fn_export.so 0x70C20000 0x00010000
@@ -139,5 +138,4 @@ mod_proxy_hcheck.so 0x70E00000 0x00020000
mod_socache_redis.so 0x70E20000 0x00020000
mod_md.so 0x70E40000 0x00030000
mod_proxy_uwsgi.so 0x70E70000 0x00020000
libapreq.dll 0x70E90000 0x00020000
mod_log_json.so 0x70EB0000 0x00020000

View File

@@ -15,11 +15,7 @@ LTLIBRARY_SOURCES = \
util_filter.c util_pcre.c util_regex.c $(EXPORTS_DOT_C) \
scoreboard.c error_bucket.c protocol.c core.c request.c ssl.c provider.c \
eoc_bucket.c eor_bucket.c headers_bucket.c core_filters.c \
util_expr_parse.c util_expr_scan.c util_expr_eval.c \
apreq_cookie.c apreq_error.c apreq_module.c \
apreq_module_cgi.c apreq_module_custom.c apreq_param.c \
apreq_parser.c apreq_parser_header.c apreq_parser_multipart.c \
apreq_parser_urlencoded.c apreq_util.c
util_expr_parse.c util_expr_scan.c util_expr_eval.c
LTLIBRARY_DEPENDENCIES = test_char.h

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -1,358 +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_tag(default_parser_pool, "apreq_default_parser");
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);
if (ctx->param == NULL)
return APR_ENOMEM;
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 && ctx->param == NULL
&& strcasecmp(ctx->name, param->v.name) == 0) {
ctx->param = param;
ctx->prev->next = hook->next;
}
return s;
}

View File

@@ -1,448 +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"
#include "apr_lib.h" /* for apr_iscntrl() & co */
#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_ENDLINE,
HDR_FOLDLINE,
HDR_LASTLINE,
HDR_COMPLETE,
HDR_ERROR
} status;
};
/********************* header parsing utils ********************/
static apr_bucket *split_header_line(apr_bucket *e, apr_size_t *off,
const char **data, apr_size_t *dlen)
{
if (*off > 1) {
apr_bucket_split(e, *off - 1);
e = APR_BUCKET_NEXT(e);
*dlen -= *off - 1;
*data += *off - 1;
*off = 1;
}
return e;
}
static apr_status_t consume_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;
apr_array_header_t arr;
char *dest;
const char *data;
apr_size_t dlen;
int i, eol = 0;
param = apreq_param_make(pool, NULL, nlen, NULL, vlen);
if (param == NULL)
return APR_ENOMEM;
*(const apreq_value_t **)&v = &param->v;
arr.pool = pool;
arr.elt_size = sizeof(struct iovec);
arr.nelts = 0;
arr.nalloc = APREQ_DEFAULT_NELTS;
arr.elts = (char *)vec;
e = APR_BRIGADE_FIRST(bb);
/* store name in a temporary iovec array */
do {
apr_size_t len;
assert(e != APR_BRIGADE_SENTINEL(bb));
iov = (struct iovec *)apr_array_push(&arr);
s = apr_bucket_read(e, (const char **)&iov->iov_base,
&len, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
iov->iov_len = len;
assert(nlen >= len);
nlen -= len;
e = APR_BUCKET_NEXT(e);
} while (nlen > 0);
/* skip gap */
do {
assert(e != APR_BRIGADE_SENTINEL(bb));
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);
} while (glen > 0);
/* copy value */
dest = v->data;
do {
apr_size_t off;
assert(e != APR_BRIGADE_SENTINEL(bb));
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
for (off = 0; off < dlen; ++off) {
const char ch = data[off];
if (ch == '\r' || ch == '\n') {
/* Eat [CR]LF of continuation or end of line */
if (!vlen && ch == '\n')
eol = 1; /* done */
continue;
}
assert(vlen > 0);
*dest = ch;
++dest;
--vlen;
}
e = APR_BUCKET_NEXT(e);
} while (!eol);
v->dlen = dest - v->data;
*dest++ = 0;
/* write name */
v->name = dest;
for (i = 0; i < arr.nelts; ++i) {
iov = &((struct iovec *)arr.elts)[i];
memcpy(dest, iov->iov_base, iov->iov_len);
dest += iov->iov_len;
++iov;
}
v->nlen = dest - v->name;
*dest = 0;
while ((f = APR_BRIGADE_FIRST(bb)) != e)
apr_bucket_delete(f);
apreq_param_tainted_on(param);
*p = param;
return APR_SUCCESS;
}
#define IS_TOKEN_CHAR(c) (apr_isalnum(c) \
|| ((c) && strchr("!#$%&'*+-.^_`|~", (c))))
APREQ_DECLARE_PARSER(apreq_parse_headers)
{
apr_pool_t *pool = parser->pool;
apr_bucket *e;
struct hdr_ctx *ctx;
char ch;
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 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) {
ch = data[off++];
switch (ch) {
case ':':
if (!ctx->nlen) {
ctx->status = HDR_ERROR;
return APREQ_ERROR_BADHEADER;
}
e = split_header_line(e, &off, &data, &dlen);
++ctx->glen;
ctx->status = HDR_GAP;
goto parse_hdr_bucket;
default:
if (!IS_TOKEN_CHAR(ch)) {
ctx->status = HDR_ERROR;
return APREQ_ERROR_BADCHAR;
}
++ctx->nlen;
}
}
break;
case HDR_GAP:
while (off < dlen) {
ch = data[off++];
switch (ch) {
case ' ':
case '\t':
++ctx->glen;
break;
case '\n':
e = split_header_line(e, &off, &data, &dlen);
ctx->status = HDR_NEWLINE;
goto parse_hdr_bucket;
case '\r':
e = split_header_line(e, &off, &data, &dlen);
ctx->status = HDR_ENDLINE;
goto parse_hdr_bucket;
default:
if (apr_iscntrl(ch)) {
ctx->status = HDR_ERROR;
return APREQ_ERROR_BADCHAR;
}
e = split_header_line(e, &off, &data, &dlen);
++ctx->vlen;
ctx->status = HDR_VALUE;
goto parse_hdr_bucket;
}
}
break;
case HDR_VALUE:
while (off < dlen) {
ch = data[off++];
switch (ch) {
case '\n':
ctx->status = HDR_NEWLINE;
goto parse_hdr_bucket;
case '\r':
ctx->status = HDR_ENDLINE;
goto parse_hdr_bucket;
default:
if (apr_iscntrl(ch)) {
ctx->status = HDR_ERROR;
return APREQ_ERROR_BADCHAR;
}
++ctx->vlen;
}
}
break;
case HDR_ENDLINE:
case HDR_LASTLINE:
if (off == dlen)
break;
if (data[off++] != '\n') {
ctx->status = HDR_ERROR;
return APREQ_ERROR_BADHEADER;
}
if (ctx->status == HDR_LASTLINE) {
ctx->status = HDR_COMPLETE;
goto parse_hdr_bucket;
}
/* fall thru */
ctx->status = HDR_NEWLINE;
case HDR_NEWLINE:
if (off == dlen)
break;
ch = data[off++];
switch (ch) {
case ' ':
case '\t':
++ctx->vlen;
break;
default:
e = split_header_line(e, &off, &data, &dlen);
/* consume from splitted brigade now */
s = consume_header_line(&param, pool, ctx->bb,
ctx->nlen, ctx->glen, ctx->vlen);
if (parser->hook != NULL && s == APR_SUCCESS)
s = apreq_hook_run(parser->hook, param, NULL);
if (s != APR_SUCCESS) {
ctx->status = HDR_ERROR;
return s;
}
apreq_value_table_add(&param->v, t);
ctx->nlen = 0;
ctx->vlen = 0;
ctx->glen = 0;
switch (ch) {
case '\n':
ctx->status = HDR_COMPLETE;
break;
case '\r':
ctx->status = HDR_LASTLINE;
break;
default:
if (!IS_TOKEN_CHAR(ch)) {
ctx->status = HDR_ERROR;
return APREQ_ERROR_BADCHAR;
}
++ctx->nlen;
ctx->status = HDR_NAME;
break;
}
goto parse_hdr_bucket;
}
/* fall thru */
ctx->status = HDR_FOLDLINE;
case HDR_FOLDLINE:
while (off < dlen) {
ch = data[off++];
switch (ch) {
case ' ':
case '\t':
++ctx->vlen;
break;
case '\n':
ctx->status = HDR_NEWLINE;
goto parse_hdr_bucket;
case '\r':
ctx->status = HDR_ENDLINE;
goto parse_hdr_bucket;
default:
if (apr_iscntrl(ch)) {
ctx->status = HDR_ERROR;
return APREQ_ERROR_BADCHAR;
}
ctx->status = HDR_VALUE;
++ctx->vlen;
goto parse_hdr_bucket;
}
}
break;
case HDR_COMPLETE:
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);
return APR_SUCCESS;
default:
assert(0); /* not reached */
}
}
apreq_brigade_setaside(ctx->bb,pool);
return APR_INCOMPLETE;
}

View File

@@ -1,689 +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;
const char *attr;
char *buf;
attr = (content_type) ? strchr(content_type, ';') : NULL;
if (!attr)
return NULL; /* missing semicolon */
ctx = apr_palloc(pool, sizeof *ctx);
attr++;
blen = strlen(attr) + 1;
buf = apr_palloc(pool, 4 + blen);
buf += 4;
memcpy(buf, attr, blen);
s = apreq_header_attribute(buf, "boundary", 8,
(const char **)&ctx->bdry, &blen);
if (s != APR_SUCCESS || !blen)
return NULL; /* missing or empty 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);
if (next_ctx == NULL) {
ctx->status = MFD_ERROR;
goto mfd_parse_brigade;
}
if (cd != NULL) {
s = apreq_header_attribute(cd, "name", 4,
&name, &nlen);
if (s == APR_SUCCESS && nlen) {
next_ctx->param_name = apr_pstrmemdup(pool, name,
nlen);
}
else if (s != APREQ_ERROR_NOATTR) {
ctx->status = MFD_ERROR;
goto mfd_parse_brigade;
}
}
if (!next_ctx->param_name) {
const char *cid = apr_table_get(ctx->info,
"Content-ID");
if (cid) {
next_ctx->param_name = apr_pstrdup(pool, cid);
}
else {
next_ctx->param_name = "";
}
}
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 || !nlen) {
ctx->status = MFD_ERROR;
goto mfd_parse_brigade;
}
s = apreq_header_attribute(cd, "filename",
8, &filename, &flen);
if (s == APR_SUCCESS && flen) {
apreq_param_t *param;
param = apreq_param_make(pool, name, nlen,
filename, flen);
if (param == NULL)
return APR_ENOMEM;
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 if (s != APREQ_ERROR_NOATTR) {
ctx->status = MFD_ERROR;
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 || !flen || !ctx->param_name) {
ctx->status = MFD_ERROR;
goto mfd_parse_brigade;
}
name = ctx->param_name;
nlen = strlen(name);
param = apreq_param_make(pool, name, nlen,
filename, flen);
if (param == NULL)
return APR_ENOMEM;
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);
if (param == NULL)
return APR_ENOMEM;
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);
if (param == NULL)
return APR_ENOMEM;
apreq_param_tainted_on(param);
param->info = ctx->info;
*(const apreq_value_t **)&v = &param->v;
apr_brigade_flatten(ctx->bb, v->data, &len);
v->data[len] = 0;
if (parser->hook != NULL) {
s = apreq_hook_run(parser->hook, param, NULL);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
return s;
}
}
apreq_param_charset_set(param,
apreq_charset_divine(v->data, len));
apreq_value_table_add(v, t);
ctx->status = MFD_NEXTLINE;
ctx->param_name = NULL;
apr_brigade_cleanup(ctx->bb);
goto mfd_parse_brigade;
default:
ctx->status = MFD_ERROR;
return s;
}
}
break; /* not reached */
case MFD_UPLOAD:
{
apreq_param_t *param = ctx->upload;
s = split_on_bdry(ctx->bb, ctx->in, ctx->pattern, ctx->bdry);
switch (s) {
case APR_INCOMPLETE:
if (parser->hook != NULL) {
s = apreq_hook_run(parser->hook, param, ctx->bb);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
return s;
}
}
apreq_brigade_setaside(ctx->bb, pool);
apreq_brigade_setaside(ctx->in, pool);
s = apreq_brigade_concat(pool, parser->temp_dir,
parser->brigade_limit,
param->upload, ctx->bb);
return (s == APR_SUCCESS) ? APR_INCOMPLETE : s;
case APR_SUCCESS:
if (parser->hook != NULL) {
APR_BRIGADE_INSERT_TAIL(ctx->bb, ctx->eos);
s = apreq_hook_run(parser->hook, param, ctx->bb);
APR_BUCKET_REMOVE(ctx->eos);
if (s != APR_SUCCESS) {
ctx->status = MFD_ERROR;
return s;
}
}
apreq_value_table_add(&param->v, t);
apreq_brigade_setaside(ctx->bb, pool);
s = apreq_brigade_concat(pool, parser->temp_dir,
parser->brigade_limit,
param->upload, ctx->bb);
if (s != APR_SUCCESS)
return s;
ctx->status = MFD_NEXTLINE;
goto mfd_parse_brigade;
default:
ctx->status = MFD_ERROR;
return s;
}
}
break; /* not reached */
case MFD_MIXED:
{
s = apreq_parser_run(ctx->next_parser, t, ctx->in);
switch (s) {
case APR_SUCCESS:
ctx->status = MFD_INIT;
ctx->param_name = NULL;
goto mfd_parse_brigade;
case APR_INCOMPLETE:
APR_BRIGADE_CONCAT(bb, ctx->in);
return APR_INCOMPLETE;
default:
ctx->status = MFD_ERROR;
return s;
}
}
break; /* not reached */
default:
return APREQ_ERROR_GENERAL;
}
return APR_INCOMPLETE;
}

View File

@@ -1,277 +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);
if (param == NULL)
return APR_ENOMEM;
*(const apreq_value_t **)&v = &param->v;
arr.pool = pool;
arr.elt_size = sizeof(struct iovec);
arr.nelts = 0;
arr.nalloc = APREQ_DEFAULT_NELTS;
arr.elts = (char *)vec;
++nlen, ++vlen;
e = APR_BRIGADE_FIRST(bb);
while (!APR_BUCKET_IS_EOS(e)) {
struct iovec *iov = apr_array_push(&arr);
apr_size_t len;
s = apr_bucket_read(e, (const char **)&iov->iov_base,
&len, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
iov->iov_len = len;
nlen -= len;
e = APR_BUCKET_NEXT(e);
if (nlen == 0) {
iov->iov_len--;
break;
}
}
mark = arr.nelts;
while (!APR_BUCKET_IS_EOS(e)) {
struct iovec *iov = apr_array_push(&arr);
apr_size_t len;
s = apr_bucket_read(e, (const char **)&iov->iov_base,
&len, APR_BLOCK_READ);
if (s != APR_SUCCESS)
return s;
iov->iov_len = len;
vlen -= len;
e = APR_BUCKET_NEXT(e);
if (vlen == 0) {
iov->iov_len--;
break;
}
}
s = apreq_decodev(v->data, &vlen,
(struct iovec *)arr.elts + mark, arr.nelts - mark);
if (s != APR_SUCCESS)
return s;
charset = apreq_charset_divine(v->data, vlen);
v->name = v->data + vlen + 1;
v->dlen = vlen;
s = apreq_decodev(v->name, &nlen, (struct iovec *)arr.elts, mark);
if (s != APR_SUCCESS)
return s;
switch (apreq_charset_divine(v->name, nlen)) {
case APREQ_CHARSET_UTF8:
if (charset == APREQ_CHARSET_ASCII)
charset = APREQ_CHARSET_UTF8;
case APREQ_CHARSET_ASCII:
break;
case APREQ_CHARSET_LATIN1:
if (charset != APREQ_CHARSET_CP1252)
charset = APREQ_CHARSET_LATIN1;
break;
case APREQ_CHARSET_CP1252:
charset = APREQ_CHARSET_CP1252;
}
v->nlen = nlen;
while ((f = APR_BRIGADE_FIRST(bb)) != e)
apr_bucket_delete(f);
apreq_param_tainted_on(param);
apreq_param_charset_set(param, charset);
*p = param;
return APR_SUCCESS;
}
APREQ_DECLARE_PARSER(apreq_parse_urlencoded)
{
apr_pool_t *pool = parser->pool;
apr_bucket *e;
struct url_ctx *ctx;
if (parser->ctx == NULL) {
ctx = apr_pcalloc(pool, sizeof *ctx);
ctx->bb = apr_brigade_create(pool, parser->bucket_alloc);
parser->ctx = ctx;
ctx->status = URL_NAME;
}
else
ctx = parser->ctx;
PARSER_STATUS_CHECK(URL);
e = APR_BRIGADE_LAST(ctx->bb);
APR_BRIGADE_CONCAT(ctx->bb, bb);
parse_url_brigade:
for (e = APR_BUCKET_NEXT(e);
e != APR_BRIGADE_SENTINEL(ctx->bb);
e = APR_BUCKET_NEXT(e))
{
apreq_param_t *param;
apr_size_t off = 0, dlen;
const char *data;
apr_status_t s;
if (APR_BUCKET_IS_EOS(e)) {
if (ctx->status == URL_NAME) {
s = APR_SUCCESS;
}
else {
s = split_urlword(&param, pool, ctx->bb, ctx->nlen, ctx->vlen);
if (parser->hook != NULL && s == APR_SUCCESS)
s = apreq_hook_run(parser->hook, param, NULL);
if (s == APR_SUCCESS) {
apreq_value_table_add(&param->v, t);
ctx->status = URL_COMPLETE;
}
else {
ctx->status = URL_ERROR;
}
}
APR_BRIGADE_CONCAT(bb, ctx->bb);
return s;
}
s = apr_bucket_read(e, &data, &dlen, APR_BLOCK_READ);
if ( s != APR_SUCCESS ) {
ctx->status = URL_ERROR;
return s;
}
parse_url_bucket:
switch (ctx->status) {
case URL_NAME:
while (off < dlen) {
switch (data[off++]) {
case '=':
apr_bucket_split(e, off);
dlen -= off;
data += off;
off = 0;
e = APR_BUCKET_NEXT(e);
ctx->status = URL_VALUE;
goto parse_url_bucket;
default:
++ctx->nlen;
}
}
break;
case URL_VALUE:
while (off < dlen) {
switch (data[off++]) {
case '&':
case ';':
apr_bucket_split(e, off);
s = split_urlword(&param, pool, ctx->bb,
ctx->nlen, ctx->vlen);
if (parser->hook != NULL && s == APR_SUCCESS)
s = apreq_hook_run(parser->hook, param, NULL);
if (s != APR_SUCCESS) {
ctx->status = URL_ERROR;
return s;
}
apreq_value_table_add(&param->v, t);
ctx->status = URL_NAME;
ctx->nlen = 0;
ctx->vlen = 0;
e = APR_BRIGADE_SENTINEL(ctx->bb);
goto parse_url_brigade;
default:
++ctx->vlen;
}
}
break;
default:
; /* not reached */
}
}
apreq_brigade_setaside(ctx->bb, pool);
return APR_INCOMPLETE;
}

File diff suppressed because it is too large Load Diff