Modified: httpd/apreq/branches/multi-env-unstable/src/apreq_env_cgi.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/src/apreq_env_cgi.c?view=diff&r1=151385&r2=151386 ============================================================================== --- httpd/apreq/branches/multi-env-unstable/src/apreq_env_cgi.c (original) +++ httpd/apreq/branches/multi-env-unstable/src/apreq_env_cgi.c Fri Feb 4 10:27:55 2005 @@ -13,6 +13,7 @@ ** See the License for the specific language governing permissions and ** limitations under the License. */ +#include <assert.h> #include "apreq.h" #include "apreq_env.h" @@ -20,23 +21,46 @@ #include "apr_lib.h" #include "apr_env.h" -#define dP struct cgi_env *cgi_env = (struct cgi_env*)env; \ - apr_pool_t *p = cgi_env->pool +#define USER_DATA_KEY "apreq" + +/* Parroting APLOG_* ... */ + +#define CGILOG_EMERG 0 /* system is unusable */ +#define CGILOG_ALERT 1 /* action must be taken immediately */ +#define CGILOG_CRIT 2 /* critical conditions */ +#define CGILOG_ERR 3 /* error conditions */ +#define CGILOG_WARNING 4 /* warning conditions */ +#define CGILOG_NOTICE 5 /* normal but significant condition */ +#define CGILOG_INFO 6 /* informational */ +#define CGILOG_DEBUG 7 /* debug-level messages */ + +#define CGILOG_LEVELMASK 7 +#define CGILOG_MARK __FILE__, __LINE__ + + + + +struct cgi_handle { + struct apreq_env_handle_t env; + + apr_pool_t *pool; + apr_bucket_alloc_t *bucket_alloc; + + apr_table_t *jar, *args, *body; + apr_status_t jar_status, + args_status, + body_status; + + apreq_parser_t *parser; + apreq_hook_t *hook_queue; + + const char *temp_dir; + apr_size_t brigade_limit; + apr_uint64_t read_limit; + apr_uint64_t bytes_read; + + apr_bucket_brigade *in; -static struct { - apreq_request_t *req; - apreq_jar_t *jar; - apr_status_t status; - const char *temp_dir; - apr_off_t max_body; - apr_ssize_t max_brigade; - apr_bucket_brigade *in; - apr_off_t bytes_read; -} ctx = {NULL, NULL, APR_SUCCESS, NULL, -1, APREQ_MAX_BRIGADE_LEN, NULL, 0}; - -struct cgi_env { - struct apreq_env_handle_t env; - apr_pool_t *pool; }; #define CRLF "\015\012" @@ -49,47 +73,29 @@ } \ } while (0) -#define APREQ_MODULE_NAME "CGI" -#define APREQ_MODULE_MAGIC_NUMBER 20041130 - -static apr_pool_t *cgi_pool(apreq_env_handle_t *env) -{ - struct cgi_env *cgi_env = (struct cgi_env*)env; - - return cgi_env->pool; -} - -static apr_status_t bucket_alloc_cleanup(void *data) -{ - apr_bucket_alloc_t *ba = data; - apr_bucket_alloc_destroy(ba); - return APR_SUCCESS; -} - - -static apr_bucket_alloc_t *cgi_bucket_alloc(apreq_env_handle_t *env) -{ - struct cgi_env *cgi_env = (struct cgi_env*)env; - apr_bucket_alloc_t *ba = apr_bucket_alloc_create(cgi_env->pool); - - apr_pool_cleanup_register(cgi_env->pool, ba, - bucket_alloc_cleanup, - bucket_alloc_cleanup); - return ba; -} - -static const char *cgi_query_string(apreq_env_handle_t *env) -{ - dP; - char *value = NULL, qs[] = "QUERY_STRING"; - APREQ_ENV_STATUS(apr_env_get(&value, qs, p), qs); - return value; -} +typedef struct { + const char *t_name; + int t_val; +} TRANS; + +static const TRANS priorities[] = { + {"emerg", CGILOG_EMERG}, + {"alert", CGILOG_ALERT}, + {"crit", CGILOG_CRIT}, + {"error", CGILOG_ERR}, + {"warn", CGILOG_WARNING}, + {"notice", CGILOG_NOTICE}, + {"info", CGILOG_INFO}, + {"debug", CGILOG_DEBUG}, + {NULL, -1}, +}; + static const char *cgi_header_in(apreq_env_handle_t *env, const char *name) { - dP; + struct cgi_handle *handle = (struct cgi_handle *)env; + apr_pool_t *p = handle->pool; char *key = apr_pstrcat(p, "HTTP_", name, NULL); char *k, *value = NULL; for (k = key; *k; ++k) { @@ -105,269 +111,569 @@ key += 5; /* strlen("HTTP_") */ } - APREQ_ENV_STATUS(apr_env_get(&value, key, p), key); + apr_env_get(&value, key, p); return value; } + + + +static void cgi_log_error(const char *file, int line, int level, + apr_status_t status, apreq_env_handle_t *env, + const char *fmt, ...) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + apr_pool_t *p = handle->pool; + char buf[256]; + char *log_level_string, *ra; + const char *remote_addr; + unsigned log_level = CGILOG_WARNING; + char date[APR_CTIME_LEN]; + va_list vp; +#ifndef WIN32 + apr_file_t *err; +#endif + + va_start(vp, fmt); + + if (apr_env_get(&log_level_string, "LOG_LEVEL", p) == APR_SUCCESS) + log_level = (log_level_string[0] - '0'); + + level &= CGILOG_LEVELMASK; + + if (level < (int)log_level) { + + if (apr_env_get(&ra, "REMOTE_ADDR", p) == APR_SUCCESS) + remote_addr = ra; + else + remote_addr = "address unavailable"; + + apr_ctime(date, apr_time_now()); + +#ifndef WIN32 + + apr_file_open_stderr(&err, p); + apr_file_printf(err, "[%s] [%s] [%s] %s(%d): %s: %s\n", + date, priorities[level].t_name, remote_addr, file, line, + apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp)); + apr_file_flush(err); + +#else + fprintf(stderr, "[%s] [%s] [%s] %s(%d): %s: %s\n", + date, priorities[level].t_name, remote_addr, file, line, + apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp)); +#endif + } + + va_end(vp); + +} + static apr_status_t cgi_header_out(apreq_env_handle_t *env, const char *name, char *value) { - dP; + struct cgi_handle *handle = (struct cgi_handle *)env; + apr_pool_t *p = handle->pool; apr_file_t *out; int bytes; apr_status_t s = apr_file_open_stdout(&out, p); - apreq_log(APREQ_DEBUG s, env, "Setting header: %s => %s", name, value); + cgi_log_error(CGILOG_MARK, CGILOG_DEBUG, s, env, + "Setting header: %s => %s", name, value); bytes = apr_file_printf(out, "%s: %s" CRLF, name, value); apr_file_flush(out); return bytes > 0 ? APR_SUCCESS : APR_EGENERAL; } -static apreq_jar_t *cgi_jar(apreq_env_handle_t *env, apreq_jar_t *jar) +APR_INLINE +static const char *cgi_query_string(apreq_env_handle_t *env) { - (void)env; + struct cgi_handle *handle = (struct cgi_handle *)env; + char *value = NULL, qs[] = "QUERY_STRING"; + apr_env_get(&value, qs, handle->pool); + return value; +} + - if (jar != NULL) { - apreq_jar_t *old_jar = ctx.jar; - ctx.jar = jar; - return old_jar; +static void init_body(apreq_env_handle_t *env) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + const char *cl_header = cgi_header_in(env, "Content-Length"); + apr_bucket_alloc_t *ba = handle->bucket_alloc; + apr_pool_t *pool = handle->pool; + apr_file_t *file; + apr_bucket *eos, *pipe; + + handle->body = apr_table_make(pool, APREQ_DEFAULT_NELTS); + + if (cl_header != NULL) { + char *dummy; + apr_int64_t content_length = apr_strtoi64(cl_header, &dummy, 0); + + if (dummy == NULL || *dummy != 0) { + handle->body_status = APREQ_ERROR_BADHEADER; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, handle->body_status, env, + "Invalid Content-Length header (%s)", cl_header); + return; + } + else if ((apr_uint64_t)content_length > handle->read_limit) { + handle->body_status = APREQ_ERROR_OVERLIMIT; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, handle->body_status, env, + "Content-Length header (%s) exceeds configured " + "max_body limit (%" APR_UINT64_T_FMT ")", + cl_header, handle->read_limit); + return; + } + } + + if (handle->parser == NULL) { + const char *ct_header = cgi_header_in(env, "Content-Type"); + + if (ct_header != NULL) { + apreq_parser_function_t pf = apreq_parser(ct_header); + + if (pf != NULL) { + handle->parser = apreq_make_parser(handle->pool, + ba, + ct_header, + pf, + handle->brigade_limit, + handle->temp_dir, + handle->hook_queue, + NULL); + } + else { + handle->body_status = APREQ_ERROR_NOPARSER; + return; + } + } + else { + handle->body_status = APREQ_ERROR_NOHEADER; + return; + } } + else { + if (handle->parser->brigade_limit > handle->brigade_limit) + handle->parser->brigade_limit = handle->brigade_limit; + if (handle->temp_dir != NULL) + handle->parser->temp_dir = handle->temp_dir; + if (handle->hook_queue != NULL) + apreq_parser_add_hook(handle->parser, handle->hook_queue); + } + + handle->hook_queue = NULL; + handle->in = apr_brigade_create(pool, ba); + + apr_file_open_stdin(&file, pool); // error status? + pipe = apr_bucket_pipe_create(file, ba); + eos = apr_bucket_eos_create(ba); + APR_BRIGADE_INSERT_HEAD(handle->in, pipe); + APR_BRIGADE_INSERT_TAIL(handle->in, eos); + + handle->body_status = APR_INCOMPLETE; - return ctx.jar; } -static apreq_request_t *cgi_request(apreq_env_handle_t *env, - apreq_request_t *req) +static apr_status_t cgi_read(apreq_env_handle_t *env, + apr_off_t bytes) { - (void)env; + struct cgi_handle *handle = (struct cgi_handle *)env; + apr_bucket *e; + apr_status_t s; + + if (handle->body_status == APR_EINIT) + init_body(env); + + if (handle->body_status != APR_INCOMPLETE) + return handle->body_status; + + + switch (s = apr_brigade_partition(handle->in, bytes, &e)) { + apr_bucket_brigade *bb; + apr_off_t len; + + case APR_SUCCESS: + + bb = handle->in; + handle->in = apr_brigade_split(bb, e); + handle->bytes_read += bytes; + + if (handle->bytes_read > handle->read_limit) { + handle->body_status = APREQ_ERROR_OVERLIMIT; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, handle->body_status, + env, "Bytes read (%" APR_UINT64_T_FMT + ") exceeds configured limit (%" APR_UINT64_T_FMT ")", + handle->bytes_read, handle->read_limit); + break; + } - if (req != NULL) { - apreq_request_t *old_req = ctx.req; - ctx.req = req; - return old_req; + handle->body_status = + APREQ_RUN_PARSER(handle->parser, handle->body, bb); + apr_brigade_destroy(bb); + break; + + + case APR_INCOMPLETE: + + bb = handle->in; + handle->in = apr_brigade_split(bb, e); + s = apr_brigade_length(bb, 1, &len); + + if (s != APR_SUCCESS) { + handle->body_status = s; + break; + } + handle->bytes_read += len; + + if (handle->bytes_read > handle->read_limit) { + handle->body_status = APREQ_ERROR_OVERLIMIT; + cgi_log_error(CGILOG_MARK, CGILOG_ERR, handle->body_status, env, + "Bytes read (%" APR_UINT64_T_FMT + ") exceeds configured limit (%" APR_UINT64_T_FMT ")", + handle->bytes_read, handle->read_limit); + + break; + } + + handle->body_status = + APREQ_RUN_PARSER(handle->parser, handle->body, bb); + apr_brigade_destroy(bb); + break; + + default: + handle->body_status = s; } - return ctx.req; + + return handle->body_status; } -typedef struct { - const char *t_name; - int t_val; -} TRANS; -static const TRANS priorities[] = { - {"emerg", APREQ_LOG_EMERG}, - {"alert", APREQ_LOG_ALERT}, - {"crit", APREQ_LOG_CRIT}, - {"error", APREQ_LOG_ERR}, - {"warn", APREQ_LOG_WARNING}, - {"notice", APREQ_LOG_NOTICE}, - {"info", APREQ_LOG_INFO}, - {"debug", APREQ_LOG_DEBUG}, - {NULL, -1}, -}; +static apr_status_t cgi_jar(apreq_env_handle_t *env, + const apr_table_t **t) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + if (handle->jar_status == APR_EINIT) { + const char *cookies = cgi_header_in(env, "Cookie"); + if (cookies != NULL) { + handle->jar = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS); + handle->jar_status = + apreq_parse_cookie_header(handle->pool, handle->jar, cookies); + } + else + handle->jar_status = APREQ_ERROR_NODATA; + } + + *t = handle->jar; + return handle->jar_status; +} -static void cgi_log(const char *file, int line, int level, - apr_status_t status, apreq_env_handle_t *env, - const char *fmt, va_list vp) +static apr_status_t cgi_args(apreq_env_handle_t *env, + const apr_table_t **t) { - dP; - char buf[256]; - char *log_level_string, *ra; - const char *remote_addr; - unsigned log_level = APREQ_LOG_WARNING; - char date[APR_CTIME_LEN]; -#ifndef WIN32 - apr_file_t *err; -#endif + struct cgi_handle *handle = (struct cgi_handle *)env; + if (handle->args_status == APR_EINIT) { + const char *query_string = cgi_query_string(env); + if (query_string != NULL) { + handle->args = apr_table_make(handle->pool, APREQ_DEFAULT_NELTS); + handle->args_status = + apreq_parse_query_string(handle->pool, handle->args, query_string); + } + else + handle->args_status = APREQ_ERROR_NODATA; + } - if (apr_env_get(&log_level_string, "LOG_LEVEL", p) == APR_SUCCESS) - log_level = (log_level_string[0] - '0'); + *t = handle->args; + return handle->args_status; +} - level &= APREQ_LOG_LEVELMASK; - if (level > (int)log_level) - return; - if (apr_env_get(&ra, "REMOTE_ADDR", p) == APR_SUCCESS) - remote_addr = ra; + +static apreq_cookie_t *cgi_jar_get(apreq_env_handle_t *env, + const char *name) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + const apr_table_t *t; + const char *val; + + if (handle->jar_status == APR_EINIT) + cgi_jar(env, &t); else - remote_addr = "address unavailable"; + t = handle->jar; - apr_ctime(date, apr_time_now()); + if (t == NULL) + return NULL; -#ifndef WIN32 + val = apr_table_get(t, name); + if (val == NULL) + return NULL; - apr_file_open_stderr(&err, p); - apr_file_printf(err, "[%s] [%s] [%s] %s(%d): %s: %s\n", - date, priorities[level].t_name, remote_addr, file, line, - apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp)); - apr_file_flush(err); + return apreq_value_to_cookie(val); +} -#else - fprintf(stderr, "[%s] [%s] [%s] %s(%d): %s: %s\n", - date, priorities[level].t_name, remote_addr, file, line, - apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp)); -#endif +static apreq_param_t *cgi_args_get(apreq_env_handle_t *env, + const char *name) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + const apr_table_t *t; + const char *val; + + if (handle->args_status == APR_EINIT) + cgi_args(env, &t); + else + t = handle->args; + + if (t == NULL) + return NULL; + val = apr_table_get(t, name); + if (val == NULL) + return NULL; + + return apreq_value_to_param(val); } -static apr_status_t cgi_read(apreq_env_handle_t *env, - apr_read_type_e block, - apr_off_t bytes) + + +static apr_status_t cgi_body(apreq_env_handle_t *env, + const apr_table_t **t) { - dP; - apreq_request_t *req = apreq_request(env, NULL); - apr_bucket *e; - apr_status_t s; + struct cgi_handle *handle = (struct cgi_handle *)env; - (void)block; + switch (handle->body_status) { - if (ctx.in == NULL) { - apr_bucket_alloc_t *alloc = apr_bucket_alloc_create(p); - apr_bucket *stdin_pipe, *eos = apr_bucket_eos_create(alloc); - apr_file_t *in; - apr_file_open_stdin(&in, p); - stdin_pipe = apr_bucket_pipe_create(in,alloc); - ctx.in = apr_brigade_create(p, alloc); - APR_BRIGADE_INSERT_HEAD(ctx.in, stdin_pipe); - APR_BRIGADE_INSERT_TAIL(ctx.in, eos); - ctx.status = APR_INCOMPLETE; - - if (ctx.max_body >= 0) { - const char *cl = apreq_env_header_in(env, "Content-Length"); - if (cl != NULL) { - char *dummy; - apr_int64_t content_length = apr_strtoi64(cl,&dummy,0); - - if (dummy == NULL || *dummy != 0) { - apreq_log(APREQ_ERROR APR_EGENERAL, env, - "Invalid Content-Length header (%s)", cl); - ctx.status = APR_EGENERAL; - req->body_status = APR_EGENERAL; - } - else if (content_length > (apr_int64_t)ctx.max_body) { - apreq_log(APREQ_ERROR APR_EGENERAL, env, - "Content-Length header (%s) exceeds configured " - "max_body limit (%" APR_OFF_T_FMT ")", - cl, ctx.max_body); - ctx.status = APR_EGENERAL; - req->body_status = APR_EGENERAL; - } - } - } + case APR_EINIT: + init_body(env); + if (handle->body_status != APR_INCOMPLETE) + break; + + case APR_INCOMPLETE: + while (cgi_read(env, APREQ_DEFAULT_READ_BLOCK_SIZE) == APR_INCOMPLETE) + ; /*loop*/ } + *t = handle->body; + return handle->body_status; +} - if (ctx.status != APR_INCOMPLETE) - return ctx.status; +static apreq_param_t *cgi_body_get(apreq_env_handle_t *env, + const char *name) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + const char *val; - switch (s = apr_brigade_partition(ctx.in, bytes, &e)) { - apr_bucket_brigade *bb; - apr_off_t len; + switch (handle->body_status) { - case APR_SUCCESS: - bb = ctx.in; - ctx.in = apr_brigade_split(bb, e); - ctx.bytes_read += bytes; - if (ctx.max_body >= 0) { - if (ctx.bytes_read > ctx.max_body) { - apreq_log(APREQ_ERROR APR_EGENERAL, env, - "Bytes read (%" APR_OFF_T_FMT - ") exceeds configured limit (%" APR_OFF_T_FMT ")", - ctx.bytes_read, ctx.max_body); - req->body_status = APR_EGENERAL; - return ctx.status = APR_EGENERAL; - } - } - ctx.status = apreq_parse_request(req, bb); - apr_brigade_cleanup(bb); - break; + case APR_EINIT: + + init_body(env); + if (handle->body_status != APR_INCOMPLETE) + return NULL; + cgi_read(env, APREQ_DEFAULT_READ_BLOCK_SIZE); case APR_INCOMPLETE: - bb = ctx.in; - ctx.in = apr_brigade_split(bb, e); - s = apr_brigade_length(bb,1,&len); - if (s != APR_SUCCESS) - return ctx.status = s; - ctx.bytes_read += len; - if (ctx.max_body >= 0) { - if (ctx.bytes_read > ctx.max_body) { - apreq_log(APREQ_ERROR APR_EGENERAL, env, - "Bytes read (%" APR_OFF_T_FMT - ") exceeds configured limit (%" APR_OFF_T_FMT ")", - ctx.bytes_read, ctx.max_body); - req->body_status = APR_EGENERAL; - return ctx.status = APR_EGENERAL; - } - } - ctx.status = apreq_parse_request(req, bb); - apr_brigade_cleanup(bb); - break; + + val = apr_table_get(handle->body, name); + if (val != NULL) + return apreq_value_to_param(val); + + do { + /* riff on Duff's device */ + cgi_read(env, APREQ_DEFAULT_READ_BLOCK_SIZE); default: - ctx.status = s; + + val = apr_table_get(handle->body, name); + if (val != NULL) + return apreq_value_to_param(val); + + } while (handle->body_status == APR_INCOMPLETE); + } - return ctx.status; + return NULL; } +static apr_status_t cgi_parser_get(apreq_env_handle_t *env, + const apreq_parser_t **parser) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + + *parser = handle->parser; + return APR_SUCCESS; +} -static const char *cgi_temp_dir(apreq_env_handle_t *env, const char *path) +static apr_status_t cgi_parser_set(apreq_env_handle_t *env, + apreq_parser_t *parser) { - if (path != NULL) { - dP; - const char *rv = ctx.temp_dir; - ctx.temp_dir = apr_pstrdup(p, path); - return rv; + struct cgi_handle *handle = (struct cgi_handle *)env; + + if (handle->parser == NULL) { + + if (handle->hook_queue != NULL) { + apr_status_t s = apreq_parser_add_hook(parser, handle->hook_queue); + if (s != APR_SUCCESS) + return s; + } + if (handle->temp_dir != NULL) { + parser->temp_dir = handle->temp_dir; + } + if (handle->brigade_limit < parser->brigade_limit) { + parser->brigade_limit = handle->brigade_limit; + } + + handle->hook_queue = NULL; + handle->parser = parser; + return APR_SUCCESS; } - if (ctx.temp_dir == NULL) { - dP; - if (apr_temp_dir_get(&ctx.temp_dir, p) != APR_SUCCESS) - ctx.temp_dir = NULL; + else + return APREQ_ERROR_CONFLICT; +} + + +static apr_status_t cgi_hook_add(apreq_env_handle_t *env, + apreq_hook_t *hook) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + + if (handle->parser != NULL) { + return apreq_parser_add_hook(handle->parser, hook); + } + else if (handle->hook_queue != NULL) { + apreq_hook_t *h = handle->hook_queue; + while (h->next != NULL) + h = h->next; + h->next = hook; + } + else { + handle->hook_queue = hook; } + return APR_SUCCESS; - return ctx.temp_dir; } +static apr_status_t cgi_brigade_limit_set(apreq_env_handle_t *env, + apr_size_t bytes) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + apr_size_t *limit = (handle->parser == NULL) + ? &handle->brigade_limit + : &handle->parser->brigade_limit; + + if (*limit > bytes) { + *limit = bytes; + return APR_SUCCESS; + } + + return APREQ_ERROR_CONFLICT; +} + +static apr_status_t cgi_brigade_limit_get(apreq_env_handle_t *env, + apr_size_t *bytes) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + *bytes = (handle->parser == NULL) + ? handle->brigade_limit + : handle->parser->brigade_limit; + + return APR_SUCCESS; +} -static apr_off_t cgi_max_body(apreq_env_handle_t *env, apr_off_t bytes) +static apr_status_t cgi_read_limit_set(apreq_env_handle_t *env, + apr_uint64_t bytes) { - (void)env; + struct cgi_handle *handle = (struct cgi_handle *)env; - if (bytes >= 0) { - apr_off_t rv = ctx.max_body; - ctx.max_body = bytes; - return rv; + if (handle->read_limit > bytes && handle->bytes_read < bytes) { + handle->read_limit = bytes; + return APR_SUCCESS; } - return ctx.max_body; + + return APREQ_ERROR_CONFLICT; } -static apr_ssize_t cgi_max_brigade(apreq_env_handle_t *env, apr_ssize_t bytes) +static apr_status_t cgi_read_limit_get(apreq_env_handle_t *env, + apr_uint64_t *bytes) { - (void)env; + struct cgi_handle *handle = (struct cgi_handle *)env; + *bytes = handle->read_limit; + return APR_SUCCESS; +} - if (bytes >= 0) { - apr_ssize_t rv = ctx.max_brigade; - ctx.max_brigade = bytes; - return rv; + +static apr_status_t cgi_temp_dir_set(apreq_env_handle_t *env, + const char *path) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + const char **temp_dir = (handle->parser == NULL) + ? &handle->temp_dir + : &handle->parser->temp_dir; + + + if (*temp_dir == NULL && handle->bytes_read == 0) { + if (path != NULL) + *temp_dir = apr_pstrdup(handle->pool, path); + return APR_SUCCESS; } - return ctx.max_brigade; + + return APREQ_ERROR_CONFLICT; } -APREQ_ENV_MODULE(cgi, APREQ_MODULE_NAME, - APREQ_MODULE_MAGIC_NUMBER); -APREQ_DECLARE(apreq_env_handle_t*) apreq_env_make_cgi(apr_pool_t *pool) { - struct cgi_env *handle; +static apr_status_t cgi_temp_dir_get(apreq_env_handle_t *env, + const char **path) +{ + struct cgi_handle *handle = (struct cgi_handle *)env; + *path = (handle->parser == NULL) + ? handle->temp_dir + : handle->parser->temp_dir; + return APR_SUCCESS; +} + + + + +static apr_status_t cgi_cleanup(void *data) +{ + struct cgi_handle *handle = data; + apr_bucket_alloc_destroy(handle->bucket_alloc); + return APR_SUCCESS; +} + +static APREQ_MODULE(cgi, 20050130); + +APREQ_DECLARE(apreq_env_handle_t *)apreq_handle_cgi(apr_pool_t *pool) +{ + apr_bucket_alloc_t *ba; + struct cgi_handle *handle; + void *data; + + apr_pool_userdata_get(&data, USER_DATA_KEY, pool); + + if (data != NULL) + return data; + + handle = apr_pcalloc(pool, sizeof *handle); + ba = apr_bucket_alloc_create(pool); + + /* check pool's userdata first. */ + + handle->env.module = &cgi_module; + handle->pool = pool; + handle->bucket_alloc = ba; + handle->read_limit = (apr_uint64_t) -1; + handle->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT; + + handle->args_status = + handle->jar_status = + handle->body_status = APR_EINIT; - handle = apr_pcalloc(pool, sizeof(*handle)); - handle->env.module = &cgi_module; - handle->pool = pool; + apr_pool_userdata_setn(&handle->env, USER_DATA_KEY, cgi_cleanup, pool); return &handle->env; }
Modified: httpd/apreq/branches/multi-env-unstable/src/apreq_env_custom.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/src/apreq_env_custom.c?view=diff&r1=151385&r2=151386 ============================================================================== --- httpd/apreq/branches/multi-env-unstable/src/apreq_env_custom.c (original) +++ httpd/apreq/branches/multi-env-unstable/src/apreq_env_custom.c Fri Feb 4 10:27:55 2005 @@ -14,252 +14,320 @@ ** limitations under the License. */ -#include <apr_strings.h> - -#include "apreq.h" +#include "apr_strings.h" #include "apreq_env.h" +#define READ_BYTES (64 * 1024) + struct custom_handle { - struct apreq_env_handle_t env; - apr_pool_t *pool; - const char *query_string; - apreq_request_t *request; - const char *content_type; - const char *cookie_string, *cookie2_string; - apreq_jar_t *jar; - const char *temp_dir; - apr_off_t max_body; - apr_ssize_t max_brigade; - - /* body state */ - apr_status_t status; - apr_off_t bytes_read; - apr_bucket_brigade *in; + struct apreq_env_handle_t env; + const char *cookie_header, *cookie2_header; + + 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; }; -static apr_pool_t *custom_pool(apreq_env_handle_t *env) { + +static apr_status_t custom_parse_brigade(apreq_env_handle_t *env, apr_uint64_t bytes) +{ struct custom_handle *handle = (struct custom_handle*)env; + apr_status_t s; + apr_bucket *e; + + if (handle->body_status != APR_INCOMPLETE) + return handle->body_status; + + switch (s = apr_brigade_partition(handle->in, bytes, &e)) { + apr_bucket_brigade *bb; + apr_uint64_t len; + + case APR_SUCCESS: + bb = apr_brigade_split(handle->in, e); + handle->bytes_read += bytes; + + if (handle->bytes_read > handle->read_limit) { + handle->body_status = APREQ_ERROR_OVERLIMIT; + break; + } + + handle->body_status = + APREQ_RUN_PARSER(handle->parser, handle->body, handle->in); + + apr_brigade_cleanup(handle->in); + APR_BRIGADE_CONCAT(handle->in, bb); + break; + + case APR_INCOMPLETE: + bb = apr_brigade_split(handle->in, e); + s = apr_brigade_length(handle->in, 1, &len); + if (s != APR_SUCCESS) { + handle->body_status = s; + break; + } + handle->bytes_read += len; + + if (handle->bytes_read > handle->read_limit) { + handle->body_status = APREQ_ERROR_OVERLIMIT; + break; + } + handle->body_status = + APREQ_RUN_PARSER(handle->parser, handle->body, handle->in); + + apr_brigade_cleanup(handle->in); + APR_BRIGADE_CONCAT(handle->in, bb); + break; + + default: + handle->body_status = s; + } - return handle->pool; + return handle->body_status; } -static apr_status_t bucket_alloc_cleanup(void *data) + + +static apr_status_t custom_jar(apreq_env_handle_t *env, const apr_table_t **t) { - apr_bucket_alloc_t *ba = data; - apr_bucket_alloc_destroy(ba); - return APR_SUCCESS; + struct custom_handle *handle = (struct custom_handle*)env; + *t = handle->jar; + return handle->jar_status; } -static apr_bucket_alloc_t *custom_bucket_alloc(apreq_env_handle_t *env) +static apr_status_t custom_args(apreq_env_handle_t *env, const apr_table_t **t) { struct custom_handle *handle = (struct custom_handle*)env; - apr_bucket_alloc_t *ba = apr_bucket_alloc_create(handle->pool); - - apr_pool_cleanup_register(handle->pool, ba, - bucket_alloc_cleanup, - bucket_alloc_cleanup); - return ba; + *t = handle->args; + return handle->args_status; } -static const char *custom_query_string(apreq_env_handle_t *env) +static apr_status_t custom_body(apreq_env_handle_t *env, const apr_table_t **t) { struct custom_handle *handle = (struct custom_handle*)env; - - return handle->query_string; + while (handle->body_status == APR_INCOMPLETE) + custom_parse_brigade(env, READ_BYTES); + *t = handle->body; + return handle->body_status; } -static const char *custom_header_in(apreq_env_handle_t *env, - const char *name) + + +static apreq_cookie_t *custom_jar_get(apreq_env_handle_t *env, const char *name) { struct custom_handle *handle = (struct custom_handle*)env; + const char *val; - if (strcasecmp(name, "Content-Type") == 0) - return handle->content_type; - else if (strcasecmp(name, "Cookie") == 0) - return handle->cookie_string; - else if (strcasecmp(name, "Cookie2") == 0) - return handle->cookie2_string; - else + if (handle->jar == NULL || name == NULL) return NULL; + + val = apr_table_get(handle->jar, name); + + if (val == NULL) + return NULL; + + return apreq_value_to_cookie(val); } -static apr_status_t custom_header_out(apreq_env_handle_t *env, const char *name, - char *value) +static apreq_param_t *custom_args_get(apreq_env_handle_t *env, const char *name) { - (void)env; - (void)name; - (void)value; + struct custom_handle *handle = (struct custom_handle*)env; + const char *val; - return APR_SUCCESS; + if (handle->args == NULL || name == NULL) + return NULL; + + val = apr_table_get(handle->args, name); + + if (val == NULL) + return NULL; + + return apreq_value_to_param(val); } -static apreq_jar_t *custom_jar(apreq_env_handle_t *env, apreq_jar_t *jar) +static apreq_param_t *custom_body_get(apreq_env_handle_t *env, const char *name) { struct custom_handle *handle = (struct custom_handle*)env; - apreq_jar_t *value = handle->jar; + const char *val; - if (jar != NULL) - handle->jar = jar; + if (handle->body == NULL || name == NULL) + return NULL; - return value; + get_body_value: + + *(const char **)&val = apr_table_get(handle->body, name); + if (val == NULL) { + if (handle->body_status == APR_INCOMPLETE) { + custom_parse_brigade(env, READ_BYTES); + goto get_body_value; + } + else + return NULL; + } + + return apreq_value_to_param(val); } -static apreq_request_t *custom_request(apreq_env_handle_t *env, - apreq_request_t *req) + + +static apr_status_t custom_parser_get(apreq_env_handle_t *env, + const apreq_parser_t **parser) { struct custom_handle *handle = (struct custom_handle*)env; - apreq_request_t *value = handle->request; + *parser = handle->parser; - if (req != NULL) - handle->request = req; - - return value; + return APR_SUCCESS; } -static void custom_log(const char *file, int line, int level, - apr_status_t status, apreq_env_handle_t *env, - const char *fmt, va_list vp) +static apr_status_t custom_parser_set(apreq_env_handle_t *env, + apreq_parser_t *parser) { - (void)file; - (void)line; - (void)level; - (void)status; (void)env; - (void)fmt; - (void)vp; + (void)parser; + return APR_ENOTIMPL; } -static apr_status_t custom_read(apreq_env_handle_t *env, - apr_read_type_e block, - apr_off_t bytes) +static apr_status_t custom_hook_add(apreq_env_handle_t *env, + apreq_hook_t *hook) { struct custom_handle *handle = (struct custom_handle*)env; - apr_bucket *e; - - (void)block; - - if (handle->status != APR_INCOMPLETE) - return handle->status; + apreq_parser_add_hook(handle->parser, hook); + return APR_SUCCESS; +} - handle->status = apr_brigade_partition(handle->in, bytes, &e); - switch (handle->status) { - apr_bucket_brigade *bb; - apr_off_t len; - apreq_request_t *req; +static apr_status_t custom_brigade_limit_get(apreq_env_handle_t *env, + apr_size_t *bytes) +{ + struct custom_handle *handle = (struct custom_handle*)env; + *bytes = handle->parser->brigade_limit; + return APR_SUCCESS; +} - case APR_SUCCESS: - bb = apr_brigade_split(handle->in, e); - req = apreq_request(env, NULL); - if (handle->max_body >= 0 && - handle->bytes_read + bytes > handle->max_body) { - apreq_log(APREQ_ERROR APR_EGENERAL, env, - "Bytes read (%" APR_OFF_T_FMT - ") exceeds configured limit (%" APR_OFF_T_FMT ")", - handle->bytes_read, handle->max_body); - req->body_status = APR_EGENERAL; - return handle->status = APR_EGENERAL; - } - handle->bytes_read += bytes; - handle->status = apreq_parse_request(req, handle->in); - apr_brigade_cleanup(handle->in); - APR_BRIGADE_CONCAT(handle->in, bb); - break; +static apr_status_t custom_brigade_limit_set(apreq_env_handle_t *env, + apr_size_t bytes) +{ + (void)env; + (void)bytes; + return APR_ENOTIMPL; +} - case APR_INCOMPLETE: - bb = apr_brigade_split(handle->in, e); - handle->status = apr_brigade_length(handle->in,1,&len); - if (handle->status != APR_SUCCESS) - return handle->status; - req = apreq_request(env, NULL); - if (handle->max_body >= 0 && - handle->bytes_read + len > handle->max_body) { - apreq_log(APREQ_ERROR APR_EGENERAL, env, - "Bytes read (%" APR_OFF_T_FMT - ") exceeds configured limit (%" APR_OFF_T_FMT ")", - handle->bytes_read, handle->max_body); - req->body_status = APR_EGENERAL; - return handle->status = APR_EGENERAL; - } - handle->bytes_read += len; - handle->status = apreq_parse_request(req, handle->in); - apr_brigade_cleanup(handle->in); - APR_BRIGADE_CONCAT(handle->in, bb); - break; - } +static apr_status_t custom_read_limit_get(apreq_env_handle_t *env, + apr_uint64_t *bytes) +{ + struct custom_handle *handle = (struct custom_handle*)env; + *bytes = handle->read_limit; + return APR_SUCCESS; +} - return handle->status; +static apr_status_t custom_read_limit_set(apreq_env_handle_t *env, + apr_uint64_t bytes) +{ + (void)env; + (void)bytes; + return APR_ENOTIMPL; } -static const char *custom_temp_dir(apreq_env_handle_t *env, const char *path) +static apr_status_t custom_temp_dir_get(apreq_env_handle_t *env, + const char **path) { struct custom_handle *handle = (struct custom_handle*)env; - const char *value = handle->temp_dir; - if (path != NULL) - handle->temp_dir = apr_pstrdup(handle->pool, path); + *path = handle->parser->temp_dir; + return APR_SUCCESS; +} - if (handle->temp_dir == NULL) { - apr_status_t status; +static apr_status_t custom_temp_dir_set(apreq_env_handle_t *env, + const char *path) +{ + (void)env; + (void)path; + return APR_ENOTIMPL; +} - status = apr_temp_dir_get(&value, handle->pool); - if (status != APR_SUCCESS) - value = NULL; - handle->temp_dir = value; - } - return value; -} -static apr_off_t custom_max_body(apreq_env_handle_t *env, apr_off_t bytes) +static const char *custom_header_in(apreq_env_handle_t *env, + const char *name) { struct custom_handle *handle = (struct custom_handle*)env; - apr_off_t value = handle->max_body; - if (bytes >= 0) - handle->max_body = bytes; - - return value; + if (strcasecmp(name, "Content-Type") == 0) + return handle->parser->content_type; + else if (strcasecmp(name, "Cookie") == 0) + return handle->cookie_header; + else if (strcasecmp(name, "Cookie2") == 0) + return handle->cookie2_header; + else + return NULL; } -static apr_ssize_t custom_max_brigade(apreq_env_handle_t *env, apr_ssize_t bytes) +static apr_status_t custom_header_out(apreq_env_handle_t *env, const char *name, + char *value) { - struct custom_handle *handle = (struct custom_handle*)env; - apr_off_t value = handle->max_brigade; - - if (bytes >= 0) - handle->max_brigade = bytes; + (void)env; + (void)name; + (void)value; - return value; + return APR_ENOTIMPL; } -static APREQ_ENV_MODULE(custom, "Custom", 20050110); -APREQ_DECLARE(apreq_env_handle_t*) apreq_env_make_custom(apr_pool_t *pool, - const char *query_string, - const char *cookie, - const char *cookie2, - const char *content_type, - apr_bucket_brigade *in) { - struct custom_handle *handle; +static APREQ_MODULE(custom, 20050130); - handle = apr_pcalloc(pool, sizeof(*handle)); +APREQ_DECLARE(apreq_env_handle_t*) apreq_handle_custom(apr_pool_t *pool, + const char *query_string, + const char *cookie, + const char *cookie2, + apreq_parser_t *parser, + apr_uint64_t read_limit, + apr_bucket_brigade *in) +{ + struct custom_handle *handle; + handle = apr_palloc(pool, sizeof(*handle)); handle->env.module = &custom_module; - handle->pool = pool; - handle->max_body = -1; - handle->max_brigade = -1; - - if (query_string != NULL) - handle->query_string = apr_pstrdup(pool, query_string); - if (content_type != NULL) - handle->content_type = apr_pstrdup(pool, content_type); - if (cookie != NULL) - handle->cookie_string = apr_pstrdup(pool, cookie); - if (cookie2 != NULL) - handle->cookie2_string = apr_pstrdup(pool, cookie2); - + handle->cookie_header = cookie; + handle->cookie2_header = cookie2; + handle->read_limit = read_limit; + handle->parser = parser; handle->in = in; - handle->status = handle->in == NULL ? APR_ENOTIMPL : APR_INCOMPLETE; + + if (cookie != NULL) { + handle->jar = apr_table_make(pool, APREQ_DEFAULT_NELTS); + handle->jar_status = + apreq_parse_cookie_header(pool, handle->args, query_string); + } + else { + handle->jar = NULL; + handle->jar_status = APREQ_ERROR_NODATA; + } + + + if (query_string != NULL) { + handle->args = apr_table_make(pool, APREQ_DEFAULT_NELTS); + handle->args_status = + apreq_parse_query_string(pool, handle->args, query_string); + } + else { + handle->args = NULL; + handle->args_status = APREQ_ERROR_NODATA; + } + + if (in != NULL) { + handle->body = apr_table_make(pool, APREQ_DEFAULT_NELTS); + handle->body_status = APR_INCOMPLETE; + } + else { + handle->body = NULL; + handle->body_status = APREQ_ERROR_NODATA; + } return &handle->env; } + Modified: httpd/apreq/branches/multi-env-unstable/src/apreq_params.c URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/src/apreq_params.c?view=diff&r1=151385&r2=151386 ============================================================================== --- httpd/apreq/branches/multi-env-unstable/src/apreq_params.c (original) +++ httpd/apreq/branches/multi-env-unstable/src/apreq_params.c Fri Feb 4 10:27:55 2005 @@ -15,7 +15,6 @@ */ #include "apreq_params.h" -#include "apreq_env.h" #include "apr_strings.h" #include "apr_lib.h" @@ -30,204 +29,58 @@ const apr_size_t vlen) { apreq_param_t *param = apr_palloc(p, nlen + vlen + 1 + sizeof *param); - apreq_value_t *v = ¶m->v; - char *writable_name; + apreq_value_t *v; param->info = NULL; - param->bb = NULL; + param->upload = NULL; + *(const apreq_value_t **)&v = ¶m->v; v->size = vlen; - memcpy(v->data, val, vlen); + if (vlen) + memcpy(v->data, val, vlen); v->data[vlen] = 0; - writable_name = v->data + vlen + 1; - memcpy(writable_name, name, nlen); - writable_name[nlen] = 0; - v->name = writable_name; + v->name = v->data + vlen + 1; + if (nlen) + memcpy(v->name, name, nlen); + v->name[nlen] = 0; return param; } -APREQ_DECLARE(apreq_request_t *) apreq_request(apreq_env_handle_t *env, - const char *qs) +APREQ_DECLARE(apr_status_t) apreq_decode_param(apreq_param_t **param, + apr_pool_t *pool, + const char *word, + const apr_size_t nlen, + const apr_size_t vlen) { - apreq_request_t *req; - apr_pool_t *p; - - if (qs == NULL) { - apreq_request_t *old_req = apreq_env_request(env,NULL); - if (old_req != NULL) - return old_req; - - p = apreq_env_pool(env); - qs = apreq_env_query_string(env); - - req = apr_palloc(p, sizeof *req); - req->env = env; - req->args = apr_table_make(p, APREQ_NELTS); - req->body = NULL; - req->parser = NULL; - - /* XXX get/set race condition here wrt apreq_env_request? */ - old_req = apreq_env_request(env, req); - - if (old_req != NULL) { - apreq_log(APREQ_ERROR APR_EGENERAL, env, "race condition" - "between consecutive calls of apreq_env_request"); - apreq_env_request(env, old_req); /* reset old_req */ - return old_req; - } - - } - else { - p = apreq_env_pool(env); - - req = apr_palloc(p, sizeof *req); - req->env = env; - req->args = apr_table_make(p, APREQ_NELTS); - req->body = NULL; - req->parser = NULL; - - } - - if (qs != NULL) { - req->args_status = apreq_parse_query_string(p, req->args, qs); - if (req->args_status != APR_SUCCESS) - apreq_log(APREQ_ERROR req->args_status, env, - "invalid query string: %s", qs); - } - else - req->args_status = APR_SUCCESS; - - req->body_status = APR_EINIT; - return req; -} - - -APREQ_DECLARE(apreq_param_t *)apreq_param(const apreq_request_t *req, - const char *name) -{ - const char *val = apr_table_get(req->args, name); + apr_status_t status; + apreq_value_t *v; + apreq_param_t *p; + apr_size_t size; - while (val == NULL) { - apr_status_t s = req->body_status; - switch (s) { - case APR_INCOMPLETE: - case APR_EINIT: - s = apreq_env_read(req->env, APR_BLOCK_READ, APREQ_READ_AHEAD); + if (nlen == 0) + return APR_EBADARG; - default: - if (req->body == NULL) - return NULL; - val = apr_table_get(req->body, name); - if (s != APR_INCOMPLETE && val == NULL) - return NULL; + p = apr_palloc(pool, nlen + vlen + 1 + sizeof *p); + p->info = NULL; + p->upload = NULL; + *(const apreq_value_t **)&v = &p->v; + + if (vlen > 0) { + status = apreq_decode(v->data, &v->size, word + nlen + 1, vlen); + if (status != APR_SUCCESS) { + *param = NULL; + return status; } } - - return apreq_value_to_param(apreq_strtoval(val)); -} - - -APREQ_DECLARE(apr_table_t *) apreq_params(apr_pool_t *pool, - const apreq_request_t *req) -{ - apr_status_t s; - - switch (req->body_status) { - case APR_INCOMPLETE: - case APR_EINIT: - do s = apreq_env_read(req->env, APR_BLOCK_READ, APREQ_READ_AHEAD); - while (s == APR_INCOMPLETE); - } - return req->body ? apr_table_overlay(pool, req->args, req->body) : - apr_table_copy(pool, req->args); -} - - -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(apreq_strtoval(val)); - return 1; /* keep going */ -} - - -APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p, - apreq_request_t *req, - const char *key) -{ - apr_status_t s; - apr_array_header_t *arr = apr_array_make(p, apr_table_elts(req->args)->nelts, - sizeof(apreq_param_t *)); - - apr_table_do(param_push, arr, req->args, key, NULL); - - switch (req->body_status) { - case APR_INCOMPLETE: - case APR_EINIT: - do s = apreq_env_read(req->env, APR_BLOCK_READ, APREQ_READ_AHEAD); - while (s == APR_INCOMPLETE); - } - - if (req->body) - apr_table_do(param_push, arr, req->body, key, NULL); - - return arr; -} - -APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p, - apreq_request_t *req, - const char *key, - apreq_join_t mode) -{ - /* Must adjust apreq_param_t pointers to apreq_value_t. */ -#ifdef DEBUG - assert(sizeof(apreq_param_t **) == sizeof(apreq_value_t **)); -#endif - apr_array_header_t *arr = apreq_params_as_array(p, req, key); - apreq_param_t **elt = (apreq_param_t **)arr->elts; - apreq_param_t **const end = elt + arr->nelts; - if (arr->nelts == 0) - return NULL; - - while (elt < end) { - *(apreq_value_t **)elt = &(**elt).v; - ++elt; + else { + v->data[0] = 0; + v->size = 0; } - return apreq_join(p, ", ", arr, mode); -} - - -APREQ_DECLARE(apreq_param_t *) apreq_decode_param(apr_pool_t *pool, - const char *word, - const apr_size_t nlen, - const apr_size_t vlen) -{ - apreq_param_t *param; - apr_ssize_t size; - - if (nlen == 0) - return NULL; - - param = apr_palloc(pool, nlen + vlen + 1 + sizeof *param); - param->info = NULL; - param->bb = NULL; - - param->v.name = NULL; - - size = apreq_decode(param->v.data, word + nlen + 1, vlen); - - if (size < 0) - return NULL; - - param->v.size = size; - param->v.name = param->v.data + size + 1; + v->name = v->data + v->size + 1; + *param = p; - if (apreq_decode(param->v.data + size + 1, word, nlen) < 0) - return NULL; - - return param; + return apreq_decode(v->name, &size, word, nlen); } @@ -273,14 +126,15 @@ 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; - param = apreq_decode_param(pool, start, nlen, vlen); - if (param == NULL) - return APR_EGENERAL; + s = apreq_decode_param(¶m, pool, start, nlen, vlen); + if (s != APR_SUCCESS) + return s; apr_table_addn(t, param->v.name, param->v.data); } @@ -296,65 +150,76 @@ return APR_INCOMPLETE; } -APREQ_DECLARE(apr_status_t) apreq_parse_request(apreq_request_t *req, - apr_bucket_brigade *bb) + + + +static int param_push(void *data, const char *key, const char *val) { - switch (req->body_status) { - case APR_EINIT: - if (req->parser == NULL) { - req->parser = apreq_parser(req->env,NULL); - if (req->parser == NULL) - return APR_ENOTIMPL; - } - if (req->body == NULL) - req->body = apr_table_make(apreq_env_pool(req->env),APREQ_NELTS); + 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 NULL; - case APR_INCOMPLETE: - req->body_status = APREQ_RUN_PARSER(req->parser, req->env, - req->body, bb); - default: - return req->body_status; + 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(apreq_strtoval(val)); - if (p->bb) + apreq_param_t *p = apreq_value_to_param(val); + + if (p->upload != NULL) apr_table_addn(t, key, val); return 1; /* keep going */ } -APREQ_DECLARE(apr_table_t *) apreq_uploads(apr_pool_t *pool, - const apreq_request_t *req) +APREQ_DECLARE(const apr_table_t *) apreq_uploads(const apr_table_t *body, + apr_pool_t *pool) { - apr_table_t *t; - apr_status_t s; - - switch (req->body_status) { - case APR_INCOMPLETE: - case APR_EINIT: - do s = apreq_env_read(req->env, APR_BLOCK_READ, APREQ_READ_AHEAD); - while (s == APR_INCOMPLETE); - } - if (req->body == NULL) - return NULL; - - t = apr_table_make(pool, APREQ_NELTS); - /* XXX needs appropriate copy/merge callbacks */ - apr_table_do(upload_push, t, req->body, NULL); + apr_table_t *t = apr_table_make(pool, APREQ_DEFAULT_NELTS); + apr_table_do(upload_push, t, body, NULL); return t; } -static int upload_get(void *data, const char *key, const char *val) +static int upload_set(void *data, const char *key, const char *val) { - apreq_param_t *p = apreq_value_to_param(apreq_strtoval(val)); - apreq_param_t **q = data; - if (p->bb) { + 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 */ } @@ -363,25 +228,12 @@ } -APREQ_DECLARE(apreq_param_t *) apreq_upload(const apreq_request_t *req, - const char *key) +APREQ_DECLARE(const apreq_param_t *) apreq_upload(const apr_table_t *body, + const char *name) { - apreq_param_t *param = NULL; - do { - apr_status_t s = req->body_status; - switch (s) { - case APR_INCOMPLETE: - case APR_EINIT: - s = apreq_env_read(req->env, APR_BLOCK_READ, APREQ_READ_AHEAD); - - default: - if (req->body == NULL) - return NULL; - apr_table_do(upload_get, ¶m, req->body, key, NULL); - if (s != APR_INCOMPLETE) - return param; - } - } while (param == NULL); - + const apreq_param_t *param = NULL; + apr_table_do(upload_set, ¶m, body, name, NULL); return param; } + + Modified: httpd/apreq/branches/multi-env-unstable/src/apreq_params.h URL: http://svn.apache.org/viewcvs/httpd/apreq/branches/multi-env-unstable/src/apreq_params.h?view=diff&r1=151385&r2=151386 ============================================================================== --- httpd/apreq/branches/multi-env-unstable/src/apreq_params.h (original) +++ httpd/apreq/branches/multi-env-unstable/src/apreq_params.h Fri Feb 4 10:27:55 2005 @@ -30,19 +30,29 @@ * @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 *bb; /**< brigade to spool upload files */ - apreq_value_t v; /**< underlying name/value/status info */ + apr_table_t *info; /**< header table associated with the param */ + apr_bucket_brigade *upload; /**< brigade used to spool upload files */ + unsigned char flags; /**< charsets, taint marks, app-specific bits */ + const apreq_value_t v; /**< underlying name/value/status info */ } apreq_param_t; -/* These structs are defined below */ -typedef struct apreq_hook_t apreq_hook_t; -typedef struct apreq_parser_t apreq_parser_t; + +/** 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)); +} + /** accessor macros */ -#define apreq_value_to_param(ptr) apreq_attr_to_type(apreq_param_t, v, ptr) #define apreq_param_name(p) ((p)->v.name) #define apreq_param_value(p) ((p)->v.data) #define apreq_param_info(p) ((p)->info) @@ -55,91 +65,6 @@ const char *val, const apr_size_t vlen); -/** Structure which manages the request data. */ -typedef struct apreq_request_t { - apr_table_t *args; /**< parsed query-string */ - apr_table_t *body; /**< parsed post data */ - apreq_parser_t *parser; /**< active parser for this request */ - apreq_env_handle_t *env; /**< request environment */ - apr_status_t args_status; /**< status of query-string parse */ - apr_status_t body_status; /**< status of post data parse */ -} apreq_request_t; - - -/** - * Creates an apreq_request_t object. - * @param env The current request environment. - * @param qs The query string. - * @remark "qs = NULL" has special behavior. In this case, - * apreq_request(env,NULL) will attempt to fetch a cached object - * from the environment via apreq_env_request. Failing that, it will - * replace "qs" with the result of apreq_env_query_string(env), - * parse that, and store the resulting apreq_request_t object back - * within the environment. This maneuver is designed to both mimimize - * parsing work and allow the environent to place the parsed POST data in - * req->body (otherwise the caller may need to do this manually). - * For details on this, see the environment's documentation for - * the apreq_env_read function. - */ - -APREQ_DECLARE(apreq_request_t *)apreq_request(apreq_env_handle_t *env, - const char *qs); - - -/** - * Returns the first parameter value with the desired name, - * NULL if none found. The name is case-insensitive. - * @param req The current apreq_request_t object. - * @param name Nul-terminated search key. Returns the first table value - * if NULL. - * @return First matching parameter. - * @remark Also parses the request as necessary. - */ -APREQ_DECLARE(apreq_param_t *) apreq_param(const apreq_request_t *req, - const char *name); - - -/** - * Returns a table containing key-value pairs for the full request - * (args + body). - * @param p Allocates the returned table. - * @param req The current apreq_request_t object. - * @remark Also parses the request if necessary. - */ -APREQ_DECLARE(apr_table_t *) apreq_params(apr_pool_t *p, - const apreq_request_t *req); - - - -/** - * Returns an array of parameters (apreq_param_t *) matching the given key. - * The key is case-insensitive. - * @param p Allocates the returned array. - * @param req The current apreq_request_t object. - * @param key Null-terminated search key. key==NULL fetches all parameters. - * @remark Also parses the request if necessary. - */ -APREQ_DECLARE(apr_array_header_t *) apreq_params_as_array(apr_pool_t *p, - apreq_request_t *req, - const char *key); - -/** - * Returns a ", " -separated string containing all parameters - * for the requested key, NULL if none are found. The key is case-insensitive. - * @param p Allocates the return string. - * @param req The current apreq_request_t object. - * @param key Null-terminated parameter name. key==NULL fetches all values. - * @param mode Join type- see apreq_join(). - * @return Returned string is the data attribute of an apreq_value_t, - * so it is safe to use in apreq_strlen() and apreq_strtoval(). - * @remark Also parses the request if necessary. - */ -APREQ_DECLARE(const char *) apreq_params_as_string(apr_pool_t *p, - apreq_request_t *req, - const char *key, - apreq_join_t mode); - - /** * Url-decodes a name=value pair into a param. * @param pool Pool from which the param is allocated. @@ -150,11 +75,11 @@ * exactly one character ('=') which separates the pair. * */ - -APREQ_DECLARE(apreq_param_t *) apreq_decode_param(apr_pool_t *pool, - const char *word, - const apr_size_t nlen, - const apr_size_t vlen); +APREQ_DECLARE(apr_status_t) apreq_decode_param(apreq_param_t **param, + apr_pool_t *pool, + const char *word, + const apr_size_t nlen, + const apr_size_t vlen); /** * Url-encodes the param into a name-value pair. * @param pool Pool which allocates the returned string. @@ -181,257 +106,59 @@ apr_table_t *t, const char *qs); + + /** - * Parse a brigade as incoming POST data. - * @param req Current request. - * @param bb Brigade to parse. See remarks below. - * @return APR_INCOMPLETE if the parse is incomplete, - * APR_SUCCESS if the parser is finished (saw eos), - * APR_ENOTIMPL if no parser is available for this request - * (i.e. unrecognized Content-Type header), - * unrecoverable error value otherwise. + * Returns an array of parameters (apreq_param_t *) matching the given key. + * The key is case-insensitive. + * @param p Allocates the returned array. + * @param req The current apreq_request_t object. + * @param key Null-terminated search key. key==NULL fetches all parameters. + * @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 ", " -separated string containing all parameters + * for the requested key, NULL if none are found. The key is case-insensitive. + * @param p Allocates the return string. + * @param req The current apreq_request_t object. + * @param key Null-terminated parameter name. key==NULL fetches all values. + * @param mode Join type- see apreq_join(). + * @return Returned string is the data attribute of an apreq_value_t, + * so it is safe to use in apreq_strlen() and apreq_strtoval(). + * @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); -APREQ_DECLARE(apr_status_t)apreq_parse_request(apreq_request_t *req, - apr_bucket_brigade *bb); /** - * Returns a table of all params in req->body with non-NULL bucket brigades. + * Returns a table of all params in req->body with non-NULL upload brigades. * @param pool Pool which allocates the table struct. * @param req Current request. * @return Upload table. * @remark Will parse the request if necessary. */ -APREQ_DECLARE(apr_table_t *) apreq_uploads(apr_pool_t *pool, - const apreq_request_t *req); +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 and param->bb != NULL. + * matching key and param->upload != NULL. * @param req The current request. * @param key Parameter name. key == NULL returns first upload. * @return Corresponding upload, NULL if none found. * @remark Will parse the request as necessary. */ -APREQ_DECLARE(apreq_param_t *) apreq_upload(const apreq_request_t *req, - const char *key); -#include "apreq.h" - -/** Parser arguments. */ -#define APREQ_PARSER_ARGS apreq_parser_t *parser, \ - apreq_env_handle_t *env, \ - apr_table_t *t, \ - apr_bucket_brigade *bb - -/** Hook arguments */ -#define APREQ_HOOK_ARGS apreq_hook_t *hook, \ - apreq_env_handle_t *env, \ - apreq_param_t *param, \ - apr_bucket_brigade *bb +APREQ_DECLARE(const apreq_param_t *) + apreq_upload(const apr_table_t *body, const char *name); -typedef apr_status_t (*apreq_parser_function_t)(APREQ_PARSER_ARGS); -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) - -/** - * Singly linked list of hooks. - * - */ -struct apreq_hook_t { - apreq_hook_function_t hook; - apreq_hook_t *next; - void *ctx; -}; - -/** - * Request parser with associated enctype and hooks. - * - */ -struct apreq_parser_t { - apreq_parser_function_t parser; - const char *enctype; - apreq_hook_t *hook; - 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. - */ -#define APREQ_RUN_PARSER(psr,env,t,bb) (psr)->parser(psr,env,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. - */ -#define APREQ_RUN_HOOK(h,env,param,bb) (h)->hook(h,env,param,bb) - -/** - * Concatenates the brigades, spooling large brigades into - * a tempfile bucket according to the environment's max_brigade - * setting- see apreq_env_max_brigade(). - * @param env Environment. - * @param out Resulting brigade. - * @param in Brigade to append. - * @return APR_SUCCESS on success, error code otherwise. - */ -APREQ_DECLARE(apr_status_t) apreq_brigade_concat(apreq_env_handle_t *env, - apr_bucket_brigade *out, - apr_bucket_brigade *in); - - -/** - * Rfc822 Header parser. It will reject all data - * after the first CRLF CRLF sequence (an empty line). - * See #APREQ_RUN_PARSER for more info on rejected data. - */ -APREQ_DECLARE_PARSER(apreq_parse_headers); - -/** - * Rfc2396 application/x-www-form-urlencoded parser. - */ -APREQ_DECLARE_PARSER(apreq_parse_urlencoded); - -/** - * Rfc2388 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_RUN_PARSER 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 enctype Content-type that this parser can deal with. - * @param parser The parser function. - * @param hook Hooks to asssociate this parser with. - * @param ctx Parser's internal scratch pad. - * @return New parser. - */ -APREQ_DECLARE(apreq_parser_t *) - apreq_make_parser(apr_pool_t *pool, - const char *enctype, - apreq_parser_function_t parser, - 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_make_hook(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(void) apreq_add_hook(apreq_parser_t *p, - apreq_hook_t *h); - - -/** - * Create the default parser associated with the - * current request's Content-Type (if possible). - * @param env The current environment. - * @param hook Hook(s) to add to the parser. - * @return New parser, NULL if the Content-Type is - * unrecognized. - * - * @param env The current environment. - * @param hook Additional hooks to supply the parser with. - * @return The parser; NULL if the environment's - * Content-Type is unrecognized. - */ -APREQ_DECLARE(apreq_parser_t *)apreq_parser(apreq_env_handle_t *env, - apreq_hook_t *hook); - - -/** - * 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 parser The function to use during parsing. Setting - * parser == NULL will remove an existing parser. - * @remark This is not a thread-safe operation, so applications - * should only call this during process startup, - * or within a request-thread mutex. - */ - -APREQ_DECLARE(void) apreq_register_parser(const char *enctype, - apreq_parser_function_t parser); - - -/** - * Returns APR_EGENERAL. 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); #ifdef __cplusplus }
