mirror of
https://github.com/apache/httpd.git
synced 2025-08-15 23:27:39 +00:00
Expose "new" ap_parse_form_data() function instead of requiring
mod_request for any module that may want to parse form data... git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1072099 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
3
CHANGES
3
CHANGES
@ -2,6 +2,9 @@
|
||||
|
||||
Changes with Apache 2.3.11
|
||||
|
||||
*) core: new util function: ap_parse_form_data(). Previously,
|
||||
this capability was tucked away in mod_request. [Jim Jagielski]
|
||||
|
||||
*) core: new hook: ap_run_pre_read_request. [Jim Jagielski]
|
||||
|
||||
*) mod_cache: When a request other than GET or HEAD arrives, we must
|
||||
|
@ -300,7 +300,8 @@
|
||||
* 20110117.1 (2.3.11-dev) Add ap_pstr2_alnum() and ap_str2_alnum()
|
||||
* 20110203.0 (2.3.11-dev) Raise DYNAMIC_MODULE_LIMIT to 256
|
||||
* 20110203.1 (2.3.11-dev) Add ap_state_query()
|
||||
* 20110203.2 (2.3.11-dev) Add ap_run_pre_read_request() hook
|
||||
* 20110203.2 (2.3.11-dev) Add ap_run_pre_read_request() hook and
|
||||
* ap_parse_form_data() util
|
||||
*/
|
||||
|
||||
#define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
|
||||
|
@ -1853,6 +1853,33 @@ AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
|
||||
*/
|
||||
AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest);
|
||||
|
||||
/**
|
||||
* Structure to store the contents of an HTTP form of the type
|
||||
* application/x-www-form-urlencoded.
|
||||
*
|
||||
* Currently it contains the name as a char* of maximum length
|
||||
* HUGE_STRING_LEN, and a value in the form of a bucket brigade
|
||||
* of arbitrary length.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *name;
|
||||
apr_bucket_brigade *value;
|
||||
} ap_form_pair_t;
|
||||
|
||||
/**
|
||||
* Read the body and parse any form found, which must be of the
|
||||
* type application/x-www-form-urlencoded.
|
||||
* @param r request containing POSTed form data
|
||||
* @param f filter
|
||||
* @param ptr returned array of ap_form_pair_t
|
||||
* @param num max num of params or -1 for unlimited
|
||||
* @param size max size allowed for parsed data
|
||||
* @return OK or HTTP error
|
||||
*/
|
||||
AP_DECLARE(int) ap_parse_form_data(request_rec *r, struct ap_filter_t *f,
|
||||
apr_array_header_t **ptr,
|
||||
apr_size_t num, apr_size_t size);
|
||||
|
||||
/* Misc system hackery */
|
||||
/**
|
||||
* Given the name of an object in the file system determine if it is a directory
|
||||
|
@ -52,56 +52,6 @@ typedef struct {
|
||||
int keep_body_set;
|
||||
} request_dir_conf;
|
||||
|
||||
/**
|
||||
* Structure to store the contents of an HTTP form of the type
|
||||
* application/x-www-form-urlencoded.
|
||||
*
|
||||
* Currently it contains the name as a char* of maximum length
|
||||
* HUGE_STRING_LEN, and a value in the form of a bucket brigade
|
||||
* of arbitrary length.
|
||||
*/
|
||||
typedef struct {
|
||||
const char *name;
|
||||
apr_bucket_brigade *value;
|
||||
} ap_form_pair_t;
|
||||
|
||||
/**
|
||||
* Read the body and parse any form found, which must be of the
|
||||
* type application/x-www-form-urlencoded.
|
||||
*
|
||||
* Name/value pairs are returned in an array, with the names as
|
||||
* strings with a maximum length of HUGE_STRING_LEN, and the
|
||||
* values as bucket brigades. This allows values to be arbitrarily
|
||||
* large.
|
||||
*
|
||||
* All url-encoding is removed from both the names and the values
|
||||
* on the fly. The names are interpreted as strings, while the
|
||||
* values are interpreted as blocks of binary data, that may
|
||||
* contain the 0 character.
|
||||
*
|
||||
* In order to ensure that resource limits are not exceeded, a
|
||||
* maximum size must be provided. If the sum of the lengths of
|
||||
* the names and the values exceed this size, this function
|
||||
* will return HTTP_REQUEST_ENTITY_TOO_LARGE.
|
||||
*
|
||||
* An optional number of parameters can be provided, if the number
|
||||
* of parameters provided exceeds this amount, this function will
|
||||
* return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
|
||||
* no limit is imposed, and the number of parameters is in turn
|
||||
* constrained by the size parameter above.
|
||||
*
|
||||
* This function honours any kept_body configuration, and the
|
||||
* original raw request body will be saved to the kept_body brigade
|
||||
* if so configured, just as ap_discard_request_body does.
|
||||
*
|
||||
* NOTE: File upload is not yet supported, but can be without change
|
||||
* to the function call.
|
||||
*/
|
||||
|
||||
APR_DECLARE_OPTIONAL_FN(int, ap_parse_request_form, (request_rec * r, ap_filter_t * f,
|
||||
apr_array_header_t ** ptr,
|
||||
apr_size_t num, apr_size_t size));
|
||||
|
||||
APR_DECLARE_OPTIONAL_FN(void, ap_request_insert_filter, (request_rec * r));
|
||||
|
||||
APR_DECLARE_OPTIONAL_FN(void, ap_request_remove_filter, (request_rec * r));
|
||||
|
@ -46,9 +46,6 @@ static void (*ap_session_get_fn) (request_rec * r, session_rec * z,
|
||||
const char *key, const char **value) = NULL;
|
||||
static void (*ap_session_set_fn) (request_rec * r, session_rec * z,
|
||||
const char *key, const char *value) = NULL;
|
||||
static int (*ap_parse_request_form_fn) (request_rec * r, ap_filter_t *f,
|
||||
apr_array_header_t ** ptr,
|
||||
apr_size_t num, apr_size_t size) = NULL;
|
||||
static void (*ap_request_insert_filter_fn) (request_rec * r) = NULL;
|
||||
static void (*ap_request_remove_filter_fn) (request_rec * r) = NULL;
|
||||
|
||||
@ -187,11 +184,10 @@ static const char *add_authn_provider(cmd_parms * cmd, void *config,
|
||||
}
|
||||
}
|
||||
|
||||
if (!ap_parse_request_form_fn || !ap_request_insert_filter_fn || !ap_request_remove_filter_fn) {
|
||||
ap_parse_request_form_fn = APR_RETRIEVE_OPTIONAL_FN(ap_parse_request_form);
|
||||
if (!ap_request_insert_filter_fn || !ap_request_remove_filter_fn) {
|
||||
ap_request_insert_filter_fn = APR_RETRIEVE_OPTIONAL_FN(ap_request_insert_filter);
|
||||
ap_request_remove_filter_fn = APR_RETRIEVE_OPTIONAL_FN(ap_request_remove_filter);
|
||||
if (!ap_parse_request_form_fn || !ap_request_insert_filter_fn || !ap_request_remove_filter_fn) {
|
||||
if (!ap_request_insert_filter_fn || !ap_request_remove_filter_fn) {
|
||||
return "You must load mod_request to enable the mod_auth_form "
|
||||
"functions";
|
||||
}
|
||||
@ -607,7 +603,7 @@ static int get_form_auth(request_rec * r,
|
||||
return OK;
|
||||
}
|
||||
|
||||
res = ap_parse_request_form_fn(r, NULL, &pairs, -1, conf->form_size);
|
||||
res = ap_parse_form_data(r, NULL, &pairs, -1, conf->form_size);
|
||||
if (res != OK) {
|
||||
return res;
|
||||
}
|
||||
|
@ -267,221 +267,6 @@ static apr_status_t kept_body_filter(ap_filter_t *f, apr_bucket_brigade *b,
|
||||
|
||||
}
|
||||
|
||||
/* form parsing stuff */
|
||||
typedef enum {
|
||||
FORM_NORMAL,
|
||||
FORM_AMP,
|
||||
FORM_NAME,
|
||||
FORM_VALUE,
|
||||
FORM_PERCENTA,
|
||||
FORM_PERCENTB,
|
||||
FORM_ABORT
|
||||
} ap_form_type_t;
|
||||
|
||||
/**
|
||||
* Read the body and parse any form found, which must be of the
|
||||
* type application/x-www-form-urlencoded.
|
||||
*
|
||||
* Name/value pairs are returned in an array, with the names as
|
||||
* strings with a maximum length of HUGE_STRING_LEN, and the
|
||||
* values as bucket brigades. This allows values to be arbitrarily
|
||||
* large.
|
||||
*
|
||||
* All url-encoding is removed from both the names and the values
|
||||
* on the fly. The names are interpreted as strings, while the
|
||||
* values are interpreted as blocks of binary data, that may
|
||||
* contain the 0 character.
|
||||
*
|
||||
* In order to ensure that resource limits are not exceeded, a
|
||||
* maximum size must be provided. If the sum of the lengths of
|
||||
* the names and the values exceed this size, this function
|
||||
* will return HTTP_REQUEST_ENTITY_TOO_LARGE.
|
||||
*
|
||||
* An optional number of parameters can be provided, if the number
|
||||
* of parameters provided exceeds this amount, this function will
|
||||
* return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
|
||||
* no limit is imposed, and the number of parameters is in turn
|
||||
* constrained by the size parameter above.
|
||||
*
|
||||
* This function honours any kept_body configuration, and the
|
||||
* original raw request body will be saved to the kept_body brigade
|
||||
* if so configured, just as ap_discard_request_body does.
|
||||
*
|
||||
* NOTE: File upload is not yet supported, but can be without change
|
||||
* to the function call.
|
||||
*/
|
||||
static int ap_parse_request_form(request_rec * r, ap_filter_t * f,
|
||||
apr_array_header_t ** ptr,
|
||||
apr_size_t num, apr_size_t usize)
|
||||
{
|
||||
apr_bucket_brigade *bb = NULL;
|
||||
int seen_eos = 0;
|
||||
char buffer[HUGE_STRING_LEN + 1];
|
||||
const char *ct;
|
||||
apr_size_t offset = 0;
|
||||
apr_ssize_t size;
|
||||
ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
|
||||
ap_form_pair_t *pair = NULL;
|
||||
apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
|
||||
|
||||
char hi = 0;
|
||||
char low = 0;
|
||||
|
||||
*ptr = pairs;
|
||||
|
||||
/* sanity check - we only support forms for now */
|
||||
ct = apr_table_get(r->headers_in, "Content-Type");
|
||||
if (!ct || strcmp("application/x-www-form-urlencoded", ct)) {
|
||||
return ap_discard_request_body(r);
|
||||
}
|
||||
|
||||
if (usize > APR_SIZE_MAX >> 1)
|
||||
size = APR_SIZE_MAX >> 1;
|
||||
else
|
||||
size = usize;
|
||||
|
||||
if (!f) {
|
||||
f = r->input_filters;
|
||||
}
|
||||
|
||||
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
do {
|
||||
apr_bucket *bucket = NULL, *last = NULL;
|
||||
|
||||
int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
|
||||
APR_BLOCK_READ, HUGE_STRING_LEN);
|
||||
if (rv != APR_SUCCESS) {
|
||||
apr_brigade_destroy(bb);
|
||||
return (rv == AP_FILTER_ERROR) ? rv : HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
for (bucket = APR_BRIGADE_FIRST(bb);
|
||||
bucket != APR_BRIGADE_SENTINEL(bb);
|
||||
last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
|
||||
const char *data;
|
||||
apr_size_t len, slide;
|
||||
|
||||
if (last) {
|
||||
apr_bucket_delete(last);
|
||||
}
|
||||
if (APR_BUCKET_IS_EOS(bucket)) {
|
||||
seen_eos = 1;
|
||||
break;
|
||||
}
|
||||
if (bucket->length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
|
||||
if (rv != APR_SUCCESS) {
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
slide = len;
|
||||
while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
|
||||
char c = *data++;
|
||||
if ('+' == c) {
|
||||
c = ' ';
|
||||
}
|
||||
else if ('&' == c) {
|
||||
state = FORM_AMP;
|
||||
}
|
||||
if ('%' == c) {
|
||||
percent = FORM_PERCENTA;
|
||||
continue;
|
||||
}
|
||||
if (FORM_PERCENTA == percent) {
|
||||
if (c >= 'a') {
|
||||
hi = c - 'a' + 10;
|
||||
}
|
||||
else if (c >= 'A') {
|
||||
hi = c - 'A' + 10;
|
||||
}
|
||||
else if (c >= '0') {
|
||||
hi = c - '0';
|
||||
}
|
||||
hi = hi << 4;
|
||||
percent = FORM_PERCENTB;
|
||||
continue;
|
||||
}
|
||||
if (FORM_PERCENTB == percent) {
|
||||
if (c >= 'a') {
|
||||
low = c - 'a' + 10;
|
||||
}
|
||||
else if (c >= 'A') {
|
||||
low = c - 'A' + 10;
|
||||
}
|
||||
else if (c >= '0') {
|
||||
low = c - '0';
|
||||
}
|
||||
c = low | hi;
|
||||
percent = FORM_NORMAL;
|
||||
}
|
||||
switch (state) {
|
||||
case FORM_AMP:
|
||||
if (pair) {
|
||||
const char *tmp = apr_pmemdup(r->pool, buffer, offset);
|
||||
apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(pair->value, b);
|
||||
}
|
||||
state = FORM_NAME;
|
||||
pair = NULL;
|
||||
offset = 0;
|
||||
num--;
|
||||
break;
|
||||
case FORM_NAME:
|
||||
if (offset < HUGE_STRING_LEN) {
|
||||
if ('=' == c) {
|
||||
buffer[offset] = 0;
|
||||
offset = 0;
|
||||
pair = (ap_form_pair_t *) apr_array_push(pairs);
|
||||
pair->name = apr_pstrdup(r->pool, buffer);
|
||||
pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
state = FORM_VALUE;
|
||||
}
|
||||
else {
|
||||
buffer[offset++] = c;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
state = FORM_ABORT;
|
||||
}
|
||||
break;
|
||||
case FORM_VALUE:
|
||||
if (offset >= HUGE_STRING_LEN) {
|
||||
const char *tmp = apr_pmemdup(r->pool, buffer, offset);
|
||||
apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(pair->value, b);
|
||||
offset = 0;
|
||||
}
|
||||
buffer[offset++] = c;
|
||||
size--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
apr_brigade_cleanup(bb);
|
||||
} while (!seen_eos);
|
||||
|
||||
if (FORM_ABORT == state || size < 0 || num == 0) {
|
||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
}
|
||||
else if (FORM_VALUE == state && pair && offset > 0) {
|
||||
const char *tmp = apr_pmemdup(r->pool, buffer, offset);
|
||||
apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(pair->value, b);
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether this filter is not already present.
|
||||
*/
|
||||
@ -596,7 +381,6 @@ static void register_hooks(apr_pool_t *p)
|
||||
ap_register_input_filter(KEPT_BODY_FILTER, kept_body_filter,
|
||||
kept_body_filter_init, AP_FTYPE_RESOURCE);
|
||||
ap_hook_insert_filter(ap_request_insert_filter, NULL, NULL, APR_HOOK_LAST);
|
||||
APR_REGISTER_OPTIONAL_FN(ap_parse_request_form);
|
||||
APR_REGISTER_OPTIONAL_FN(ap_request_insert_filter);
|
||||
APR_REGISTER_OPTIONAL_FN(ap_request_remove_filter);
|
||||
}
|
||||
|
222
server/util.c
222
server/util.c
@ -2147,7 +2147,7 @@ AP_DECLARE(int) ap_request_has_body(request_rec *r)
|
||||
char *estr;
|
||||
const char *cls;
|
||||
int has_body;
|
||||
|
||||
|
||||
has_body = (!r->header_only
|
||||
&& (r->kept_body
|
||||
|| apr_table_get(r->headers_in, "Transfer-Encoding")
|
||||
@ -2168,7 +2168,7 @@ AP_DECLARE_NONSTD(apr_status_t) ap_pool_cleanup_set_null(void *data_)
|
||||
}
|
||||
|
||||
AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
|
||||
|
||||
|
||||
for ( ; *src; src++, dest++)
|
||||
{
|
||||
if (!apr_isprint(*src))
|
||||
@ -2180,7 +2180,7 @@ AP_DECLARE(apr_status_t) ap_str2_alnum(const char *src, char *dest) {
|
||||
}
|
||||
*dest = '\0';
|
||||
return APR_SUCCESS;
|
||||
|
||||
|
||||
}
|
||||
|
||||
AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
|
||||
@ -2192,3 +2192,219 @@ AP_DECLARE(apr_status_t) ap_pstr2_alnum(apr_pool_t *p, const char *src,
|
||||
*dest = new;
|
||||
return ap_str2_alnum(src, new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the body and parse any form found, which must be of the
|
||||
* type application/x-www-form-urlencoded.
|
||||
*
|
||||
* Name/value pairs are returned in an array, with the names as
|
||||
* strings with a maximum length of HUGE_STRING_LEN, and the
|
||||
* values as bucket brigades. This allows values to be arbitrarily
|
||||
* large.
|
||||
*
|
||||
* All url-encoding is removed from both the names and the values
|
||||
* on the fly. The names are interpreted as strings, while the
|
||||
* values are interpreted as blocks of binary data, that may
|
||||
* contain the 0 character.
|
||||
*
|
||||
* In order to ensure that resource limits are not exceeded, a
|
||||
* maximum size must be provided. If the sum of the lengths of
|
||||
* the names and the values exceed this size, this function
|
||||
* will return HTTP_REQUEST_ENTITY_TOO_LARGE.
|
||||
*
|
||||
* An optional number of parameters can be provided, if the number
|
||||
* of parameters provided exceeds this amount, this function will
|
||||
* return HTTP_REQUEST_ENTITY_TOO_LARGE. If this value is negative,
|
||||
* no limit is imposed, and the number of parameters is in turn
|
||||
* constrained by the size parameter above.
|
||||
*
|
||||
* This function honours any kept_body configuration, and the
|
||||
* original raw request body will be saved to the kept_body brigade
|
||||
* if so configured, just as ap_discard_request_body does.
|
||||
*
|
||||
* NOTE: File upload is not yet supported, but can be without change
|
||||
* to the function call.
|
||||
*/
|
||||
|
||||
/* form parsing stuff */
|
||||
typedef enum {
|
||||
FORM_NORMAL,
|
||||
FORM_AMP,
|
||||
FORM_NAME,
|
||||
FORM_VALUE,
|
||||
FORM_PERCENTA,
|
||||
FORM_PERCENTB,
|
||||
FORM_ABORT
|
||||
} ap_form_type_t;
|
||||
|
||||
AP_DECLARE(int) ap_parse_form_data(request_rec *r, ap_filter_t *f,
|
||||
apr_array_header_t **ptr,
|
||||
apr_size_t num, apr_size_t usize)
|
||||
{
|
||||
apr_bucket_brigade *bb = NULL;
|
||||
int seen_eos = 0;
|
||||
char buffer[HUGE_STRING_LEN + 1];
|
||||
const char *ct;
|
||||
apr_size_t offset = 0;
|
||||
apr_ssize_t size;
|
||||
ap_form_type_t state = FORM_NAME, percent = FORM_NORMAL;
|
||||
ap_form_pair_t *pair = NULL;
|
||||
apr_array_header_t *pairs = apr_array_make(r->pool, 4, sizeof(ap_form_pair_t));
|
||||
|
||||
char hi = 0;
|
||||
char low = 0;
|
||||
|
||||
*ptr = pairs;
|
||||
|
||||
/* sanity check - we only support forms for now */
|
||||
ct = apr_table_get(r->headers_in, "Content-Type");
|
||||
if (!ct || strcmp("application/x-www-form-urlencoded", ct)) {
|
||||
return ap_discard_request_body(r);
|
||||
}
|
||||
|
||||
if (usize > APR_SIZE_MAX >> 1)
|
||||
size = APR_SIZE_MAX >> 1;
|
||||
else
|
||||
size = usize;
|
||||
|
||||
if (!f) {
|
||||
f = r->input_filters;
|
||||
}
|
||||
|
||||
bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
do {
|
||||
apr_bucket *bucket = NULL, *last = NULL;
|
||||
|
||||
int rv = ap_get_brigade(f, bb, AP_MODE_READBYTES,
|
||||
APR_BLOCK_READ, HUGE_STRING_LEN);
|
||||
if (rv != APR_SUCCESS) {
|
||||
apr_brigade_destroy(bb);
|
||||
return (rv == AP_FILTER_ERROR) ? rv : HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
for (bucket = APR_BRIGADE_FIRST(bb);
|
||||
bucket != APR_BRIGADE_SENTINEL(bb);
|
||||
last = bucket, bucket = APR_BUCKET_NEXT(bucket)) {
|
||||
const char *data;
|
||||
apr_size_t len, slide;
|
||||
|
||||
if (last) {
|
||||
apr_bucket_delete(last);
|
||||
}
|
||||
if (APR_BUCKET_IS_EOS(bucket)) {
|
||||
seen_eos = 1;
|
||||
break;
|
||||
}
|
||||
if (bucket->length == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rv = apr_bucket_read(bucket, &data, &len, APR_BLOCK_READ);
|
||||
if (rv != APR_SUCCESS) {
|
||||
apr_brigade_destroy(bb);
|
||||
return HTTP_BAD_REQUEST;
|
||||
}
|
||||
|
||||
slide = len;
|
||||
while (state != FORM_ABORT && slide-- > 0 && size >= 0 && num != 0) {
|
||||
char c = *data++;
|
||||
if ('+' == c) {
|
||||
c = ' ';
|
||||
}
|
||||
else if ('&' == c) {
|
||||
state = FORM_AMP;
|
||||
}
|
||||
if ('%' == c) {
|
||||
percent = FORM_PERCENTA;
|
||||
continue;
|
||||
}
|
||||
if (FORM_PERCENTA == percent) {
|
||||
if (c >= 'a') {
|
||||
hi = c - 'a' + 10;
|
||||
}
|
||||
else if (c >= 'A') {
|
||||
hi = c - 'A' + 10;
|
||||
}
|
||||
else if (c >= '0') {
|
||||
hi = c - '0';
|
||||
}
|
||||
hi = hi << 4;
|
||||
percent = FORM_PERCENTB;
|
||||
continue;
|
||||
}
|
||||
if (FORM_PERCENTB == percent) {
|
||||
if (c >= 'a') {
|
||||
low = c - 'a' + 10;
|
||||
}
|
||||
else if (c >= 'A') {
|
||||
low = c - 'A' + 10;
|
||||
}
|
||||
else if (c >= '0') {
|
||||
low = c - '0';
|
||||
}
|
||||
c = low | hi;
|
||||
percent = FORM_NORMAL;
|
||||
}
|
||||
switch (state) {
|
||||
case FORM_AMP:
|
||||
if (pair) {
|
||||
const char *tmp = apr_pmemdup(r->pool, buffer, offset);
|
||||
apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(pair->value, b);
|
||||
}
|
||||
state = FORM_NAME;
|
||||
pair = NULL;
|
||||
offset = 0;
|
||||
num--;
|
||||
break;
|
||||
case FORM_NAME:
|
||||
if (offset < HUGE_STRING_LEN) {
|
||||
if ('=' == c) {
|
||||
buffer[offset] = 0;
|
||||
offset = 0;
|
||||
pair = (ap_form_pair_t *) apr_array_push(pairs);
|
||||
pair->name = apr_pstrdup(r->pool, buffer);
|
||||
pair->value = apr_brigade_create(r->pool, r->connection->bucket_alloc);
|
||||
state = FORM_VALUE;
|
||||
}
|
||||
else {
|
||||
buffer[offset++] = c;
|
||||
size--;
|
||||
}
|
||||
}
|
||||
else {
|
||||
state = FORM_ABORT;
|
||||
}
|
||||
break;
|
||||
case FORM_VALUE:
|
||||
if (offset >= HUGE_STRING_LEN) {
|
||||
const char *tmp = apr_pmemdup(r->pool, buffer, offset);
|
||||
apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(pair->value, b);
|
||||
offset = 0;
|
||||
}
|
||||
buffer[offset++] = c;
|
||||
size--;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
apr_brigade_cleanup(bb);
|
||||
} while (!seen_eos);
|
||||
|
||||
if (FORM_ABORT == state || size < 0 || num == 0) {
|
||||
return HTTP_REQUEST_ENTITY_TOO_LARGE;
|
||||
}
|
||||
else if (FORM_VALUE == state && pair && offset > 0) {
|
||||
const char *tmp = apr_pmemdup(r->pool, buffer, offset);
|
||||
apr_bucket *b = apr_bucket_pool_create(tmp, offset, r->pool, r->connection->bucket_alloc);
|
||||
APR_BRIGADE_INSERT_TAIL(pair->value, b);
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user