home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 9 / CDACTUAL9.iso / share / Os2 / varios / APACHE / HTTP_REQ.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-17  |  20.7 KB  |  698 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.  
  74. /*****************************************************************
  75.  *
  76.  * Getting and checking directory configuration.  Also checks the
  77.  * FollowSymlinks and FollowSymOwner stuff, since this is really the
  78.  * only place that can happen (barring a new mid_dir_walk callout).
  79.  *
  80.  * We can't do it as an access_checker module function which gets
  81.  * called with the final per_dir_config, since we could have a directory
  82.  * with FollowSymLinks disabled, which contains a symlink to another
  83.  * with a .htaccess file which turns FollowSymLinks back on --- and
  84.  * access in such a case must be denied.  So, whatever it is that
  85.  * checks FollowSymLinks needs to know the state of the options as
  86.  * they change, all the way down.
  87.  */
  88.  
  89. int check_symlinks (char *d, int opts)
  90. {
  91.     struct stat lfi, fi;
  92.     char *lastp;
  93.     int res;
  94.   
  95. #ifdef __EMX__
  96.     /* OS/2 dosen't have symlinks */
  97.     return OK;
  98. #else
  99.  
  100.     if (opts & OPT_SYM_LINKS) return OK;
  101.  
  102.     /* Strip trailing '/', if any, off what we're checking; trailing
  103.      * slashes make some systems follow symlinks to directories even in
  104.      * lstat().  After we've done the lstat, put it back.  Also, don't
  105.      * bother checking '/' at all...
  106.      *
  107.      * Note that we don't have to worry about multiple slashes here
  108.      * because of no2slash() below...
  109.      */
  110.  
  111.     lastp = d + strlen(d) - 1;
  112.     if (lastp == d) return OK;    /* Root directory, '/' */
  113.     
  114.     if (*lastp == '/') *lastp = '\0';
  115.     else lastp = NULL;
  116.     
  117.     res = lstat (d, &lfi);
  118.  
  119.     if (lastp) *lastp = '/';
  120.     
  121.     /* Note that we don't reject accesses to nonexistent files (multiviews
  122.      * or the like may cons up a way to run the transaction anyway)...
  123.      */
  124.             
  125.     if (!(res >= 0) || !S_ISLNK(lfi.st_mode)) return OK;
  126.  
  127.     /* OK, it's a symlink.  May still be OK with OPT_SYM_OWNER */
  128.     
  129.     if (!(opts & OPT_SYM_OWNER)) return FORBIDDEN;
  130.     
  131.     if (stat (d, &fi) < 0) return FORBIDDEN;
  132.     
  133.     return (fi.st_uid == lfi.st_uid) ? OK : FORBIDDEN;
  134. #endif
  135. }
  136.     
  137. /* Dealing with the file system to get PATH_INFO
  138.  */
  139.  
  140. void get_path_info(request_rec *r)
  141. {
  142.     char *cp;
  143.     char *path = r->filename;
  144.     char *end = &path[strlen(path)];
  145.     char *last_cp = NULL;
  146.     int rv;
  147.  
  148.     /* Advance over trailing slashes ... NOT part of filename */
  149.  
  150.     for (cp = end; cp > path && cp[-1] == '/'; --cp)
  151.     continue;
  152.     
  153.     while (cp > path) {
  154.       
  155.     /* See if the pathname ending here exists... */
  156.       
  157.     *cp = '\0';
  158.     rv = stat(path, &r->finfo);
  159.     if (cp != end) *cp = '/';
  160.       
  161.     if (!rv) {
  162.  
  163.         /* Aha!  Found something.  If it was a directory, we will
  164.          * search contents of that directory for a multi_match, so
  165.          * the PATH_INFO argument starts with the component after that.
  166.          */
  167.     
  168.         if (S_ISDIR(r->finfo.st_mode) && last_cp) {
  169.             r->finfo.st_mode = 0; /* No such file... */
  170.         cp = last_cp;
  171.         }
  172.     
  173.         r->path_info = pstrdup (r->pool, cp);
  174.         *cp = '\0';
  175.         return;
  176.     }
  177.     else {
  178.         last_cp = cp;
  179.     
  180.         while (--cp > path && *cp != '/')
  181.         continue;
  182.  
  183.         while (cp > path && cp[-1] == '/')
  184.         --cp;
  185.     }
  186.     }
  187. }
  188.  
  189. int directory_walk (request_rec *r)
  190. {
  191.     core_server_config *sconf = get_module_config (r->server->module_config,
  192.                            &core_module);
  193.     array_header *sec_array = copy_array (r->pool, sconf->sec);
  194.     
  195.     core_dir_config **sec = (core_dir_config **)sec_array->elts;
  196.     int num_sec = sec_array->nelts;
  197.     void *per_dir_defaults = r->server->lookup_defaults;
  198.     char *test_filename = pstrdup (r->pool, r->filename);
  199.  
  200.     int num_dirs, res;
  201.     int i;
  202.  
  203.     /* Go down the directory hierarchy.  Where we have to check for symlinks,
  204.      * do so.  Where a .htaccess file has permission to override anything,
  205.      * try to find one.  If either of these things fails, we could poke
  206.      * around, see why, and adjust the lookup_rec accordingly --- this might
  207.      * save us a call to get_path_info (with the attendant stat()s); however,
  208.      * for the moment, that's not worth the trouble.
  209.      */
  210.  
  211.     no2slash (test_filename);
  212.     num_dirs = count_dirs(test_filename);
  213.     get_path_info (r);
  214.     
  215.     if (S_ISDIR (r->finfo.st_mode)) ++num_dirs;
  216.  
  217.     for (i = 1; i <= num_dirs; ++i) {
  218.         core_dir_config *core_dir =
  219.       (core_dir_config *)get_module_config(per_dir_defaults, &core_module);
  220.     int allowed_here = core_dir->opts;
  221.     int overrides_here = core_dir->override;
  222.         void *this_conf = NULL, *htaccess_conf = NULL;
  223.     char *this_dir = make_dirstr (r->pool, test_filename, i);
  224.     char *config_name = make_full_path(r->pool, this_dir,
  225.                        sconf->access_name);
  226.     int j;
  227.       
  228.     /* Do symlink checks first, because they are done with the
  229.      * permissions appropriate to the *parent* directory...
  230.      */
  231.     
  232.     if ((res = check_symlinks (this_dir, allowed_here)))
  233.     {
  234.         log_reason("Symbolic link not allowed", this_dir, r);
  235.         return res;
  236.     }
  237.     
  238.     /* Begin *this* level by looking for matching <Directory> sections from
  239.      * access.conf.
  240.      */
  241.     
  242.     for (j = 0; j < num_sec; ++j) {
  243.         void *entry_config = sec[j];
  244.         core_dir_config *entry_core;
  245.         char *entry_dir;
  246.  
  247.         if (!entry_config) continue;
  248.         
  249.         entry_core =
  250.           (core_dir_config *)get_module_config(entry_config, &core_module);
  251.         entry_dir = entry_core->d;
  252.     
  253.         if (is_matchexp(entry_dir) && !strcmp_match(this_dir, entry_dir)) {
  254.         /* Don't try this wildcard again --- if it ends in '*'
  255.          * it'll match again, and subdirectories won't be able to
  256.          * override it...
  257.          */
  258.         sec[j] = NULL;    
  259.             this_conf = entry_config;
  260.         }
  261.         else if (!strcmp (this_dir, entry_dir))
  262.             this_conf = entry_config;
  263.     }
  264.  
  265.     if (this_conf)
  266.     {
  267.         per_dir_defaults =
  268.             merge_per_dir_configs (r->pool, per_dir_defaults, this_conf);
  269.         core_dir =(core_dir_config *)get_module_config(per_dir_defaults,
  270.                                &core_module);
  271.     }
  272.     overrides_here = core_dir->override;
  273.  
  274.     /* If .htaccess files are enabled, check for one.
  275.      */
  276.     
  277.     if (overrides_here) {
  278.         res = parse_htaccess (&htaccess_conf, r, overrides_here,
  279.                   this_dir, config_name);
  280.         if (res) return res;
  281.     }
  282.  
  283.     if (htaccess_conf)
  284.         per_dir_defaults =
  285.             merge_per_dir_configs (r->pool, per_dir_defaults,
  286.                        htaccess_conf);
  287.     
  288.     }
  289.  
  290.     r->per_dir_config = per_dir_defaults;
  291.  
  292.     if ((res = check_symlinks (r->filename, allow_options(r))))
  293.     {
  294.     log_reason("Symbolic link not allowed", r->filename, r);
  295.     return res;
  296.     }
  297.     
  298.     return OK;            /* Can only "fail" if access denied
  299.                  * by the symlink goop.
  300.                  */
  301. }
  302.  
  303. /*****************************************************************
  304.  *
  305.  * The sub_request mechanism.
  306.  *
  307.  * Fns to look up a relative URI from, e.g., a map file or SSI document.
  308.  * These do all access checks, etc., but don't actually run the transaction
  309.  * ... use run_sub_req below for that.  Also, be sure to use destroy_sub_req
  310.  * as appropriate if you're likely to be creating more than a few of these.
  311.  * (An early Shambhala version didn't destroy the sub_reqs used in directory
  312.  * indexing.  The result, when indexing a directory with 800-odd files in
  313.  * it, was massively excessive storage allocation).
  314.  *
  315.  * Note more manipulation of protocol-specific vars in the request
  316.  * structure...
  317.  */
  318.  
  319. request_rec *make_sub_request (request_rec *r)
  320. {
  321.     pool *rrp = make_sub_pool (r->pool);
  322.     request_rec *rr = pcalloc (rrp, sizeof (request_rec));
  323.     
  324.     rr->pool = rrp;
  325.     return rr;
  326. }
  327.  
  328. request_rec *sub_req_lookup_simple (char *new_file, request_rec *r)
  329. {
  330.     /* This handles the simple case, common to ..._lookup_uri and _file,
  331.      * of looking up another file in the same directory.
  332.      */
  333.     request_rec *rnew = make_sub_request (r);
  334.     pool *rnewp = rnew->pool;
  335.     int res;
  336.     
  337.     char *udir = make_dirstr(rnewp, r->uri, count_dirs(r->uri));
  338.     char *fdir = make_dirstr(rnewp, r->filename, count_dirs(r->filename));
  339.  
  340.     *rnew = *r;            /* Copy per_dir config, etc. */
  341.     rnew->pool = rnewp;
  342.     rnew->uri = make_full_path (rnewp, udir, new_file);
  343.     rnew->filename = make_full_path (rnewp, fdir, new_file);
  344.     set_sub_req_protocol (rnew, r);
  345.     
  346.     rnew->finfo.st_mode = 0;
  347.     
  348.     if ((res = check_symlinks (rnew->filename, allow_options (rnew))))
  349.     {
  350.         rnew->status = res;
  351.     }
  352.  
  353.     if (rnew->finfo.st_mode == 0 && stat (rnew->filename, &rnew->finfo) < 0)
  354.         rnew->finfo.st_mode = 0;
  355.  
  356.     if ((rnew->status == 200) && (res = find_types (rnew)))
  357.         rnew->status = res;
  358.     
  359.     if ((rnew->status == 200) && (res = run_fixups (rnew)))
  360.         rnew->status = res;
  361.     
  362.     return rnew;
  363. }
  364.  
  365. request_rec *sub_req_lookup_uri (char *new_file, request_rec *r)
  366. {
  367.     request_rec *rnew;
  368.     int res;
  369.     char *udir;
  370.     
  371.     rnew = make_sub_request (r);
  372.     rnew->connection = r->connection; 
  373.     rnew->server = r->server;
  374.     rnew->request_config = create_request_config (rnew->pool);
  375.     set_sub_req_protocol (rnew, r);
  376.     
  377.     if (new_file[0] == '/')
  378.     parse_uri(rnew, new_file);
  379.     else
  380.     {
  381.     udir = make_dirstr (rnew->pool, r->uri, count_dirs (r->uri));
  382.     udir = escape_uri(rnew->pool, udir); /* re-escape it */
  383.     parse_uri (rnew, make_full_path (rnew->pool, udir, new_file));
  384.     }
  385.     
  386.     res = unescape_url (rnew->uri);
  387.     if (res)
  388.     {
  389.     rnew->status = res;
  390.     return rnew;
  391.     }
  392.  
  393.     getparents (rnew->uri);
  394.     
  395.     res = translate_name(rnew);
  396.     if (res)
  397.     {
  398.     rnew->status = res;
  399.     return rnew;
  400.     }
  401.  
  402.     /* We could be clever at this point, and avoid calling directory_walk, etc.
  403.      * However, we'd need to test that the old and new filenames contain the
  404.      * same directory components, so it would require duplicating the start
  405.      * of translate_name.
  406.      * Maybe it would be easier to implement a cache for directory and
  407.      * .htaccess stats, or perhaps pass the old request to translate_name()
  408.      * for it to do the optimisation.
  409.      */
  410.     
  411.     if ((res = directory_walk (rnew))
  412.     || (!auth_type (rnew) ? 0 :
  413.          ((res = check_user_id (rnew)) || (res = check_auth (rnew))))
  414.     || (res = check_access (rnew))
  415.     || (res = find_types (rnew))
  416.     || (res = run_fixups (rnew))
  417.     )
  418.     {
  419.         rnew->status = res;
  420.     }
  421.  
  422.     return rnew;
  423. }
  424.  
  425. request_rec *sub_req_lookup_file (char *new_file, request_rec *r)
  426. {
  427.     request_rec *rnew;
  428.     int res;
  429.     char *fdir;
  430.     
  431.     /* Check for a special case... if there are no '/' characters in new_file
  432.      * at all, then we are looking at a relative lookup in the same directory.
  433.      * That means we don't have to redo any access checks.
  434.      */
  435.  
  436.     if (strchr (new_file, '/') == NULL) 
  437.         return sub_req_lookup_simple (new_file, r);
  438.  
  439.     rnew = make_sub_request (r);
  440.     fdir = make_dirstr (rnew->pool, r->filename, count_dirs (r->filename));
  441.     
  442.     rnew->connection = r->connection; /* For now... */
  443.     rnew->server = r->server;
  444.     rnew->request_config = create_request_config (rnew->pool);
  445.     set_sub_req_protocol (rnew, r);
  446.     
  447.     rnew->uri = "INTERNALLY GENERATED file-relative req";
  448.     rnew->filename = ((new_file[0] == '/') ?
  449.               new_file :
  450.               make_full_path (rnew->pool, fdir, new_file));
  451.     
  452.     if ((res = directory_walk (rnew))
  453.     || (res = check_access (rnew))
  454.     || (!auth_type (rnew) ? 0 :
  455.          ((res = check_user_id (rnew)) && (res = check_auth (rnew))))
  456.     || (res = find_types (rnew))
  457.     || (res = run_fixups (rnew))
  458.     )
  459.     {
  460.         rnew->status = res;
  461.     }
  462.  
  463.     return rnew;
  464. }
  465.  
  466. int run_sub_req (request_rec *r)
  467. {
  468.     int retval = invoke_handler (r);
  469.     finalize_sub_req_protocol (r);
  470.     return retval;
  471. }
  472.  
  473. void destroy_sub_req (request_rec *r)
  474. {
  475.     /* Reclaim the space */
  476.     destroy_pool (r->pool);
  477. }
  478.  
  479. /*****************************************************************
  480.  *
  481.  * Mainline request processing...
  482.  */
  483.  
  484. void die(int type, request_rec *r)
  485. {
  486.     int error_index = index_of_response (type);
  487.     char *custom_response = response_code_string(r, error_index);
  488.     int recursive_error = 0;
  489.     
  490.     /* The following takes care of Apache redirects to custom response URLs
  491.      * Note that if we are already dealing with the response to some other
  492.      * error condition, we just report on the original error, and give up on
  493.      * any attempt to handle the other thing "intelligently"...
  494.      */
  495.  
  496.     if (r->status != 200) {
  497.         recursive_error = type;
  498.  
  499.     while (r->prev && r->prev->status != 200)
  500.       r = r->prev; /* Get back to original error */
  501.     
  502.     type = r->status;
  503.     custom_response = NULL;    /* Do NOT retry the custom thing! */
  504.     }
  505.        
  506.     r->status = type;
  507.     
  508.     /* Two types of custom redirects --- plain text, and URLs.
  509.      * Plain text has a leading '"', so the URL code, here, is triggered
  510.      * on its absence
  511.      */
  512.     
  513.     if (custom_response && custom_response[0] != '"') {
  514.           
  515.         if (is_url(custom_response)) {
  516.         /* The URL isn't local, so lets drop through the rest of
  517.          * this apache code, and continue with the usual REDIRECT
  518.          * handler.  But note that the client will ultimately see
  519.          * the wrong status...
  520.          */
  521.         r->status = REDIRECT;
  522.         table_set (r->headers_out, "Location", custom_response);
  523.     } else if ( custom_response[0] == '/') {
  524.         r->no_cache = 1;    /* Do NOT send USE_LOCAL_COPY for
  525.                  * error documents!
  526.                  */
  527.         internal_redirect (custom_response, r);
  528.         return;
  529.     } else {
  530.         /* Dumb user has given us a bad url to redirect to
  531.          * --- fake up dying with a recursive server error...
  532.          */
  533.         recursive_error = SERVER_ERROR;
  534.         log_reason("Invalid error redirection directive", custom_response,
  535.                r);
  536.     }       
  537.     }
  538.  
  539.     send_error_response (r, recursive_error);
  540. }
  541.  
  542. static void decl_die (int status, char *phase, request_rec *r)
  543. {
  544.     if (status == DECLINED) {
  545.     log_reason (pstrcat (r->pool,
  546.                  "configuration error:  couldn't ",
  547.                  phase, NULL),
  548.             r->uri,
  549.             r);
  550.     die (SERVER_ERROR, r);
  551.     }
  552.     else die (status, r);
  553. }
  554.  
  555. void process_request_internal (request_rec *r)
  556. {
  557.     int access_status;
  558.   
  559.     /* Kludge to be reading the assbackwards field outside of protocol.c,
  560.      * but we've got to check for this sort of nonsense somewhere...
  561.      */
  562.     
  563.     if (r->assbackwards && r->header_only) {
  564.     /* Client asked for headers only with HTTP/0.9, which doesn't
  565.      * send headers!  Have to dink things even to make sure the
  566.      * error message comes through...
  567.      */
  568.     log_reason ("client sent illegal HTTP/0.9 request", r->uri, r);
  569.     r->header_only = 0;
  570.     die (BAD_REQUEST, r);
  571.     return;
  572.     }
  573.     
  574.     access_status = unescape_url(r->uri);
  575.     if (access_status)
  576.     {
  577.     die(access_status, r);
  578.     return;
  579.     }
  580.  
  581.     getparents(r->uri);        /* OK --- shrinking transformations... */
  582.  
  583.     if ((access_status = translate_name (r))) {
  584.         decl_die (access_status, "translate", r);
  585.     return;
  586.     }
  587.     
  588.     if ((access_status = directory_walk (r))) {
  589.         die (access_status, r);
  590.     return;
  591.     }    
  592.     
  593.     if ((access_status = check_access (r)) != 0) {
  594.         decl_die (access_status, "check access", r);
  595.     return;
  596.     }
  597.     
  598.     if (auth_type (r)) {
  599.         if ((access_status = check_user_id (r)) != 0) {
  600.         decl_die (access_status, "check user.  No user file?", r);
  601.         return;
  602.     }
  603.  
  604.     if ((access_status = check_auth (r)) != 0) {
  605.         decl_die (access_status, "check access.  No groups file?", r);
  606.         return;
  607.     }
  608.     }
  609.  
  610.     if ((access_status = find_types (r)) != 0) {
  611.         decl_die (access_status, "find types", r);
  612.     return;
  613.     }
  614.  
  615.     if ((access_status = run_fixups (r)) != 0) {
  616.         die (access_status, r);
  617.     return;
  618.     }
  619.  
  620.     if ((access_status = invoke_handler (r)) != 0)
  621.         die (access_status, r);
  622. }
  623.  
  624. void process_request (request_rec *r)
  625. {
  626.     process_request_internal (r);
  627.     log_transaction (r);
  628. }
  629.  
  630. table *rename_original_env (pool *p, table *t)
  631. {
  632.     array_header *env_arr = table_elts (t);
  633.     table_entry *elts = (table_entry *)env_arr->elts;
  634.     table *new = make_table (p, env_arr->nelts);
  635.     int i;
  636.     
  637.     for (i = 0; i < env_arr->nelts; ++i) {
  638.         if (!elts[i].key) continue;
  639.     table_set (new, pstrcat (p, "REDIRECT_", elts[i].key, NULL),
  640.            elts[i].val);
  641.     }
  642.  
  643.     return new;
  644. }
  645.  
  646. void internal_redirect (char *new_uri, request_rec *r)
  647. {
  648.     request_rec *new = (request_rec *)pcalloc(r->pool, sizeof(request_rec));
  649.     char t[10];            /* Long enough... */
  650.   
  651.     new->connection = r->connection;
  652.     new->server = r->server;
  653.     new->pool = r->pool;
  654.     
  655.     /* A whole lot of this really ought to be shared with protocol.c...
  656.      * another missing cleanup.  It's particularly inappropriate to be
  657.      * setting header_only, etc., here.
  658.      */
  659.     
  660.     parse_uri (new, new_uri);
  661.     new->request_config = create_request_config (r->pool);
  662.     new->per_dir_config = r->server->lookup_defaults;
  663.     
  664.     new->prev = r;
  665.     r->next = new;
  666.     
  667.     /* We are redirecting.  Treat the internally generated transaction
  668.      * as a GET, since there is not a chance of its getting POST-style
  669.      * arguments.   
  670.      */
  671.     new->method = "GET";
  672.     new->method_number = M_GET;
  673.  
  674.     /* Inherit the rest of the protocol info... */
  675.     
  676.     new->status = r->status;
  677.     new->assbackwards = r->assbackwards;
  678.     new->header_only = r->header_only;
  679.     new->protocol = r->protocol;
  680.     new->main = r->main;
  681.  
  682.     new->headers_in = r->headers_in;
  683.     new->headers_out = make_table (r->pool, 5);
  684.     new->err_headers_out = r->err_headers_out;
  685.     new->subprocess_env = rename_original_env (r->pool, r->subprocess_env);
  686.     new->notes = make_table (r->pool, 5);
  687.     
  688.     new->no_cache = r->no_cache; /* If we've already made up our minds
  689.                   * about this, don't change 'em back!
  690.                   */
  691.  
  692.     sprintf (t, "%d", r->status);
  693.     table_set (new->subprocess_env, "REDIRECT_STATUS", pstrdup (r->pool, t));
  694.  
  695.     process_request_internal (new);
  696. }
  697.  
  698.