You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by Rodent of Unusual Size <co...@hyperreal.com> on 1997/05/05 12:47:10 UTC
cvs commit: apache/src/modules/example mod_example.c
coar 97/05/05 03:47:09
Modified: src/modules/example mod_example.c
Log:
Latest cure for memory bloat; some additional documentation about
read-only nature of module configuration records and command-handler
return values; display broken into `static' and `this-request'
segments.
Revision Changes Path
1.9 +201 -60 apache/src/modules/example/mod_example.c
Index: mod_example.c
===================================================================
RCS file: /export/home/cvs/apache/src/modules/example/mod_example.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -C3 -r1.8 -r1.9
*** mod_example.c 1997/04/22 15:52:06 1.8
--- mod_example.c 1997/05/05 10:47:08 1.9
***************
*** 83,88 ****
--- 83,94 ----
* both, though, so the handlers need to be able to tell them apart. One
* possibility is for both structures to start with an int which is zero for
* one and 1 for the other.
+ *
+ * Note that while the per-directory and per-server configuration records are
+ * available to most of the module handlers, they should be treated as
+ * READ-ONLY by all except the command and merge handlers. Sometimes handlers
+ * are handed a record that applies to the current location by implication or
+ * inheritance, and modifying it will change the rules for other locations.
*/
typedef struct example_config {
int cmode; /* Environment to which record applies (directory, */
***************
*** 99,107 ****
/*
* Let's set up a module-local static cell to point to the accreting callback
* trace. As each API callback is made to us, we'll tack on the particulars
! * to whatever we've already recorded.
*/
static char *trace = NULL;
/*
* To avoid leaking memory from pools other than the per-request one, we
--- 105,117 ----
/*
* Let's set up a module-local static cell to point to the accreting callback
* trace. As each API callback is made to us, we'll tack on the particulars
! * to whatever we've already recorded. To avoid massive memory bloat as
! * directories are walked again and again, we record the routine/environment
! * the first time (non-request context only), and ignore subsequent calls for
! * the same routine/environment.
*/
static char *trace = NULL;
+ static table *static_calls_made = NULL;
/*
* To avoid leaking memory from pools other than the per-request one, we
***************
*** 261,296 ****
}
/*
! * This routine is used to add a trace of a callback to the list. We're
! * passed the server record (if available), an allocation pool, a pointer to
! * our private configuration record (if available) for the environment to
! * which the callback is supposed to apply, and some text. We turn this into
! * a textual representation and add it to the tail of the list. The list can
! * be displayed by the example_handler() routine.
*/
! static void trace_add
! (server_rec *s, example_config *mconfig, const char *note) {
! char *sofar;
! char *addon;
! char *where;
! pool *subpool;
/*
! * Make a new sub-pool and copy any existing trace to it.
*/
! subpool = make_sub_pool (example_pool);
! if (trace != NULL) {
! addon = pstrcat (subpool, trace, NULL);
! }
/*
! * Now, if we have a sub-pool from before, nuke it and replace with the
! * one we just allocated.
*/
! if (example_subpool != NULL) {
! destroy_pool (example_subpool);
}
- example_subpool = subpool;
/*
* If we weren't passed a configuration record, we can't figure out to
* what location this call applies. This only happens for co-routines
--- 271,405 ----
}
/*
! * Likewise for our configuration record for the specified request.
*/
! static example_config *our_rconfig
! (request_rec *r) {
! return (example_config *) get_module_config
! (
! r->request_config,
! &example_module
! );
! }
+ /*
+ * This routine sets up some module-wide cells if they haven't been already.
+ */
+ static void setup_module_cells () {
/*
! * If we haven't already allocated our module-private pool, do so now.
*/
! if (example_pool == NULL) {
! example_pool = make_sub_pool (NULL);
! };
/*
! * Likewise for the table of routine/environment pairs we visit outside of
! * request context.
*/
! if (static_calls_made == NULL) {
! static_calls_made = make_table (example_pool, 16);
! };
! }
!
! /*
! * This routine is used to add a trace of a callback to the list. We're
! * passed the server record (if available), the request record (if available),
! * a pointer to our private configuration record (if available) for the
! * environment to which the callback is supposed to apply, and some text. We
! * turn this into a textual representation and add it to the tail of the list.
! * The list can be displayed by the example_handler() routine.
! *
! * If the call occurs within a request context (i.e., we're passed a request
! * record), we put the trace into the request pool and attach it to the
! * request via the request_config mechanism. Otherwise, the trace gets added
! * to the static (non-request-specific) list.
! *
! * Note that this method is not a formal part of the API. The use of the
! * request_config field in the request_rec record is not currently defined.
! * However, the only defined method of maintaining per-request information,
! * the r->notes table, is string-oriented and can't conveniently handle
! * arbitrary data.
! *
! * In any other context, what we're doing here - accessing components outside
! * our scope, like the main request - would be considered a technical
! * violation of the API. However, we can do what we want with undefined
! * aspects, as long as we're prepared for them to have undefined results.
! */
! static void trace_add
! (server_rec *s, request_rec *r, example_config *mconfig,
! const char *note) {
!
! char *sofar;
! char *addon;
! char *where;
! pool *p;
! char **ctrace;
! request_rec
! *req = r;
! example_config
! *rconfig;
!
! /*
! * Make sure our pools and tables are set up - we need 'em.
! */
! setup_module_cells ();
! /*
! * Now, if we're in request-context, we use the request pool.
! */
! if (r != NULL) {
! /*
! * Make sure that we're storing our trace in the main request; we want
! * to track all activities for subrequests as well.
! */
! if (req->main != NULL) {
! req = req->main;
! }
! p = req->pool;
! /*
! * Find our per-request configuration record, which holds the trace
! * of activities specific to the request itself.
! */
! rconfig = (example_config *) get_module_config
! (req->request_config, &example_module);
! /*
! * If there isn't one, create one and add it.
! */
! if (rconfig == NULL) {
! rconfig = pcalloc (req->pool, sizeof(example_config));
! set_module_config (req->request_config, &example_module, rconfig);
! rconfig->trace = NULL;
! }
! /*
! * Note that the trace data from this call go into the per-request
! * list, not the static one.
! */
! ctrace = &rconfig->trace;
! } else {
! /*
! * We're not in request context, so the trace gets attached to our
! * module-wide pool. We do the create/destroy every time we're called
! * in non-request context; this avoids leaking memory in some of
! * the subsequent calls that allocate memory only once (such as the
! * key formation below).
! *
! * Make a new sub-pool and copy any existing trace to it. Point the
! * trace cell at the copied value.
! */
! p = make_sub_pool (example_pool);
! if (trace != NULL) {
! trace = pstrdup (p, trace);
! }
! /*
! * Now, if we have a sub-pool from before, nuke it and replace with
! * the one we just allocated.
! */
! if (example_subpool != NULL) {
! destroy_pool (example_subpool);
! }
! example_subpool = p;
! ctrace = &trace;
}
/*
* If we weren't passed a configuration record, we can't figure out to
* what location this call applies. This only happens for co-routines
***************
*** 300,308 ****
*/
where = (mconfig != NULL) ? mconfig->loc : "nowhere";
where = (where != NULL) ? where : "";
addon = pstrcat
(
! subpool,
" <LI>\n",
" <DL>\n",
" <DT><SAMP>",
--- 409,439 ----
*/
where = (mconfig != NULL) ? mconfig->loc : "nowhere";
where = (where != NULL) ? where : "";
+ /*
+ * Now, if we're not in request context, see if we've been called with
+ * this particular combination before. The table is allocated in the
+ * module's private pool, which doesn't get destroyed.
+ */
+ if (req == NULL) {
+ char *key;
+
+ key = pstrcat (p, note, ":", where, NULL);
+ if (table_get (static_calls_made, key) != NULL) {
+ /*
+ * Been here, done this.
+ */
+ return;
+ } else {
+ /*
+ * First time for this combination of routine and environment -
+ * log it so we don't do it again.
+ */
+ table_set (static_calls_made, key, "been here");
+ }
+ }
addon = pstrcat
(
! p,
" <LI>\n",
" <DL>\n",
" <DT><SAMP>",
***************
*** 317,332 ****
" </LI>\n",
NULL
);
! sofar = (trace == NULL) ? "" : trace;
! trace = pstrcat (subpool, sofar, addon, NULL);
! /*
! * Store a copy of the same information in the configuration record, if
! * there is one.
! */
! if (mconfig != NULL) {
! sofar = (mconfig->trace == NULL) ? "" : mconfig->trace;
! mconfig->trace = pstrcat (subpool, sofar, addon, NULL);
! }
/*
* You *could* uncomment the following if you wanted to see the calling
* sequence reported in the server's error_log, but beware - almost all of
--- 448,455 ----
" </LI>\n",
NULL
);
! sofar = (*ctrace == NULL) ? "" : *ctrace;
! *ctrace = pstrcat (p, sofar, addon, NULL);
/*
* You *could* uncomment the following if you wanted to see the calling
* sequence reported in the server's error_log, but beware - almost all of
***************
*** 341,347 ****
}
/*--------------------------------------------------------------------------*/
- /* */
/* We prototyped the various syntax for command handlers (routines that */
/* are called when the configuration parser detects a directive declared */
/* by our module) earlier. Now we actually declare a "real" routine that */
--- 464,469 ----
***************
*** 351,356 ****
--- 473,485 ----
/* If a command handler encounters a problem processing the directive, it */
/* signals this fact by returning a non-NULL pointer to a string */
/* describing the problem. */
+ /* */
+ /* The magic return value DECLINE_CMD is used to deal with directives */
+ /* that might be declared by multiple modules. If the command handler */
+ /* returns NULL, the directive was processed; if it returns DECLINE_CMD, */
+ /* the next module (if any) that declares the directive is given a chance */
+ /* at it. If it returns any other value, it's treated as the text of an */
+ /* error message. */
/*--------------------------------------------------------------------------*/
/*
* Command handler for the NO_ARGS "Example" directive. All we do is mark the
***************
*** 367,373 ****
* "Example Wuz Here"
*/
cfg->local = 1;
! trace_add (cmd->server, cfg, "cmd_example()");
return NULL;
}
--- 496,502 ----
* "Example Wuz Here"
*/
cfg->local = 1;
! trace_add (cmd->server, NULL, cfg, "cmd_example()");
return NULL;
}
***************
*** 399,408 ****
(request_rec *r) {
example_config
! *cfg;
! cfg = our_dconfig (r);
! trace_add (r->server, cfg, "example_handler()");
/*
* We're about to start sending content, so we need to force the HTTP
* headers to be sent at this point. Otherwise, no headers will be sent
--- 528,540 ----
(request_rec *r) {
example_config
! *dcfg;
! example_config
! *rcfg;
! dcfg = our_dconfig (r);
! rcfg = our_rconfig (r);
! trace_add (r->server, r, dcfg, "example_handler()");
/*
* We're about to start sending content, so we need to force the HTTP
* headers to be sent at this point. Otherwise, no headers will be sent
***************
*** 461,481 ****
rputs (" indicates a location in the URL or filesystem\n", r);
rputs (" namespace.\n", r);
rputs (" </P>\n", r);
! rprintf (r, " <H2>Callbacks so far:</H2>\n <OL>\n%s </OL>\n", trace);
rputs (" <H2>Environment for <EM>this</EM> call:</H2>\n", r);
rputs (" <UL>\n", r);
! rprintf (r, " <LI>Applies-to: <SAMP>%s</SAMP>\n </LI>\n", cfg->loc);
rprintf
(
r,
" <LI>\"Example\" directive declared here: %s\n </LI>\n",
! (cfg->local ? "YES" : "NO")
);
rprintf
(
r,
" <LI>\"Example\" inherited: %s\n </LI>\n",
! (cfg->congenital ? "YES" : "NO")
);
rputs (" </UL>\n", r);
rputs (" </BODY>\n", r);
--- 593,624 ----
rputs (" indicates a location in the URL or filesystem\n", r);
rputs (" namespace.\n", r);
rputs (" </P>\n", r);
! rprintf
! (
! r,
! " <H2>Static callbacks so far:</H2>\n <OL>\n%s </OL>\n",
! trace
! );
! rprintf
! (
! r,
! " <H2>Request-specific callbacks so far:</H2>\n <OL>\n%s </OL>\n",
! rcfg->trace
! );
rputs (" <H2>Environment for <EM>this</EM> call:</H2>\n", r);
rputs (" <UL>\n", r);
! rprintf (r, " <LI>Applies-to: <SAMP>%s</SAMP>\n </LI>\n", dcfg->loc);
rprintf
(
r,
" <LI>\"Example\" directive declared here: %s\n </LI>\n",
! (dcfg->local ? "YES" : "NO")
);
rprintf
(
r,
" <LI>\"Example\" inherited: %s\n </LI>\n",
! (dcfg->congenital ? "YES" : "NO")
);
rputs (" </UL>\n", r);
rputs (" </BODY>\n", r);
***************
*** 541,558 ****
char *sname = s->server_hostname;
/*
! * If we haven't already allocated our module-private pool, do so now.
*/
! if (example_pool == NULL) {
! example_pool = make_sub_pool (NULL);
! };
/*
* The arbitrary text we add to our trace entry indicates for which server
* we're being called.
*/
sname = (sname != NULL) ? sname : "";
note = pstrcat (p, "example_init(", sname, ")", NULL);
! trace_add (s, NULL, note);
}
/*
--- 684,699 ----
char *sname = s->server_hostname;
/*
! * Set up any module cells that ought to be initialised.
*/
! setup_module_cells ();
/*
* The arbitrary text we add to our trace entry indicates for which server
* we're being called.
*/
sname = (sname != NULL) ? sname : "";
note = pstrcat (p, "example_init(", sname, ")", NULL);
! trace_add (s, NULL, NULL, note);
}
/*
***************
*** 590,596 ****
*/
dname = (dname != NULL) ? dname : "";
cfg->loc = pstrcat (p, "DIR(", dname, ")", NULL);
! trace_add (NULL, cfg, "example_dir_create()");
return (void *) cfg;
}
--- 731,737 ----
*/
dname = (dname != NULL) ? dname : "";
cfg->loc = pstrcat (p, "DIR(", dname, ")", NULL);
! trace_add (NULL, NULL, cfg, "example_dir_create()");
return (void *) cfg;
}
***************
*** 654,660 ****
"\")",
NULL
);
! trace_add (NULL, merged_config, note);
return (void *) merged_config;
}
--- 795,801 ----
"\")",
NULL
);
! trace_add (NULL, NULL, merged_config, note);
return (void *) merged_config;
}
***************
*** 685,691 ****
*/
sname = (sname != NULL) ? sname : "";
cfg->loc = pstrcat (p, "SVR(", sname, ")", NULL);
! trace_add (s, cfg, "example_server_create()");
return (void *) cfg;
}
--- 826,832 ----
*/
sname = (sname != NULL) ? sname : "";
cfg->loc = pstrcat (p, "SVR(", sname, ")", NULL);
! trace_add (s, NULL, cfg, "example_server_create()");
return (void *) cfg;
}
***************
*** 736,742 ****
"\")",
NULL
);
! trace_add (NULL, merged_config, note);
return (void *) merged_config;
}
--- 877,883 ----
"\")",
NULL
);
! trace_add (NULL, NULL, merged_config, note);
return (void *) merged_config;
}
***************
*** 759,765 ****
* We don't actually *do* anything here, except note the fact that we were
* called.
*/
! trace_add (r->server, cfg, "example_xlate()");
return DECLINED;
}
--- 900,906 ----
* We don't actually *do* anything here, except note the fact that we were
* called.
*/
! trace_add (r->server, r, cfg, "example_xlate()");
return DECLINED;
}
***************
*** 782,788 ****
/*
* Don't do anything except log the call.
*/
! trace_add (r->server, cfg, "example_ckuser()");
return DECLINED;
}
--- 923,929 ----
/*
* Don't do anything except log the call.
*/
! trace_add (r->server, r, cfg, "example_ckuser()");
return DECLINED;
}
***************
*** 807,813 ****
* Log the call and return OK, or access will be denied (even though we
* didn't actually do anything).
*/
! trace_add (r->server, cfg, "example_ckauth()");
return OK;
}
--- 948,954 ----
* Log the call and return OK, or access will be denied (even though we
* didn't actually do anything).
*/
! trace_add (r->server, r, cfg, "example_ckauth()");
return OK;
}
***************
*** 827,833 ****
*cfg;
cfg = our_dconfig (r);
! trace_add (r->server, cfg, "example_ckaccess()");
return OK;
}
--- 968,974 ----
*cfg;
cfg = our_dconfig (r);
! trace_add (r->server, r, cfg, "example_ckaccess()");
return OK;
}
***************
*** 850,856 ****
* Log the call, but don't do anything else - and report truthfully that
* we didn't do anything.
*/
! trace_add (r->server, cfg, "example_typer()");
return DECLINED;
}
--- 991,997 ----
* Log the call, but don't do anything else - and report truthfully that
* we didn't do anything.
*/
! trace_add (r->server, r, cfg, "example_typer()");
return DECLINED;
}
***************
*** 872,878 ****
/*
* Log the call and exit.
*/
! trace_add (r->server, cfg, "example_fixer()");
return OK;
}
--- 1013,1019 ----
/*
* Log the call and exit.
*/
! trace_add (r->server, r, cfg, "example_fixer()");
return OK;
}
***************
*** 890,896 ****
*cfg;
cfg = our_dconfig (r);
! trace_add (r->server, cfg, "example_logger()");
return DECLINED;
}
--- 1031,1037 ----
*cfg;
cfg = our_dconfig (r);
! trace_add (r->server, r, cfg, "example_logger()");
return DECLINED;
}
***************
*** 909,915 ****
*cfg;
cfg = our_dconfig (r);
! trace_add (r->server, cfg, "example_hparser()");
return DECLINED;
}
--- 1050,1056 ----
*cfg;
cfg = our_dconfig (r);
! trace_add (r->server, r, cfg, "example_hparser()");
return DECLINED;
}