apreq_module_cgi.c revision 6ac28b74a504006c016d4df3fb84d2cd2e373942
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/*
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**
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen** http://www.apache.org/licenses/LICENSE-2.0
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen**
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*/
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include <assert.h>
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define APR_WANT_STRFUNC
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include "apr_want.h"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include "apreq_module.h"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include "apreq_error.h"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include "apr_strings.h"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include "apr_lib.h"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include "apr_env.h"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#include "apreq_util.h"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define USER_DATA_KEY "apreq"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/* Parroting APLOG_* ... */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
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_ERR 3 /* error conditions */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_WARNING 4 /* warning conditions */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_NOTICE 5 /* normal but significant condition */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_INFO 6 /* informational */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_DEBUG 7 /* debug-level messages */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_LEVELMASK 7
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CGILOG_MARK __FILE__, __LINE__
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
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 Gundersen */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstruct cgi_handle {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen struct apreq_handle_t handle;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_table_t *jar, *args, *body;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_status_t jar_status,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen args_status,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen body_status;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apreq_parser_t *parser;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apreq_hook_t *hook_queue;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apreq_hook_t *find_param;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *temp_dir;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_size_t brigade_limit;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_uint64_t read_limit;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_uint64_t bytes_read;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_bucket_brigade *in;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_bucket_brigade *tmpbb;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen int interactive_mode;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *promptstr;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_t *sout, *sin;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen};
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define CRLF "\015\012"
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic const char *nullstr = 0;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define DEFAULT_PROMPT "([$t] )$n(\\($l\\))([$d]): "
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define MAX_PROMPT_NESTING_LEVELS 8
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#define MAX_BUFFER_SIZE 65536
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersentypedef struct {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *t_name;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen int t_val;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen} TRANS;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic const TRANS priorities[] = {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"emerg", CGILOG_EMERG},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"alert", CGILOG_ALERT},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"crit", CGILOG_CRIT},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"error", CGILOG_ERR},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"warn", CGILOG_WARNING},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"notice", CGILOG_NOTICE},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"info", CGILOG_INFO},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {"debug", CGILOG_DEBUG},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {NULL, -1},
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen};
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic char* chomp(char* str) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_size_t p = strlen(str);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen while (--p >= 0) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen switch ((char)(str[p])) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case '\015':
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case '\012':str[p]='\000';
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen default:return str;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen return str;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen}
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
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
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen name must be defined. type can be null.
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen we take the promptstring defined in the handle and interpolate variables as
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen follows:
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
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 is available
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
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
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 lib)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen $d - default value for the param (currently unused in lib)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen*/
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 const char *defval = nullstr;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *label = NULL;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *cprompt;
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 int plevel;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen cprompt = req->promptstr - 1;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen *buf[0] = plevel = 0;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen start = buf[0];
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen while (*(++cprompt) != 0) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen switch (*cprompt) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case '$': /* interpolate argument; curarg[plevel] => 1 */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen cprompt++;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen switch (*cprompt) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case 't':
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (type != NULL) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen strcpy(start, type);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen start += strlen(type);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen curarg[plevel] = 1;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen } else {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen curarg[plevel] = curarg[plevel] | 0;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case 'n':
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Name can't be null :-) [If it can, we should
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * immediately return NULL] */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen strcpy(start, name);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen start += strlen(name);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen curarg[plevel] = 1;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case 'l':
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (label != NULL) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen strcpy(start, label);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen start += strlen(label);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen curarg[plevel] = 1;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen } else {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen curarg[plevel] = curarg[plevel] | 0;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case 'd':
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* TODO: Once null defaults are available,
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog * remove if and use nullstr if defval == NULL */
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog if (defval != NULL) {
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog strcpy(start, defval);
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog start += strlen(defval);
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog curarg[plevel] = 1;
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog } else {
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog curarg[plevel] = curarg[plevel] | 0;
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog }
848e3e24b00a61130f20226ef5f051433d478c69Umut Tezduyar Lindskog break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen default:
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Handle this? */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case '(':
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen if (plevel <= MAX_PROMPT_NESTING_LEVELS) {
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen plevel++;
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen curarg[plevel] = *buf[plevel] = 0;
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen start = buf[plevel];
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* else? */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case ')':
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (plevel > 0) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen *start = 0; /* Null terminate current string */
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen /* Move pointer to end of string */
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen plevel--;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen start = buf[plevel] + strlen(buf[plevel]);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* If old curarg was set, concat buffer with level down */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (curarg[plevel + 1]) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen strcpy(start, buf[plevel + 1]);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen start += strlen(buf[plevel + 1]);
06f021a8048583d66202e3ac5cd0a12386d33ac2Tom Gundersen }
cb44f25c12f6203ad1f173d5b32d4059f446508eTom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen break;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen case '\\': /* Check next character for escape sequence
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen * (just ignore it for now) */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen (void)*cprompt++;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen /* Fallthrough */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen default:
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen *start++ = *cprompt;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen *start = 0; /* Null terminate the string */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_printf(req->sout, "%s", buf[0]);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_gets(buf[0], MAX_BUFFER_SIZE, req->sin);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen chomp(buf[0]);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (strcmp(buf[0], "")) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/* if (strcmp(buf[0], nullstr)) */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen return apr_pstrdup(handle->pool, buf[0]);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen/* return NULL; */
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen }
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen if (defval != nullstr)
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen return apr_pstrdup(handle->pool, defval);
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen return NULL;
fe6b2d55bcb379d01664ed28cea40634cb6b52e3Tom Gundersen}
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic const char *cgi_header_in(apreq_handle_t *handle,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *name)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen{
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_pool_t *p = handle->pool;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char *key = apr_pstrcat(p, "HTTP_", name, NULL);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char *k, *value = NULL;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen for (k = key; *k; ++k) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (*k == '-')
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen *k = '_';
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen else
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen *k = apr_toupper(*k);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (!strcmp(key, "HTTP_CONTENT_TYPE")
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen || !strcmp(key, "HTTP_CONTENT_LENGTH"))
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen key += 5; /* strlen("HTTP_") */
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_env_get(&value, key, p);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen return value;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen}
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic void cgi_log_error(const char *file, int line, int level,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_status_t status, apreq_handle_t *handle,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *fmt, ...)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen{
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_pool_t *p = handle->pool;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char buf[256];
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char *log_level_string, *ra;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen const char *remote_addr;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen unsigned log_level = CGILOG_WARNING;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char date[APR_CTIME_LEN];
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen va_list vp;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#ifndef WIN32
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_t *err;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#endif
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen va_start(vp, fmt);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (apr_env_get(&log_level_string, "LOG_LEVEL", p) == APR_SUCCESS)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen log_level = (log_level_string[0] - '0');
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen level &= CGILOG_LEVELMASK;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (level < (int)log_level) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (apr_env_get(&ra, "REMOTE_ADDR", p) == APR_SUCCESS)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen remote_addr = ra;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen else
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen remote_addr = "address unavailable";
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_ctime(date, apr_time_now());
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#ifndef WIN32
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_open_stderr(&err, p);
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 apr_file_flush(err);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen#else
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 Gundersen#endif
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen va_end(vp);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen}
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom GundersenAPR_INLINE
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic const char *cgi_query_string(apreq_handle_t *handle)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen{
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char *value = NULL, qs[] = "QUERY_STRING";
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_env_get(&value, qs, handle->pool);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen return value;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen}
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersenstatic void init_body(apreq_handle_t *handle)
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen{
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_pool_t *pool = handle->pool;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_file_t *file;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_bucket *eos, *pipe;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (cl_header != NULL) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen char *dummy;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen apr_int64_t content_length = apr_strtoi64(cl_header, &dummy, 0);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen if (dummy == NULL || *dummy != 0) {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen req->body_status = APREQ_ERROR_BADHEADER;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen "Invalid Content-Length header (%s)", cl_header);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen return;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen else if ((apr_uint64_t)content_length > req->read_limit) {
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma req->body_status = APREQ_ERROR_OVERLIMIT;
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma "Content-Length header (%s) exceeds configured "
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma "max_body limit (%" APR_UINT64_T_FMT ")",
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma cl_header, req->read_limit);
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma return;
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma }
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma }
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma if (req->parser == NULL) {
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma const char *ct_header = cgi_header_in(handle, "Content-Type");
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma if (ct_header != NULL) {
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma apreq_parser_function_t pf = apreq_parser(ct_header);
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma if (pf != NULL) {
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma req->parser = apreq_parser_make(pool,
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma ba,
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma ct_header,
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma pf,
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma req->brigade_limit,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen req->temp_dir,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen req->hook_queue,
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen NULL);
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen else {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen req->body_status = APREQ_ERROR_NOPARSER;
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma return;
f47c5c47d1a7bcfa1842ff7cc52b1f7fc1d86bcfpoma }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen }
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen else {
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen req->body_status = APREQ_ERROR_NOHEADER;
eac684ef1c29684b1bcd27a89c38c202e568e469Tom Gundersen return;
}
}
else {
if (req->parser->brigade_limit > req->brigade_limit)
req->parser->brigade_limit = req->brigade_limit;
if (req->temp_dir != NULL)
req->parser->temp_dir = req->temp_dir;
if (req->hook_queue != NULL)
apreq_parser_add_hook(req->parser, req->hook_queue);
}
req->hook_queue = NULL;
req->in = apr_brigade_create(pool, ba);
req->tmpbb = apr_brigade_create(pool, ba);
apr_file_open_stdin(&file, pool); // error status?
pipe = apr_bucket_pipe_create(file, ba);
eos = apr_bucket_eos_create(ba);
APR_BRIGADE_INSERT_HEAD(req->in, pipe);
APR_BRIGADE_INSERT_TAIL(req->in, eos);
req->body_status = APR_INCOMPLETE;
}
static apr_status_t cgi_read(apreq_handle_t *handle,
apr_off_t bytes)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
apr_bucket *e;
apr_status_t s;
if (req->body_status == APR_EINIT)
init_body(handle);
if (req->body_status != APR_INCOMPLETE)
return req->body_status;
switch (s = apr_brigade_partition(req->in, bytes, &e)) {
apr_off_t len;
case APR_SUCCESS:
apreq_brigade_move(req->tmpbb, req->in, e);
req->bytes_read += bytes;
if (req->bytes_read > req->read_limit) {
req->body_status = APREQ_ERROR_OVERLIMIT;
cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status,
handle, "Bytes read (%" APR_UINT64_T_FMT
") exceeds configured limit (%" APR_UINT64_T_FMT ")",
req->bytes_read, req->read_limit);
break;
}
req->body_status =
apreq_parser_run(req->parser, req->body, req->tmpbb);
apr_brigade_cleanup(req->tmpbb);
break;
case APR_INCOMPLETE:
apreq_brigade_move(req->tmpbb, req->in, e);
s = apr_brigade_length(req->tmpbb, 1, &len);
if (s != APR_SUCCESS) {
req->body_status = s;
break;
}
req->bytes_read += len;
if (req->bytes_read > req->read_limit) {
req->body_status = APREQ_ERROR_OVERLIMIT;
cgi_log_error(CGILOG_MARK, CGILOG_ERR, req->body_status, handle,
"Bytes read (%" APR_UINT64_T_FMT
") exceeds configured limit (%" APR_UINT64_T_FMT ")",
req->bytes_read, req->read_limit);
break;
}
req->body_status =
apreq_parser_run(req->parser, req->body, req->tmpbb);
apr_brigade_cleanup(req->tmpbb);
break;
default:
req->body_status = s;
}
return req->body_status;
}
static apr_status_t cgi_jar(apreq_handle_t *handle,
const apr_table_t **t)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
if (req->interactive_mode && req->jar_status != APR_SUCCESS) {
char buf[65536];
const char *name, *val;
apreq_cookie_t *p;
int i = 1;
apr_file_printf(req->sout, "[CGI] Requested all cookies\n");
while (1) {
apr_file_printf(req->sout, "[CGI] Please enter a name for cookie %d (or just hit ENTER to end): ",
i++);
apr_file_gets(buf, 65536, req->sin);
chomp(buf);
if (!strcmp(buf, "")) {
break;
}
name = apr_pstrdup(handle->pool, buf);
val = prompt(handle, name, "cookie");
if (val == NULL)
val = "";
p = apreq_cookie_make(handle->pool, name, strlen(name), val, strlen(val));
apreq_cookie_tainted_on(p);
apreq_value_table_add(&p->v, req->jar);
val = p->v.data;
}
req->jar_status = APR_SUCCESS;
} /** Fallthrough */
if (req->jar_status == APR_EINIT) {
const char *cookies = cgi_header_in(handle, "Cookie");
if (cookies != NULL) {
req->jar_status =
apreq_parse_cookie_header(handle->pool, req->jar, cookies);
}
else
req->jar_status = APREQ_ERROR_NODATA;
}
*t = req->jar;
return req->jar_status;
}
static apr_status_t cgi_args(apreq_handle_t *handle,
const apr_table_t **t)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
if (req->interactive_mode && req->args_status != APR_SUCCESS) {
char buf[65536];
const char *name, *val;
apreq_param_t *p;
int i = 1;
apr_file_printf(req->sout, "[CGI] Requested all argument parameters\n");
while (1) {
apr_file_printf(req->sout, "[CGI] Please enter a name for parameter %d (or just hit ENTER to end): ",
i++);
apr_file_gets(buf, 65536, req->sin);
chomp(buf);
if (!strcmp(buf, "")) {
break;
}
name = apr_pstrdup(handle->pool, buf);
val = prompt(handle, name, "parameter");
if (val == NULL)
val = "";
p = apreq_param_make(handle->pool, name, strlen(name), val, strlen(val));
apreq_param_tainted_on(p);
apreq_value_table_add(&p->v, req->args);
val = p->v.data;
}
req->args_status = APR_SUCCESS;
} /** Fallthrough */
if (req->args_status == APR_EINIT) {
const char *qs = cgi_query_string(handle);
if (qs != NULL) {
req->args_status =
apreq_parse_query_string(handle->pool, req->args, qs);
}
else
req->args_status = APREQ_ERROR_NODATA;
}
*t = req->args;
return req->args_status;
}
static apreq_cookie_t *cgi_jar_get(apreq_handle_t *handle,
const char *name)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
const apr_table_t *t;
const char *val = NULL;
if (req->jar_status == APR_EINIT && !req->interactive_mode)
cgi_jar(handle, &t);
else
t = req->jar;
val = apr_table_get(t, name);
if (val == NULL) {
if (!req->interactive_mode) {
return NULL;
} else {
apreq_cookie_t *p;
val = prompt(handle, name, "cookie");
if (val == NULL)
return NULL;
p = apreq_cookie_make(handle->pool, name, strlen(name), val, strlen(val));
apreq_cookie_tainted_on(p);
apreq_value_table_add(&p->v, req->jar);
val = p->v.data;
}
}
return apreq_value_to_cookie(val);
}
static apreq_param_t *cgi_args_get(apreq_handle_t *handle,
const char *name)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
const apr_table_t *t;
const char *val = NULL;
if (req->args_status == APR_EINIT && !req->interactive_mode)
cgi_args(handle, &t);
else
t = req->args;
val = apr_table_get(t, name);
if (val == NULL) {
if (!req->interactive_mode) {
return NULL;
} else {
apreq_param_t *p;
val = prompt(handle, name, "parameter");
if (val == NULL)
return NULL;
p = apreq_param_make(handle->pool, name, strlen(name), val, strlen(val));
apreq_param_tainted_on(p);
apreq_value_table_add(&p->v, req->args);
val = p->v.data;
}
}
return apreq_value_to_param(val);
}
static apr_status_t cgi_body(apreq_handle_t *handle,
const apr_table_t **t)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
if (req->interactive_mode && req->body_status != APR_SUCCESS) {
const char *name, *val;
apreq_param_t *p;
int i = 1;
apr_file_printf(req->sout, "[CGI] Requested all body parameters\n");
while (1) {
char buf[65536];
apr_file_printf(req->sout, "[CGI] Please enter a name for parameter %d (or just hit ENTER to end): ",
i++);
apr_file_gets(buf, 65536, req->sin);
chomp(buf);
if (!strcmp(buf, "")) {
break;
}
name = apr_pstrdup(handle->pool, buf);
val = prompt(handle, name, "parameter");
if (val == NULL)
val = "";
p = apreq_param_make(handle->pool, name, strlen(name), val, strlen(val));
apreq_param_tainted_on(p);
apreq_value_table_add(&p->v, req->body);
val = p->v.data;
}
req->body_status = APR_SUCCESS;
} /** Fallthrough */
switch (req->body_status) {
case APR_EINIT:
init_body(handle);
if (req->body_status != APR_INCOMPLETE)
break;
case APR_INCOMPLETE:
while (cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE)
== APR_INCOMPLETE)
; /*loop*/
}
*t = req->body;
return req->body_status;
}
static apreq_param_t *cgi_body_get(apreq_handle_t *handle,
const char *name)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
const char *val = NULL;
apreq_hook_t *h;
apreq_hook_find_param_ctx_t *hook_ctx;
if (req->interactive_mode) {
val = apr_table_get(req->body, name);
if (val == NULL) {
return NULL;
} else {
apreq_param_t *p;
val = prompt(handle, name, "parameter");
if (val == NULL)
return NULL;
p = apreq_param_make(handle->pool, name, strlen(name), val, strlen(val));
apreq_param_tainted_on(p);
apreq_value_table_add(&p->v, req->body);
val = p->v.data;
return apreq_value_to_param(val);
}
}
switch (req->body_status) {
case APR_SUCCESS:
val = apr_table_get(req->body, name);
if (val != NULL)
return apreq_value_to_param(val);
return NULL;
case APR_EINIT:
init_body(handle);
if (req->body_status != APR_INCOMPLETE)
return NULL;
cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE);
case APR_INCOMPLETE:
val = apr_table_get(req->body, name);
if (val != NULL)
return apreq_value_to_param(val);
/* Not seen yet, so we need to scan for
param while prefetching the body */
hook_ctx = apr_palloc(handle->pool, sizeof *hook_ctx);
if (req->find_param == NULL)
req->find_param = apreq_hook_make(handle->pool,
apreq_hook_find_param,
NULL, NULL);
h = req->find_param;
h->next = req->parser->hook;
req->parser->hook = h;
h->ctx = hook_ctx;
hook_ctx->name = name;
hook_ctx->param = NULL;
hook_ctx->prev = req->parser->hook;
do {
cgi_read(handle, APREQ_DEFAULT_READ_BLOCK_SIZE);
if (hook_ctx->param != NULL)
return hook_ctx->param;
} while (req->body_status == APR_INCOMPLETE);
req->parser->hook = h->next;
return NULL;
default:
if (req->body == NULL)
return NULL;
val = apr_table_get(req->body, name);
if (val != NULL)
return apreq_value_to_param(val);
return NULL;
}
/* not reached */
return NULL;
}
static apr_status_t cgi_parser_get(apreq_handle_t *handle,
const apreq_parser_t **parser)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
*parser = req->parser;
return APR_SUCCESS;
}
static apr_status_t cgi_parser_set(apreq_handle_t *handle,
apreq_parser_t *parser)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
if (req->parser == NULL) {
if (req->hook_queue != NULL) {
apr_status_t s = apreq_parser_add_hook(parser, req->hook_queue);
if (s != APR_SUCCESS)
return s;
}
if (req->temp_dir != NULL) {
parser->temp_dir = req->temp_dir;
}
if (req->brigade_limit < parser->brigade_limit) {
parser->brigade_limit = req->brigade_limit;
}
req->hook_queue = NULL;
req->parser = parser;
return APR_SUCCESS;
}
else
return APREQ_ERROR_MISMATCH;
}
static apr_status_t cgi_hook_add(apreq_handle_t *handle,
apreq_hook_t *hook)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
if (req->parser != NULL) {
return apreq_parser_add_hook(req->parser, hook);
}
else if (req->hook_queue != NULL) {
apreq_hook_t *h = req->hook_queue;
while (h->next != NULL)
h = h->next;
h->next = hook;
}
else {
req->hook_queue = hook;
}
return APR_SUCCESS;
}
static apr_status_t cgi_brigade_limit_set(apreq_handle_t *handle,
apr_size_t bytes)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
apr_size_t *limit = (req->parser == NULL)
? &req->brigade_limit
: &req->parser->brigade_limit;
if (*limit > bytes) {
*limit = bytes;
return APR_SUCCESS;
}
return APREQ_ERROR_MISMATCH;
}
static apr_status_t cgi_brigade_limit_get(apreq_handle_t *handle,
apr_size_t *bytes)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
*bytes = (req->parser == NULL)
? req->brigade_limit
: req->parser->brigade_limit;
return APR_SUCCESS;
}
static apr_status_t cgi_read_limit_set(apreq_handle_t *handle,
apr_uint64_t bytes)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
if (req->read_limit > bytes && req->bytes_read < bytes) {
req->read_limit = bytes;
return APR_SUCCESS;
}
return APREQ_ERROR_MISMATCH;
}
static apr_status_t cgi_read_limit_get(apreq_handle_t *handle,
apr_uint64_t *bytes)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
*bytes = req->read_limit;
return APR_SUCCESS;
}
static apr_status_t cgi_temp_dir_set(apreq_handle_t *handle,
const char *path)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
const char **temp_dir = (req->parser == NULL)
? &req->temp_dir
: &req->parser->temp_dir;
if (*temp_dir == NULL && req->bytes_read == 0) {
if (path != NULL)
*temp_dir = apr_pstrdup(handle->pool, path);
return APR_SUCCESS;
}
return APREQ_ERROR_MISMATCH;
}
static apr_status_t cgi_temp_dir_get(apreq_handle_t *handle,
const char **path)
{
struct cgi_handle *req = (struct cgi_handle *)handle;
*path = (req->parser == NULL)
? req->temp_dir
: req->parser->temp_dir;
return APR_SUCCESS;
}
#ifdef APR_POOL_DEBUG
static apr_status_t ba_cleanup(void *data)
{
apr_bucket_alloc_t *ba = data;
apr_bucket_alloc_destroy(ba);
return APR_SUCCESS;
}
#endif
/** Determine if we're interactive mode or not. Order is
QUERY_STRING ? NO : Interactive
I think we should just rely on GATEWAY_INTERFACE to set
non-interactive mode, and be interactive if it's not there
Behaviour change should really be:
Always check query_string before prompting user,
but rewrite body/cookies to get if interactive
Definately more work needed here...
*/
static int is_interactive_mode(apr_pool_t *pool) {
char *value = NULL, qs[] = "GATEWAY_INTERFACE";
apr_status_t rv;
rv = apr_env_get(&value, qs, pool);
if (rv != APR_SUCCESS)
if (rv == APR_ENOENT)
return 1;
/** handle else? (!SUCCESS && !ENOENT) */
return 0;
}
static APREQ_MODULE(cgi, 20090110);
APREQ_DECLARE(apreq_handle_t *)apreq_handle_cgi(apr_pool_t *pool)
{
apr_bucket_alloc_t *ba;
struct cgi_handle *req;
void *data;
apr_pool_userdata_get(&data, USER_DATA_KEY, pool);
if (data != NULL)
return data;
req = apr_pcalloc(pool, sizeof *req);
ba = apr_bucket_alloc_create(pool);
/* check pool's userdata first. */
req->handle.module = &cgi_module;
req->handle.pool = pool;
req->handle.bucket_alloc = ba;
req->read_limit = (apr_uint64_t) -1;
req->brigade_limit = APREQ_DEFAULT_BRIGADE_LIMIT;
req->args = apr_table_make(pool, APREQ_DEFAULT_NELTS);
req->body = apr_table_make(pool, APREQ_DEFAULT_NELTS);
req->jar = apr_table_make(pool, APREQ_DEFAULT_NELTS);
req->args_status =
req->jar_status =
req->body_status = APR_EINIT;
if (is_interactive_mode(pool)) {
req->interactive_mode = 1;
apr_file_open_stdout(&(req->sout), pool);
apr_file_open_stdin(&(req->sin), pool);
req->promptstr=apr_pstrdup(pool, DEFAULT_PROMPT);
}
apr_pool_userdata_setn(&req->handle, USER_DATA_KEY, NULL, pool);
#ifdef APR_POOL_DEBUG
apr_pool_cleanup_register(pool, ba, ba_cleanup, ba_cleanup);
#endif
return &req->handle;
}