httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From r..@covalent.net
Subject Add hook to get server read.
Date Thu, 11 May 2000 17:54:10 GMT

Okay, so I am posting this because it is a relatively large patch.  I
would like to commit this ASAP before too much other stuff
changes.  Basically, this patch allows module authors to hook into the
config file read stage.  Module authors declare that their variables
should be EXEC_ON_READ, and when that directive is read, the associated
function is called.  This should only be done for directives that modify
how the server interprets the config, not for modifying the tree
itself.  For example, in this patch, I have got LoadModule, AddModule,
ClearModuleList, IfModule and IfDefine as EXEC_ON_READ.  The
Load/Add/Clear Module stuff should just make sense.  If the modules aren't
included in the server, the server doesn't understand all of the
directives.  The IfModule and IfDefine are EXEC_ON_READ because We really
don't want the things inside those containers in the config if the
statement is false.

This is also how mod_perl will hook things for the <perl>
directive.  Basically, <perl> will be EXEC_ON_READ, so when this is hit,
mod_perl takes over and reads from the config file until </perl>, and this
whole section of the file _should_ be put into the tree as raw
text.  Then, during the walk phase, mod_perl converts the perl code into
actual Apache directives.

If you want external config parsers, then your whole config becomes:

ReadExternalConfig "foobar"

And the ReadExternalConfig directive would be EXEC_ON_READ.  This
directive is not implemented anywhere, but it is allowed for since some
people seem to like this approach.

Please, make comments quickly, because I am likely to commit quickly if
too many other changes start going into the tree.

Ryan

? src/main/.http_core.c.swp
Index: src/CHANGES
===================================================================
RCS file: /home/cvs/apache-2.0/src/CHANGES,v
retrieving revision 1.109
diff -u -d -b -w -u -r1.109 CHANGES
--- src/CHANGES	2000/05/11 20:25:38	1.109
+++ src/CHANGES	2000/05/11 20:46:36
@@ -1,8 +1,21 @@
+<<<<<<< CHANGES
+Changes with Apache 2.0a4-dev
+  *) Add the ability to hook into the config file reading phase.  Basically
+     if a directive is specified EXEC_ON_READ, then when that directive is
+     read from the config file, the assocaited function is executed.  This
+     should only be used for those directives that must muck with HOW the
+     server INTERPRETS the config.  This should not be used for directives
+     that re-order or replace items in the config tree.  Those changes should
+     be made in the pre-config step.
+     [Ryan Bloom]
+
+=======
 Changes with Apache 2.0a4
 
   *) Add mod_example to the build system.
      [Tony Finch]
 
+>>>>>>> 1.109
   *) APR: Add ap_xlate_conv_byte() to convert one char between single-
      byte character sets. [Jeff Trawick]
 
Index: src/include/http_config.h
===================================================================
RCS file: /home/cvs/apache-2.0/src/include/http_config.h,v
retrieving revision 1.18
diff -u -d -b -w -u -r1.18 http_config.h
--- src/include/http_config.h	2000/04/26 07:14:30	1.18
+++ src/include/http_config.h	2000/05/11 20:46:36
@@ -135,6 +135,7 @@
 #define OR_UNSET 32
 #define ACCESS_CONF 64
 #define RSRC_CONF 128
+#define EXEC_ON_READ 256
 #define OR_ALL (OR_LIMIT|OR_OPTIONS|OR_FILEINFO|OR_AUTHCFG|OR_INDEXES)
 
 /* This can be returned by a function if they don't wish to handle
@@ -144,6 +145,16 @@
 
 #define DECLINE_CMD "\a\b"
 
+/* Common structure for reading of config files / passwd files etc. */
+typedef struct {
+    int (*getch) (void *param);	/* a getc()-like function */
+    void *(*getstr) (void *buf, size_t bufsiz, void *param); /* a fgets()-like function */
+    int (*close) (void *param);	/* a close hander function */
+    void *param;		/* the argument passed to getch/getstr/close */
+    const char *name;		/* the filename / description */
+    unsigned line_number;	/* current line number, starting at 1 */
+} configfile_t;
+
 /*
  * This structure is passed to a command which is being invoked,
  * to carry a large variety of miscellaneous data which is all of
@@ -155,6 +166,7 @@
     int override;		/* Which allow-override bits are set */
     int limited;		/* Which methods are <Limit>ed */
 
+    configfile_t *config_file;  /* Config file structure. */
     ap_directive_t *directive;	/* the directive specifying this command */
 
     ap_pool_t *pool;			/* Pool to allocate new storage in */
@@ -304,16 +316,6 @@
 API_EXPORT(const char *) ap_find_module_name(module *m);
 API_EXPORT(module *) ap_find_linked_module(const char *name);
 
-/* Common structure for reading of config files / passwd files etc. */
-typedef struct {
-    int (*getch) (void *param);	/* a getc()-like function */
-    void *(*getstr) (void *buf, size_t bufsiz, void *param); /* a fgets()-like function */
-    int (*close) (void *param);	/* a close hander function */
-    void *param;		/* the argument passed to getch/getstr/close */
-    const char *name;		/* the filename / description */
-    unsigned line_number;	/* current line number, starting at 1 */
-} configfile_t;
-
 /* Open a configfile_t as FILE, return open configfile_t struct pointer */
 API_EXPORT(ap_status_t) ap_pcfg_openfile(configfile_t **, ap_pool_t *p, const char *name);
 
@@ -334,7 +336,7 @@
 API_EXPORT(int) ap_cfg_closefile(configfile_t *cfp);
 
 /* for implementing subconfigs and customized config files */
-API_EXPORT(const char *) ap_build_config(configfile_t *cfp,
+API_EXPORT(const char *) ap_build_config(cmd_parms *parms,
 					 ap_pool_t *conf_pool,
 					 ap_pool_t *temp_pool,
 					 ap_directive_t **conftree);
Index: src/main/http_config.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/http_config.c,v
retrieving revision 1.45
diff -u -d -b -w -u -r1.45 http_config.c
--- src/main/http_config.c	2000/05/09 22:46:03	1.45
+++ src/main/http_config.c	2000/05/11 20:46:41
@@ -831,15 +831,80 @@
     return mconfig;
 }
 
+static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, 
+                         ap_pool_t *p, ap_pool_t *ptempi,
+                         ap_directive_t **sub_tree, ap_directive_t *parent);
+
+static const char * ap_build_cont_config(ap_pool_t *p, ap_pool_t *temp_pool,
+					cmd_parms *parms,
+					ap_directive_t **current,
+					ap_directive_t **curr_parent,
+                                        char *orig_directive)
+{
+    const char *args;
+    char l[MAX_STRING_LEN];
+    char *cmd_name;
+    ap_directive_t *newdir;
+
+    while(!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
+#if RESOLVE_ENV_PER_TOKEN
+        args = l;
+#else
+        args = ap_resolve_env(parms->temp_pool, l);
+#endif
+        cmd_name = ap_getword_conf(parms->pool, &args);
+        if (cmd_name[0] == '<') {
+            if (cmd_name[1] != '/') {
+                (*current) = ap_add_node(curr_parent, *current, newdir, 1);
+            }
+	    else {
+	        char *bracket = ap_pstrcat(p, orig_directive + 1, ">", NULL);
+
+	        if (cmd_name[strlen(cmd_name) - 1] != '>') {
+		    return ap_pstrcat(p, cmd_name,
+				  "> directive missing closing '>'", NULL);
+	        }
+                
+	        if (strcasecmp(cmd_name + 2,
+			    bracket) != 0) {
+		    return ap_pstrcat(p, "Expected </",
+				  orig_directive + 1, "> but saw ",
+				  cmd_name, NULL);
+	        }
+
+	        /* done with this section; move up a level */
+                if (*curr_parent == NULL) {
+                    /* We are just building a sub tree, so once we hit this 
+                     * we should return.
+                     */
+                    return NULL;
+                }
+                *current = *curr_parent;
+                *curr_parent = (*current)->parent;
+            }
+        }
+        else {
+            newdir = ap_pcalloc(p, sizeof(ap_directive_t));
+            newdir->filename = parms->config_file->name;
+            newdir->line_num = parms->config_file->line_number;
+            newdir->directive = cmd_name;
+            newdir->args = ap_pstrdup(p, args);
+
+            *current = ap_add_node(curr_parent, *current, newdir, 0);
+        }
+    }
+}
+
 static const char * ap_build_config_sub(ap_pool_t *p, ap_pool_t *temp_pool,
-					const configfile_t *cfp,
-					const char *l,
+					const char *l, cmd_parms *parms,
 					ap_directive_t **current,
 					ap_directive_t **curr_parent)
 {
     const char *args;
     char *cmd_name;
     ap_directive_t *newdir;
+    module *mod = top_module;
+    const command_rec *cmd;
 
     if (*l == '#' || *l == '\0')
 	return NULL;
@@ -857,9 +922,24 @@
 	return NULL;
     }
 
+    if (cmd = ap_find_command_in_modules(cmd_name, &mod)) {
+        if (cmd->req_override & EXEC_ON_READ) {
+            const char *retval;
+            ap_directive_t *sub_tree = NULL;
+
+            retval = execute_now(cmd_name, args, parms, p, temp_pool, 
+                                 &sub_tree, *curr_parent);
+            (*current)->next = sub_tree;
+            while ((*current)->next != NULL) {
+                (*current) = (*current)->next;
+            }
+            return retval;
+        }
+    }
+
     newdir = ap_pcalloc(p, sizeof(ap_directive_t));
-    newdir->filename = cfp->name;
-    newdir->line_num = cfp->line_number;
+    newdir->filename = parms->config_file->name;
+    newdir->line_num = parms->config_file->line_number;
     newdir->directive = cmd_name;
     newdir->args = ap_pstrdup(p, args);
 
@@ -956,7 +1036,7 @@
 }
 
 
-API_EXPORT(const char *) ap_build_config(configfile_t *cfp,
+API_EXPORT(const char *) ap_build_config(cmd_parms *parms,
 					 ap_pool_t *p, ap_pool_t *temp_pool,
 					 ap_directive_t **conftree)
 {
@@ -967,9 +1047,9 @@
 
     *conftree = NULL;
 
-    while (!(ap_cfg_getline(l, MAX_STRING_LEN, cfp))) {
+    while (!(ap_cfg_getline(l, MAX_STRING_LEN, parms->config_file))) {
 
-	errmsg = ap_build_config_sub(p, temp_pool, cfp, l,
+	errmsg = ap_build_config_sub(p, temp_pool, l, parms,
 				     &current, &curr_parent);
 	if (errmsg != NULL)
 	    return errmsg;
@@ -1064,6 +1144,71 @@
     return ap_make_full_path(p, ap_server_root, file);
 }
 
+API_EXPORT(const char *) ap_soak_end_container(cmd_parms *cmd, char *directive)
+{
+    char l[MAX_STRING_LEN];
+    const char *args;
+    char *cmd_name;
+
+    while(!(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) {
+#if RESOLVE_ENV_PER_TOKEN
+        args = l;
+#else
+        args = ap_resolve_env(cmd->temp_pool, l);
+#endif
+        cmd_name = ap_getword_conf(cmd->pool, &args);
+        if (cmd_name[0] == '<') {
+            if (cmd_name[1] == '/') {
+                char *bracket = '\0';
+                if (strcasecmp(cmd_name + 2,
+                                directive + 1) != 0) {
+                    return ap_pstrcat(cmd->pool, "Expected </",
+                                      directive + 1, "> but saw ",
+                                      cmd_name, ">", NULL);
+                }
+                break;
+            }
+            else {
+                ap_soak_end_container(cmd, cmd_name);
+            }
+        }
+    }
+}
+
+static const char *execute_now(char *cmd_line, const char *args, cmd_parms *parms, 
+                         ap_pool_t *p, ap_pool_t *ptemp, 
+                         ap_directive_t **sub_tree, ap_directive_t *parent)
+{
+    module *mod = top_module;
+    const command_rec *cmd;
+
+    if (!(cmd = ap_find_command_in_modules(cmd_line, &mod))) {
+        return ap_pstrcat(parms->pool, "Invalid command '", 
+                          cmd_line,
+                          "', perhaps mis-spelled or defined by a module "
+                          "not included in the server configuration",
+                          NULL);
+    }
+    else {
+        void *mconfig = ap_set_config_vectors(parms, 
+                                parms->server->lookup_defaults, mod);
+        const char *retval;
+
+        retval = invoke_cmd(cmd, parms, mconfig, args);
+        if (retval == NULL) {
+            int one = 1;
+            if (*(int *)mconfig == 1) {
+                return ap_build_cont_config(p, ptemp, parms, sub_tree, &parent, cmd_line);
+            }
+            else {
+                ap_soak_end_container(parms, cmd_line);
+                return retval;
+            }
+        }
+        if (strcmp(retval, DECLINE_CMD) != 0)
+            return retval;
+        }
+}
 
 /* This structure and the following functions are needed for the
  * table-based config file reading. They are passed to the
@@ -1112,7 +1257,6 @@
     cmd_parms parms;
     arr_elts_param_t arr_parms;
     ap_directive_t *conftree;
-    configfile_t *cfp;
 
     arr_parms.curr_idx = 0;
     arr_parms.array = arr;
@@ -1123,11 +1267,11 @@
     parms.server = s;
     parms.override = (RSRC_CONF | OR_ALL) & ~(OR_AUTHCFG | OR_LIMIT);
 
-    cfp = ap_pcfg_open_custom(p, "-c/-C directives",
+    parms.config_file = ap_pcfg_open_custom(p, "-c/-C directives",
 			      &arr_parms, NULL,
 			      arr_elts_getstr, arr_elts_close);
 
-    errmsg = ap_build_config(cfp, p, ptemp, &conftree);
+    errmsg = ap_build_config(&parms, p, ptemp, &conftree);
     if (errmsg == NULL)
 	errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults);
     if (errmsg) {
@@ -1136,7 +1280,7 @@
         exit(1);
     }
 
-    ap_cfg_closefile(cfp);
+    ap_cfg_closefile(parms.config_file);
 }
 
 void ap_process_resource_config(server_rec *s, const char *fname, ap_pool_t *p, ap_pool_t
*ptemp)
@@ -1171,7 +1315,8 @@
 	exit(1);
     }
 
-    errmsg = ap_build_config(cfp, p, ptemp, &conftree);
+    parms.config_file = cfp;
+    errmsg = ap_build_config(&parms, p, ptemp, &conftree);
     if (errmsg == NULL)
 	errmsg = ap_walk_config(conftree, &parms, s->lookup_defaults);
 
@@ -1228,7 +1373,8 @@
 
             dc = ap_create_per_dir_config(r->pool);
 
-            errmsg = ap_build_config(f, r->pool, r->pool, &conftree);
+            parms.config_file = f;
+            errmsg = ap_build_config(&parms, r->pool, r->pool, &conftree);
 	    if (errmsg == NULL)
 		errmsg = ap_walk_config(conftree, &parms, dc);
 
Index: src/main/http_core.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/main/http_core.c,v
retrieving revision 1.56
diff -u -d -b -w -u -r1.56 http_core.c
--- src/main/http_core.c	2000/05/11 02:32:05	1.56
+++ src/main/http_core.c	2000/05/11 20:46:41
@@ -1539,6 +1539,7 @@
 {
     char *endp = strrchr(arg, '>');
     int not = (arg[0] == '!');
+    int one = 1;
     module *found;
 
     if (endp == NULL) {
@@ -1554,8 +1555,14 @@
     found = ap_find_linked_module(arg);
 
     if ((!not && found) || (not && !found)) {
-        return ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
+        *(int *)dummy = one;
+        return NULL;
     }
+    else { 
+        one = 0;
+        *(int *)dummy = one;
+        return NULL;
+    }
 
     return NULL;
 }
@@ -1578,6 +1585,7 @@
 {
     char *endp;
     int defined;
+    int one = 1;
     int not = 0;
 
     endp = strrchr(arg, '>');
@@ -1593,10 +1601,15 @@
     }
 
     defined = ap_exists_config_define(arg);
-
     if ((!not && defined) || (not && !defined)) {
-        return ap_walk_config(cmd->directive->first_child, cmd, cmd->context);
+        *(int *)dummy = one;
+        return NULL;
     }
+    else {
+        one = 0;
+        *(int *)dummy = one;
+        return NULL;
+    }
 
     return NULL;
 }
@@ -2162,9 +2175,9 @@
 { "<LimitExcept", ap_limit_section, (void*)1, OR_ALL, RAW_ARGS,
   "Container for authentication directives to be applied when any HTTP "
   "method other than those specified is used to access the resource" },
-{ "<IfModule", start_ifmod, NULL, OR_ALL, TAKE1,
+{ "<IfModule", start_ifmod, NULL, EXEC_ON_READ | OR_ALL, TAKE1,
   "Container for directives based on existance of specified modules" },
-{ "<IfDefine", start_ifdefine, NULL, OR_ALL, TAKE1,
+{ "<IfDefine", start_ifdefine, NULL, EXEC_ON_READ | OR_ALL, TAKE1,
   "Container for directives based on existance of command line defines" },
 { "<DirectoryMatch", dirsection, (void*)1, RSRC_CONF, RAW_ARGS,
   "Container for directives affecting resources located in the "
@@ -2245,10 +2258,10 @@
   RSRC_CONF|ACCESS_CONF, TAKE1,
   "How to work out the ServerName : Port when constructing URLs" },
 /* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
-{ "AddModule", add_module_command, NULL, RSRC_CONF, ITERATE,
+{ "AddModule", add_module_command, NULL, RSRC_CONF | EXEC_ON_READ, ITERATE,
   "The name of a module" },
-{ "ClearModuleList", clear_module_list_command, NULL, RSRC_CONF, NO_ARGS, 
-  NULL },
+{ "!ClearModuleList", clear_module_list_command, NULL, RSRC_CONF | EXEC_ON_READ,
+  NO_ARGS, NULL },
 /* TODO: ListenBacklog in MPM */
 { "Include", include_config, NULL, (RSRC_CONF | ACCESS_CONF), TAKE1,
   "Name of the config file to be included" },
Index: src/modules/standard/mod_so.c
===================================================================
RCS file: /home/cvs/apache-2.0/src/modules/standard/mod_so.c,v
retrieving revision 1.14
diff -u -d -b -w -u -r1.14 mod_so.c
--- src/modules/standard/mod_so.c	2000/04/27 04:15:48	1.14
+++ src/modules/standard/mod_so.c	2000/05/11 20:46:42
@@ -349,7 +349,7 @@
 #endif /* NO_DLOPEN */
 
 static const command_rec so_cmds[] = {
-    { "LoadModule", load_module, NULL, RSRC_CONF, TAKE2,
+    { "LoadModule", load_module, EXEC_ON_READ, RSRC_CONF, TAKE2,
       "a module name and the name of a shared object file to load it from"},
     { "LoadFile", load_file, NULL, RSRC_CONF, ITERATE,
       "shared object file or library to load into the server at runtime"},


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


Mime
View raw message