httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Paul J. Reder" <rede...@raleigh.ibm.com>
Subject [Patch]: Update of the code to move cgi stuff from mod_include to mod_cgi(d)
Date Thu, 01 Feb 2001 19:53:10 GMT
Yes I realize that this is not vital to the beta. It doesn't fix any bugs.
It just makes maintenance a bit easier.

Besides I needed to update my last patch to use Ben's optional hook code.

This code works in all permutations with and without mod_include, mod_cgi,
and mod_cgid.

The only compelling reason I can give for committing this before the beta
is that I am tired of re-porting this every time someone makes more changes
to mod_include or mod_cgi(d) (third shot now).
-- 
Paul J. Reder
-----------------------------------------------------------
"The strength of the Constitution lies entirely in the determination of each
citizen to defend it.  Only if every single citizen feels duty bound to do
his share in this defense are the constitutional rights secure."
-- Albert Einstein


Index: modules/filters/mod_include.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/filters/mod_include.c,v
retrieving revision 1.91
diff -u -r1.91 mod_include.c
--- modules/filters/mod_include.c	2001/01/29 17:58:01	1.91
+++ modules/filters/mod_include.c	2001/02/01 19:24:51
@@ -83,6 +83,7 @@
 #include "http_main.h"
 #include "util_script.h"
 #include "http_core.h"
+#include "apr_optional.h"
 #include "mod_include.h"
 #ifdef HAVE_STRING_H
 #include <string.h>
@@ -94,7 +95,9 @@
 
 
 static apr_hash_t *include_hash;
+static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *ssi_pfn_register;
 
+
 /* ------------------------ Environment function -------------------------- */
 
 /* XXX: could use ap_table_overlap here */
@@ -496,7 +499,7 @@
 
 #define SKIP_TAG_WHITESPACE(ptr) while ((*ptr != '\0') && (apr_isspace (*ptr))) ptr++
 
-static void get_tag_and_value(include_ctx_t *ctx, char **tag,
+static void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag,
                               char **tag_val, int dodecode)
 {
     char *c = ctx->curr_tag_pos;
@@ -574,8 +577,8 @@
 /*
  * Do variable substitution on strings
  */
-static void parse_string(request_rec *r, const char *in, char *out,
-			size_t length, int leave_name)
+static void ap_ssi_parse_string(request_rec *r, const char *in, char *out,
+                         size_t length, int leave_name)
 {
     char ch;
     char *next = out;
@@ -601,7 +604,6 @@
             break;
         case '$':
             {
-/* pjr hack     char var[MAX_STRING_LEN]; */
 		const char *start_of_var_name;
 		char *end_of_var_name;	/* end of var name + 1 */
 		const char *expansion, *temp_end, *val;
@@ -637,17 +639,10 @@
 		 * pass a non-nul terminated string */
 		l = end_of_var_name - start_of_var_name;
 		if (l != 0) {
-/* pjr - this is a test hack to avoid a memcpy. Make sure that this works...
-*		    l = (l > sizeof(var) - 1) ? (sizeof(var) - 1) : l;
-*		    memcpy(var, start_of_var_name, l);
-*		    var[l] = '\0';
-*
-*		    val = apr_table_get(r->subprocess_env, var);
-*/
-/* pjr hack */      tmp_store        = *end_of_var_name;
-/* pjr hack */      *end_of_var_name = '\0';
-/* pjr hack */      val = apr_table_get(r->subprocess_env, start_of_var_name);
-/* pjr hack */      *end_of_var_name = tmp_store;
+                    tmp_store        = *end_of_var_name;
+                    *end_of_var_name = '\0';
+                    val = apr_table_get(r->subprocess_env, start_of_var_name);
+                    *end_of_var_name = tmp_store;
 
 		    if (val) {
 			expansion = val;
@@ -685,68 +680,6 @@
 
 /* --------------------------- Action handlers ---------------------------- */
 
-static int include_cgi(char *s, request_rec *r, ap_filter_t *next,
-                       apr_bucket *head_ptr, apr_bucket **inserted_head)
-{
-    request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
-    int rr_status;
-    apr_bucket  *tmp_buck, *tmp2_buck;
-
-    if (rr->status != HTTP_OK) {
-        return -1;
-    }
-
-    /* No hardwired path info or query allowed */
-
-    if ((rr->path_info && rr->path_info[0]) || rr->args) {
-        return -1;
-    }
-    if (rr->finfo.protection == 0) {
-        return -1;
-    }
-
-    /* Script gets parameters of the *document*, for back compatibility */
-
-    rr->path_info = r->path_info;       /* hard to get right; see mod_cgi.c */
-    rr->args = r->args;
-
-    /* Force sub_req to be treated as a CGI request, even if ordinary
-     * typing rules would have called it something else.
-     */
-
-    rr->content_type = CGI_MAGIC_TYPE;
-
-    /* Run it. */
-
-    rr_status = ap_run_sub_req(rr);
-    if (ap_is_HTTP_REDIRECT(rr_status)) {
-        apr_size_t len_loc, h_wrt;
-        const char *location = apr_table_get(rr->headers_out, "Location");
-
-        location = ap_escape_html(rr->pool, location);
-        len_loc = strlen(location);
-
-        tmp_buck = apr_bucket_create_immortal("<A HREF=\"", sizeof("<A HREF=\""));
-        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
-        tmp2_buck = apr_bucket_create_heap(location, len_loc, 1, &h_wrt);
-        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-        tmp2_buck = apr_bucket_create_immortal("\">", sizeof("\">"));
-        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-        tmp2_buck = apr_bucket_create_heap(location, len_loc, 1, &h_wrt);
-        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-        tmp2_buck = apr_bucket_create_immortal("</A>", sizeof("</A>"));
-        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-
-        if (*inserted_head == NULL) {
-            *inserted_head = tmp_buck;
-        }
-    }
-
-    ap_destroy_sub_req(rr);
-
-    return 0;
-}
-
 /* ensure that path is relative, and does not contain ".." elements
  * ensentially ensure that it does not match the regex:
  * (^/|(^|/)\.\.(/|$))
@@ -798,7 +731,7 @@
     *inserted_head = NULL;
     if (ctx->flags & FLAG_PRINTING) {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 1);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
             if (tag_val == NULL) {
                 if (tag == NULL) {
                     return (0);
@@ -811,7 +744,7 @@
                 request_rec *rr = NULL;
                 char *error_fmt = NULL;
 
-                parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+                ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
                 if (tag[0] == 'f') {
                     /* be safe; only files in this directory or below allowed */
     		if (!is_only_below(parsed_string)) {
@@ -884,10 +817,9 @@
     		ap_set_module_config(rr->request_config, &includes_module, r);
 
                 if (!error_fmt) {
-                    SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx);
-/*
-                    rr->output_filters = f->next;
-*/                    if (ap_run_sub_req(rr)) {
+                    SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next);
+                    
+                    if (ap_run_sub_req(rr)) {
                         error_fmt = "unable to include \"%s\" in parsed file %s";
                     }
                 }
@@ -915,214 +847,7 @@
     return 0;
 }
 
-typedef struct {
-#ifdef TPF
-    TPF_FORK_CHILD t;
-#endif
-    request_rec *r;
-    char *s;
-} include_cmd_arg;
-
-
-
-static apr_status_t build_argv_list(char ***argv, request_rec *r, apr_pool_t *p)
-{
-    int numwords, x, idx;
-    char *w;
-    const char *args = r->args;
-
-    if (!args || !args[0] || ap_strchr_c(args, '=')) {
-       numwords = 1;
-    }
-    else {
-        /* count the number of keywords */
-        for (x = 0, numwords = 1; args[x]; x++) {
-            if (args[x] == '+') {
-                ++numwords;
-            }
-        }
-    }
-    /* Everything is - 1 to account for the first parameter which is the
-     * program name.  We didn't used to have to do this, but APR wants it.
-     */
-    if (numwords > APACHE_ARG_MAX - 1) {
-        numwords = APACHE_ARG_MAX - 1;	/* Truncate args to prevent overrun */
-    }
-    *argv = (char **) apr_palloc(p, (numwords + 2) * sizeof(char *));
- 
-    for (x = 1, idx = 1; x < numwords; x++) {
-        w = ap_getword_nulls(p, &args, '+');
-        ap_unescape_url(w);
-        (*argv)[idx++] = ap_escape_shell_cmd(p, w);
-    }
-    (*argv)[idx] = NULL;
-
-    return APR_SUCCESS;
-}
-
-
-
-static int include_cmd(include_ctx_t *ctx, apr_bucket_brigade **bb, char *s,
-                       request_rec *r, ap_filter_t *f)
-{
-    include_cmd_arg arg;
-    apr_procattr_t *procattr;
-    apr_proc_t *procnew;
-    apr_status_t rc;
-    apr_table_t *env = r->subprocess_env;
-    char **argv;
-    apr_file_t *file = NULL;
-#if defined(RLIMIT_CPU)  || defined(RLIMIT_NPROC) || \
-    defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS)
-    core_dir_config *conf; 
-    conf = (core_dir_config *) ap_get_module_config(r->per_dir_config,
-                                                    &core_module);
-#endif
-
-    arg.r = r;
-    arg.s = s;
-#ifdef TPF
-    arg.t.filename = r->filename;
-    arg.t.subprocess_env = r->subprocess_env;
-    arg.t.prog_type = FORK_FILE;
-#endif
-
-    if (r->path_info && r->path_info[0] != '\0') {
-        request_rec *pa_req;
-
-        apr_table_setn(env, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info));
-
-        pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, f->next);
-        if (pa_req->filename) {
-            apr_table_setn(env, "PATH_TRANSLATED",
-                      apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info,
-                              NULL));
-        }
-    }
 
-    if (r->args) {
-        char *arg_copy = apr_pstrdup(r->pool, r->args);
-
-        apr_table_setn(env, "QUERY_STRING", r->args);
-        ap_unescape_url(arg_copy);
-        apr_table_setn(env, "QUERY_STRING_UNESCAPED",
-                  ap_escape_shell_cmd(r->pool, arg_copy));
-    }
-
-    if (((rc = apr_createprocattr_init(&procattr, r->pool)) != APR_SUCCESS) ||
-        ((rc = apr_setprocattr_io(procattr, APR_NO_PIPE, 
-                                  APR_FULL_BLOCK, APR_NO_PIPE)) != APR_SUCCESS) ||
-        ((rc = apr_setprocattr_dir(procattr, ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) ||
-#ifdef RLIMIT_CPU
-        ((rc = apr_setprocattr_limit(procattr, APR_LIMIT_CPU, conf->limit_cpu)) != APR_SUCCESS) ||
-#endif
-#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS)
-        ((rc = apr_setprocattr_limit(procattr, APR_LIMIT_MEM, conf->limit_mem)) != APR_SUCCESS) ||
-#endif
-#ifdef RLIMIT_NPROC
-        ((rc = apr_setprocattr_limit(procattr, APR_LIMIT_NPROC, conf->limit_nproc)) != APR_SUCCESS) ||
-#endif
-        ((rc = apr_setprocattr_cmdtype(procattr, APR_SHELLCMD)) != APR_SUCCESS)) {
-        /* Something bad happened, tell the world. */
-	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
-            "couldn't initialize proc attributes: %s %s", r->filename, s);
-        rc = !APR_SUCCESS;
-    }
-    else {
-        SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx);
-        build_argv_list(&argv, r, r->pool);
-        argv[0] = apr_pstrdup(r->pool, s);
-        procnew = apr_pcalloc(r->pool, sizeof(*procnew));
-        rc = apr_create_process(procnew, s, (const char * const *) argv,
-                                (const char * const *)ap_create_environment(r->pool, env),
-                                procattr, r->pool);
-
-        if (rc != APR_SUCCESS) {
-            /* Bad things happened. Everyone should have cleaned up. */
-            ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
-                        "couldn't create child process: %d: %s", rc, s);
-        }
-        else {
-            apr_bucket_brigade *bcgi;
-            apr_bucket *b;
-
-            apr_note_subprocess(r->pool, procnew, kill_after_timeout);
-            /* Fill in BUFF structure for parents pipe to child's stdout */
-            file = procnew->out;
-            if (!file)
-                return APR_EBADF;
-            bcgi = apr_brigade_create(r->pool);
-            b = apr_bucket_create_pipe(file);
-            APR_BRIGADE_INSERT_TAIL(bcgi, b);
-            ap_pass_brigade(f->next, bcgi);
-        
-            /* We can't close the pipe here, because we may return before the
-             * full CGI has been sent to the network.  That's okay though,
-             * because we can rely on the pool to close the pipe for us.
-             */
-        }
-    }
-
-    return 0;
-}
-
-static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
-                       ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
-{
-    char *tag     = NULL;
-    char *tag_val = NULL;
-    char *file = r->filename;
-    apr_bucket  *tmp_buck;
-    char parsed_string[MAX_STRING_LEN];
-
-    *inserted_head = NULL;
-    if (ctx->flags & FLAG_PRINTING) {
-        if (ctx->flags & FLAG_NO_EXEC) {
-            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
-                      "exec used but not allowed in %s", r->filename);
-            CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
-        }
-        else {
-            while (1) {
-                get_tag_and_value(ctx, &tag, &tag_val, 1);
-                if (tag_val == NULL) {
-                    if (tag == NULL) {
-                        return (0);
-                    }
-                    else {
-                        return 1;
-                    }
-                }
-                if (!strcmp(tag, "cmd")) {
-                    parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 1);
-                    if (include_cmd(ctx, bb, parsed_string, r, f) == -1) {
-                        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
-                                    "execution failure for parameter \"%s\" "
-                                    "to tag exec in file %s", tag, r->filename);
-                        CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
-                    }
-                    /* just in case some stooge changed directories */
-                }
-                else if (!strcmp(tag, "cgi")) {
-                    parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
-                    SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx);
-                    if (include_cgi(parsed_string, r, f->next, head_ptr, inserted_head) == -1) {
-                        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
-                                    "invalid CGI ref \"%s\" in %s", tag_val, file);
-                        CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
-                    }
-                }
-                else {
-                    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
-                                "unknown parameter \"%s\" to tag exec in %s", tag, file);
-                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
-                }
-            }
-        }
-    }
-    return 0;
-}
-
 static int handle_echo(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
                        ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
 {
@@ -1138,7 +863,7 @@
     *inserted_head = NULL;
     if (ctx->flags & FLAG_PRINTING) {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 1);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
             if (tag_val == NULL) {
                 if (tag != NULL) {
                     return 1;
@@ -1206,7 +931,7 @@
     *inserted_head = NULL;
     if (ctx->flags & FLAG_PRINTING) {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 0);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
             if (tag_val == NULL) {
                 if (tag == NULL) {
                     return 0;  /* Reached the end of the string. */
@@ -1216,20 +941,20 @@
                 }
             }
             if (!strcmp(tag, "errmsg")) {
-                parse_string(r, tag_val, ctx->error_str, MAX_STRING_LEN, 0);
+                ap_ssi_parse_string(r, tag_val, ctx->error_str, MAX_STRING_LEN, 0);
                 ctx->error_length = strlen(ctx->error_str);
             }
             else if (!strcmp(tag, "timefmt")) {
                 apr_time_t date = r->request_time;
 
-                parse_string(r, tag_val, ctx->time_str, MAX_STRING_LEN, 0);
+                ap_ssi_parse_string(r, tag_val, ctx->time_str, MAX_STRING_LEN, 0);
                 apr_table_setn(env, "DATE_LOCAL", ap_ht_time(r->pool, date, ctx->time_str, 0));
                 apr_table_setn(env, "DATE_GMT", ap_ht_time(r->pool, date, ctx->time_str, 1));
                 apr_table_setn(env, "LAST_MODIFIED",
                                ap_ht_time(r->pool, r->finfo.mtime, ctx->time_str, 0));
             }
             else if (!strcmp(tag, "sizefmt")) {
-                parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+                ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
                 decodehtml(parsed_string);
                 if (!strcmp(parsed_string, "bytes")) {
                     ctx->flags |= FLAG_SIZE_IN_BYTES;
@@ -1367,7 +1092,7 @@
     *inserted_head = NULL;
     if (ctx->flags & FLAG_PRINTING) {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 1);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
             if (tag_val == NULL) {
                 if (tag == NULL) {
                     return 0;
@@ -1377,7 +1102,7 @@
                 }
             }
             else {
-                parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+                ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
                 if (!find_file(r, "fsize", tag, parsed_string, &finfo)) {
                     char buff[50];
 
@@ -1429,7 +1154,7 @@
     *inserted_head = NULL;
     if (ctx->flags & FLAG_PRINTING) {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 1);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
             if (tag_val == NULL) {
                 if (tag == NULL) {
                     return 0;
@@ -1439,7 +1164,7 @@
                 }
             }
             else {
-                parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+                ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
                 if (!find_file(r, "flastmod", tag, parsed_string, &finfo)) {
                     char *t_val;
 
@@ -1981,7 +1706,7 @@
                     sizeof ("     Evaluate string\n"));
             debug_pos += sizeof ("     Evaluate string\n");
 #endif
-            parse_string(r, current->token.value, buffer, sizeof(buffer), 0);
+            ap_ssi_parse_string(r, current->token.value, buffer, sizeof(buffer), 0);
 	    apr_cpystrn(current->token.value, buffer, sizeof(current->token.value));
             current->value = (current->token.value[0] != '\0');
             current->done = 1;
@@ -2006,7 +1731,7 @@
             if (!current->left->done) {
                 switch (current->left->token.type) {
                 case token_string:
-                    parse_string(r, current->left->token.value,
+                    ap_ssi_parse_string(r, current->left->token.value,
                                  buffer, sizeof(buffer), 0);
                     apr_cpystrn(current->left->token.value, buffer,
                             sizeof(current->left->token.value));
@@ -2021,7 +1746,7 @@
             if (!current->right->done) {
                 switch (current->right->token.type) {
                 case token_string:
-                    parse_string(r, current->right->token.value,
+                    ap_ssi_parse_string(r, current->right->token.value,
                                  buffer, sizeof(buffer), 0);
                     apr_cpystrn(current->right->token.value, buffer,
                             sizeof(current->right->token.value));
@@ -2070,11 +1795,11 @@
                 *was_error = 1;
                 goto RETURN;
             }
-            parse_string(r, current->left->token.value,
+            ap_ssi_parse_string(r, current->left->token.value,
                          buffer, sizeof(buffer), 0);
             apr_cpystrn(current->left->token.value, buffer,
 			sizeof(current->left->token.value));
-            parse_string(r, current->right->token.value,
+            ap_ssi_parse_string(r, current->right->token.value,
                          buffer, sizeof(buffer), 0);
             apr_cpystrn(current->right->token.value, buffer,
 			sizeof(current->right->token.value));
@@ -2141,11 +1866,11 @@
                 *was_error = 1;
                 goto RETURN;
             }
-            parse_string(r, current->left->token.value,
+            ap_ssi_parse_string(r, current->left->token.value,
                          buffer, sizeof(buffer), 0);
             apr_cpystrn(current->left->token.value, buffer,
 			sizeof(current->left->token.value));
-            parse_string(r, current->right->token.value,
+            ap_ssi_parse_string(r, current->right->token.value,
                          buffer, sizeof(buffer), 0);
             apr_cpystrn(current->right->token.value, buffer,
 			sizeof(current->right->token.value));
@@ -2307,7 +2032,7 @@
     }
     else {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 0);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
             if (tag == NULL) {
                 if (expr == NULL) {
                     ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
@@ -2375,7 +2100,7 @@
     *inserted_head = NULL;
     if (!ctx->if_nesting_level) {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 0);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 0);
             if (tag == '\0') {
                 LOG_COND_STATUS(ctx, tmp_buck, head_ptr, *inserted_head, " elif");
                 
@@ -2443,7 +2168,7 @@
 
     *inserted_head = NULL;
     if (!ctx->if_nesting_level) {
-        get_tag_and_value(ctx, &tag, &tag_val, 1);
+        ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
         if ((tag != NULL) || (tag_val != NULL)) {
             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
                         "else directive does not take tags in %s", r->filename);
@@ -2476,7 +2201,7 @@
 
     *inserted_head = NULL;
     if (!ctx->if_nesting_level) {
-        get_tag_and_value(ctx, &tag, &tag_val, 1);
+        ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
         if ((tag != NULL) || (tag_val != NULL)) {
             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
                         "endif directive does not take tags in %s", r->filename);
@@ -2507,7 +2232,7 @@
     *inserted_head = NULL;
     if (ctx->flags & FLAG_PRINTING) {
         while (1) {
-            get_tag_and_value(ctx, &tag, &tag_val, 1);
+            ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
             if ((tag == NULL) && (tag_val == NULL)) {
                 return 0;
             }
@@ -2525,7 +2250,7 @@
                     CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
                     return (-1);
                 }
-                parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+                ap_ssi_parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
                 apr_table_setn(r->subprocess_env, apr_pstrdup(r->pool, var),
                                apr_pstrdup(r->pool, parsed_string));
             }
@@ -2548,7 +2273,7 @@
     apr_bucket *tmp_buck;
 
     if (ctx->flags & FLAG_PRINTING) {
-        get_tag_and_value(ctx, &tag, &tag_val, 1);
+        ap_ssi_get_tag_and_value(ctx, &tag, &tag_val, 1);
         if ((tag == NULL) && (tag_val == NULL)) {
             apr_array_header_t *arr = apr_table_elts(r->subprocess_env);
             apr_table_entry_t *elts = (apr_table_entry_t *)arr->elts;
@@ -3018,7 +2743,7 @@
     return OK;
 }
 
-void ap_register_include_handler(char *tag, handler func)
+static void ap_register_include_handler(char *tag, handler func)
 {
     apr_hash_set(include_hash, tag, strlen(tag) + 1, (const void *)func);
 }
@@ -3027,19 +2752,22 @@
                                 apr_pool_t *ptemp, server_rec *s)
 {
     include_hash = apr_make_hash(p);
+
+    ssi_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
 
-    ap_register_include_handler("if", handle_if);
-    ap_register_include_handler("set", handle_set);
-    ap_register_include_handler("else", handle_else);
-    ap_register_include_handler("elif", handle_elif);
-    ap_register_include_handler("exec", handle_exec);
-    ap_register_include_handler("echo", handle_echo);
-    ap_register_include_handler("endif", handle_endif);
-    ap_register_include_handler("fsize", handle_fsize);
-    ap_register_include_handler("config", handle_config);
-    ap_register_include_handler("include", handle_include);
-    ap_register_include_handler("flastmod", handle_flastmod);
-    ap_register_include_handler("printenv", handle_printenv);
+    if(ssi_pfn_register) {
+        ssi_pfn_register("if", handle_if);
+        ssi_pfn_register("set", handle_set);
+        ssi_pfn_register("else", handle_else);
+        ssi_pfn_register("elif", handle_elif);
+        ssi_pfn_register("echo", handle_echo);
+        ssi_pfn_register("endif", handle_endif);
+        ssi_pfn_register("fsize", handle_fsize);
+        ssi_pfn_register("config", handle_config);
+        ssi_pfn_register("include", handle_include);
+        ssi_pfn_register("flastmod", handle_flastmod);
+        ssi_pfn_register("printenv", handle_printenv);
+    }
 }
 
 /*
@@ -3054,6 +2782,9 @@
 
 static void register_hooks(apr_pool_t *p)
 {
+    APR_REGISTER_OPTIONAL_FN(ap_ssi_get_tag_and_value);
+    APR_REGISTER_OPTIONAL_FN(ap_ssi_parse_string);
+    APR_REGISTER_OPTIONAL_FN(ap_register_include_handler);
     ap_hook_post_config(include_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
     ap_register_output_filter("INCLUDES", includes_filter, AP_FTYPE_CONTENT);
 }
Index: modules/filters/mod_include.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/filters/mod_include.h,v
retrieving revision 1.8
diff -u -r1.8 mod_include.h
--- modules/filters/mod_include.h	2001/01/20 05:18:05	1.8
+++ modules/filters/mod_include.h	2001/02/01 19:24:52
@@ -59,8 +59,6 @@
 #ifndef _MOD_INCLUDE_H
 #define _MOD_INCLUDE_H 1
 
-
-
 #define STARTING_SEQUENCE "<!--#"
 #define ENDING_SEQUENCE "-->"
 
@@ -177,29 +175,40 @@
 #define CREATE_ERROR_BUCKET(cntx, t_buck, h_ptr, ins_head)        \
 {                                                                 \
     apr_size_t e_wrt;                                             \
-    t_buck = apr_bucket_create_heap(cntx->error_str,               \
+    t_buck = apr_bucket_create_heap(cntx->error_str,              \
                                    ctx->error_length, 1, &e_wrt); \
-    APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck);                       \
+    APR_BUCKET_INSERT_BEFORE(h_ptr, t_buck);                      \
                                                                   \
     if (ins_head == NULL) {                                       \
         ins_head = t_buck;                                        \
     }                                                             \
 }
 
-#define SPLIT_AND_PASS_PRETAG_BUCKETS(brgd, cntxt)               \
+#define SPLIT_AND_PASS_PRETAG_BUCKETS(brgd, cntxt, next)          \
 if ((APR_BRIGADE_EMPTY(cntxt->ssi_tag_brigade)) &&                \
-    (cntxt->head_start_bucket != NULL)) {                        \
+    (cntxt->head_start_bucket != NULL)) {                         \
     apr_bucket_brigade *tag_plus;                                 \
-                                                                 \
+                                                                  \
     tag_plus = apr_brigade_split(brgd, cntxt->head_start_bucket); \
-    ap_pass_brigade(f->next, brgd);                              \
-    brgd = tag_plus;                                             \
+    ap_pass_brigade(next, brgd);                                  \
+    brgd = tag_plus;                                              \
 }
 
+
 typedef int (*handler)(include_ctx_t *ctx, apr_bucket_brigade **bb, 
                        request_rec *r, ap_filter_t *f, apr_bucket *head_ptr, 
                        apr_bucket **inserted_head);
 
-void ap_register_include_handler(char *tag, handler func);
+APR_DECLARE_OPTIONAL_FN(void, ap_ssi_get_tag_and_value, (include_ctx_t *ctx,
+                                                        char **tag,
+                                                        char **tag_val,
+                                                        int dodecode))
+APR_DECLARE_OPTIONAL_FN(void, ap_ssi_parse_string, (request_rec *r,
+                                                    const char *in,
+                                                    char *out,
+                                                    size_t length,
+                                                    int leave_name))
+APR_DECLARE_OPTIONAL_FN(void, ap_register_include_handler, (char *tag,
+                                                            handler func))
 
 #endif /* MOD_INCLUDE */
Index: modules/generators/mod_cgi.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/generators/mod_cgi.c,v
retrieving revision 1.81
diff -u -r1.81 mod_cgi.c
--- modules/generators/mod_cgi.c	2001/01/27 23:35:21	1.81
+++ modules/generators/mod_cgi.c	2001/02/01 19:24:55
@@ -88,6 +88,8 @@
 #include "util_script.h"
 #include "ap_mpm.h"
 #include "http_conf_globals.h"
+#include "apr_optional.h"
+#include "../filters/mod_include.h"
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
@@ -97,6 +99,23 @@
 
 module AP_MODULE_DECLARE_DATA cgi_module;
 
+static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgi_pfn_reg_with_ssi;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgi_pfn_gtv;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgi_pfn_ps;
+
+typedef enum {RUN_AS_SSI, RUN_AS_CGI} prog_types;
+
+typedef struct {
+    apr_int32_t          in_pipe;
+    apr_int32_t          out_pipe;
+    apr_int32_t          err_pipe;
+    apr_cmdtype_e        cmd_type;
+    prog_types           prog_type;
+    apr_bucket_brigade **bb;
+    include_ctx_t       *ctx;
+    ap_filter_t         *next;
+} exec_info;
+
 /* KLUDGE --- for back-combatibility, we don't have to check ExecCGI
  * in ScriptAliased directories, which means we need to know if this
  * request came through ScriptAlias or not... so the Alias module
@@ -313,21 +332,52 @@
     return ret;
 }
 
+
+/* This is the special environment used for running the "exec cmd="
+ *   variety of SSI directives.
+ */
+static void add_ssi_vars(request_rec *r, ap_filter_t *next)
+{
+    apr_table_t *e = r->subprocess_env;
+
+    if (r->path_info && r->path_info[0] != '\0') {
+        request_rec *pa_req;
+
+        apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info));
+
+        pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, next);
+        if (pa_req->filename) {
+            apr_table_setn(e, "PATH_TRANSLATED",
+                           apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL));
+        }
+    }
+
+    if (r->args) {
+        char *arg_copy = apr_pstrdup(r->pool, r->args);
+
+        apr_table_setn(e, "QUERY_STRING", r->args);
+        ap_unescape_url(arg_copy);
+        apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy));
+    }
+}
+
 static apr_status_t run_cgi_child(apr_file_t **script_out,
                                   apr_file_t **script_in,
                                   apr_file_t **script_err, 
                                   const char *command,
                                   const char * const argv[],
-                                  request_rec *r, apr_pool_t *p)
+                                  request_rec *r,
+                                  apr_pool_t *p,
+                                  exec_info *e_info)
 {
     const char * const *env;
     apr_procattr_t *procattr;
-    apr_proc_t *procnew = apr_pcalloc(p, sizeof(*procnew));
+    apr_proc_t *procnew;
     apr_status_t rc = APR_SUCCESS;
 #if defined(RLIMIT_CPU)  || defined(RLIMIT_NPROC) || \
     defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined (RLIMIT_AS)
     core_dir_config *conf;
-    conf = (core_dir_config *) ap_get_module_config(r->per_dir_config,                                                              &core_module);
+    conf = (core_dir_config *) ap_get_module_config(r->per_dir_config, &core_module);
 #endif
 
 
@@ -347,7 +397,13 @@
 	    r->filename, cld->nph ? "NPH " : "", argv0);
 #endif
 
-    ap_add_cgi_vars(r);
+    if (e_info->prog_type == RUN_AS_CGI) {
+        ap_add_cgi_vars(r);
+    }
+    else /* SSIs want a controlled environment and a special path. */
+    {
+        add_ssi_vars(r, e_info->next);
+    }
     env = (const char * const *)ap_create_environment(p, r->subprocess_env);
 
 #ifdef DEBUG_CGI
@@ -360,10 +416,10 @@
      * NB only ISINDEX scripts get decoded arguments.
      */
     if (((rc = apr_createprocattr_init(&procattr, p)) != APR_SUCCESS) ||
-        ((rc = apr_setprocattr_io(procattr, 
-                                 APR_CHILD_BLOCK, 
-                                 APR_CHILD_BLOCK,
-                                 APR_CHILD_BLOCK)) != APR_SUCCESS) ||
+        ((rc = apr_setprocattr_io(procattr,
+                                  e_info->in_pipe,
+                                  e_info->out_pipe,
+                                  e_info->err_pipe)) != APR_SUCCESS) ||
         ((rc = apr_setprocattr_dir(procattr, 
                                   ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) ||
 #ifdef RLIMIT_CPU
@@ -375,12 +431,17 @@
 #ifdef RLIMIT_NPROC
         ((rc = apr_setprocattr_limit(procattr, APR_LIMIT_NPROC, conf->limit_nproc)) != APR_SUCCESS) ||
 #endif
-        ((rc = apr_setprocattr_cmdtype(procattr, APR_PROGRAM)) != APR_SUCCESS)) {
+        ((rc = apr_setprocattr_cmdtype(procattr, e_info->cmd_type)) != APR_SUCCESS)) {
         /* Something bad happened, tell the world. */
 	ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
 		      "couldn't set child process attributes: %s", r->filename);
     }
     else {
+        procnew = apr_pcalloc(p, sizeof(*procnew));
+        if (e_info->prog_type == RUN_AS_SSI) {
+            SPLIT_AND_PASS_PRETAG_BUCKETS(*(e_info->bb), e_info->ctx, e_info->next);
+        }
+
         rc = ap_os_create_privileged_process(r, procnew, command, argv, env, procattr, p);
     
         if (rc != APR_SUCCESS) {
@@ -393,21 +454,20 @@
 
             *script_in = procnew->out;
             if (!script_in)
-                return APR_EBADF;
-            apr_set_pipe_timeout(*script_in, 
-                                 (int)(r->server->timeout * APR_USEC_PER_SEC));
-
-            *script_out = procnew->in;
-            if (!*script_out)
                 return APR_EBADF;
-            apr_set_pipe_timeout(*script_out, 
-                                 (int)(r->server->timeout * APR_USEC_PER_SEC));
+            apr_set_pipe_timeout(*script_in, (int)(r->server->timeout * APR_USEC_PER_SEC));
 
-            *script_err = procnew->err;
-            if (!*script_err)
-                return APR_EBADF;
-            apr_set_pipe_timeout(*script_err, 
-                                 (int)(r->server->timeout * APR_USEC_PER_SEC));
+            if (e_info->prog_type == RUN_AS_CGI) {
+                *script_out = procnew->in;
+                if (!*script_out)
+                    return APR_EBADF;
+                apr_set_pipe_timeout(*script_out, (int)(r->server->timeout * APR_USEC_PER_SEC));
+
+                *script_err = procnew->err;
+                if (!*script_err)
+                    return APR_EBADF;
+                apr_set_pipe_timeout(*script_err, (int)(r->server->timeout * APR_USEC_PER_SEC));
+            }
         }
     }
     return (rc);
@@ -516,6 +576,7 @@
     apr_pool_t *p;
     cgi_server_conf *conf;
     apr_status_t rv;
+    exec_info e_info;
 
     if(strcmp(r->handler,CGI_MAGIC_TYPE) && strcmp(r->handler,"cgi-script"))
 	return DECLINED;
@@ -600,9 +661,18 @@
     }
     argv[0] = apr_pstrdup(p, command);
 
+    e_info.cmd_type  = APR_PROGRAM;
+    e_info.in_pipe   = APR_CHILD_BLOCK;
+    e_info.out_pipe  = APR_CHILD_BLOCK;
+    e_info.err_pipe  = APR_CHILD_BLOCK;
+    e_info.prog_type = RUN_AS_CGI;
+    e_info.bb        = NULL;
+    e_info.ctx       = NULL;
+    e_info.next      = NULL;
+
     /* run the script in its own process */
     if ((rv = run_cgi_child(&script_out, &script_in, &script_err,
-                            command, argv, r, p)) != APR_SUCCESS) {
+                            command, argv, r, p, &e_info)) != APR_SUCCESS) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, r,
                       "couldn't spawn child process: %s", r->filename);
         return HTTP_INTERNAL_SERVER_ERROR;
@@ -723,9 +793,204 @@
     return OK;			/* NOT r->status, even if it has changed. */
 }
 
+/*============================================================================
+ *============================================================================
+ * This is the beginning of the cgi filter code moved from mod_include. This
+ *   is the code required to handle the "exec" SSI directive.
+ *============================================================================
+ *============================================================================*/
+static int include_cgi(char *s, request_rec *r, ap_filter_t *next,
+                       apr_bucket *head_ptr, apr_bucket **inserted_head)
+{
+    request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
+    int rr_status;
+    apr_bucket  *tmp_buck, *tmp2_buck;
+
+    if (rr->status != HTTP_OK) {
+        return -1;
+    }
+
+    /* No hardwired path info or query allowed */
+
+    if ((rr->path_info && rr->path_info[0]) || rr->args) {
+        return -1;
+    }
+    if (rr->finfo.protection == 0) {
+        return -1;
+    }
+
+    /* Script gets parameters of the *document*, for back compatibility */
+
+    rr->path_info = r->path_info;       /* hard to get right; see mod_cgi.c */
+    rr->args = r->args;
+
+    /* Force sub_req to be treated as a CGI request, even if ordinary
+     * typing rules would have called it something else.
+     */
+
+    rr->content_type = CGI_MAGIC_TYPE;
+
+    /* Run it. */
+
+    rr_status = ap_run_sub_req(rr);
+    if (ap_is_HTTP_REDIRECT(rr_status)) {
+        apr_size_t len_loc, h_wrt;
+        const char *location = apr_table_get(rr->headers_out, "Location");
+
+        location = ap_escape_html(rr->pool, location);
+        len_loc = strlen(location);
+
+        tmp_buck = apr_bucket_create_immortal("<A HREF=\"", sizeof("<A HREF=\""));
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+        tmp2_buck = apr_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = apr_bucket_create_immortal("\">", sizeof("\">"));
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = apr_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = apr_bucket_create_immortal("</A>", sizeof("</A>"));
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+
+        if (*inserted_head == NULL) {
+            *inserted_head = tmp_buck;
+        }
+    }
+
+    ap_destroy_sub_req(rr);
+
+    return 0;
+}
+
+
+static int include_cmd(include_ctx_t *ctx, apr_bucket_brigade **bb, char *command,
+                       request_rec *r, ap_filter_t *f)
+{
+    exec_info      e_info;
+    const char   **argv;
+    apr_file_t    *script_out = NULL, *script_in = NULL, *script_err = NULL;
+    apr_bucket_brigade *bcgi;
+    apr_bucket *b;
+
+    if (build_argv_list(&argv, r, r->pool) != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                      "couldn't spawn cmd child process: %s", r->filename);
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+    argv[0] = apr_pstrdup(r->pool, command);
+
+    e_info.cmd_type  = APR_SHELLCMD;
+    e_info.in_pipe   = APR_NO_PIPE;
+    e_info.out_pipe  = APR_FULL_BLOCK;
+    e_info.err_pipe  = APR_NO_PIPE;
+    e_info.prog_type = RUN_AS_SSI;
+    e_info.bb        = bb;
+    e_info.ctx       = ctx;
+    e_info.next      = f->next;
+
+    /* run the script in its own process */
+    if (run_cgi_child(&script_out, &script_in, &script_err,
+                      command, argv, r, r->pool, &e_info) != APR_SUCCESS) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                      "couldn't spawn child process: %s", r->filename);
+        return HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    bcgi = apr_brigade_create(r->pool);
+    b = apr_bucket_create_pipe(script_in);
+    APR_BRIGADE_INSERT_TAIL(bcgi, b);
+    ap_pass_brigade(f->next, bcgi);
+
+    /* We can't close the pipe here, because we may return before the
+     * full CGI has been sent to the network.  That's okay though,
+     * because we can rely on the pool to close the pipe for us.
+     */
+
+    return 0;
+}
+
+static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+                       ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
+{
+    char *tag     = NULL;
+    char *tag_val = NULL;
+    char *file = r->filename;
+    apr_bucket  *tmp_buck;
+    char parsed_string[MAX_STRING_LEN];
+
+    *inserted_head = NULL;
+    if (ctx->flags & FLAG_PRINTING) {
+        if (ctx->flags & FLAG_NO_EXEC) {
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                      "exec used but not allowed in %s", r->filename);
+            CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+        }
+        else {
+            while (1) {
+                cgi_pfn_gtv(ctx, &tag, &tag_val, 1);
+                if (tag_val == NULL) {
+                    if (tag == NULL) {
+                        return (0);
+                    }
+                    else {
+                        return 1;
+                    }
+                }
+                if (!strcmp(tag, "cmd")) {
+                    cgi_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 1);
+                    if (include_cmd(ctx, bb, parsed_string, r, f) == -1) {
+                        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                                    "execution failure for parameter \"%s\" "
+                                    "to tag exec in file %s", tag, r->filename);
+                        CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+                    }
+                }
+                else if (!strcmp(tag, "cgi")) {
+                    cgi_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+                    SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next);
+                    if (include_cgi(parsed_string, r, f->next, head_ptr, inserted_head) == -1) {
+                        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                                    "invalid CGI ref \"%s\" in %s", tag_val, file);
+                        CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+                    }
+                }
+                else {
+                    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                                "unknown parameter \"%s\" to tag exec in %s", tag, file);
+                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+                }
+            }
+        }
+    }
+    return 0;
+}
+
+
+/*============================================================================
+ *============================================================================
+ * This is the end of the cgi filter code moved from mod_include.
+ *============================================================================
+ *============================================================================*/
+
+
+static void cgi_post_config(apr_pool_t *p, apr_pool_t *plog,
+                                apr_pool_t *ptemp, server_rec *s)
+{
+    cgi_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
+    cgi_pfn_gtv          = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value);
+    cgi_pfn_ps           = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string);
+
+    if ((cgi_pfn_reg_with_ssi) && (cgi_pfn_gtv) && (cgi_pfn_ps)) {
+        /* Required by mod_include filter. This is how mod_cgi registers
+         *   with mod_include to provide processing of the exec directive.
+         */
+        cgi_pfn_reg_with_ssi("exec", handle_exec);
+    }
+}
+
 static void register_hooks(apr_pool_t *p)
 {
     ap_hook_handler(cgi_handler, NULL, NULL, APR_HOOK_MIDDLE);
+    ap_hook_post_config(cgi_post_config, NULL, NULL, APR_HOOK_REALLY_FIRST);
 }
 
 module AP_MODULE_DECLARE_DATA cgi_module =
Index: modules/generators/mod_cgid.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/generators/mod_cgid.c,v
retrieving revision 1.64
diff -u -r1.64 mod_cgid.c
--- modules/generators/mod_cgid.c	2001/01/29 19:42:11	1.64
+++ modules/generators/mod_cgid.c	2001/02/01 19:24:55
@@ -92,6 +92,8 @@
 #include "ap_mpm.h"
 #include "unixd.h"
 #include "mod_suexec.h"
+#include "apr_optional.h"
+#include "../filters/mod_include.h"
 #include <sys/stat.h>
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
@@ -108,7 +110,13 @@
 module AP_MODULE_DECLARE_DATA cgid_module; 
 
 static void cgid_init(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *main_server); 
+static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+                       ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head);
 
+static APR_OPTIONAL_FN_TYPE(ap_register_include_handler) *cgid_pfn_reg_with_ssi;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_get_tag_and_value) *cgid_pfn_gtv;
+static APR_OPTIONAL_FN_TYPE(ap_ssi_parse_string) *cgid_pfn_ps;
+
 static apr_pool_t *pcgi; 
 static int total_modules = 0;
 
@@ -132,6 +140,9 @@
 
 #define SHELL_PATH "/bin/sh"
 
+#define CGI_REQ 1
+#define SSI_REQ 2
+
 /* DEFAULT_CGID_LISTENBACKLOG controls the max depth on the unix socket's
  * pending connection queue.  If a bunch of cgi requests arrive at about
  * the same time, connections from httpd threads/processes will back up
@@ -228,7 +239,7 @@
 #endif
 }
 
-static void get_req(int fd, request_rec *r, char **filename, char **argv0, char ***env) 
+static void get_req(int fd, request_rec *r, char **filename, char **argv0, char ***env, int *req_type) 
 { 
     int i, len, j; 
     unsigned char *data; 
@@ -239,6 +250,7 @@
 
     r->server = apr_pcalloc(r->pool, sizeof(server_rec)); 
 
+    read(fd, req_type, sizeof(int));
     read(fd, &j, sizeof(int)); 
     read(fd, &len, sizeof(int)); 
     data = apr_pcalloc(r->pool, len + 1); /* get a cleared byte for final '\0' */
@@ -321,9 +333,9 @@
 
 
 
-static void send_req(int fd, request_rec *r, char *argv0, char **env) 
+static void send_req(int fd, request_rec *r, char *argv0, char **env, int req_type) 
 { 
-    int len; 
+    int len, r_type = req_type; 
     int i = 0; 
     char *data; 
     module *suexec_mod = ap_find_linked_module("mod_suexec.c");
@@ -335,6 +347,13 @@
         continue; 
     } 
 
+    /* Write the request type (SSI "exec cmd" or cgi). */
+    if (write(fd, &r_type, sizeof(int)) < 0) {
+        ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r,
+                     "write to cgi daemon process");
+    }
+
+    /* Write the number of entries in the environment. */
     if (write(fd, &i, sizeof(int)) < 0) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, 
                      "write to cgi daemon process"); 
@@ -345,18 +364,21 @@
     } 
     data = apr_pstrcat(r->pool, data, r->args, NULL); 
     len = strlen(data); 
+    /* Write the length of the concatenated env string. */
     if (write(fd, &len, sizeof(int)) < 0) { 
         ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, 
                      "write to cgi daemon process"); 
-        }     
+    }
+    /* Write the concatted env string. */     
     if (write(fd, data, len) < 0) {
         ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, 
                      "write to cgi daemon process"); 
-        }     
+    }
+    /* Write module_index id value. */     
     if (write(fd, &core_module.module_index, sizeof(int)) < 0) { 
         ap_log_rerror(APLOG_MARK, APLOG_ERR, errno, r, 
                      "write to cgi daemon process"); 
-        }     
+    }     
     if (suexec_mod) {
         suexec_config_t *suexec_cfg = ap_get_module_config(r->per_dir_config,
                                                            suexec_mod);
@@ -409,7 +431,7 @@
 static int cgid_server(void *data) 
 { 
     struct sockaddr_un unix_addr;
-    int sd, sd2, rc;
+    int sd, sd2, rc, req_type;
     mode_t omask;
     apr_socklen_t len;
     server_rec *main_server = data;
@@ -466,6 +488,10 @@
         char *filename; 
         char **env; 
         const char * const *argv; 
+        apr_int32_t   in_pipe  = APR_CHILD_BLOCK;
+        apr_int32_t   out_pipe = APR_CHILD_BLOCK;
+        apr_int32_t   err_pipe = APR_CHILD_BLOCK;
+        apr_cmdtype_e cmd_type = APR_PROGRAM;
         apr_pool_t *p; 
         request_rec *r; 
         apr_procattr_t *procattr = NULL;
@@ -489,21 +515,29 @@
         r = apr_pcalloc(p, sizeof(request_rec)); 
         procnew = apr_pcalloc(p, sizeof(*procnew));
         r->pool = p; 
-        get_req(sd2, r, &filename, &argv0, &env); 
+        get_req(sd2, r, &filename, &argv0, &env, &req_type); 
         apr_put_os_file(&r->server->error_log, &errfileno, r->pool);
         apr_put_os_file(&inout, &sd2, r->pool);
 
+        if (req_type == SSI_REQ) {
+            in_pipe  = APR_NO_PIPE;
+            out_pipe = APR_FULL_BLOCK;
+            err_pipe = APR_NO_PIPE;
+            cmd_type = APR_SHELLCMD;
+        }
+
         if (((rc = apr_createprocattr_init(&procattr, p)) != APR_SUCCESS) ||
-            ((rc = apr_setprocattr_io(procattr,
-                                     APR_CHILD_BLOCK,
-                                     APR_CHILD_BLOCK,
-                                     APR_CHILD_BLOCK)) != APR_SUCCESS) ||
-            ((rc = apr_setprocattr_childin(procattr, inout, NULL)) != APR_SUCCESS) ||
+            ((req_type == CGI_REQ) && 
+             (((rc = apr_setprocattr_io(procattr,
+                                        in_pipe,
+                                        out_pipe,
+                                        err_pipe)) != APR_SUCCESS) ||
+              ((rc = apr_setprocattr_childerr(procattr, r->server->error_log, NULL)) != APR_SUCCESS) ||
+              ((rc = apr_setprocattr_childin(procattr, inout, NULL)) != APR_SUCCESS))) ||
             ((rc = apr_setprocattr_childout(procattr, inout, NULL)) != APR_SUCCESS) ||
-            ((rc = apr_setprocattr_childerr(procattr, r->server->error_log, NULL)) != APR_SUCCESS) ||
             ((rc = apr_setprocattr_dir(procattr,
                                   ap_make_dirstr_parent(r->pool, r->filename))) != APR_SUCCESS) ||
-            ((rc = apr_setprocattr_cmdtype(procattr, APR_PROGRAM)) != APR_SUCCESS)) {
+            ((rc = apr_setprocattr_cmdtype(procattr, cmd_type)) != APR_SUCCESS)) {
             /* Something bad happened, tell the world. */
             ap_log_rerror(APLOG_MARK, APLOG_ERR, rc, r,
                       "couldn't set child process attributes: %s", r->filename);
@@ -565,6 +599,17 @@
 #if APR_HAS_OTHER_CHILD
         apr_register_other_child(procnew, cgid_maint, NULL, NULL, p);
 #endif
+
+        cgid_pfn_reg_with_ssi = APR_RETRIEVE_OPTIONAL_FN(ap_register_include_handler);
+        cgid_pfn_gtv          = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_get_tag_and_value);
+        cgid_pfn_ps           = APR_RETRIEVE_OPTIONAL_FN(ap_ssi_parse_string);
+
+        if ((cgid_pfn_reg_with_ssi) && (cgid_pfn_gtv) && (cgid_pfn_ps)) {
+            /* Required by mod_include filter. This is how mod_cgid registers
+             *   with mod_include to provide processing of the exec directive.
+             */
+            cgid_pfn_reg_with_ssi("exec", handle_exec);
+        }
     }
 } 
 
@@ -847,7 +892,7 @@
                                    "unable to connect to cgi daemon");
     } 
 
-    send_req(sd, r, argv0, env); 
+    send_req(sd, r, argv0, env, CGI_REQ); 
 
     /* We are putting the tempsock variable into a file so that we can use
      * a pipe bucket to send the data to the client.
@@ -963,6 +1008,254 @@
 
     return OK; /* NOT r->status, even if it has changed. */ 
 } 
+
+
+
+
+/*============================================================================
+ *============================================================================
+ * This is the beginning of the cgi filter code moved from mod_include. This
+ *   is the code required to handle the "exec" SSI directive.
+ *============================================================================
+ *============================================================================*/
+static int include_cgi(char *s, request_rec *r, ap_filter_t *next,
+                       apr_bucket *head_ptr, apr_bucket **inserted_head)
+{
+    request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
+    int rr_status;
+    apr_bucket  *tmp_buck, *tmp2_buck;
+
+    if (rr->status != HTTP_OK) {
+        return -1;
+    }
+
+    /* No hardwired path info or query allowed */
+
+    if ((rr->path_info && rr->path_info[0]) || rr->args) {
+        return -1;
+    }
+    if (rr->finfo.protection == 0) {
+        return -1;
+    }
+
+    /* Script gets parameters of the *document*, for back compatibility */
+
+    rr->path_info = r->path_info;       /* hard to get right; see mod_cgi.c */
+    rr->args = r->args;
+
+    /* Force sub_req to be treated as a CGI request, even if ordinary
+     * typing rules would have called it something else.
+     */
+
+    rr->content_type = CGI_MAGIC_TYPE;
+
+    /* Run it. */
+
+    rr_status = ap_run_sub_req(rr);
+    if (ap_is_HTTP_REDIRECT(rr_status)) {
+        apr_size_t len_loc, h_wrt;
+        const char *location = apr_table_get(rr->headers_out, "Location");
+
+        location = ap_escape_html(rr->pool, location);
+        len_loc = strlen(location);
+
+        tmp_buck = apr_bucket_create_immortal("<A HREF=\"", sizeof("<A HREF=\""));
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+        tmp2_buck = apr_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = apr_bucket_create_immortal("\">", sizeof("\">"));
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = apr_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = apr_bucket_create_immortal("</A>", sizeof("</A>"));
+        APR_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+
+        if (*inserted_head == NULL) {
+            *inserted_head = tmp_buck;
+        }
+    }
+
+    ap_destroy_sub_req(rr);
+
+    return 0;
+}
+
+
+/* This is the special environment used for running the "exec cmd="
+ *   variety of SSI directives.
+ */
+static void add_ssi_vars(request_rec *r, ap_filter_t *next)
+{
+    apr_table_t *e = r->subprocess_env;
+
+    if (r->path_info && r->path_info[0] != '\0') {
+        request_rec *pa_req;
+
+        apr_table_setn(e, "PATH_INFO", ap_escape_shell_cmd(r->pool, r->path_info));
+
+        pa_req = ap_sub_req_lookup_uri(ap_escape_uri(r->pool, r->path_info), r, next);
+        if (pa_req->filename) {
+            apr_table_setn(e, "PATH_TRANSLATED",
+                           apr_pstrcat(r->pool, pa_req->filename, pa_req->path_info, NULL));
+        }
+    }
+
+    if (r->args) {
+        char *arg_copy = apr_pstrdup(r->pool, r->args);
+
+        apr_table_setn(e, "QUERY_STRING", r->args);
+        ap_unescape_url(arg_copy);
+        apr_table_setn(e, "QUERY_STRING_UNESCAPED", ap_escape_shell_cmd(r->pool, arg_copy));
+    }
+}
+
+static int include_cmd(include_ctx_t *ctx, apr_bucket_brigade **bb, char *command,
+                       request_rec *r, ap_filter_t *f)
+{
+    char **env; 
+    const char *location; 
+    int sd;
+    int retval; 
+    apr_bucket_brigade *bcgi;
+    apr_bucket *b;
+    struct sockaddr_un unix_addr;
+    apr_file_t *tempsock = NULL;
+    void *sconf = r->server->module_config; 
+    cgid_server_conf *conf = (cgid_server_conf *) ap_get_module_config(sconf, &cgid_module); 
+
+    add_ssi_vars(r, f->next);
+    env = ap_create_environment(r->pool, r->subprocess_env);
+
+    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, 0, 
+                                   "unable to create socket to cgi daemon");
+    }
+
+    memset(&unix_addr, 0, sizeof(unix_addr));
+    unix_addr.sun_family = AF_UNIX;
+    strcpy(unix_addr.sun_path, conf->sockname);
+
+    if (connect(sd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) < 0) {
+            return log_scripterror(r, conf, HTTP_INTERNAL_SERVER_ERROR, 0, 
+                                   "unable to connect to cgi daemon");
+    } 
+
+    SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next);
+
+    send_req(sd, r, command, env, SSI_REQ); 
+
+    /* We are putting the tempsock variable into a file so that we can use
+     * a pipe bucket to send the data to the client.
+     */
+    apr_put_os_file(&tempsock, &sd, r->pool);
+
+    if ((retval = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) 
+        return retval; 
+    
+    location = apr_table_get(r->headers_out, "Location"); 
+
+    if (location && location[0] == '/' && r->status == 200) { 
+        char argsbuffer[HUGE_STRING_LEN]; 
+
+        /* Soak up all the script output */ 
+        while (apr_fgets(argsbuffer, HUGE_STRING_LEN, tempsock) > 0) { 
+            continue; 
+        } 
+        /* This redirect needs to be a GET no matter what the original 
+         * method was. 
+         */ 
+        r->method = apr_pstrdup(r->pool, "GET"); 
+        r->method_number = M_GET; 
+
+        /* We already read the message body (if any), so don't allow 
+         * the redirected request to think it has one. We can ignore 
+         * Transfer-Encoding, since we used REQUEST_CHUNKED_ERROR. 
+         */ 
+        apr_table_unset(r->headers_in, "Content-Length"); 
+
+        ap_internal_redirect_handler(location, r); 
+        return OK; 
+    } 
+    else if (location && r->status == 200) { 
+        /* XX Note that if a script wants to produce its own Redirect 
+         * body, it now has to explicitly *say* "Status: 302" 
+         */ 
+        return HTTP_MOVED_TEMPORARILY; 
+    } 
+
+    ap_send_http_header(r); 
+    if (!r->header_only) { 
+        bcgi = apr_brigade_create(r->pool);
+        b    = apr_bucket_create_pipe(tempsock);
+        APR_BRIGADE_INSERT_TAIL(bcgi, b);
+        ap_pass_brigade(f->next, bcgi);
+    } 
+
+    return 0;
+}
+
+static int handle_exec(include_ctx_t *ctx, apr_bucket_brigade **bb, request_rec *r,
+                       ap_filter_t *f, apr_bucket *head_ptr, apr_bucket **inserted_head)
+{
+    char *tag     = NULL;
+    char *tag_val = NULL;
+    char *file = r->filename;
+    apr_bucket  *tmp_buck;
+    char parsed_string[MAX_STRING_LEN];
+
+    *inserted_head = NULL;
+    if (ctx->flags & FLAG_PRINTING) {
+        if (ctx->flags & FLAG_NO_EXEC) {
+            ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                      "exec used but not allowed in %s", r->filename);
+            CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+        }
+        else {
+            while (1) {
+                cgid_pfn_gtv(ctx, &tag, &tag_val, 1);
+                if (tag_val == NULL) {
+                    if (tag == NULL) {
+                        return (0);
+                    }
+                    else {
+                        return 1;
+                    }
+                }
+                if (!strcmp(tag, "cmd")) {
+                    cgid_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 1);
+                    if (include_cmd(ctx, bb, parsed_string, r, f) == -1) {
+                        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                                    "execution failure for parameter \"%s\" "
+                                    "to tag exec in file %s", tag, r->filename);
+                        CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+                    }
+                    /* just in case some stooge changed directories */
+                }
+                else if (!strcmp(tag, "cgi")) {
+                    cgid_pfn_ps(r, tag_val, parsed_string, sizeof(parsed_string), 0);
+                    SPLIT_AND_PASS_PRETAG_BUCKETS(*bb, ctx, f->next);
+                    if (include_cgi(parsed_string, r, f->next, head_ptr, inserted_head) == -1) {
+                        ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                                    "invalid CGI ref \"%s\" in %s", tag_val, file);
+                        CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+                    }
+                }
+                else {
+                    ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
+                                "unknown parameter \"%s\" to tag exec in %s", tag, file);
+                    CREATE_ERROR_BUCKET(ctx, tmp_buck, head_ptr, *inserted_head);
+                }
+            }
+        }
+    }
+    return 0;
+}
+/*============================================================================
+ *============================================================================
+ * This is the end of the cgi filter code moved from mod_include.
+ *============================================================================
+ *============================================================================*/
+
 
 static void register_hook(apr_pool_t *p)
 {

Mime
View raw message