You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Paul J. Reder" <re...@raleigh.ibm.com> on 2001/01/12 21:16:17 UTC

[Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

The following patch moves the "exec cgi" and "exec cmd" logic from mod_include
to mod_cgi and mod_cgid. As much duplicate code as possible was removed in the
process.

We now have the first example of an external module registering as an SSI
directive handler with the mod_include code.

This patch is based from the CVS repository as of 1/11/2001 around noon.

The only thing I'm not sure of is what the preferred way to include the
mod_include.h file in mod_cgi(d).c.

-- 
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.85
diff -u -r1.85 mod_include.c
--- modules/filters/mod_include.c	2001/01/09 05:12:40	1.85
+++ modules/filters/mod_include.c	2001/01/12 19:46:46
@@ -505,7 +505,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,
+void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag,
                               char **tag_val, int dodecode)
 {
     char *c = ctx->curr_tag_pos;
@@ -583,8 +583,8 @@
 /*
  * Do variable substitution on strings
  */
-static void parse_string(request_rec *r, const char *in, char *out,
-			size_t length, int leave_name)
+void ap_ssi_parse_string(request_rec *r, const char *in, char *out,
+                         size_t length, int leave_name)
 {
     char ch;
     char *next = out;
@@ -610,7 +610,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;
@@ -646,17 +645,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;
@@ -694,69 +686,6 @@
 
 /* --------------------------- Action handlers ---------------------------- */
 
-static int include_cgi(char *s, request_rec *r, ap_filter_t *next,
-                       ap_bucket *head_ptr, ap_bucket **inserted_head)
-{
-    request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
-    int rr_status;
-    ap_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 = ap_bucket_create_immortal("<A HREF=\"", sizeof("<A HREF=\""));
-        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
-        tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
-        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-        tmp2_buck = ap_bucket_create_immortal("\">", sizeof("\">"));
-        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-        tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
-        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-        tmp2_buck = ap_bucket_create_immortal("</A>", sizeof("</A>"));
-        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
-
-        if (*inserted_head == NULL) {
-            *inserted_head = tmp_buck;
-        }
-    }
-
-    ap_destroy_sub_req(rr);
-    ap_chdir_file(r->filename);
-
-    return 0;
-}
-
 /* ensure that path is relative, and does not contain ".." elements
  * ensentially ensure that it does not match the regex:
  * (^/|(^|/)\.\.(/|$))
@@ -808,7 +737,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);
@@ -821,7 +750,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)) {
@@ -894,10 +823,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";
                     }
                 }
@@ -926,215 +854,6 @@
     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, ap_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 {
-            ap_bucket_brigade *bcgi;
-            ap_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 = ap_brigade_create(r->pool);
-            b = ap_bucket_create_pipe(file);
-            AP_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, ap_bucket_brigade **bb, request_rec *r,
-                       ap_filter_t *f, ap_bucket *head_ptr, ap_bucket **inserted_head)
-{
-    char *tag     = NULL;
-    char *tag_val = NULL;
-    char *file = r->filename;
-    ap_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 */
-                    ap_chdir_file(r->filename);
-                }
-                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);
-                    }
-                    ap_chdir_file(r->filename);
-                }
-                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, ap_bucket_brigade **bb, request_rec *r,
                        ap_filter_t *f, ap_bucket *head_ptr, ap_bucket **inserted_head)
@@ -1151,7 +870,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;
@@ -1219,7 +938,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. */
@@ -1229,20 +948,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;
@@ -1379,7 +1098,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;
@@ -1389,7 +1108,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];
 
@@ -1441,7 +1160,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;
@@ -1451,7 +1170,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;
 
@@ -1993,7 +1712,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;
@@ -2018,7 +1737,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));
@@ -2033,7 +1752,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));
@@ -2082,11 +1801,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));
@@ -2153,11 +1872,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));
@@ -2319,7 +2038,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,
@@ -2387,7 +2106,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");
                 
@@ -2455,7 +2174,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);
@@ -2488,7 +2207,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);
@@ -2519,7 +2238,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;
             }
@@ -2537,7 +2256,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));
             }
@@ -2560,7 +2279,7 @@
     ap_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;
@@ -3045,7 +2764,6 @@
     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);
Index: modules/filters/mod_include.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/filters/mod_include.h,v
retrieving revision 1.6
diff -u -r1.6 mod_include.h
--- modules/filters/mod_include.h	2000/12/20 16:43:37	1.6
+++ modules/filters/mod_include.h	2001/01/12 19:46:46
@@ -190,15 +190,21 @@
     }                                                             \
 }
 
-#define SPLIT_AND_PASS_PRETAG_BUCKETS(brgd, cntxt)               \
+#define SPLIT_AND_PASS_PRETAG_BUCKETS(brgd, cntxt, next)         \
 if ((AP_BRIGADE_EMPTY(cntxt->ssi_tag_brigade)) &&                \
     (cntxt->head_start_bucket != NULL)) {                        \
     ap_bucket_brigade *tag_plus;                                 \
                                                                  \
     tag_plus = ap_brigade_split(brgd, cntxt->head_start_bucket); \
-    ap_pass_brigade(f->next, brgd);                              \
+    ap_pass_brigade(next, brgd);                                 \
     brgd = tag_plus;                                             \
 }
+
+void ap_ssi_get_tag_and_value(include_ctx_t *ctx, char **tag,
+                              char **tag_val, int dodecode);
+
+void ap_ssi_parse_string(request_rec *r, const char *in, char *out,
+                         size_t length, int leave_name);
 
 typedef int (*handler)(include_ctx_t *ctx, ap_bucket_brigade **bb, 
                        request_rec *r, ap_filter_t *f, ap_bucket *head_ptr, 
Index: modules/generators/mod_cgi.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/generators/mod_cgi.c,v
retrieving revision 1.77
diff -u -r1.77 mod_cgi.c
--- modules/generators/mod_cgi.c	2001/01/08 23:54:52	1.77
+++ modules/generators/mod_cgi.c	2001/01/12 19:46:47
@@ -88,6 +88,7 @@
 #include "util_script.h"
 #include "ap_mpm.h"
 #include "http_conf_globals.h"
+#include "../filters/mod_include.h"
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
@@ -97,6 +98,19 @@
 
 module AP_MODULE_DECLARE_DATA cgi_module;
 
+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;
+    ap_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
@@ -310,21 +324,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
 
 
@@ -344,7 +389,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
@@ -357,10 +408,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
@@ -372,12 +423,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) {
@@ -391,20 +447,19 @@
             *script_in = procnew->out;
             if (!script_in)
                 return APR_EBADF;
-            apr_set_pipe_timeout(*script_in, 
-                                 (int)(r->server->timeout * APR_USEC_PER_SEC));
+            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));
-
-            *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);
@@ -513,6 +568,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;
@@ -597,9 +653,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;
@@ -720,9 +785,202 @@
     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,
+                       ap_bucket *head_ptr, ap_bucket **inserted_head)
+{
+    request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
+    int rr_status;
+    ap_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 = ap_bucket_create_immortal("<A HREF=\"", sizeof("<A HREF=\""));
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+        tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = ap_bucket_create_immortal("\">", sizeof("\">"));
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = ap_bucket_create_immortal("</A>", sizeof("</A>"));
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+
+        if (*inserted_head == NULL) {
+            *inserted_head = tmp_buck;
+        }
+    }
+
+    ap_destroy_sub_req(rr);
+    ap_chdir_file(r->filename);
+
+    return 0;
+}
+
+
+static int include_cmd(include_ctx_t *ctx, ap_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;
+    ap_bucket_brigade *bcgi;
+    ap_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 = ap_brigade_create(r->pool);
+    b = ap_bucket_create_pipe(script_in);
+    AP_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, ap_bucket_brigade **bb, request_rec *r,
+                       ap_filter_t *f, ap_bucket *head_ptr, ap_bucket **inserted_head)
+{
+    char *tag     = NULL;
+    char *tag_val = NULL;
+    char *file = r->filename;
+    ap_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) {
+                ap_ssi_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")) {
+                    ap_ssi_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 */
+                    ap_chdir_file(r->filename);
+                }
+                else if (!strcmp(tag, "cgi")) {
+                    ap_ssi_parse_string(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);
+                    }
+                    ap_chdir_file(r->filename);
+                }
+                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)
+{
+    /* Required by mod_include filter. This is how mod_cgi registers
+     *   with mod_include to provide processing of the exec directive.
+     */
+    ap_register_include_handler("exec", handle_exec);
+}
+
 static void register_hooks(void)
 {
     ap_hook_handler(cgi_handler, NULL, NULL, AP_HOOK_MIDDLE);
+    ap_hook_post_config(cgi_post_config, NULL, NULL, AP_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.59
diff -u -r1.59 mod_cgid.c
--- modules/generators/mod_cgid.c	2001/01/08 23:54:53	1.59
+++ modules/generators/mod_cgid.c	2001/01/12 19:46:48
@@ -91,6 +91,7 @@
 #include "http_conf_globals.h" 
 #include "ap_mpm.h"
 #include "unixd.h"
+#include "../filters/mod_include.h"
 #include <sys/stat.h>
 #ifdef HAVE_SYS_SOCKET_H
 #include <sys/socket.h>
@@ -107,6 +108,8 @@
 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, ap_bucket_brigade **bb, request_rec *r,
+                       ap_filter_t *f, ap_bucket *head_ptr, ap_bucket **inserted_head);
 
 static apr_pool_t *pcgi; 
 
@@ -130,6 +133,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
@@ -224,7 +230,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; 
@@ -234,6 +240,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' */
@@ -304,9 +311,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; 
 
@@ -317,28 +324,38 @@
         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"); 
-        }     
+    }     
 
     for (i = 0; env[i]; i++) { 
         data = apr_pstrcat(r->pool, data, env[i], "\n", NULL); 
     } 
     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 0
 #ifdef RLIMIT_CPU 
     if (conf->limit_cpu) { 
@@ -381,7 +398,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;
@@ -439,6 +456,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;
@@ -462,21 +483,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);
@@ -532,6 +561,11 @@
 #if APR_HAS_OTHER_CHILD
         apr_register_other_child(procnew, cgid_maint, NULL, NULL, p);
 #endif
+
+        /* Required by mod_include filter. This is how mod_cgid registers
+         *   with mod_include to provide processing of the exec directive.
+         */
+        ap_register_include_handler("exec", handle_exec);
     }
 } 
 
@@ -814,7 +848,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.
@@ -930,6 +964,257 @@
 
     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,
+                       ap_bucket *head_ptr, ap_bucket **inserted_head)
+{
+    request_rec *rr = ap_sub_req_lookup_uri(s, r, next);
+    int rr_status;
+    ap_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 = ap_bucket_create_immortal("<A HREF=\"", sizeof("<A HREF=\""));
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp_buck);
+        tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = ap_bucket_create_immortal("\">", sizeof("\">"));
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = ap_bucket_create_heap(location, len_loc, 1, &h_wrt);
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+        tmp2_buck = ap_bucket_create_immortal("</A>", sizeof("</A>"));
+        AP_BUCKET_INSERT_BEFORE(head_ptr, tmp2_buck);
+
+        if (*inserted_head == NULL) {
+            *inserted_head = tmp_buck;
+        }
+    }
+
+    ap_destroy_sub_req(rr);
+    ap_chdir_file(r->filename);
+
+    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, ap_bucket_brigade **bb, char *command,
+                       request_rec *r, ap_filter_t *f)
+{
+    char **env; 
+    const char *location; 
+    int sd;
+    int retval; 
+    ap_bucket_brigade *bcgi;
+    ap_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 = ap_brigade_create(r->pool);
+        b    = ap_bucket_create_pipe(tempsock);
+        AP_BRIGADE_INSERT_TAIL(bcgi, b);
+        ap_pass_brigade(f->next, bcgi);
+    } 
+
+    return 0;
+}
+
+static int handle_exec(include_ctx_t *ctx, ap_bucket_brigade **bb, request_rec *r,
+                       ap_filter_t *f, ap_bucket *head_ptr, ap_bucket **inserted_head)
+{
+    char *tag     = NULL;
+    char *tag_val = NULL;
+    char *file = r->filename;
+    ap_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) {
+                ap_ssi_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")) {
+                    ap_ssi_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 */
+                    ap_chdir_file(r->filename);
+                }
+                else if (!strcmp(tag, "cgi")) {
+                    ap_ssi_parse_string(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);
+                    }
+                    ap_chdir_file(r->filename);
+                }
+                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(void)
 {

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by rb...@covalent.net.
> By the way, mod_include will build and work without mod_cgi(d). This would
> make sense if the user didn't want any execing. 
> 
> As for the other way around (mod_cgi(d) without mod_include). Doesn't mod_include
> get built in by default. Under what conditions would someone build Apache
> with cgi support but not SSI support?
> 
> I realize you are concerned about a bigger more general problem, but does
> it really apply here?

Yes, it does apply here.  Take this example:

both mod_include and mod_cgi are shared objects.  All of a sudden,
mod_include MUST be loaded before mod_cgi.

As for the fact that mod_include is a default module, so is mod_cgi.  It
doesn't matter.  This is a bug that we can't release a beta with.  As
things stand now, the server works, even if we would like to see some
of the organization change.

Why is this an issue?  We are hoping to get the beta out the door VERY
quickly, so delaying the patch until we release the beta really shouldn't
be a big deal.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by "Paul J. Reder" <re...@raleigh.ibm.com>.
rbb@covalent.net wrote:
> 1)  This won't link unless both cgi(d) and include modules are
> present.

By the way, mod_include will build and work without mod_cgi(d). This would
make sense if the user didn't want any execing. 

As for the other way around (mod_cgi(d) without mod_include). Doesn't mod_include
get built in by default. Under what conditions would someone build Apache
with cgi support but not SSI support?

I realize you are concerned about a bigger more general problem, but does
it really apply here?

-- 
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

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by rb...@covalent.net.
> > I have reviewed this patch, and I am -1 for it's inclusion right now.  I
> > have two major problems with it.
> > 
> > 1)  This won't link unless both cgi(d) and include modules are
> > present.  Until we figure out how to allow a module to have a function
> > that other modules can call even if the module isn't there, this patch
> > can't go it.
> 
> I understand the concern, but this was the design that was decided upon on
> the list. In fact I had done an earlier implementation using hooks that
> I don't think would have this problem, but was requested to go with the
> direct call implementation instead.

This is the correct design, but it isn't complete.  The hook mechanism is
the wrong paradigm for this.  Besides, the hook solution was fixed with
the introduction of the generic hooks, so two weeks ago, even the hooks
wouldn't have worked.

> > 2)  We need to be in feature freeze.  This patch must wait until after the
> > beta.
> 
> I am not pleased about this. The code freeze is only hours old. This code
> was done a week ago but was held up because Apache wouldn't build and because
> the code had to be re-ported because of the hook changes (including the
> problems with AddHandler that I commented on). This was discussed and agreed
> to weeks ago, long before the code freeze was even discussed. I could also
> argue that this is not a new feature, though I would have a harder time
> arguing that this is just a bug fix ;).

This may not be a new feature, but it is much more than a bug fix, and it
has the potential to break the server.  In fact, it does break the server
when mod_include is not used but mod_cgi is.  If we add this now, we need
to solve the other problem as well.  We want to see a beta soon,
regardless of whether EVERYTHING is perfect or not.  This patch looks
good, but it is only half of the solution, and we can't apply this until
the other half is solved, or we definately break the server.

We will get this patch in, but it should wait until after the beta IMNSHO.

Ryan
_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by "Paul J. Reder" <re...@raleigh.ibm.com>.
rbb@covalent.net wrote:
> 
> I have reviewed this patch, and I am -1 for it's inclusion right now.  I
> have two major problems with it.
> 
> 1)  This won't link unless both cgi(d) and include modules are
> present.  Until we figure out how to allow a module to have a function
> that other modules can call even if the module isn't there, this patch
> can't go it.

I understand the concern, but this was the design that was decided upon on
the list. In fact I had done an earlier implementation using hooks that
I don't think would have this problem, but was requested to go with the
direct call implementation instead.

> 
> 2)  We need to be in feature freeze.  This patch must wait until after the
> beta.

I am not pleased about this. The code freeze is only hours old. This code
was done a week ago but was held up because Apache wouldn't build and because
the code had to be re-ported because of the hook changes (including the
problems with AddHandler that I commented on). This was discussed and agreed
to weeks ago, long before the code freeze was even discussed. I could also
argue that this is not a new feature, though I would have a harder time
arguing that this is just a bug fix ;).

> 
> Ryan

-- 
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

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by Ben Laurie <be...@algroup.co.uk>.
rbb@covalent.net wrote:
> The second problem is a bit different.  One module implements a function
> that another module uses.  This is the problem we are talking about
> here.  In this case, mod_include implements ap_register_include_handler,
> and mod_cgi(d) needs to use this function.

For those that don't watch CVS, I've just commited the code for
type-safe optional functions - see apr_optional.h and
mod_optional_fn_{im,ex}port.c.

I have _not_ done anything about making include/cgi use it. Out of time,
sorry.

Cheers,

Ben.

--
http://www.apache-ssl.org/ben.html

"There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit." - Robert Woodruff

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by rb...@covalent.net.
> > Okay, could you explain how this works if the module is built into the
> > core?  Would that just be part of the macro?
> 
> I don't think I understand the question. But probably it would be part
> of the macro, yes.
> 
> Ah. Ack. I presume that if we _don't_ use DSO, then the dso symbol
> lookup isn't going to work. So we're back to the idea of "reverse hooks"
> (and I promise I won't call them that!), with the function being
> registered in the core.

Yeah, basically, the dso_sym works if we can look in the mod_include.so
file, but if it is compiled into the core, then where do we look.  I guess
we could do a fall back, where we always start looking in mod_foo.so, and
if it isn't there, then we check httpd.  I'm not sure how I like that, but
since you have designed the whole thing so far, I leave this in your more
than capable hands Ben.  Thanks for taking this on.  :-)

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by Ben Laurie <be...@algroup.co.uk>.
rbb@covalent.net wrote:
> > Typesafety gets added by making foo a pointer to a function of
> > appropriate type! Again, we probably want to macro-ize that.
> 
> Okay, could you explain how this works if the module is built into the
> core?  Would that just be part of the macro?

I don't think I understand the question. But probably it would be part
of the macro, yes.

Ah. Ack. I presume that if we _don't_ use DSO, then the dso symbol
lookup isn't going to work. So we're back to the idea of "reverse hooks"
(and I promise I won't call them that!), with the function being
registered in the core.

Cheers,

Ben.

--
http://www.apache-ssl.org/ben.html

"There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit." - Robert Woodruff

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by rb...@covalent.net.
> > > So, moving on, I presume that there's a desire to avoid using the
> > > standard dl stuff to do this (i.e. dlsym()) - why? Shouldn't APR provide
> > > a facility to call (or not, as the case may be) a dynamically loaded
> > > function? Or is this something that tends to not be portable?
> > 
> > APR already provides apr_dso_sym.  I guess we could do something as simple
> > as:
> > 
> > if (modp = ap_find_linked_module("mod_include")) {
> >     apr_dso_sym(&foo, modp->dynamic_handle, "ap_register_include_handler");
> >     if (foo) {
> >         foo(....);
> >     }
> >     else {
> >         /* how do we get the symbol if the module was compiled into the
> >          * core?
> >          */
> >     }
> > }
> > 
> > That would probably work.  Now, we just throw that into a macro, and use
> > it.  Unfortunately, this removes type-saftey, doesn't it.  That was
> > something we were trying to avoid.
> 
> Typesafety gets added by making foo a pointer to a function of
> appropriate type! Again, we probably want to macro-ize that.

Okay, could you explain how this works if the module is built into the
core?  Would that just be part of the macro?  

> Where's Paul's patch? It'd help to know what I'm aiming at. Sadly it may
> not be today, I have to do stuff with the kids and I have a massive
> hangover, to boot.

Paul's patch was the very first message in this thread, and it was posted
to new-httpd.  If you still can't find it, let me know and I'll forward it
to you privately.  No worries about getting it done today.  If this patch
doesn't go in until after the beta, everything will still work.  All we
are doing is fixing a small hole that most people won't use anyway, so I'm
okay releasing a beta with this bug.  We can fix it immediately after the
beta.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------



Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by Ben Laurie <be...@algroup.co.uk>.
rbb@covalent.net wrote:
> 
> On Sat, 20 Jan 2001, Ben Laurie wrote:
> 
> > rbb@covalent.net wrote:
> > > The second problem is a bit different.  One module implements a function
> > > that another module uses.  This is the problem we are talking about
> > > here.  In this case, mod_include implements ap_register_include_handler,
> > > and mod_cgi(d) needs to use this function.
> >
> > Of course, one can bend generic hooks (that was a really stupid name
> 
> So change the name.  :-)  Nobody ever likes what I call things, I've
> gotten over it.  :-)

:-) Actually I am as much to blame as you on this one!

> > choice, btw) to do this: mod_cgi(d) creates a hook that mod_include
> > registers for. But this would be somewhat weird.
> >
> > So, moving on, I presume that there's a desire to avoid using the
> > standard dl stuff to do this (i.e. dlsym()) - why? Shouldn't APR provide
> > a facility to call (or not, as the case may be) a dynamically loaded
> > function? Or is this something that tends to not be portable?
> 
> APR already provides apr_dso_sym.  I guess we could do something as simple
> as:
> 
> if (modp = ap_find_linked_module("mod_include")) {
>     apr_dso_sym(&foo, modp->dynamic_handle, "ap_register_include_handler");
>     if (foo) {
>         foo(....);
>     }
>     else {
>         /* how do we get the symbol if the module was compiled into the
>          * core?
>          */
>     }
> }
> 
> That would probably work.  Now, we just throw that into a macro, and use
> it.  Unfortunately, this removes type-saftey, doesn't it.  That was
> something we were trying to avoid.

Typesafety gets added by making foo a pointer to a function of
appropriate type! Again, we probably want to macro-ize that.

> > If so, then I'd propose we do something just like generic hooks, only
> > the "other way round" - mod_include declares
> > ap_register_include_handler(), registers it with the core, which allows
> > it to be called by name (or resolved by name) when present, and use the
> > same kind of casting trick I used for generic hooks to render it
> > typesafe.
> 
> That was what I had originally envisioned, but I haven't really had the
> time to research the generic hooks, so I haven't done anything with it
> yet.  Please, please, please, if you have time today, pick one and
> implement it, then we can commit Paul's patch before the beta.  :-)

Where's Paul's patch? It'd help to know what I'm aiming at. Sadly it may
not be today, I have to do stuff with the kids and I have a massive
hangover, to boot.

Cheers,

Ben.

--
http://www.apache-ssl.org/ben.html

"There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit." - Robert Woodruff

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by rb...@covalent.net.
On Sat, 20 Jan 2001, Ben Laurie wrote:

> rbb@covalent.net wrote:
> > The second problem is a bit different.  One module implements a function
> > that another module uses.  This is the problem we are talking about
> > here.  In this case, mod_include implements ap_register_include_handler,
> > and mod_cgi(d) needs to use this function.
> 
> Of course, one can bend generic hooks (that was a really stupid name

So change the name.  :-)  Nobody ever likes what I call things, I've
gotten over it.  :-)

> choice, btw) to do this: mod_cgi(d) creates a hook that mod_include
> registers for. But this would be somewhat weird.
> 
> So, moving on, I presume that there's a desire to avoid using the
> standard dl stuff to do this (i.e. dlsym()) - why? Shouldn't APR provide
> a facility to call (or not, as the case may be) a dynamically loaded
> function? Or is this something that tends to not be portable?

APR already provides apr_dso_sym.  I guess we could do something as simple
as:

if (modp = ap_find_linked_module("mod_include")) {
    apr_dso_sym(&foo, modp->dynamic_handle, "ap_register_include_handler");
    if (foo) {
        foo(....);
    }
    else {
        /* how do we get the symbol if the module was compiled into the
         * core?
         */
    }
}

That would probably work.  Now, we just throw that into a macro, and use
it.  Unfortunately, this removes type-saftey, doesn't it.  That was
something we were trying to avoid.

> If so, then I'd propose we do something just like generic hooks, only
> the "other way round" - mod_include declares
> ap_register_include_handler(), registers it with the core, which allows
> it to be called by name (or resolved by name) when present, and use the
> same kind of casting trick I used for generic hooks to render it
> typesafe.

That was what I had originally envisioned, but I haven't really had the
time to research the generic hooks, so I haven't done anything with it
yet.  Please, please, please, if you have time today, pick one and
implement it, then we can commit Paul's patch before the beta.  :-)

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------


Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by Ben Laurie <be...@algroup.co.uk>.
rbb@covalent.net wrote:
> The second problem is a bit different.  One module implements a function
> that another module uses.  This is the problem we are talking about
> here.  In this case, mod_include implements ap_register_include_handler,
> and mod_cgi(d) needs to use this function.

Of course, one can bend generic hooks (that was a really stupid name
choice, btw) to do this: mod_cgi(d) creates a hook that mod_include
registers for. But this would be somewhat weird.

So, moving on, I presume that there's a desire to avoid using the
standard dl stuff to do this (i.e. dlsym()) - why? Shouldn't APR provide
a facility to call (or not, as the case may be) a dynamically loaded
function? Or is this something that tends to not be portable?

If so, then I'd propose we do something just like generic hooks, only
the "other way round" - mod_include declares
ap_register_include_handler(), registers it with the core, which allows
it to be called by name (or resolved by name) when present, and use the
same kind of casting trick I used for generic hooks to render it
typesafe.

Cheers,

Ben.

--
http://www.apache-ssl.org/ben.html

"There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit." - Robert Woodruff

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by rb...@covalent.net.
> > I have reviewed this patch, and I am -1 for it's inclusion right now.  I
> > have two major problems with it.
> > 
> > 1)  This won't link unless both cgi(d) and include modules are
> > present.  Until we figure out how to allow a module to have a function
> > that other modules can call even if the module isn't there, this patch
> > can't go it.
> 
> What? Isn't that what my hooks stuff did?

Close.  There were two problems, you solved the second.  :-)  The problem
you solved, is that one module needs to be able to implement a hook that
another module is going to use.  For example, in EAPI mod_SSL implements a
hook that mod_proxy uses.

The second problem is a bit different.  One module implements a function
that another module uses.  This is the problem we are talking about
here.  In this case, mod_include implements ap_register_include_handler,
and mod_cgi(d) needs to use this function.

Ryan

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------



Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by Ben Laurie <be...@algroup.co.uk>.
rbb@covalent.net wrote:
> 
> I have reviewed this patch, and I am -1 for it's inclusion right now.  I
> have two major problems with it.
> 
> 1)  This won't link unless both cgi(d) and include modules are
> present.  Until we figure out how to allow a module to have a function
> that other modules can call even if the module isn't there, this patch
> can't go it.

What? Isn't that what my hooks stuff did?

Cheers,

Ben.

--
http://www.apache-ssl.org/ben.html

"There is no limit to what a man can do or how far he can go if he
doesn't mind who gets the credit." - Robert Woodruff

Re: [Patch]:Move SSI "exec" directive support from mod_include to mod_cgi(d).

Posted by rb...@covalent.net.
I have reviewed this patch, and I am -1 for it's inclusion right now.  I
have two major problems with it.

1)  This won't link unless both cgi(d) and include modules are
present.  Until we figure out how to allow a module to have a function
that other modules can call even if the module isn't there, this patch
can't go it.

2)  We need to be in feature freeze.  This patch must wait until after the
beta.

Ryan

On Fri, 12 Jan 2001, Paul J. Reder wrote:

> The following patch moves the "exec cgi" and "exec cmd" logic from mod_include
> to mod_cgi and mod_cgid. As much duplicate code as possible was removed in the
> process.
> 
> We now have the first example of an external module registering as an SSI
> directive handler with the mod_include code.
> 
> This patch is based from the CVS repository as of 1/11/2001 around noon.
> 
> The only thing I'm not sure of is what the preferred way to include the
> mod_include.h file in mod_cgi(d).c.

_______________________________________________________________________________
Ryan Bloom                        	rbb@apache.org
406 29th St.
San Francisco, CA 94131
-------------------------------------------------------------------------------