coar        99/05/13 11:25:59

  Modified:    htdocs/manual/mod mod_autoindex.html
               src      CHANGES
               src/modules/standard mod_autoindex.c mod_include.c
  Log:
        Someone finally stood up and made the ReadmeName and HeaderName
        features use subrequests.  Not only that, but they can be
        parsed for SSIs too!
  
  PR:           1574, 3026, 3529, 3569, 4256
  Submitted by: Raymond S Brand <[EMAIL PROTECTED]>
  Reviewed by:  Ken Coar
  
  Revision  Changes    Path
  1.31      +57 -17    apache-1.3/htdocs/manual/mod/mod_autoindex.html
  
  Index: mod_autoindex.html
  ===================================================================
  RCS file: /home/cvs/apache-1.3/htdocs/manual/mod/mod_autoindex.html,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -r1.30 -r1.31
  --- mod_autoindex.html        1999/01/04 14:35:53     1.30
  +++ mod_autoindex.html        1999/05/13 18:25:45     1.31
  @@ -426,20 +426,53 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mod_autoindex<P>
  +><STRONG>Module:</STRONG></A> mod_autoindex
  +  <BR>
  +  <A
  +   HREF="directive-dict.html#Compatibility"
  +   REL="Help"
  +  ><STRONG>Compatibility:</STRONG></A> some features only available after
  + 1.3.6; see text
   
  +<P>
   The HeaderName directive sets the name of the file that will be inserted
   at the top of the index listing. <EM>Filename</EM> is the name of the file
  -to include, and is taken to be relative to the directory being indexed.
  -The server first attempts to include <EM>filename</EM><CODE>.html</CODE>
  -as an HTML document, otherwise it will include <EM>filename</EM> as plain
  -text. Example:
  +to include.
  +</P>
  +<BLOCKQUOTE><STRONG>Apache 1.3.6 and earlier:</STRONG>
  +The module first attempts to include <EM>filename</EM><CODE>.html</CODE>
  +as an HTML document, otherwise it will try to include <EM>filename</EM> as
  +plain text.  <EM>Filename</EM> is treated as a filesystem path relative
  +to the directory being indexed.  In no case is SSI processing done.
  +Example:
   <BLOCKQUOTE><CODE>HeaderName HEADER</CODE></BLOCKQUOTE>
   when indexing the directory <CODE>/web</CODE>, the server will first look for
   the HTML file <CODE>/web/HEADER.html</CODE> and include it if found, 
otherwise
   it will include the plain text file <CODE>/web/HEADER</CODE>, if it exists.
  -
  -<P>See also <A HREF="#readmename">ReadmeName</A>.<P><HR>
  +</BLOCKQUOTE>
  +<BLOCKQUOTE><STRONG>Apache versions after 1.3.6:</STRONG>
  +<EM>Filename</EM> is treated as a URI path relative to the one used
  +to access the directory being indexed, and must resolve to a document
  +with a major content type of "<SAMP>text</SAMP>" (<EM>e.g.</EM>,
  +<SAMP>text/html</SAMP>, <SAMP>text/plain</SAMP>, <EM>etc.</EM>).
  +This means that <EM>filename</EM> may refer to a CGI script if the
  +script's actual file type (as opposed to its output) is marked as
  +<SAMP>text/html</SAMP> such as with a directive like:
  +<PRE>
  +    AddType text/html .cgi
  +</PRE>
  +<A HREF="../content-negotiation.html">Content negotiation</A>
  +will be performed if the <SAMP>MultiViews</SAMP>
  +<A HREF="core.html#options">option</A> is enabled.
  +If <EM>filename</EM> resolves to a static <SAMP>text/html</SAMP> document
  +(not a CGI script) and the
  +<SAMP>Includes</SAMP> <A HREF="core.html#options">option</A> is enabled,
  +the file will be processed for server-side includes (see the
  +<A HREF="mod_include.html"><SAMP>mod_include</SAMP></A> documentation).
  +</BLOCKQUOTE>
  +<P>
  +See also <A HREF="#readmename">ReadmeName</A>.
  +<P><HR>
   
   <H2><A NAME="indexignore">IndexIgnore</A></H2>
   <!--%plaintext &lt;?INDEX {\tt IndexIgnore} directive&gt; -->
  @@ -753,19 +786,26 @@
   <A
    HREF="directive-dict.html#Module"
    REL="Help"
  -><STRONG>Module:</STRONG></A> mod_autoindex<P>
  +><STRONG>Module:</STRONG></A> mod_autoindex
  +  <BR>
  +  <A
  +   HREF="directive-dict.html#Compatibility"
  +   REL="Help"
  +  ><STRONG>Compatibility:</STRONG></A> some features only available after
  + 1.3.6; see text
   
  +<P>
   The ReadmeName directive sets the name of the file that will be appended
   to the end of the index listing. <EM>Filename</EM> is the name of the file
  -to include, and is taken to be relative to the directory being indexed.
  -The server first attempts to include <EM>filename</EM><CODE>.html</CODE>
  -as an HTML document, otherwise it will include <EM>filename</EM> as plain
  -text. Example:
  -<BLOCKQUOTE><CODE>ReadmeName README</CODE></BLOCKQUOTE>
  -when indexing the directory <CODE>/web</CODE>, the server will first look for
  -the HTML file <CODE>/web/README.html</CODE> and include it if found, 
otherwise
  -it will include the plain text file <CODE>/web/README</CODE>, if it exists.
  -
  +to include, and is taken to be relative to the location being indexed.
  +</P>
  +<BLOCKQUOTE>
  +<STRONG>The <EM>filename</EM> argument is treated as a stub filename
  +in Apache 1.3.6 and earlier, and as a relative URI in later versions.
  +Details of how it is handled may be found under the description of
  +the <A HREF="#headername">HeaderName</A> directive, which uses the
  +same mechanism and changed at the same time as ReadmeName.</STRONG>
  +</BLOCKQUOTE>
   <P>See also <A HREF="#headername">HeaderName</A>.<P>
   
   
  
  
  
  1.1354    +8 -0      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1353
  retrieving revision 1.1354
  diff -u -r1.1353 -r1.1354
  --- CHANGES   1999/05/12 16:50:40     1.1353
  +++ CHANGES   1999/05/13 18:25:50     1.1354
  @@ -1,5 +1,13 @@
   Changes with Apache 1.3.7
   
  +  *) Support for server-parsed and multiview-determined ReadmeName and
  +     HeaderName files in mod_autoindex. Removed the restriction on
  +     "/"s in ReadmeName and HeaderName directives since the *sub_req*
  +     routines will deal with the access issues. (It's now possible to
  +     have {site|group|project|customer|...} wide readmes and headers.)
  +     [Raymond S Brand <[EMAIL PROTECTED]>, Ken Coar] PR#1574, 3026, 3529,
  +     3569, 4256
  +
     *) When stat() fails, don't assume anything about the contents of
        the struct stat.  [Ed Korthof <[EMAIL PROTECTED]>]
   
  
  
  
  1.107     +208 -99   apache-1.3/src/modules/standard/mod_autoindex.c
  
  Index: mod_autoindex.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_autoindex.c,v
  retrieving revision 1.106
  retrieving revision 1.107
  diff -u -r1.106 -r1.107
  --- mod_autoindex.c   1999/05/03 20:48:43     1.106
  +++ mod_autoindex.c   1999/05/13 18:25:56     1.107
  @@ -322,9 +322,6 @@
   
   static const char *add_header(cmd_parms *cmd, void *d, char *name)
   {
  -    if (strchr(name, '/')) {
  -     return "HeaderName cannot contain a /";
  -    }
       push_item(((autoindex_config_rec *) d)->hdr_list, 0, NULL, cmd->path,
              name);
       return NULL;
  @@ -332,9 +329,6 @@
   
   static const char *add_readme(cmd_parms *cmd, void *d, char *name)
   {
  -    if (strchr(name, '/')) {
  -     return "ReadmeName cannot contain a /";
  -    }
       push_item(((autoindex_config_rec *) d)->rdme_list, 0, NULL, cmd->path,
              name);
       return NULL;
  @@ -864,99 +858,223 @@
    */
   
   /*
  - * Look for the specified file, and pump it into the response stream if we
  - * find it.
  + * Elements of the emitted document:
  + *   Preamble
  + *           Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req
  + *           succeeds for the (content_type == text/html) header file.
  + *   Header file
  + *           Emitted if found (and able).
  + *   H1 tag line
  + *           Emitted if a header file is NOT emitted.
  + *   Directory stuff
  + *           Always emitted.
  + *   HR
  + *           Emitted if FANCY_INDEXING is set.
  + *   Readme file
  + *           Emitted if found (and able).
  + *   ServerSig
  + *           Emitted if ServerSignature is not Off AND a readme file
  + *           is NOT emitted.
  + *   Postamble
  + *           Emitted unless SUPPRESS_PREAMBLE is set AND ap_run_sub_req
  + *           succeeds for the (content_type == text/html) readme file.
    */
  -static int insert_readme(char *name, char *readme_fname, char *title,
  -                      int hrule, int whichend, request_rec *r)
  +
  +
  +/*
  + * emit a plain text file
  + */
  +static void do_emit_plain(request_rec *r, FILE *f)
   {
  -    char *fn;
  -    FILE *f;
  -    struct stat finfo;
  -    int plaintext = 0;
  -    request_rec *rr;
  -    autoindex_config_rec *cfg;
  -    int autoindex_opts;
  +    char buf[IOBUFSIZE + 1];
  +    int i, n, c, ch;
   
  -    cfg = (autoindex_config_rec *) ap_get_module_config(r->per_dir_config,
  -                                                     &autoindex_module);
  -    autoindex_opts = cfg->opts;
  -    /* XXX: this is a load of crap, it needs to do a full sub_req_lookup_uri 
*/
  -    fn = ap_make_full_path(r->pool, name, readme_fname);
  -    fn = ap_pstrcat(r->pool, fn, ".html", NULL);
  -    if (stat(fn, &finfo) == -1) {
  -     /* A brief fake multiviews search for README.html */
  -     fn[strlen(fn) - 5] = '\0';
  -     if (stat(fn, &finfo) == -1) {
  -         return 0;
  -     }
  -     plaintext = 1;
  -     if (hrule) {
  -         ap_rputs("<HR>\n", r);
  +    ap_rputs("<PRE>\n", r);
  +    while (!feof(f)) {
  +     do {
  +         n = fread(buf, sizeof(char), IOBUFSIZE, f);
  +     }
  +     while (n == -1 && ferror(f) && errno == EINTR);
  +     if (n == -1 || n == 0) {
  +         break;
  +     }
  +     buf[n] = '\0';
  +     c = 0;
  +     while (c < n) {
  +         for (i = c; i < n; i++) {
  +             if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') {
  +                 break;
  +             }
  +         }
  +         ch = buf[i];
  +         buf[i] = '\0';
  +         ap_rputs(&buf[c], r);
  +         if (ch == '<') {
  +             ap_rputs("&lt;", r);
  +         }
  +         else if (ch == '>') {
  +             ap_rputs("&gt;", r);
  +         }
  +         else if (ch == '&') {
  +             ap_rputs("&amp;", r);
  +         }
  +         c = i + 1;
        }
  -    }
  -    else if (hrule) {
  -     ap_rputs("<HR>\n", r);
       }
  -    /* XXX: when the above is rewritten properly, this necessary security
  -     * check will be redundant. -djg */
  -    rr = ap_sub_req_lookup_file(fn, r);
  -    if (rr->status != HTTP_OK) {
  -     ap_destroy_sub_req(rr);
  -     return 0;
  -    }
  -    ap_destroy_sub_req(rr);
  -    if (!(f = ap_pfopen(r->pool, fn, "r"))) {
  -        return 0;
  +    ap_rputs("</PRE>\n", r);
  +}
  +
  +/* See mod_include */
  +#define SUB_REQ_STRING       "Sub request to mod_include"
  +#define PARENT_STRING        "Parent request to mod_include"
  +
  +/*
  + * Handle the preamble through the H1 tag line, inclusive.  Locate
  + * the file with a subrequests.  Process text/html documents by actually
  + * running the subrequest; text/xxx documents get copied verbatim,
  + * and any other content type is ignored.  This means that a non-text
  + * document (such as HEADER.gif) might get multiviewed as the result
  + * instead of a text document, meaning nothing will be displayed, but
  + * oh well.
  + */
  +static void emit_head(request_rec *r, char *header_fname, int suppress_amble,
  +                   char *title)
  +{
  +    FILE *f;
  +    request_rec *rr = NULL;
  +    int emit_amble = 1;
  +    int emit_H1 = 1;
  +
  +    /*
  +     * If there's a header file, send a subrequest to look for it.  If it's
  +     * found and a text file, handle it -- otherwise fall through and
  +     * pretend there's nothing there.
  +     */
  +    if ((header_fname != NULL)
  +     && (rr = ap_sub_req_lookup_uri(header_fname, r))
  +     && (rr->status == HTTP_OK)
  +     && (rr->filename != NULL)
  +     && S_ISREG(rr->finfo.st_mode)) {
  +     /*
  +      * Check for the two specific cases we allow: text/html and
  +      * text/anything-else.  The former is allowed to be processed for
  +      * SSIs.
  +      */
  +     if (rr->content_type != NULL) {
  +         if (!strcasecmp("text/html", rr->content_type)) {
  +             /* Hope everything will work... */
  +             emit_amble = 0;
  +             emit_H1 = 0;
  +
  +             if (! suppress_amble) {
  +                 emit_preamble(r, title);
  +             }
  +             ap_table_add(r->notes, PARENT_STRING, "");
  +             ap_table_add(rr->notes, SUB_REQ_STRING, "");
  +             /*
  +              * If there's a problem running the subrequest, display the
  +              * preamble if we didn't do it before -- the header file
  +              * didn't get displayed.
  +              */
  +             if (ap_run_sub_req(rr) != OK) {
  +                 /* It didn't work */
  +                 emit_amble = suppress_amble;
  +                 emit_H1 = 1;
  +             }
  +         }
  +         else if (!strncasecmp("text/", rr->content_type, 5)) {
  +             /*
  +              * If we can open the file, prefix it with the preamble
  +              * regardless; since we'll be sending a <PRE> block around
  +              * the file's contents, any HTML header it had won't end up
  +              * where it belongs.
  +              */
  +             if ((f = ap_pfopen(r->pool, rr->filename, "r")) != 0) {
  +                 emit_preamble(r, title);
  +                 emit_amble = 0;
  +                 do_emit_plain(r, f);
  +                 ap_pfclose(r->pool, f);
  +                 emit_H1 = 0;
  +             }
  +         }
  +     }
       }
  -    if ((whichend == FRONT_MATTER)
  -     && (!(autoindex_opts & SUPPRESS_PREAMBLE))) {
  +
  +    if (emit_amble) {
        emit_preamble(r, title);
       }
  -    if (!plaintext) {
  -     ap_send_fd(f, r);
  +    if (emit_H1) {
  +     ap_rvputs(r, "<H1>Index of ", title, "</H1>\n", NULL);
       }
  -    else {
  -     char buf[IOBUFSIZE + 1];
  -     int i, n, c, ch;
  -     ap_rputs("<PRE>\n", r);
  -     while (!feof(f)) {
  -         do {
  -             n = fread(buf, sizeof(char), IOBUFSIZE, f);
  -         }
  -         while (n == -1 && ferror(f) && errno == EINTR);
  -         if (n == -1 || n == 0) {
  -             break;
  -         }
  -         buf[n] = '\0';
  -         c = 0;
  -         while (c < n) {
  -             for (i = c; i < n; i++) {
  -                 if (buf[i] == '<' || buf[i] == '>' || buf[i] == '&') {
  -                     break;
  -                 }
  -             }
  -             ch = buf[i];
  -             buf[i] = '\0';
  -             ap_rputs(&buf[c], r);
  -             if (ch == '<') {
  -                 ap_rputs("&lt;", r);
  -             }
  -             else if (ch == '>') {
  -                 ap_rputs("&gt;", r);
  +    if (rr != NULL) {
  +     ap_destroy_sub_req(rr);
  +    }
  +}
  +
  +
  +/*
  + * Handle the Readme file through the postamble, inclusive.  Locate
  + * the file with a subrequests.  Process text/html documents by actually
  + * running the subrequest; text/xxx documents get copied verbatim,
  + * and any other content type is ignored.  This means that a non-text
  + * document (such as FOOTER.gif) might get multiviewed as the result
  + * instead of a text document, meaning nothing will be displayed, but
  + * oh well.
  + */
  +static void emit_tail(request_rec *r, char *readme_fname, int suppress_amble)
  +{
  +    FILE *f;
  +    request_rec *rr = NULL;
  +    int suppress_post = 0;
  +    int suppress_sig = 0;
  +
  +    /*
  +     * If there's a readme file, send a subrequest to look for it.  If it's
  +     * found and a text file, handle it -- otherwise fall through and
  +     * pretend there's nothing there.
  +     */
  +    if ((readme_fname != NULL)
  +     && (rr = ap_sub_req_lookup_uri(readme_fname, r))
  +     && (rr->status == HTTP_OK)
  +     && (rr->filename != NULL)
  +     && S_ISREG(rr->finfo.st_mode)) {
  +     /*
  +      * Check for the two specific cases we allow: text/html and
  +      * text/anything-else.  The former is allowed to be processed for
  +      * SSIs.
  +      */
  +     if (rr->content_type != NULL) {
  +         if (!strcasecmp("text/html", rr->content_type)) {
  +             ap_table_add(r->notes, PARENT_STRING, "");
  +             ap_table_add(rr->notes, SUB_REQ_STRING, "");
  +             if (ap_run_sub_req(rr) == OK) {
  +                 /* worked... */
  +                 suppress_sig = 1;
  +                 suppress_post = suppress_amble;
                }
  -             else if (ch == '&') {
  -                 ap_rputs("&amp;", r);
  +         }
  +         else if (!strncasecmp("text/", rr->content_type, 5)) {
  +             /*
  +              * If we can open the file, suppress the signature.
  +              */
  +             if ((f = ap_pfopen(r->pool, rr->filename, "r")) != 0) {
  +                 do_emit_plain(r, f);
  +                 ap_pfclose(r->pool, f);
  +                 suppress_sig = 1;
                }
  -             c = i + 1;
            }
        }
  +    }
  +    
  +    if (!suppress_sig) {
  +     ap_rputs(ap_psignature("", r), r);
       }
  -    ap_pfclose(r->pool, f);
  -    if (plaintext) {
  -     ap_rputs("</PRE>\n", r);
  +    if (!suppress_post) {
  +     ap_rputs("</BODY></HTML>\n", r);
  +    }
  +    if (rr != NULL) {
  +     ap_destroy_sub_req(rr);
       }
  -    return 1;
   }
   
   
  @@ -1389,7 +1507,6 @@
       int num_ent = 0, x;
       struct ent *head, *p;
       struct ent **ar = NULL;
  -    char *tmp;
       const char *qstring;
       int autoindex_opts = autoindex_conf->opts;
       char keyid;
  @@ -1419,12 +1536,8 @@
        *title_endp-- = '\0';
       }
   
  -    if ((!(tmp = find_header(autoindex_conf, r)))
  -     || (!(insert_readme(name, tmp, title_name, NO_HRULE, FRONT_MATTER, r)))
  -     ) {
  -     emit_preamble(r, title_name);
  -     ap_rvputs(r, "<H1>Index of ", title_name, "</H1>\n", NULL);
  -    }
  +    emit_head(r, find_header(autoindex_conf, r),
  +           autoindex_opts & SUPPRESS_PREAMBLE, title_name);
   
       /*
        * Figure out what sort of indexing (if any) we're supposed to use.
  @@ -1489,15 +1602,11 @@
                       direction);
       ap_pclosedir(r->pool, d);
   
  -    if ((tmp = find_readme(autoindex_conf, r))) {
  -     if (!insert_readme(name, tmp, "",
  -                        ((autoindex_opts & FANCY_INDEXING) ? HRULE
  -                                                           : NO_HRULE),
  -                        END_MATTER, r)) {
  -         ap_rputs(ap_psignature("<HR>\n", r), r);
  -     }
  +    if (autoindex_opts & FANCY_INDEXING) {
  +     ap_rputs("<HR>\n", r);
       }
  -    ap_rputs("</BODY></HTML>\n", r);
  +    emit_tail(r, find_readme(autoindex_conf, r),
  +           autoindex_opts & SUPPRESS_PREAMBLE);
   
       ap_kill_timeout(r);
       return 0;
  
  
  
  1.115     +40 -9     apache-1.3/src/modules/standard/mod_include.c
  
  Index: mod_include.c
  ===================================================================
  RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_include.c,v
  retrieving revision 1.114
  retrieving revision 1.115
  diff -u -r1.114 -r1.115
  --- mod_include.c     1999/05/05 17:46:07     1.114
  +++ mod_include.c     1999/05/13 18:25:57     1.115
  @@ -108,9 +108,6 @@
   
   module MODULE_VAR_EXPORT includes_module;
   
  -/* just need some arbitrary non-NULL pointer which can't also be a 
request_rec */
  -#define NESTED_INCLUDE_MAGIC (&includes_module)
  -
   /* ------------------------ Environment function -------------------------- 
*/
   
   /* XXX: could use ap_table_overlap here */
  @@ -746,9 +743,7 @@
               }
   
            /* destroy the sub request if it's not a nested include */
  -            if (rr != NULL
  -             && ap_get_module_config(rr->request_config, &includes_module)
  -                 != NESTED_INCLUDE_MAGIC) {
  +         if (rr != NULL) {
                ap_destroy_sub_req(rr);
               }
           }
  @@ -2376,6 +2371,41 @@
           return OK;
       }
   
  +#define SUB_REQ_STRING       "Sub request to mod_include"
  +#define PARENT_STRING        "Parent request to mod_include"
  +
  +    if (ap_table_get(r->notes, SUB_REQ_STRING) != NULL) {
  +     request_rec *p = r->main;
  +
  +     /*
  +      * The note is a flag to mod_include that this request is actually
  +      * a subrequest from another module and that mod_include needs to
  +      * treat it as if it's a subrequest from mod_include.
  +      *
  +      * HACK ALERT!
  +      * There is no good way to pass the parent request_rec to mod_include.
  +      * Tables only take string values and there is nowhere appropriate in
  +      * in the request_rec that can safely be used.
  +      *
  +      * So we search up the chain of requests and redirects looking for
  +      * the parent request.
  +      */
  +
  +     while (p) {
  +         if (ap_table_get(p->notes, PARENT_STRING) != NULL) {
  +             /* Kludge --- See below */
  +             ap_set_module_config(r->request_config, &includes_module, p);
  +
  +             ap_add_common_vars(p);
  +             ap_add_cgi_vars(p);
  +             add_include_vars(p, DEFAULT_TIME_FORMAT);
  +             ap_table_unset(r->notes, SUB_REQ_STRING);
  +             break;
  +         }
  +         p = (p->prev) ? p->prev : p->main;
  +     }
  +    }
  +
       if ((parent = ap_get_module_config(r->request_config, 
&includes_module))) {
        /* Kludge --- for nested includes, we want to keep the subprocess
         * environment of the base document (for compatibility); that means
  @@ -2411,9 +2441,10 @@
       send_parsed_content(f, r);
   
       if (parent) {
  -     /* signify that the sub request should not be killed */
  -     ap_set_module_config(r->request_config, &includes_module,
  -         NESTED_INCLUDE_MAGIC);
  +     /* Kludge --- Doing this allows the caller to safely destroy the
  +      * sub_req
  +      */
  +     r->pool = ap_make_sub_pool(r->pool);
       }
   
       ap_kill_timeout(r);
  
  
  

Reply via email to