Repost. Looking for feedback. Thanks! -Glenn
Date: Fri, 9 May 2003 04:11:06 -0400
Subject: server-side includes "virtual" and "exec" questions/patches
Message-ID: <[EMAIL PROTECTED]>
1) Why does includes "virtual" sometimes fail with
"unable to include potential exec \"%s\" in parsed file %s"
when Options IncludesNoEXEC is used? Why is this check performed?
What is the reasoning behind it?
--- httpd-2.0.45/modules/filters/mod_include.c 2003-02-03 12:31:38.000000000 -0500
+++ httpd-2.0.45/modules/filters/mod_include.c.new 2003-05-07 15:38:58.000000000
-0400
@@ -1274,12 +1274,6 @@
error_fmt = "unable to include \"%s\" in parsed file %s";
}
- if (!error_fmt && (ctx->flags & FLAG_NO_EXEC) &&
- rr->content_type &&
- (strncmp(rr->content_type, "text/", 5))) {
- error_fmt = "unable to include potential exec \"%s\" "
- "in parsed file %s";
- }
if (error_fmt == NULL) {
/* try to avoid recursive includes. We do this by walking
* up the r->main list of subrequests, and at each level
The documentation for IncludeNoEXEC (with the Options directive) states:
IncludesNOEXEC
Server-side includes are permitted, but the #exec command and
#exec CGI are disabled. It is still possible to #include virtual
CGI scripts from ScriptAliase'd directories.
When Options IncludesNoEXEC is used, the code for include virtual="..."
currently checks the initial content-type of the target for for text/*
(before running the subrequest) and therefore disallows, for example,
<!--#include virtual="/cgi-bin/foo.php"-->
since the initial content-type can be application/x-httpd-php. This
fails even when /cgi-bin/ is marked Options +ExecCGI. (A workaround
may be to use AddHandler to set it to "cgi-script" and to use AddType
to set the type to text/html. Or the above patch could be modified
to check for ExecCGI: (ap_allow_options(r) & OPT_EXECCGI), or else
check for ScripAlias: ap_table_get(r->notes, "alias-forced-type") )
What is the reason that the #include virtual="..." (and "file") are
peeking into the subrequest? Shouldn't they just run the subrequest
and include the results? After all, requesting the URI directly would
produce identical results, wouldn't it? Maybe only "#include file"
should check for content-type text/*, but not "#include virtual".
Can this be backported to 2.0 and 1.3?
2) Should <!--#exec cgi="..."--> be officially deprecated?
The following two statements are almost semantically equivalent AFAICT:
<!--#exec cgi="/path/to/cgi"-->
<!--#include virtual="/path/to/cgi${PATH_INFO}?${QUERY_STRING}"-->
and #include virtual is more flexible, and allowed with IncludesNoEXEC.
Besides, I really do not like the idea of the silent inheritance of
path info and query string by #exec cgi because it is an inheritance of
the path info and query string of the base document, which gets really
messy if you have nested includes and have an #include virtual in the
mix which uses its own path info and query string.
Is there any reason "#exec cgi" should remain in Apache 2.1? If people
support removing it, I'll whip up a quick patch to mod_cgi/mod_cgid.
Backwards compatibility is one thing, but this is cruft. Current
documentation says:
"The include virtual element should be used in preference to exec cgi"
but does not go so far as to deprecate it, indicating that it might be
removed in the future.
In addition to path info and query string inheritance, the only
difference between #exec cgi and #include virtual is that if the target
CGI returns a redirect, #exec cgi will turn it into a hyperlink. I'm
not sure how often this "feature" is used, but the simple workaround is
to have the CGI script return the hyperlink as the body of its output:
print "Content-type: text/plain\n\n",
"<a href="link">link</a>\n";
3) Apache2 mod_include performs lazy evaluation of a few environment
variables: DATE_GMT, DATE_LOCAL, LAST_MODIFIED, and USER_NAME
These variables end up being empty strings ("") in a CGI environment
unless they are used in the include document prior to the virtual or
exec include, e.g. the no-op
<!--#if expr="$DATE_LOCAL"--><!--#endif-->
Can this be documented somewhere? What pages should be updated?
mod_include documentation, the SSI tutorial, others?
4) Minor nit. Should USER_NAME be inherited from the base document, just
as the LAST_MODIFIED time is done? If USER_NAME was generated from the
lazy value before a sub-include, then it is inherited. If it was not
generated before a sub-include, then it will be set with the value of
the document when it is actually used, leading to inconsistencies.
--- httpd-2.0.45/modules/filters/mod_include.c 2003-02-03 12:31:38.000000000 -0500
+++ httpd-2.0.45/modules/filters/mod_include.c.new 2003-05-09 04:05:26.000000000
-0400
@@ -3386,10 +3386,12 @@
* torquing our own last_modified date as well so that the
* LAST_MODIFIED variable gets reset to the proper value if the
* nested document resets <!--#config timefmt -->.
+ * Also torque info used to generate USER_NAME.
*/
r->subprocess_env = r->main->subprocess_env;
apr_pool_join(r->main->pool, r->pool);
r->finfo.mtime = r->main->finfo.mtime;
+ r->finfo.user = r->main->finfo.user;
}
else {
/* we're not a nested include, so we create an initial
5) Can mod_include please export get_include_var() as an optional function?
How about as ap_ssi_get_include_var()?
--- httpd-2.0.45/modules/filters/mod_include.c 2003-02-03 12:31:38.000000000 -0500
+++ httpd-2.0.45/modules/filters/mod_include.c.new 2003-05-07 15:46:05.000000000
-0400
@@ -206,8 +206,8 @@
return val;
}
-static const char *get_include_var(request_rec *r, include_ctx_t *ctx,
- const char *var)
+static const char *ap_ssi_get_include_var(request_rec *r, include_ctx_t *ctx,
+ const char *var)
{
const char *val;
if (apr_isdigit(*var) && !var[1]) {
@@ -1099,7 +1099,7 @@
if (l != 0) {
tmp_store = *end_of_var_name;
*end_of_var_name = '\0';
- val = get_include_var(r, ctx, start_of_var_name);
+ val = ap_ssi_get_include_var(r, ctx, start_of_var_name);
*end_of_var_name = tmp_store;
if (val) {
@@ -1387,9 +1387,9 @@
if (!strcmp(tag, "var")) {
conn_rec *c = r->connection;
const char *val =
- get_include_var(r, ctx,
- ap_ssi_parse_string(r, ctx, tag_val, NULL,
- MAX_STRING_LEN, 0));
+ ap_ssi_get_include_var(
+ r, ctx, ap_ssi_parse_string(r, ctx, tag_val, NULL
+ MAX_STRING_LEN, 0));
if (val) {
switch(encode) {
case E_NONE:
@@ -3569,6 +3569,7 @@
static void register_hooks(apr_pool_t *p)
{
+ APR_REGISTER_OPTIONAL_FN(ap_ssi_get_include_var);
APR_REGISTER_OPTIONAL_FN(ap_ssi_get_tag_and_value);
APR_REGISTER_OPTIONAL_FN(ap_ssi_parse_string);
APR_REGISTER_OPTIONAL_FN(ap_register_include_handler);
Thanks!
Glenn