home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / modules / standard / mod_alias.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-01  |  12.4 KB  |  419 lines

  1. /* ====================================================================
  2.  * Copyright (c) 1995-1999 The Apache Group.  All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer. 
  10.  *
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in
  13.  *    the documentation and/or other materials provided with the
  14.  *    distribution.
  15.  *
  16.  * 3. All advertising materials mentioning features or use of this
  17.  *    software must display the following acknowledgment:
  18.  *    "This product includes software developed by the Apache Group
  19.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  20.  *
  21.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  22.  *    endorse or promote products derived from this software without
  23.  *    prior written permission. For written permission, please contact
  24.  *    apache@apache.org.
  25.  *
  26.  * 5. Products derived from this software may not be called "Apache"
  27.  *    nor may "Apache" appear in their names without prior written
  28.  *    permission of the Apache Group.
  29.  *
  30.  * 6. Redistributions of any form whatsoever must retain the following
  31.  *    acknowledgment:
  32.  *    "This product includes software developed by the Apache Group
  33.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  34.  *
  35.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  36.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  37.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  38.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  41.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  42.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  43.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  44.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  45.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  46.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  47.  * ====================================================================
  48.  *
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Group and was originally based
  51.  * on public domain software written at the National Center for
  52.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  53.  * For more information on the Apache Group and the Apache HTTP server
  54.  * project, please see <http://www.apache.org/>.
  55.  *
  56.  */
  57.  
  58. /*
  59.  * http_alias.c: Stuff for dealing with directory aliases
  60.  * 
  61.  * Original by Rob McCool, rewritten in succession by David Robinson
  62.  * and rst.
  63.  * 
  64.  */
  65.  
  66. #include "httpd.h"
  67. #include "http_config.h"
  68.  
  69. typedef struct {
  70.     char *real;
  71.     char *fake;
  72.     char *handler;
  73.     regex_t *regexp;
  74.     int redir_status;        /* 301, 302, 303, 410, etc */
  75. } alias_entry;
  76.  
  77. typedef struct {
  78.     array_header *aliases;
  79.     array_header *redirects;
  80. } alias_server_conf;
  81.  
  82. typedef struct {
  83.     array_header *redirects;
  84. } alias_dir_conf;
  85.  
  86. module MODULE_VAR_EXPORT alias_module;
  87.  
  88. static void *create_alias_config(pool *p, server_rec *s)
  89. {
  90.     alias_server_conf *a =
  91.     (alias_server_conf *) ap_pcalloc(p, sizeof(alias_server_conf));
  92.  
  93.     a->aliases = ap_make_array(p, 20, sizeof(alias_entry));
  94.     a->redirects = ap_make_array(p, 20, sizeof(alias_entry));
  95.     return a;
  96. }
  97.  
  98. static void *create_alias_dir_config(pool *p, char *d)
  99. {
  100.     alias_dir_conf *a =
  101.     (alias_dir_conf *) ap_pcalloc(p, sizeof(alias_dir_conf));
  102.     a->redirects = ap_make_array(p, 2, sizeof(alias_entry));
  103.     return a;
  104. }
  105.  
  106. static void *merge_alias_config(pool *p, void *basev, void *overridesv)
  107. {
  108.     alias_server_conf *a =
  109.     (alias_server_conf *) ap_pcalloc(p, sizeof(alias_server_conf));
  110.     alias_server_conf *base = (alias_server_conf *) basev, *overrides = (alias_server_conf *) overridesv;
  111.  
  112.     a->aliases = ap_append_arrays(p, overrides->aliases, base->aliases);
  113.     a->redirects = ap_append_arrays(p, overrides->redirects, base->redirects);
  114.     return a;
  115. }
  116.  
  117. static void *merge_alias_dir_config(pool *p, void *basev, void *overridesv)
  118. {
  119.     alias_dir_conf *a =
  120.     (alias_dir_conf *) ap_pcalloc(p, sizeof(alias_dir_conf));
  121.     alias_dir_conf *base = (alias_dir_conf *) basev, *overrides = (alias_dir_conf *) overridesv;
  122.     a->redirects = ap_append_arrays(p, overrides->redirects, base->redirects);
  123.     return a;
  124. }
  125.  
  126. static const char *add_alias_internal(cmd_parms *cmd, void *dummy, char *f, char *r,
  127.                       int use_regex)
  128. {
  129.     server_rec *s = cmd->server;
  130.     alias_server_conf *conf =
  131.     (alias_server_conf *) ap_get_module_config(s->module_config, &alias_module);
  132.     alias_entry *new = ap_push_array(conf->aliases);
  133.  
  134.     /* XX r can NOT be relative to DocumentRoot here... compat bug. */
  135.  
  136.     if (use_regex) {
  137.     new->regexp = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
  138.     if (new->regexp == NULL)
  139.         return "Regular expression could not be compiled.";
  140.     }
  141.  
  142.     new->fake = f;
  143.     new->real = r;
  144.     new->handler = cmd->info;
  145.  
  146.     return NULL;
  147. }
  148.  
  149. static const char *add_alias(cmd_parms *cmd, void *dummy, char *f, char *r)
  150. {
  151.     return add_alias_internal(cmd, dummy, f, r, 0);
  152. }
  153.  
  154. static const char *add_alias_regex(cmd_parms *cmd, void *dummy, char *f, char *r)
  155. {
  156.     return add_alias_internal(cmd, dummy, f, r, 1);
  157. }
  158.  
  159. static const char *add_redirect_internal(cmd_parms *cmd, alias_dir_conf * dirconf,
  160.                      char *arg1, char *arg2, char *arg3,
  161.                      int use_regex)
  162. {
  163.     alias_entry *new;
  164.     server_rec *s = cmd->server;
  165.     alias_server_conf *serverconf =
  166.     (alias_server_conf *) ap_get_module_config(s->module_config, &alias_module);
  167.     int status = (int) (long) cmd->info;
  168.     regex_t *r = NULL;
  169.     char *f = arg2;
  170.     char *url = arg3;
  171.  
  172.     if (!strcasecmp(arg1, "gone"))
  173.     status = HTTP_GONE;
  174.     else if (!strcasecmp(arg1, "permanent"))
  175.     status = HTTP_MOVED_PERMANENTLY;
  176.     else if (!strcasecmp(arg1, "temp"))
  177.     status = HTTP_MOVED_TEMPORARILY;
  178.     else if (!strcasecmp(arg1, "seeother"))
  179.     status = HTTP_SEE_OTHER;
  180.     else if (ap_isdigit(*arg1))
  181.     status = atoi(arg1);
  182.     else {
  183.     f = arg1;
  184.     url = arg2;
  185.     }
  186.  
  187.     if (use_regex) {
  188.     r = ap_pregcomp(cmd->pool, f, REG_EXTENDED);
  189.     if (r == NULL)
  190.         return "Regular expression could not be compiled.";
  191.     }
  192.  
  193.     if (ap_is_HTTP_REDIRECT(status)) {
  194.     if (!url)
  195.         return "URL to redirect to is missing";
  196.     if (!use_regex && !ap_is_url(url))
  197.         return "Redirect to non-URL";
  198.     }
  199.     else {
  200.     if (url)
  201.         return "Redirect URL not valid for this status";
  202.     }
  203.  
  204.     if (cmd->path)
  205.     new = ap_push_array(dirconf->redirects);
  206.     else
  207.     new = ap_push_array(serverconf->redirects);
  208.  
  209.     new->fake = f;
  210.     new->real = url;
  211.     new->regexp = r;
  212.     new->redir_status = status;
  213.     return NULL;
  214. }
  215.  
  216. static const char *add_redirect(cmd_parms *cmd, alias_dir_conf * dirconf, char *arg1,
  217.                 char *arg2, char *arg3)
  218. {
  219.     return add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 0);
  220. }
  221.  
  222. static const char *add_redirect_regex(cmd_parms *cmd, alias_dir_conf * dirconf,
  223.                       char *arg1, char *arg2, char *arg3)
  224. {
  225.     return add_redirect_internal(cmd, dirconf, arg1, arg2, arg3, 1);
  226. }
  227.  
  228. static const command_rec alias_cmds[] =
  229. {
  230.     {"Alias", add_alias, NULL, RSRC_CONF, TAKE2,
  231.      "a fakename and a realname"},
  232.     {"ScriptAlias", add_alias, "cgi-script", RSRC_CONF, TAKE2,
  233.      "a fakename and a realname"},
  234.     {"Redirect", add_redirect, (void *) HTTP_MOVED_TEMPORARILY,
  235.      OR_FILEINFO, TAKE23,
  236.   "an optional status, then document to be redirected and destination URL"},
  237.     {"AliasMatch", add_alias_regex, NULL, RSRC_CONF, TAKE2,
  238.      "a regular expression and a filename"},
  239.     {"ScriptAliasMatch", add_alias_regex, "cgi-script", RSRC_CONF, TAKE2,
  240.      "a regular expression and a filename"},
  241.     {"RedirectMatch", add_redirect_regex, (void *) HTTP_MOVED_TEMPORARILY,
  242.      OR_FILEINFO, TAKE23,
  243.      "an optional status, then a regular expression and destination URL"},
  244.     {"RedirectTemp", add_redirect, (void *) HTTP_MOVED_TEMPORARILY,
  245.      OR_FILEINFO, TAKE2,
  246.      "a document to be redirected, then the destination URL"},
  247.     {"RedirectPermanent", add_redirect, (void *) HTTP_MOVED_PERMANENTLY,
  248.      OR_FILEINFO, TAKE2,
  249.      "a document to be redirected, then the destination URL"},
  250.     {NULL}
  251. };
  252.  
  253. static int alias_matches(const char *uri, const char *alias_fakename)
  254. {
  255.     const char *end_fakename = alias_fakename + strlen(alias_fakename);
  256.     const char *aliasp = alias_fakename, *urip = uri;
  257.  
  258.     while (aliasp < end_fakename) {
  259.     if (*aliasp == '/') {
  260.         /* any number of '/' in the alias matches any number in
  261.          * the supplied URI, but there must be at least one...
  262.          */
  263.         if (*urip != '/')
  264.         return 0;
  265.  
  266.         while (*aliasp == '/')
  267.         ++aliasp;
  268.         while (*urip == '/')
  269.         ++urip;
  270.     }
  271.     else {
  272.         /* Other characters are compared literally */
  273.         if (*urip++ != *aliasp++)
  274.         return 0;
  275.     }
  276.     }
  277.  
  278.     /* Check last alias path component matched all the way */
  279.  
  280.     if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
  281.     return 0;
  282.  
  283.     /* Return number of characters from URI which matched (may be
  284.      * greater than length of alias, since we may have matched
  285.      * doubled slashes)
  286.      */
  287.  
  288.     return urip - uri;
  289. }
  290.  
  291. static char *try_alias_list(request_rec *r, array_header *aliases, int doesc, int *status)
  292. {
  293.     alias_entry *entries = (alias_entry *) aliases->elts;
  294.     regmatch_t regm[10];
  295.     char *found = NULL;
  296.     int i;
  297.  
  298.     for (i = 0; i < aliases->nelts; ++i) {
  299.     alias_entry *p = &entries[i];
  300.     int l;
  301.  
  302.     if (p->regexp) {
  303.         if (!regexec(p->regexp, r->uri, p->regexp->re_nsub + 1, regm, 0)) {
  304.         if (p->real) {
  305.             found = ap_pregsub(r->pool, p->real, r->uri,
  306.                     p->regexp->re_nsub + 1, regm);
  307.             if (found && doesc) {
  308.             found = ap_escape_uri(r->pool, found);
  309.             }
  310.         }
  311.         else {
  312.             /* need something non-null */
  313.             found = ap_pstrdup(r->pool, "");
  314.         }
  315.         }
  316.     }
  317.     else {
  318.         l = alias_matches(r->uri, p->fake);
  319.  
  320.         if (l > 0) {
  321.         if (doesc) {
  322.             char *escurl;
  323.             escurl = ap_os_escape_path(r->pool, r->uri + l, 1);
  324.  
  325.             found = ap_pstrcat(r->pool, p->real, escurl, NULL);
  326.         }
  327.         else
  328.             found = ap_pstrcat(r->pool, p->real, r->uri + l, NULL);
  329.         }
  330.     }
  331.  
  332.     if (found) {
  333.         if (p->handler) {    /* Set handler, and leave a note for mod_cgi */
  334.         r->handler = p->handler;
  335.         ap_table_setn(r->notes, "alias-forced-type", r->handler);
  336.         }
  337.  
  338.         *status = p->redir_status;
  339.  
  340.         return found;
  341.     }
  342.  
  343.     }
  344.  
  345.     return NULL;
  346. }
  347.  
  348. static int translate_alias_redir(request_rec *r)
  349. {
  350.     void *sconf = r->server->module_config;
  351.     alias_server_conf *serverconf =
  352.     (alias_server_conf *) ap_get_module_config(sconf, &alias_module);
  353.     char *ret;
  354.     int status;
  355.  
  356.     if (r->uri[0] != '/' && r->uri[0] != '\0')
  357.     return DECLINED;
  358.  
  359.     if ((ret = try_alias_list(r, serverconf->redirects, 1, &status)) != NULL) {
  360.     if (ap_is_HTTP_REDIRECT(status)) {
  361.         /* include QUERY_STRING if any */
  362.         if (r->args) {
  363.         ret = ap_pstrcat(r->pool, ret, "?", r->args, NULL);
  364.         }
  365.         ap_table_setn(r->headers_out, "Location", ret);
  366.     }
  367.     return status;
  368.     }
  369.  
  370.     if ((ret = try_alias_list(r, serverconf->aliases, 0, &status)) != NULL) {
  371.     r->filename = ret;
  372.     return OK;
  373.     }
  374.  
  375.     return DECLINED;
  376. }
  377.  
  378. static int fixup_redir(request_rec *r)
  379. {
  380.     void *dconf = r->per_dir_config;
  381.     alias_dir_conf *dirconf =
  382.     (alias_dir_conf *) ap_get_module_config(dconf, &alias_module);
  383.     char *ret;
  384.     int status;
  385.  
  386.     /* It may have changed since last time, so try again */
  387.  
  388.     if ((ret = try_alias_list(r, dirconf->redirects, 1, &status)) != NULL) {
  389.     if (ap_is_HTTP_REDIRECT(status))
  390.         ap_table_setn(r->headers_out, "Location", ret);
  391.     return status;
  392.     }
  393.  
  394.     return DECLINED;
  395. }
  396.  
  397. module MODULE_VAR_EXPORT alias_module =
  398. {
  399.     STANDARD_MODULE_STUFF,
  400.     NULL,            /* initializer */
  401.     create_alias_dir_config,    /* dir config creater */
  402.     merge_alias_dir_config,    /* dir merger --- default is to override */
  403.     create_alias_config,    /* server config */
  404.     merge_alias_config,        /* merge server configs */
  405.     alias_cmds,            /* command table */
  406.     NULL,            /* handlers */
  407.     translate_alias_redir,    /* filename translation */
  408.     NULL,            /* check_user_id */
  409.     NULL,            /* check auth */
  410.     NULL,            /* check access */
  411.     NULL,            /* type_checker */
  412.     fixup_redir,        /* fixups */
  413.     NULL,            /* logger */
  414.     NULL,            /* header parser */
  415.     NULL,            /* child_init */
  416.     NULL,            /* child_exit */
  417.     NULL            /* post read-request */
  418. };
  419.