home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 8 / CDACTUAL8.iso / share / os2 / varios / apache / http_req.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-28  |  27.9 KB  |  876 lines

  1.  
  2. /* ====================================================================
  3.  * Copyright (c) 1995 The Apache Group.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * 1. Redistributions of source code must retain the above copyright
  10.  *    notice, this list of conditions and the following disclaimer. 
  11.  *
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in
  14.  *    the documentation and/or other materials provided with the
  15.  *    distribution.
  16.  *
  17.  * 3. All advertising materials mentioning features or use of this
  18.  *    software must display the following acknowledgment:
  19.  *    "This product includes software developed by the Apache Group
  20.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  21.  *
  22.  * 4. The names "Apache Server" and "Apache Group" must not be used to
  23.  *    endorse or promote products derived from this software without
  24.  *    prior written permission.
  25.  *
  26.  * 5. Redistributions of any form whatsoever must retain the following
  27.  *    acknowledgment:
  28.  *    "This product includes software developed by the Apache Group
  29.  *    for use in the Apache HTTP server project (http://www.apache.org/)."
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
  32.  * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  33.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  34.  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE APACHE GROUP OR
  35.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  36.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  37.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  38.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  41.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  42.  * OF THE POSSIBILITY OF SUCH DAMAGE.
  43.  * ====================================================================
  44.  *
  45.  * This software consists of voluntary contributions made by many
  46.  * individuals on behalf of the Apache Group and was originally based
  47.  * on public domain software written at the National Center for
  48.  * Supercomputing Applications, University of Illinois, Urbana-Champaign.
  49.  * For more information on the Apache Group and the Apache HTTP server
  50.  * project, please see <http://www.apache.org/>.
  51.  *
  52.  */
  53.  
  54.  
  55. /*
  56.  * http_request.c: functions to get and process requests
  57.  * 
  58.  * Rob McCool 3/21/93
  59.  *
  60.  * Thoroughly revamped by rst for Shambhala.  NB this file reads
  61.  * best from the bottom up.
  62.  * 
  63.  */
  64.  
  65. #define CORE_PRIVATE
  66. #include "httpd.h"
  67. #include "http_config.h"
  68. #include "http_request.h"
  69. #include "http_core.h"
  70. #include "http_protocol.h"
  71. #include "http_log.h"
  72. #include "http_main.h"
  73. #include "scoreboard.h"
  74.  
  75. /*****************************************************************
  76.  *
  77.  * Getting and checking directory configuration.  Also checks the
  78.  * FollowSymlinks and FollowSymOwner stuff, since this is really the
  79.  * only place that can happen (barring a new mid_dir_walk callout).
  80.  *
  81.  * We can't do it as an access_checker module function which gets
  82.  * called with the final per_dir_config, since we could have a directory
  83.  * with FollowSymLinks disabled, which contains a symlink to another
  84.  * with a .htaccess file which turns FollowSymLinks back on --- and
  85.  * access in such a case must be denied.  So, whatever it is that
  86.  * checks FollowSymLinks needs to know the state of the options as
  87.  * they change, all the way down.
  88.  */
  89.  
  90. int check_symlinks (char *d, int opts)
  91. {
  92.     struct stat lfi, fi;
  93.     char *lastp;
  94.     int res;
  95.   
  96. #ifdef __EMX__
  97.     /* OS/2 dosen't have symlinks */
  98.     return OK;
  99. #else
  100.   
  101.     if (opts & OPT_SYM_LINKS) return OK;
  102.  
  103.     /* Strip trailing '/', if any, off what we're checking; trailing
  104.      * slashes make some systems follow symlinks to directories even in
  105.      * lstat().  After we've done the lstat, put it back.  Also, don't
  106.      * bother checking '/' at all...
  107.      *
  108.      * Note that we don't have to worry about multiple slashes here
  109.      * because of no2slash() below...
  110.      */
  111.  
  112.     lastp = d + strlen(d) - 1;
  113.     if (lastp == d) return OK;        /* Root directory, '/' */
  114.     
  115.     if (*lastp == '/') *lastp = '\0';
  116.     else lastp = NULL;
  117.         
  118.     res = lstat (d, &lfi);
  119.  
  120.     if (lastp) *lastp = '/';
  121.     
  122.     /* Note that we don't reject accesses to nonexistent files (multiviews
  123.      * or the like may cons up a way to run the transaction anyway)...
  124.      */
  125.                     
  126.     if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK;
  127.  
  128.     /* OK, it's a symlink.  May still be OK with OPT_SYM_OWNER */
  129.     
  130.     if (!(opts & OPT_SYM_OWNER)) return FORBIDDEN;
  131.         
  132.     if (stat (d, &fi) < 0) return FORBIDDEN;
  133.     
  134.     return (fi.st_uid == lfi.st_uid) ? OK : FORBIDDEN;
  135.  
  136. #endif    
  137. }
  138.     
  139. /* Dealing with the file system to get PATH_INFO
  140.  */
  141.  
  142. void get_path_info(request_rec *r)
  143. {
  144.     char *cp;
  145.     char *path = r->filename;
  146.     char *end = &path[strlen(path)];
  147.     char *last_cp = NULL;
  148.     int rv;
  149.  
  150.     /* Advance over trailing slashes ... NOT part of filename */
  151.  
  152.     for (cp = end; cp > path && cp[-1] == '/'; --cp)
  153.         continue;
  154.     
  155.     while (cp > path) {
  156.       
  157.         /* See if the pathname ending here exists... */
  158.       
  159.         *cp = '\0';
  160.         rv = stat(path, &r->finfo);
  161.         if (cp != end) *cp = '/';
  162.       
  163.         if (!rv) {
  164.  
  165.             /* Aha!  Found something.  If it was a directory, we will
  166.              * search contents of that directory for a multi_match, so
  167.              * the PATH_INFO argument starts with the component after that.
  168.              */
  169.         
  170.             if (S_ISDIR(r->finfo.st_mode) && last_cp) {
  171.                 r->finfo.st_mode = 0; /* No such file... */
  172.                 cp = last_cp;
  173.             }
  174.         
  175.             r->path_info = pstrdup (r->pool, cp);
  176.             *cp = '\0';
  177.             return;
  178.         }
  179.         else {
  180.             last_cp = cp;
  181.         
  182.             while (--cp > path && *cp != '/')
  183.                 continue;
  184.  
  185.             while (cp > path && cp[-1] == '/')
  186.                 --cp;
  187.         }
  188.     }
  189. }
  190.  
  191. int directory_walk (request_rec *r)
  192. {
  193.     core_server_config *sconf = get_module_config (r->server->module_config,
  194.                                                    &core_module);
  195.     array_header *sec_array = copy_array (r->pool, sconf->sec);
  196.     void *per_dir_defaults = r->server->lookup_defaults;
  197.     
  198.     core_dir_config **sec = (core_dir_config **)sec_array->elts;
  199.     int num_sec = sec_array->nelts;
  200.     char *test_filename = pstrdup (r->pool, r->filename);
  201.  
  202.     int num_dirs, res;
  203.     int i;
  204.  
  205.     /* Are we dealing with a file? If not, we can (hopefuly) safely assume
  206.      * we have a handler that doesn't require one, but for safety's sake,
  207.      * and so we have something find_types() can get something out of,
  208.      * fake one. But don't run through the directory entries.
  209.      */
  210.  
  211.     if (test_filename == NULL) {
  212.         r->filename = pstrdup(r->pool, r->uri);
  213.         r->finfo.st_mode = 0;        /* Not really a file... */
  214.         r->per_dir_config = per_dir_defaults;
  215.  
  216.         return OK;
  217.     }
  218.  
  219.     /* Go down the directory hierarchy.  Where we have to check for symlinks,
  220.      * do so.  Where a .htaccess file has permission to override anything,
  221.      * try to find one.  If either of these things fails, we could poke
  222.      * around, see why, and adjust the lookup_rec accordingly --- this might
  223.      * save us a call to get_path_info (with the attendant stat()s); however,
  224.      * for the moment, that's not worth the trouble.
  225.      */
  226.  
  227. #ifdef __EMX__
  228.     /* Add OS/2 drive name support */    
  229.     if ((test_filename[0] != '/') && (test_filename[1] != ':'))
  230. #else    
  231.     if (test_filename[0] != '/')
  232. #endif    
  233.     {
  234. /* fake filenames only match Directory sections */
  235.         void *this_conf, *entry_config;
  236.         core_dir_config *entry_core;
  237.         char *entry_dir;
  238.         int j;
  239.  
  240.         for (j = 0; j < num_sec; ++j) {
  241.  
  242.             entry_config = sec[j];
  243.             if (!entry_config) continue;
  244.             
  245.             entry_core =(core_dir_config *)
  246.                 get_module_config(entry_config, &core_module);
  247.             entry_dir = entry_core->d;
  248.  
  249.             this_conf = NULL;
  250.             if (is_matchexp(entry_dir)) {
  251.                 if (!strcmp_match(test_filename, entry_dir))
  252.                     this_conf = entry_config;
  253.             }
  254.             else if (!strncmp (test_filename, entry_dir, strlen(entry_dir)))
  255.                 this_conf = entry_config;
  256.  
  257.             if (this_conf)
  258.                 per_dir_defaults = merge_per_dir_configs (r->pool,
  259.                                            per_dir_defaults, this_conf);
  260.         }
  261.  
  262.         r->per_dir_config = per_dir_defaults;
  263.  
  264.         return OK;
  265.     }
  266.  
  267.     no2slash (test_filename);
  268.     num_dirs = count_dirs(test_filename);
  269.     get_path_info (r);
  270.     
  271.     if (S_ISDIR (r->finfo.st_mode)) ++num_dirs;
  272.  
  273.     for (i = 1; i <= num_dirs; ++i) {
  274.         core_dir_config *core_dir =
  275.           (core_dir_config *)get_module_config(per_dir_defaults, &core_module);
  276.         int allowed_here = core_dir->opts;
  277.         int overrides_here = core_dir->override;
  278.         void *this_conf = NULL, *htaccess_conf = NULL;
  279.         char *this_dir = make_dirstr (r->pool, test_filename, i);
  280.         char *config_name = make_full_path(r->pool, this_dir,
  281.                                            sconf->access_name);
  282.         int j;
  283.       
  284.         /* Do symlink checks first, because they are done with the
  285.          * permissions appropriate to the *parent* directory...
  286.          */
  287.         
  288.         if ((res = check_symlinks (this_dir, allowed_here)))
  289.         {
  290.             log_reason("Symbolic link not allowed", this_dir, r);
  291.             return res;
  292.         }
  293.         
  294.         /* Begin *this* level by looking for matching <Directory> sections from
  295.          * access.conf.
  296.          */
  297.     
  298.         for (j = 0; j < num_sec; ++j) {
  299.             void *entry_config = sec[j];
  300.             core_dir_config *entry_core;
  301.             char *entry_dir;
  302.  
  303.             if (!entry_config) continue;
  304.             
  305.             entry_core =
  306.               (core_dir_config *)get_module_config(entry_config, &core_module);
  307.             entry_dir = entry_core->d;
  308.         
  309.             if (is_matchexp(entry_dir) && !strcmp_match(this_dir, entry_dir)) {
  310.                 /* Don't try this wildcard again --- if it ends in '*'
  311.                  * it'll match again, and subdirectories won't be able to
  312.                  * override it...
  313.                  */
  314.                 sec[j] = NULL;        
  315.                 this_conf = entry_config;
  316.             }
  317.             else if (!strcmp (this_dir, entry_dir))
  318.                 this_conf = entry_config;
  319.         }
  320.  
  321.         if (this_conf)
  322.         {
  323.             per_dir_defaults =
  324.                 merge_per_dir_configs (r->pool, per_dir_defaults, this_conf);
  325.             core_dir =(core_dir_config *)get_module_config(per_dir_defaults,
  326.                                                            &core_module);
  327.         }
  328.         overrides_here = core_dir->override;
  329.  
  330.         /* If .htaccess files are enabled, check for one.
  331.          */
  332.         
  333.         if (overrides_here) {
  334.             res = parse_htaccess (&htaccess_conf, r, overrides_here,
  335.                                   this_dir, config_name);
  336.             if (res) return res;
  337.         }
  338.  
  339.         if (htaccess_conf)
  340.             per_dir_defaults =
  341.                 merge_per_dir_configs (r->pool, per_dir_defaults,
  342.                                        htaccess_conf);
  343.         
  344.     }
  345.  
  346.     r->per_dir_config = per_dir_defaults;
  347.  
  348.     if ((res = check_symlinks (r->filename, allow_options(r))))
  349.     {
  350.         log_reason("Symbolic link not allowed", r->filename, r);
  351.         return res;
  352.     }
  353.     
  354.     return OK;                        /* Can only "fail" if access denied
  355.                                  * by the symlink goop.
  356.                                  */
  357. }
  358.  
  359. int location_walk (request_rec *r)
  360. {
  361.     core_server_config *sconf = get_module_config (r->server->module_config,
  362.                                                    &core_module);
  363.     array_header *url_array = copy_array (r->pool, sconf->sec_url);
  364.     void *per_dir_defaults = r->per_dir_config;
  365.     
  366.     core_dir_config **url = (core_dir_config **)url_array->elts;
  367.     int num_url = url_array->nelts;
  368.     char *test_location = pstrdup (r->pool, r->uri);
  369.  
  370.     /* Go through the location entries, and check for matches. */
  371.  
  372.     if (num_url) {
  373.         void *this_conf, *entry_config;
  374.         core_dir_config *entry_core;
  375.         char *entry_url;
  376.         int j;
  377.  
  378. /* 
  379.  * we apply the directive sections in some order; should really try them
  380.  * with the most general first.
  381.  */
  382.         for (j = 0; j < num_url; ++j) {
  383.  
  384.             entry_config = url[j];
  385.             if (!entry_config) continue;
  386.             
  387.             entry_core =(core_dir_config *)
  388.                 get_module_config(entry_config, &core_module);
  389.             entry_url = entry_core->d;
  390.  
  391.             this_conf = NULL;
  392.             if (is_matchexp(entry_url)) {
  393.                 if (!strcmp_match(test_location, entry_url))
  394.                     this_conf = entry_config;
  395.             }
  396.             else if (!strncmp (test_location, entry_url, strlen(entry_url)))
  397.                 this_conf = entry_config;
  398.  
  399.             if (this_conf)
  400.                 per_dir_defaults = merge_per_dir_configs (r->pool,
  401.                                             per_dir_defaults, this_conf);
  402.         }
  403.  
  404.         r->per_dir_config = per_dir_defaults;
  405.     }
  406.  
  407.     return OK;
  408. }
  409.  
  410. /*****************************************************************
  411.  *
  412.  * The sub_request mechanism.
  413.  *
  414.  * Fns to look up a relative URI from, e.g., a map file or SSI document.
  415.  * These do all access checks, etc., but don't actually run the transaction
  416.  * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req
  417.  * as appropriate if you're likely to be creating more than a few of these.
  418.  * (An early Shambhala version didn't destroy the sub_reqs used in directory
  419.  * indexing.  The result, when indexing a directory with 800-odd files in
  420.  * it, was massively excessive storage allocation).
  421.  *
  422.  * Note more manipulation of protocol-specific vars in the request
  423.  * structure...
  424.  */
  425.  
  426. request_rec *make_sub_request (request_rec *r)
  427. {
  428.     pool *rrp = make_sub_pool (r->pool);
  429.     request_rec *rr = pcalloc (rrp, sizeof (request_rec));
  430.     
  431.     rr->pool = rrp;
  432.     return rr;
  433. }
  434.  
  435. request_rec *sub_req_lookup_simple (char *new_file, request_rec *r)
  436. {
  437.     /* This handles the simple case, common to ..._lookup_uri and _file,
  438.      * of looking up another file in the same directory.
  439.      */
  440.     request_rec *rnew = make_sub_request (r);
  441.     pool *rnewp = rnew->pool;
  442.     int res;
  443.     
  444.     char *udir = make_dirstr(rnewp, r->uri, count_dirs(r->uri));
  445.     char *fdir = make_dirstr(rnewp, r->filename, count_dirs(r->filename));
  446.  
  447.     *rnew = *r;                        /* Copy per_dir config, etc. */
  448.     rnew->pool = rnewp;
  449.     rnew->uri = make_full_path (rnewp, udir, new_file);
  450.     rnew->filename = make_full_path (rnewp, fdir, new_file);
  451.     set_sub_req_protocol (rnew, r);
  452.         
  453.     rnew->finfo.st_mode = 0;
  454.     
  455.     if ((res = check_symlinks (rnew->filename, allow_options (rnew))))
  456.     {
  457.         rnew->status = res;
  458.     }
  459.  
  460.     if (rnew->finfo.st_mode == 0 && stat (rnew->filename, &rnew->finfo) < 0)
  461.         rnew->finfo.st_mode = 0;
  462.  
  463.     if ((rnew->status == 200) && (res = find_types (rnew)))
  464.         rnew->status = res;
  465.     
  466.     if ((rnew->status == 200) && (res = run_fixups (rnew)))
  467.         rnew->status = res;
  468.     
  469.     return rnew;
  470. }
  471.  
  472.  
  473. static int some_auth_required (request_rec *r);
  474.  
  475. request_rec *sub_req_lookup_uri (char *new_file, request_rec *r)
  476. {
  477.     request_rec *rnew;
  478.     int res;
  479.     char *udir;
  480.     
  481.     rnew = make_sub_request (r);
  482.     rnew->connection = r->connection; 
  483.     rnew->server = r->server;
  484.     rnew->request_config = create_request_config (rnew->pool);
  485.     rnew->htaccess = r->htaccess; /* copy htaccess cache */
  486.     set_sub_req_protocol (rnew, r);
  487.         
  488.     if (new_file[0] == '/')
  489.         parse_uri(rnew, new_file);
  490.     else
  491.     {
  492.         udir = make_dirstr (rnew->pool, r->uri, count_dirs (r->uri));
  493.         udir = escape_uri(rnew->pool, udir); /* re-escape it */
  494.         parse_uri (rnew, make_full_path (rnew->pool, udir, new_file));
  495.     }
  496.         
  497.     res = unescape_url (rnew->uri);
  498.     if (res)
  499.     {
  500.         rnew->status = res;
  501.         return rnew;
  502.     }
  503.  
  504.     getparents (rnew->uri);
  505.         
  506.     res = translate_name(rnew);
  507.     if (res)
  508.     {
  509.         rnew->status = res;
  510.         return rnew;
  511.     }
  512.  
  513.     /* We could be clever at this point, and avoid calling directory_walk, etc.
  514.      * However, we'd need to test that the old and new filenames contain the
  515.      * same directory components, so it would require duplicating the start
  516.      * of translate_name.
  517.      * Instead we rely on the cache of .htaccess results.
  518.      */
  519.     
  520.     if ((res = directory_walk (rnew))
  521.         || (!some_auth_required (rnew) ? 0 :
  522.              ((res = check_user_id (rnew)) || (res = check_auth (rnew))))
  523.         || (res = check_access (rnew))
  524.         || (res = find_types (rnew))
  525.         || (res = run_fixups (rnew))
  526.         )
  527.     {
  528.         rnew->status = res;
  529.     }
  530.  
  531.     return rnew;
  532. }
  533.  
  534. request_rec *sub_req_lookup_file (char *new_file, request_rec *r)
  535. {
  536.     request_rec *rnew;
  537.     int res;
  538.     char *fdir;
  539.     
  540.     /* Check for a special case... if there are no '/' characters in new_file
  541.      * at all, then we are looking at a relative lookup in the same directory.
  542.      * That means we don't have to redo any access checks.
  543.      */
  544.  
  545.     if (strchr (new_file, '/') == NULL) 
  546.         return sub_req_lookup_simple (new_file, r);
  547.  
  548.     rnew = make_sub_request (r);
  549.     fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename));
  550.     
  551.     rnew->connection = r->connection; /* For now... */
  552.     rnew->server = r->server;
  553.     rnew->request_config = create_request_config (rnew->pool);
  554.     rnew->htaccess = r->htaccess; /* copy htaccess cache */
  555.     set_sub_req_protocol (rnew, r);
  556.         
  557.     rnew->uri = "INTERNALLY GENERATED file-relative req";
  558.     rnew->filename = ((new_file[0] == '/') ?
  559.                       new_file :
  560.                       make_full_path (rnew->pool, fdir, new_file));
  561.         
  562.     if ((res = directory_walk (rnew))
  563.         || (res = check_access (rnew))
  564.         || (!some_auth_required (rnew) ? 0 :
  565.              ((res = check_user_id (rnew)) && (res = check_auth (rnew))))
  566.         || (res = find_types (rnew))
  567.         || (res = run_fixups (rnew))
  568.         )
  569.     {
  570.         rnew->status = res;
  571.     }
  572.  
  573.     return rnew;
  574. }
  575.  
  576. int run_sub_req (request_rec *r)
  577. {
  578.     int retval = invoke_handler (r);
  579.     finalize_sub_req_protocol (r);
  580.     return retval;
  581. }
  582.  
  583. void destroy_sub_req (request_rec *r)
  584. {
  585.     /* Reclaim the space */
  586.     destroy_pool (r->pool);
  587. }
  588.  
  589. /*****************************************************************
  590.  *
  591.  * Mainline request processing...
  592.  */
  593.  
  594. void die(int type, request_rec *r)
  595. {
  596.     int error_index = index_of_response (type);
  597.     char *custom_response = response_code_string(r, error_index);
  598.     int recursive_error = 0;
  599.     
  600.     /* The following takes care of Apache redirects to custom response URLs
  601.      * Note that if we are already dealing with the response to some other
  602.      * error condition, we just report on the original error, and give up on
  603.      * any attempt to handle the other thing "intelligently"...
  604.      */
  605.  
  606.     if (r->status != 200) {
  607.         recursive_error = type;
  608.  
  609.         while (r->prev && r->prev->status != 200)
  610.           r = r->prev; /* Get back to original error */
  611.         
  612.         type = r->status;
  613.         custom_response = NULL;        /* Do NOT retry the custom thing! */
  614.     }
  615.        
  616.     r->status = type;
  617.     
  618.     /* Two types of custom redirects --- plain text, and URLs.
  619.      * Plain text has a leading '"', so the URL code, here, is triggered
  620.      * on its absence
  621.      */
  622.     
  623.     if (custom_response && custom_response[0] != '"') {
  624.           
  625.         if (is_url(custom_response)) {
  626.             /* The URL isn't local, so lets drop through the rest of
  627.              * this apache code, and continue with the usual REDIRECT
  628.              * handler.  But note that the client will ultimately see
  629.              * the wrong status...
  630.              */
  631.             r->status = REDIRECT;
  632.             table_set (r->headers_out, "Location", custom_response);
  633.         } else if ( custom_response[0] == '/') {
  634.             r->no_cache = 1;        /* Do NOT send USE_LOCAL_COPY for
  635.                                  * error documents!
  636.                                  */
  637.             /* This redirect needs to be a GET no matter what the original
  638.              * method was.
  639.              */
  640.             r->method = pstrdup(r->pool, "GET");
  641.             r->method_number = M_GET;
  642.             internal_redirect (custom_response, r);
  643.             return;
  644.         } else {
  645.             /* Dumb user has given us a bad url to redirect to
  646.              * --- fake up dying with a recursive server error...
  647.              */
  648.             recursive_error = SERVER_ERROR;
  649.             log_reason("Invalid error redirection directive", custom_response,
  650.                        r);
  651.         }       
  652.     }
  653.  
  654.     send_error_response (r, recursive_error);
  655. }
  656.  
  657. static void decl_die (int status, char *phase, request_rec *r)
  658. {
  659.     if (status == DECLINED) {
  660.         log_reason (pstrcat (r->pool,
  661.                              "configuration error:  couldn't ",
  662.                              phase, NULL),
  663.                     r->uri,
  664.                     r);
  665.         die (SERVER_ERROR, r);
  666.     }
  667.     else die (status, r);
  668. }
  669.  
  670. static int some_auth_required (request_rec *r)
  671. {
  672.     /* Is there a require line configured for the type of *this* req? */
  673.     
  674.     array_header *reqs_arr = requires (r);
  675.     require_line *reqs;
  676.     int i;
  677.     
  678.     if (!reqs_arr) return 0;
  679.     
  680.     reqs = (require_line *)reqs_arr->elts;
  681.  
  682.     for (i = 0; i < reqs_arr->nelts; ++i)
  683.         if (reqs[i].method_mask & (1 << r->method_number))
  684.             return 1;
  685.  
  686.     return 0;
  687. }
  688.  
  689. void process_request_internal (request_rec *r)
  690. {
  691.     int access_status;
  692.   
  693.     /* Kludge to be reading the assbackwards field outside of protocol.c,
  694.      * but we've got to check for this sort of nonsense somewhere...
  695.      */
  696.     
  697.     if (r->assbackwards && r->header_only) {
  698.         /* Client asked for headers only with HTTP/0.9, which doesn't
  699.          * send headers!  Have to dink things even to make sure the
  700.          * error message comes through...
  701.          */
  702.         log_reason ("client sent illegal HTTP/0.9 request", r->uri, r);
  703.         r->header_only = 0;
  704.         die (BAD_REQUEST, r);
  705.         return;
  706.     }
  707.  
  708.     if (!r->hostname && (r->proto_num >= 1001)) {
  709.         /* Client sent us a HTTP/1.1 or later request without telling
  710.          * us the hostname, either with a full URL or a Host: header.
  711.          * We therefore need to (as per the 1.1 spec) send an error
  712.          */
  713.         log_reason ("client sent HTTP/1.1 request without hostname",
  714.                     r->uri, r);
  715.         die (BAD_REQUEST, r);
  716.         return;
  717.     }
  718.  
  719.     if (!r->proxyreq)
  720.     {
  721.         access_status = unescape_url(r->uri);
  722.         if (access_status)
  723.         {
  724.             die(access_status, r);
  725.             return;
  726.         }
  727.  
  728.         getparents(r->uri);        /* OK --- shrinking transformations... */
  729.     }
  730.  
  731.     if ((access_status = translate_name (r))) {
  732.         decl_die (access_status, "translate", r);
  733.         return;
  734.     }
  735.     
  736.     if ((access_status = directory_walk (r))) {
  737.         die (access_status, r);
  738.         return;
  739.     }        
  740.     
  741.     if ((access_status = location_walk (r))) {
  742.         die (access_status, r);
  743.         return;
  744.     }        
  745.     
  746.     if ((access_status = check_access (r)) != 0) {
  747.         decl_die (access_status, "check access", r);
  748.         return;
  749.     }
  750.     
  751.     if (some_auth_required (r)) {
  752.         if ((access_status = check_user_id (r)) != 0) {
  753.             decl_die (access_status, "check user.  No user file?", r);
  754.             return;
  755.         }
  756.  
  757.         if ((access_status = check_auth (r)) != 0) {
  758.             decl_die (access_status, "check access.  No groups file?", r);
  759.             return;
  760.         }
  761.     }
  762.  
  763.     if ((access_status = find_types (r)) != 0) {
  764.         decl_die (access_status, "find types", r);
  765.         return;
  766.     }
  767.  
  768.     if ((access_status = run_fixups (r)) != 0) {
  769.         die (access_status, r);
  770.         return;
  771.     }
  772.  
  773.     if ((access_status = invoke_handler (r)) != 0)
  774.         die (access_status, r);
  775. }
  776.  
  777. void process_request (request_rec *r)
  778. {
  779. #ifdef STATUS
  780.     int old_stat;
  781. #endif /* STATUS */
  782.     process_request_internal (r);
  783. #ifdef STATUS
  784.     old_stat = update_child_status (r->connection->child_num, SERVER_BUSY_LOG,
  785.      r);
  786. #endif /* STATUS */
  787.     log_transaction (r);
  788. #ifdef STATUS
  789.     (void)update_child_status (r->connection->child_num, old_stat, r);
  790. #endif /* STATUS */
  791. }
  792.  
  793. table *rename_original_env (pool *p, table *t)
  794. {
  795.     array_header *env_arr = table_elts (t);
  796.     table_entry *elts = (table_entry *)env_arr->elts;
  797.     table *new = make_table (p, env_arr->nelts);
  798.     int i;
  799.     
  800.     for (i = 0; i < env_arr->nelts; ++i) {
  801.         if (!elts[i].key) continue;
  802.         table_set (new, pstrcat (p, "REDIRECT_", elts[i].key, NULL),
  803.                    elts[i].val);
  804.     }
  805.  
  806.     return new;
  807. }
  808.  
  809. request_rec *internal_internal_redirect (char *new_uri, request_rec *r)
  810. {
  811.     request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec));
  812.     char t[10];                        /* Long enough... */
  813.   
  814.     new->connection = r->connection;
  815.     new->server = r->server;
  816.     new->pool = r->pool;
  817.     
  818.     /* A whole lot of this really ought to be shared with protocol.c...
  819.      * another missing cleanup.  It's particularly inappropriate to be
  820.      * setting header_only, etc., here.
  821.      */
  822.     
  823.     parse_uri (new, new_uri);
  824.     new->request_config = create_request_config (r->pool);
  825.     new->per_dir_config = r->server->lookup_defaults;
  826.     
  827.     new->prev = r;
  828.     r->next = new;
  829.     
  830.     /* Inherit the rest of the protocol info... */
  831.  
  832.     new->method = r->method;
  833.     new->method_number = r->method_number;
  834.     
  835.     new->status = r->status;
  836.     new->assbackwards = r->assbackwards;
  837.     new->header_only = r->header_only;
  838.     new->protocol = r->protocol;
  839.     new->main = r->main;
  840.  
  841.     new->headers_in = r->headers_in;
  842.     new->headers_out = make_table (r->pool, 5);
  843.     new->err_headers_out = r->err_headers_out;
  844.     new->subprocess_env = rename_original_env (r->pool, r->subprocess_env);
  845.     new->notes = make_table (r->pool, 5);
  846.     new->htaccess = r->htaccess; /* copy .htaccess cache */
  847.     
  848.     new->no_cache = r->no_cache; /* If we've already made up our minds
  849.                                   * about this, don't change 'em back!
  850.                                   */
  851.  
  852.     sprintf (t, "%d", r->status);
  853.     table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t));
  854.  
  855.     return new;
  856. }
  857.  
  858. void internal_redirect (char *new_uri, request_rec *r)
  859. {
  860.     request_rec *new = internal_internal_redirect(new_uri, r);
  861.     process_request_internal (new);
  862. }
  863.  
  864. /* This function is designed for things like actions or CGI scripts, when
  865.  * using AddHandler, and you want to preserve the content type across
  866.  * an internal redirect.
  867.  */
  868.  
  869. void internal_redirect_handler (char *new_uri, request_rec *r)
  870. {
  871.     request_rec *new = internal_internal_redirect(new_uri, r);
  872.     if (r->handler)
  873.         new->content_type = r->content_type;
  874.     process_request_internal (new);
  875. }
  876.