mod_cgi.c revision 42d3dd0fe6973dc43e01f19f964c918e57309295
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering/* Copyright 1999-2004 The Apache Software Foundation
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * Licensed under the Apache License, Version 2.0 (the "License");
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * you may not use this file except in compliance with the License.
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * You may obtain a copy of the License at
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * http://www.apache.org/licenses/LICENSE-2.0
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * Unless required by applicable law or agreed to in writing, software
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * distributed under the License is distributed on an "AS IS" BASIS,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * See the License for the specific language governing permissions and
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * limitations under the License.
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * http_script: keeps all script-related ramblings together.
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * Compliant to CGI/1.1 spec
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * Adapted by rst from original NCSA code by Rob McCool
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * Apache adds some new env vars; REDIRECT_URL and REDIRECT_QUERY_STRING for
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * custom error responses, and DOCUMENT_ROOT because we found it useful.
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * It also adds SERVER_ADMIN - useful for scripts to know who to mail when
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering#include "apr_thread_proc.h" /* for RLIMIT stuff */
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgi_pfn_reg_with_ssi;
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgi_pfn_gtv;
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgi_pfn_ps;
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic APR_OPTIONAL_FN_TYPE(ap_cgi_build_command) *cgi_build_command;
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering/* Read and discard the data in the brigade produced by a CGI script */
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic void discard_script_output(apr_bucket_brigade *bb);
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering/* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * in ScriptAliased directories, which means we need to know if this
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * request came through ScriptAlias or not... so the Alias module
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering * leaves a note for us.
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic int is_scriptaliased(request_rec *r)
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering const char *t = apr_table_get(r->notes, "alias-forced-type");
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering return t && (!strcasecmp(t, "cgi-script"));
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering/* Configuration stuff */
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringtypedef struct {
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic void *create_cgi_config(apr_pool_t *p, server_rec *s)
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering (cgi_server_conf *) apr_pcalloc(p, sizeof(cgi_server_conf));
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic void *merge_cgi_config(apr_pool_t *p, void *basev, void *overridesv)
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering cgi_server_conf *base = (cgi_server_conf *) basev,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering *overrides = (cgi_server_conf *) overridesv;
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering return overrides->logname ? overrides : base;
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic const char *set_scriptlog(cmd_parms *cmd, void *dummy, const char *arg)
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering cgi_server_conf *conf = ap_get_module_config(s->module_config,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering conf->logname = ap_server_root_relative(cmd->pool, arg);
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering return apr_pstrcat(cmd->pool, "Invalid ScriptLog path ",
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmekstatic const char *set_scriptlog_length(cmd_parms *cmd, void *dummy,
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek cgi_server_conf *conf = ap_get_module_config(s->module_config,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic const char *set_scriptlog_buffer(cmd_parms *cmd, void *dummy,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering cgi_server_conf *conf = ap_get_module_config(s->module_config,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart PoetteringAP_INIT_TAKE1("ScriptLog", set_scriptlog, NULL, RSRC_CONF,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering "the name of a log for script debugging info"),
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart PoetteringAP_INIT_TAKE1("ScriptLogLength", set_scriptlog_length, NULL, RSRC_CONF,
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek "the maximum length (in bytes) of the script debug log"),
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart PoetteringAP_INIT_TAKE1("ScriptLogBuffer", set_scriptlog_buffer, NULL, RSRC_CONF,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering "the maximum size (in bytes) to record of a POST request"),
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmekstatic int log_scripterror(request_rec *r, cgi_server_conf * conf, int ret,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering int log_flags = rv ? APLOG_ERR : APLOG_ERR;
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering ap_log_rerror(APLOG_MARK, log_flags, rv, r,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering /* XXX Very expensive mainline case! Open, then getfileinfo! */
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering APR_FINFO_SIZE, r->pool) == APR_SUCCESS) &&
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering APR_APPEND|APR_WRITE|APR_CREATE, APR_OS_DEFAULT,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering /* "%% [Wed Jun 19 10:53:21 1996] GET /cgi-bin/printenv HTTP/1.0" */
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering apr_file_printf(f, "%%%% [%s] %s %s%s%s %s\n", time_str, r->method, r->uri,
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering r->args ? "?" : "", r->args ? r->args : "", r->protocol);
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering apr_file_printf(f, "%%%% %d %s\n", ret, r->filename);
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering apr_file_printf(f, "%%error\n%s\n", error);
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering/* Soak up stderr from a script and redirect it to the error log.
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poetteringstatic apr_status_t log_script_err(request_rec *r, apr_file_t *script_err)
9a00f57a5ba7ed431e6bac8d8b36518708503b4eLennart Poettering while ((rv = apr_file_gets(argsbuffer, HUGE_STRING_LEN,
if (newline) {
return rv;
apr_bucket *e;
const char *buf;
int first;
return ret;
*dbuf) {
e = APR_BUCKET_NEXT(e))
if (APR_BUCKET_IS_EOS(e)) {
if (first) {
first = 0;
apr_file_close(f);
return ret;
r->path_info));
r, NULL);
if (r->args) {
const char *description)
err,
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
#ifndef AP_UNSAFE_ERROR_LOG_UNESCAPED
const char *command,
const char * const argv[],
request_rec *r,
apr_pool_t *p,
const char * const *env;
&core_module);
#ifdef DEBUG_CGI
#ifdef OS2
#ifdef DEBUG_CGI
#ifdef DEBUG_CGI
for (i = 0; env[i]; ++i)
#ifdef RLIMIT_CPU
#ifdef RLIMIT_NPROC
procattr, p);
if (!*script_in)
return APR_EBADF;
if (!*script_out)
return APR_EBADF;
if (!*script_err)
return APR_EBADF;
#ifdef DEBUG_CGI
return (rc);
if (!args) {
++numwords;
ap_unescape_url(w);
return APR_SUCCESS;
apr_bucket *e;
const char *buf;
e = APR_BUCKET_NEXT(e))
if (APR_BUCKET_IS_EOS(e)) {
struct cgi_bucket_data {
request_rec *r;
APR_BUCKET_INIT(b);
data->r = r;
APR_BUCKET_INIT(b);
char *buf;
return rv;
if (*len > 0) {
apr_bucket_heap *h;
h = a->data;
return rv;
int gotdata = 0;
return rv;
} while (!gotdata);
return rv;
int nph;
const char *argv0;
const char *command;
const char **argv;
apr_bucket *b;
int is_included;
apr_pool_t *p;
return DECLINED;
return DECLINED;
ap_add_cgi_vars(r);
r->filename);
return HTTP_INTERNAL_SERVER_ERROR;
return HTTP_INTERNAL_SERVER_ERROR;
seen_eos = 0;
dbpos = 0;
return rv;
const char *data;
if (child_stopped_reading) {
int cursize;
while (!seen_eos);
if (!nph) {
const char *location;
int ret;
return OK;
return HTTP_MOVED_TEMPORARILY;
request_rec *r = f->r;
int rr_status;
return APR_EGENERAL;
return APR_EGENERAL;
return APR_EGENERAL;
if (location) {
char *buffer;
f->c->bucket_alloc));
return APR_SUCCESS;
const char **argv;
request_rec *r = f->r;
add_ssi_vars(r);
r->filename);
return rv;
return rv;
f->c->bucket_alloc));
return APR_SUCCESS;
request_rec *r = f->r;
r->filename);
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
return APR_SUCCESS;
if (!cgi_build_command) {
return OK;