apreq_module_cgi.c revision 6ac28b74a504006c016d4df3fb84d2cd2e373942
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** Licensed to the Apache Software Foundation (ASF) under one or more
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** contributor license agreements. See the NOTICE file distributed with
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** this work for additional information regarding copyright ownership.
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** The ASF licenses this file to You under the Apache License, Version 2.0
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** (the "License"); you may not use this file except in compliance with
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** the License. You may obtain a copy of the License at
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** Unless required by applicable law or agreed to in writing, software
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** distributed under the License is distributed on an "AS IS" BASIS,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** See the License for the specific language governing permissions and
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** limitations under the License.
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/* Parroting APLOG_* ... */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_EMERG 0 /* system is unusable */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_ALERT 1 /* action must be taken immediately */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_CRIT 2 /* critical conditions */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_WARNING 4 /* warning conditions */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_NOTICE 5 /* normal but significant condition */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_DEBUG 7 /* debug-level messages */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/** Interactive patch:
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * TODO Don't use 65K buffer
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * TODO Handle empty/non-existant parameters
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * TODO Allow body elements to be files
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * TODO When running body/get/cookies all at once, include previous cached
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * values (and don't start at 0 in count)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * TODO What happens if user does apreq_param, but needs POST value - we'll
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * never catch it now, as args param will match...
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic const char *nullstr = 0;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define DEFAULT_PROMPT "([$t] )$n(\\($l\\))([$d]): "
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersentypedef struct {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen while (--p >= 0) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen switch ((char)(str[p])) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen default:return str;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/** TODO: Support wide-characters */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/* prompt takes a apreq_handle and 2 strings - name and type - and prompts a
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen user for input via stdin/stdout. used in interactive mode.
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen name must be defined. type can be null.
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen we take the promptstring defined in the handle and interpolate variables as
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen $n - name of the variable we're asking for (param 2 to prompt())
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen $t - type of the variable we're asking for - like cookie, get, post, etc
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen (param 3 to prompt())
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen parentheses - if a variable is surrounded by parentheses, and interpolates
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen as null, then nothing else in the parentheses will be displayed
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen Useful if you want a string to only show up if a given variable
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen These are planned for forward-compatibility, but the underlying features
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen need some love... I left these in here just as feature reminders, rather
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen than completely removing them from the code - at least they provide sanity
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen testing of the default prompt & parentheses - issac
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen $l - label for the param - the end-user-developer can provide a textual
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen description of the param (name) being requested (currently unused in
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen $d - default value for the param (currently unused in lib)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic char *prompt(apreq_handle_t *handle, const char *name,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *type) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen struct cgi_handle *req = (struct cgi_handle *)handle;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char buf[MAX_PROMPT_NESTING_LEVELS][MAX_BUFFER_SIZE];
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Array of current arg for given p-level */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char *start, curarg[MAX_PROMPT_NESTING_LEVELS] = "";
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Parenthesis level (for argument/text grouping) */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen while (*(++cprompt) != 0) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case '$': /* interpolate argument; curarg[plevel] => 1 */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Name can't be null :-) [If it can, we should
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * immediately return NULL] */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* TODO: Once null defaults are available,
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog * remove if and use nullstr if defval == NULL */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Handle this? */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen *start = 0; /* Null terminate current string */
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen /* Move pointer to end of string */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* If old curarg was set, concat buffer with level down */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case '\\': /* Check next character for escape sequence
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * (just ignore it for now) */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Fallthrough */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_gets(buf[0], MAX_BUFFER_SIZE, req->sin);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/* if (strcmp(buf[0], nullstr)) */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/* return NULL; */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic const char *cgi_header_in(apreq_handle_t *handle,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char *key = apr_pstrcat(p, "HTTP_", name, NULL);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen for (k = key; *k; ++k) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (*k == '-')
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic void cgi_log_error(const char *file, int line, int level,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *fmt, ...)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (apr_env_get(&log_level_string, "LOG_LEVEL", p) == APR_SUCCESS)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (apr_env_get(&ra, "REMOTE_ADDR", p) == APR_SUCCESS)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_printf(err, "[%s] [%s] [%s] %s(%d): %s: %s\n",
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen date, priorities[level].t_name, remote_addr, file, line,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp));
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen fprintf(stderr, "[%s] [%s] [%s] %s(%d): %s: %s\n",
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen date, priorities[level].t_name, remote_addr, file, line,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_strerror(status,buf,255),apr_pvsprintf(p,fmt,vp));
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic const char *cgi_query_string(apreq_handle_t *handle)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen struct cgi_handle *req = (struct cgi_handle *)handle;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *cl_header = cgi_header_in(handle, "Content-Length");
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_bucket_alloc_t *ba = handle->bucket_alloc;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_int64_t content_length = apr_strtoi64(cl_header, &dummy, 0);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen "Invalid Content-Length header (%s)", cl_header);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen else if ((apr_uint64_t)content_length > req->read_limit) {
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma "Content-Length header (%s) exceeds configured "
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma const char *ct_header = cgi_header_in(handle, "Content-Type");
apr_bucket *e;
apr_status_t s;
case APR_SUCCESS:
case APR_INCOMPLETE:
if (s != APR_SUCCESS) {
const apr_table_t **t)
apreq_cookie_t *p;
const apr_table_t **t)
apreq_param_t *p;
apr_file_printf(req->sout, "[CGI] Please enter a name for parameter %d (or just hit ENTER to end): ",
const char *name)
const apr_table_t *t;
return NULL;
apreq_cookie_t *p;
return NULL;
const char *name)
const apr_table_t *t;
return NULL;
apreq_param_t *p;
return NULL;
const apr_table_t **t)
apreq_param_t *p;
apr_file_printf(req->sout, "[CGI] Please enter a name for parameter %d (or just hit ENTER to end): ",
case APR_EINIT:
case APR_INCOMPLETE:
== APR_INCOMPLETE)
const char *name)
apreq_hook_t *h;
return NULL;
apreq_param_t *p;
return NULL;
case APR_SUCCESS:
return NULL;
case APR_EINIT:
return NULL;
case APR_INCOMPLETE:
return NULL;
return NULL;
return NULL;
return NULL;
return APR_SUCCESS;
if (s != APR_SUCCESS)
return APR_SUCCESS;
return APREQ_ERROR_MISMATCH;
h = h->next;
return APR_SUCCESS;
return APR_SUCCESS;
return APREQ_ERROR_MISMATCH;
return APR_SUCCESS;
return APR_SUCCESS;
return APREQ_ERROR_MISMATCH;
return APR_SUCCESS;
const char *path)
return APR_SUCCESS;
return APREQ_ERROR_MISMATCH;
const char **path)
return APR_SUCCESS;
#ifdef APR_POOL_DEBUG
return APR_SUCCESS;
void *data;
return data;
#ifdef APR_POOL_DEBUG