home *** CD-ROM | disk | FTP | other *** search
/ PC Online 1999 April / PCO0499.ISO / filesbbs / os2 / apach134.arj / APACH134.ZIP / src / main / http_protocol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-08  |  87.3 KB  |  2,539 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_protocol.c --- routines which directly communicate with the client.
  60.  *
  61.  * Code originally by Rob McCool; much redone by Robert S. Thau
  62.  * and the Apache Group.
  63.  */
  64.  
  65. #define CORE_PRIVATE
  66. #include "httpd.h"
  67. #include "http_config.h"
  68. #include "http_core.h"
  69. #include "http_protocol.h"
  70. #include "http_main.h"
  71. #include "http_request.h"
  72. #include "http_vhost.h"
  73. #include "http_log.h"           /* For errors detected in basic auth common
  74.                                  * support code... */
  75. #include "util_date.h"          /* For parseHTTPdate and BAD_DATE */
  76. #include <stdarg.h>
  77. #include "http_conf_globals.h"
  78.  
  79. #define SET_BYTES_SENT(r) \
  80.   do { if (r->sent_bodyct) \
  81.           ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
  82.   } while (0)
  83.  
  84.  
  85. static int parse_byterange(char *range, long clength, long *start, long *end)
  86. {
  87.     char *dash = strchr(range, '-');
  88.  
  89.     if (!dash)
  90.         return 0;
  91.  
  92.     if ((dash == range)) {
  93.         /* In the form "-5" */
  94.         *start = clength - atol(dash + 1);
  95.         *end = clength - 1;
  96.     }
  97.     else {
  98.         *dash = '\0';
  99.         dash++;
  100.         *start = atol(range);
  101.         if (*dash)
  102.             *end = atol(dash);
  103.         else                    /* "5-" */
  104.             *end = clength - 1;
  105.     }
  106.  
  107.     if (*start < 0)
  108.     *start = 0;
  109.  
  110.     if (*end >= clength)
  111.         *end = clength - 1;
  112.  
  113.     if (*start > *end)
  114.     return 0;
  115.  
  116.     return (*start > 0 || *end < clength - 1);
  117. }
  118.  
  119. static int internal_byterange(int, long *, request_rec *, const char **, long *,
  120.                               long *);
  121.  
  122. API_EXPORT(int) ap_set_byterange(request_rec *r)
  123. {
  124.     const char *range, *if_range, *match;
  125.     long range_start, range_end;
  126.  
  127.     if (!r->clength || r->assbackwards)
  128.         return 0;
  129.  
  130.     /* Check for Range request-header (HTTP/1.1) or Request-Range for
  131.      * backwards-compatibility with second-draft Luotonen/Franks
  132.      * byte-ranges (e.g. Netscape Navigator 2-3).
  133.      *
  134.      * We support this form, with Request-Range, and (farther down) we
  135.      * send multipart/x-byteranges instead of multipart/byteranges for
  136.      * Request-Range based requests to work around a bug in Netscape
  137.      * Navigator 2-3 and MSIE 3.
  138.      */
  139.  
  140.     if (!(range = ap_table_get(r->headers_in, "Range")))
  141.         range = ap_table_get(r->headers_in, "Request-Range");
  142.  
  143.     if (!range || strncasecmp(range, "bytes=", 6)) {
  144.         return 0;
  145.     }
  146.  
  147.     /* Check the If-Range header for Etag or Date */
  148.  
  149.     if ((if_range = ap_table_get(r->headers_in, "If-Range"))) {
  150.         if (if_range[0] == '"') {
  151.             if (!(match = ap_table_get(r->headers_out, "Etag")) ||
  152.                 (strcasecmp(if_range, match) != 0))
  153.                 return 0;
  154.         }
  155.         else if (!(match = ap_table_get(r->headers_out, "Last-Modified")) ||
  156.                  (strcasecmp(if_range, match) != 0))
  157.             return 0;
  158.     }
  159.  
  160.     if (!strchr(range, ',')) {
  161.         /* A single range */
  162.         if (!parse_byterange(ap_pstrdup(r->pool, range + 6), r->clength,
  163.                              &range_start, &range_end))
  164.             return 0;
  165.  
  166.         r->byterange = 1;
  167.  
  168.         ap_table_setn(r->headers_out, "Content-Range",
  169.         ap_psprintf(r->pool, "bytes %ld-%ld/%ld",
  170.         range_start, range_end, r->clength));
  171.         ap_table_setn(r->headers_out, "Content-Length",
  172.         ap_psprintf(r->pool, "%ld", range_end - range_start + 1));
  173.     }
  174.     else {
  175.         /* a multiple range */
  176.         const char *r_range = ap_pstrdup(r->pool, range + 6);
  177.         long tlength = 0;
  178.  
  179.         r->byterange = 2;
  180.         r->boundary = ap_psprintf(r->pool, "%lx%lx",
  181.                 r->request_time, (long) getpid());
  182.         while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL));
  183.         ap_table_setn(r->headers_out, "Content-Length",
  184.         ap_psprintf(r->pool, "%ld", tlength));
  185.     }
  186.  
  187.     r->status = PARTIAL_CONTENT;
  188.     r->range = range + 6;
  189.  
  190.     return 1;
  191. }
  192.  
  193. API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length)
  194. {
  195.     return internal_byterange(1, NULL, r, &r->range, offset, length);
  196. }
  197.  
  198. /* If this function is called with realreq=1, it will spit out
  199.  * the correct headers for a byterange chunk, and set offset and
  200.  * length to the positions they should be.
  201.  *
  202.  * If it is called with realreq=0, it will add to tlength the length
  203.  * it *would* have used with realreq=1.
  204.  *
  205.  * Either case will return 1 if it should be called again, and 0
  206.  * when done.
  207.  */
  208. static int internal_byterange(int realreq, long *tlength, request_rec *r,
  209.                               const char **r_range, long *offset, long *length)
  210. {
  211.     long range_start, range_end;
  212.     char *range;
  213.  
  214.     if (!**r_range) {
  215.         if (r->byterange > 1) {
  216.             if (realreq)
  217.                 ap_rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL);
  218.             else
  219.                 *tlength += 4 + strlen(r->boundary) + 4;
  220.         }
  221.         return 0;
  222.     }
  223.  
  224.     range = ap_getword(r->pool, r_range, ',');
  225.     if (!parse_byterange(range, r->clength, &range_start, &range_end))
  226.         /* Skip this one */
  227.         return internal_byterange(realreq, tlength, r, r_range, offset,
  228.                                   length);
  229.  
  230.     if (r->byterange > 1) {
  231.         const char *ct = r->content_type ? r->content_type : ap_default_type(r);
  232.         char ts[MAX_STRING_LEN];
  233.  
  234.         ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end,
  235.                     r->clength);
  236.         if (realreq)
  237.             ap_rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ",
  238.                    ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012",
  239.                    NULL);
  240.         else
  241.             *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
  242.                         strlen(ts) + 4;
  243.     }
  244.  
  245.     if (realreq) {
  246.         *offset = range_start;
  247.         *length = range_end - range_start + 1;
  248.     }
  249.     else {
  250.         *tlength += range_end - range_start + 1;
  251.     }
  252.     return 1;
  253. }
  254.  
  255. API_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
  256. {
  257.     r->clength = clength;
  258.     ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
  259.     return 0;
  260. }
  261.  
  262. API_EXPORT(int) ap_set_keepalive(request_rec *r)
  263. {
  264.     int ka_sent = 0;
  265.     int wimpy = ap_find_token(r->pool,
  266.                            ap_table_get(r->headers_out, "Connection"), "close");
  267.     const char *conn = ap_table_get(r->headers_in, "Connection");
  268.  
  269.     /* The following convoluted conditional determines whether or not
  270.      * the current connection should remain persistent after this response
  271.      * (a.k.a. HTTP Keep-Alive) and whether or not the output message
  272.      * body should use the HTTP/1.1 chunked transfer-coding.  In English,
  273.      *
  274.      *   IF  we have not marked this connection as errored;
  275.      *   and the response body has a defined length due to the status code
  276.      *       being 304 or 204, the request method being HEAD, already
  277.      *       having defined Content-Length or Transfer-Encoding: chunked, or
  278.      *       the request version being HTTP/1.1 and thus capable of being set
  279.      *       as chunked [we know the (r->chunked = 1) side-effect is ugly];
  280.      *   and the server configuration enables keep-alive;
  281.      *   and the server configuration has a reasonable inter-request timeout;
  282.      *   and there is no maximum # requests or the max hasn't been reached;
  283.      *   and the response status does not require a close;
  284.      *   and the response generator has not already indicated close;
  285.      *   and the client did not request non-persistence (Connection: close);
  286.      *   and    we haven't been configured to ignore the buggy twit
  287.      *       or they're a buggy twit coming through a HTTP/1.1 proxy
  288.      *   and    the client is requesting an HTTP/1.0-style keep-alive
  289.      *       or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
  290.      *   THEN we can be persistent, which requires more headers be output.
  291.      *
  292.      * Note that the condition evaluation order is extremely important.
  293.      */
  294.     if ((r->connection->keepalive != -1) &&
  295.         ((r->status == HTTP_NOT_MODIFIED) ||
  296.          (r->status == HTTP_NO_CONTENT) ||
  297.          r->header_only ||
  298.          ap_table_get(r->headers_out, "Content-Length") ||
  299.          ap_find_last_token(r->pool,
  300.                          ap_table_get(r->headers_out, "Transfer-Encoding"),
  301.                          "chunked") ||
  302.          ((r->proto_num >= HTTP_VERSION(1,1)) &&
  303.       (r->chunked = 1))) && /* THIS CODE IS CORRECT, see comment above. */
  304.         r->server->keep_alive &&
  305.         (r->server->keep_alive_timeout > 0) &&
  306.         ((r->server->keep_alive_max == 0) ||
  307.          (r->server->keep_alive_max > r->connection->keepalives)) &&
  308.         !ap_status_drops_connection(r->status) &&
  309.         !wimpy &&
  310.         !ap_find_token(r->pool, conn, "close") &&
  311.         (!ap_table_get(r->subprocess_env, "nokeepalive") ||
  312.          ap_table_get(r->headers_in, "Via")) &&
  313.         ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) ||
  314.          (r->proto_num >= HTTP_VERSION(1,1)))
  315.        ) {
  316.         int left = r->server->keep_alive_max - r->connection->keepalives;
  317.  
  318.         r->connection->keepalive = 1;
  319.         r->connection->keepalives++;
  320.  
  321.         /* If they sent a Keep-Alive token, send one back */
  322.         if (ka_sent) {
  323.             if (r->server->keep_alive_max)
  324.         ap_table_setn(r->headers_out, "Keep-Alive",
  325.             ap_psprintf(r->pool, "timeout=%d, max=%d",
  326.                             r->server->keep_alive_timeout, left));
  327.             else
  328.         ap_table_setn(r->headers_out, "Keep-Alive",
  329.             ap_psprintf(r->pool, "timeout=%d",
  330.                             r->server->keep_alive_timeout));
  331.             ap_table_mergen(r->headers_out, "Connection", "Keep-Alive");
  332.         }
  333.  
  334.         return 1;
  335.     }
  336.  
  337.     /* Otherwise, we need to indicate that we will be closing this
  338.      * connection immediately after the current response.
  339.      *
  340.      * We only really need to send "close" to HTTP/1.1 clients, but we
  341.      * always send it anyway, because a broken proxy may identify itself
  342.      * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
  343.      * to a HTTP/1.1 client. Better safe than sorry.
  344.      */
  345.     if (!wimpy)
  346.     ap_table_mergen(r->headers_out, "Connection", "close");
  347.  
  348.     r->connection->keepalive = 0;
  349.  
  350.     return 0;
  351. }
  352.  
  353. /*
  354.  * Return the latest rational time from a request/mtime (modification time)
  355.  * pair.  We return the mtime unless it's in the future, in which case we
  356.  * return the current time.  We use the request time as a reference in order
  357.  * to limit the number of calls to time().  We don't check for futurosity
  358.  * unless the mtime is at least as new as the reference.
  359.  */
  360. API_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime)
  361. {
  362.     time_t now;
  363.  
  364.     /* For all static responses, it's almost certain that the file was
  365.      * last modified before the beginning of the request.  So there's
  366.      * no reason to call time(NULL) again.  But if the response has been
  367.      * created on demand, then it might be newer than the time the request
  368.      * started.  In this event we really have to call time(NULL) again
  369.      * so that we can give the clients the most accurate Last-Modified.  If we
  370.      * were given a time in the future, we return the current time - the
  371.      * Last-Modified can't be in the future.
  372.      */
  373.     now = (mtime < r->request_time) ? r->request_time : time(NULL);
  374.     return (mtime > now) ? now : mtime;
  375. }
  376.  
  377. API_EXPORT(int) ap_meets_conditions(request_rec *r)
  378. {
  379.     const char *etag = ap_table_get(r->headers_out, "ETag");
  380.     const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;
  381.     time_t mtime;
  382.  
  383.     /* Check for conditional requests --- note that we only want to do
  384.      * this if we are successful so far and we are not processing a
  385.      * subrequest or an ErrorDocument.
  386.      *
  387.      * The order of the checks is important, since ETag checks are supposed
  388.      * to be more accurate than checks relative to the modification time.
  389.      * However, not all documents are guaranteed to *have* ETags, and some
  390.      * might have Last-Modified values w/o ETags, so this gets a little
  391.      * complicated.
  392.      */
  393.  
  394.     if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
  395.         return OK;
  396.     }
  397.  
  398.     mtime = (r->mtime != 0) ? r->mtime : time(NULL);
  399.  
  400.     /* If an If-Match request-header field was given
  401.      * AND if our ETag does not match any of the entity tags in that field
  402.      * AND the field value is not "*" (meaning match anything), then
  403.      *     respond with a status of 412 (Precondition Failed).
  404.      */
  405.     if ((if_match = ap_table_get(r->headers_in, "If-Match")) != NULL) {
  406.         if ((etag == NULL) ||
  407.             ((if_match[0] != '*') && !ap_find_token(r->pool, if_match, etag))) {
  408.             return HTTP_PRECONDITION_FAILED;
  409.         }
  410.     }
  411.     else {
  412.         /* Else if a valid If-Unmodified-Since request-header field was given
  413.          * AND the requested resource has been modified since the time
  414.          * specified in this field, then the server MUST
  415.          *     respond with a status of 412 (Precondition Failed).
  416.          */
  417.         if_unmodified = ap_table_get(r->headers_in, "If-Unmodified-Since");
  418.         if (if_unmodified != NULL) {
  419.             time_t ius = ap_parseHTTPdate(if_unmodified);
  420.  
  421.             if ((ius != BAD_DATE) && (mtime > ius)) {
  422.                 return HTTP_PRECONDITION_FAILED;
  423.             }
  424.         }
  425.     }
  426.  
  427.     /* If an If-None-Match request-header field was given
  428.      * AND if our ETag matches any of the entity tags in that field
  429.      * OR if the field value is "*" (meaning match anything), then
  430.      *    if the request method was GET or HEAD, the server SHOULD
  431.      *       respond with a 304 (Not Modified) response.
  432.      *    For all other request methods, the server MUST
  433.      *       respond with a status of 412 (Precondition Failed).
  434.      */
  435.     if_nonematch = ap_table_get(r->headers_in, "If-None-Match");
  436.     if (if_nonematch != NULL) {
  437.         int rstatus;
  438.  
  439.         if ((if_nonematch[0] == '*')
  440.             || ((etag != NULL) && ap_find_token(r->pool, if_nonematch, etag))) {
  441.             rstatus = (r->method_number == M_GET) ? HTTP_NOT_MODIFIED
  442.                                                   : HTTP_PRECONDITION_FAILED;
  443.             return rstatus;
  444.         }
  445.     }
  446.     /* Else if a valid If-Modified-Since request-header field was given
  447.      * AND it is a GET or HEAD request
  448.      * AND the requested resource has not been modified since the time
  449.      * specified in this field, then the server MUST
  450.      *    respond with a status of 304 (Not Modified).
  451.      * A date later than the server's current request time is invalid.
  452.      */
  453.     else if ((r->method_number == M_GET)
  454.              && ((if_modified_since =
  455.                   ap_table_get(r->headers_in, "If-Modified-Since")) != NULL)) {
  456.         time_t ims = ap_parseHTTPdate(if_modified_since);
  457.  
  458.         if ((ims >= mtime) && (ims <= r->request_time)) {
  459.             return HTTP_NOT_MODIFIED;
  460.         }
  461.     }
  462.     return OK;
  463. }
  464.  
  465. /*
  466.  * Construct an entity tag (ETag) from resource information.  If it's a real
  467.  * file, build in some of the file characteristics.  If the modification time
  468.  * is newer than (request-time minus 1 second), mark the ETag as weak - it
  469.  * could be modified again in as short an interval.  We rationalize the
  470.  * modification time we're given to keep it from being in the future.
  471.  */
  472. API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak)
  473. {
  474.     char *etag;
  475.     char *weak;
  476.  
  477.     /*
  478.      * Make an ETag header out of various pieces of information. We use
  479.      * the last-modified date and, if we have a real file, the
  480.      * length and inode number - note that this doesn't have to match
  481.      * the content-length (i.e. includes), it just has to be unique
  482.      * for the file.
  483.      *
  484.      * If the request was made within a second of the last-modified date,
  485.      * we send a weak tag instead of a strong one, since it could
  486.      * be modified again later in the second, and the validation
  487.      * would be incorrect.
  488.      */
  489.     
  490.     weak = ((r->request_time - r->mtime > 1) && !force_weak) ? "" : "W/";
  491.  
  492.     if (r->finfo.st_mode != 0) {
  493.         etag = ap_psprintf(r->pool,
  494.                     "%s\"%lx-%lx-%lx\"", weak,
  495.                     (unsigned long) r->finfo.st_ino,
  496.                     (unsigned long) r->finfo.st_size,
  497.                     (unsigned long) r->mtime);
  498.     }
  499.     else {
  500.         etag = ap_psprintf(r->pool, "%s\"%lx\"", weak,
  501.                     (unsigned long) r->mtime);
  502.     }
  503.  
  504.     return etag;
  505. }
  506.  
  507. API_EXPORT(void) ap_set_etag(request_rec *r)
  508. {
  509.     char *etag;
  510.     char *variant_etag, *vlv;
  511.     int vlv_weak;
  512.  
  513.     if (!r->vlist_validator) {
  514.         etag = ap_make_etag(r, 0);
  515.     }
  516.     else {
  517.         /* If we have a variant list validator (vlv) due to the
  518.          * response being negotiated, then we create a structured
  519.          * entity tag which merges the variant etag with the variant
  520.          * list validator (vlv).  This merging makes revalidation
  521.          * somewhat safer, ensures that caches which can deal with
  522.          * Vary will (eventually) be updated if the set of variants is
  523.          * changed, and is also a protocol requirement for transparent
  524.          * content negotiation.
  525.          */
  526.  
  527.         /* if the variant list validator is weak, we make the whole
  528.          * structured etag weak.  If we would not, then clients could
  529.          * have problems merging range responses if we have different
  530.          * variants with the same non-globally-unique strong etag.
  531.          */
  532.  
  533.         vlv = r->vlist_validator;
  534.         vlv_weak = (vlv[0] == 'W');
  535.                
  536.         variant_etag = ap_make_etag(r, vlv_weak);
  537.  
  538.         /* merge variant_etag and vlv into a structured etag */
  539.  
  540.         variant_etag[strlen(variant_etag) - 1] = '\0';
  541.         if (vlv_weak)
  542.             vlv += 3;
  543.         else
  544.             vlv++;
  545.         etag = ap_pstrcat(r->pool, variant_etag, ";", vlv, NULL);
  546.     }
  547.  
  548.     ap_table_setn(r->headers_out, "ETag", etag);
  549. }
  550.  
  551. /*
  552.  * This function sets the Last-Modified output header field to the value
  553.  * of the mtime field in the request structure - rationalized to keep it from
  554.  * being in the future.
  555.  */
  556. API_EXPORT(void) ap_set_last_modified(request_rec *r)
  557. {
  558.     time_t mod_time = ap_rationalize_mtime(r, r->mtime);
  559.  
  560.     ap_table_setn(r->headers_out, "Last-Modified",
  561.               ap_gm_timestr_822(r->pool, mod_time));
  562. }
  563.  
  564. /* Get the method number associated with the given string, assumed to
  565.  * contain an HTTP method.  Returns M_INVALID if not recognized.
  566.  *
  567.  * This is the first step toward placing method names in a configurable
  568.  * list.  Hopefully it (and other routines) can eventually be moved to
  569.  * something like a mod_http_methods.c, complete with config stuff.
  570.  */
  571. API_EXPORT(int) ap_method_number_of(const char *method)
  572. {
  573.     switch (*method) {
  574.         case 'H':
  575.            if (strcmp(method, "HEAD") == 0)
  576.                return M_GET;   /* see header_only in request_rec */
  577.            break;
  578.         case 'G':
  579.            if (strcmp(method, "GET") == 0)
  580.                return M_GET;
  581.            break;
  582.         case 'P':
  583.            if (strcmp(method, "POST") == 0)
  584.                return M_POST;
  585.            if (strcmp(method, "PUT") == 0)
  586.                return M_PUT;
  587.            if (strcmp(method, "PATCH") == 0)
  588.                return M_PATCH;
  589.            if (strcmp(method, "PROPFIND") == 0)
  590.                return M_PROPFIND;
  591.            if (strcmp(method, "PROPPATCH") == 0)
  592.                return M_PROPPATCH;
  593.            break;
  594.         case 'D':
  595.            if (strcmp(method, "DELETE") == 0)
  596.                return M_DELETE;
  597.            break;
  598.         case 'C':
  599.            if (strcmp(method, "CONNECT") == 0)
  600.                return M_CONNECT;
  601.            if (strcmp(method, "COPY") == 0)
  602.                return M_COPY;
  603.            break;
  604.         case 'M':
  605.            if (strcmp(method, "MKCOL") == 0)
  606.                return M_MKCOL;
  607.            if (strcmp(method, "MOVE") == 0)
  608.                return M_MOVE;
  609.            break;
  610.         case 'O':
  611.            if (strcmp(method, "OPTIONS") == 0)
  612.                return M_OPTIONS;
  613.            break;
  614.         case 'T':
  615.            if (strcmp(method, "TRACE") == 0)
  616.                return M_TRACE;
  617.            break;
  618.         case 'L':
  619.            if (strcmp(method, "LOCK") == 0)
  620.                return M_LOCK;
  621.            break;
  622.         case 'U':
  623.            if (strcmp(method, "UNLOCK") == 0)
  624.                return M_UNLOCK;
  625.            break;
  626.     }
  627.     return M_INVALID;
  628. }
  629.  
  630. /* Get a line of protocol input, including any continuation lines
  631.  * caused by MIME folding (or broken clients) if fold != 0, and place it
  632.  * in the buffer s, of size n bytes, without the ending newline.
  633.  *
  634.  * Returns -1 on error, or the length of s.
  635.  *
  636.  * Note: Because bgets uses 1 char for newline and 1 char for NUL,
  637.  *       the most we can get is (n - 2) actual characters if it
  638.  *       was ended by a newline, or (n - 1) characters if the line
  639.  *       length exceeded (n - 1).  So, if the result == (n - 1),
  640.  *       then the actual input line exceeded the buffer length,
  641.  *       and it would be a good idea for the caller to puke 400 or 414.
  642.  */
  643. static int getline(char *s, int n, BUFF *in, int fold)
  644. {
  645.     char *pos, next;
  646.     int retval;
  647.     int total = 0;
  648.  
  649.     pos = s;
  650.  
  651.     do {
  652.         retval = ap_bgets(pos, n, in);     /* retval == -1 if error, 0 if EOF */
  653.  
  654.         if (retval <= 0)
  655.             return ((retval < 0) && (total == 0)) ? -1 : total;
  656.  
  657.         /* retval is the number of characters read, not including NUL      */
  658.  
  659.         n -= retval;            /* Keep track of how much of s is full     */
  660.         pos += (retval - 1);    /* and where s ends                        */
  661.         total += retval;        /* and how long s has become               */
  662.  
  663.         if (*pos == '\n') {     /* Did we get a full line of input?        */
  664.             /*
  665.              * Trim any extra trailing spaces or tabs except for the first
  666.              * space or tab at the beginning of a blank string.  This makes
  667.              * it much easier to check field values for exact matches, and
  668.              * saves memory as well.  Terminate string at end of line.
  669.              */
  670.             while (pos > (s + 1) && (*(pos - 1) == ' ' || *(pos - 1) == '\t')) {
  671.                 --pos;          /* trim extra trailing spaces or tabs      */
  672.                 --total;        /* but not one at the beginning of line    */
  673.                 ++n;
  674.             }
  675.             *pos = '\0';
  676.             --total;
  677.             ++n;
  678.         }
  679.         else
  680.             return total;       /* if not, input line exceeded buffer size */
  681.  
  682.         /* Continue appending if line folding is desired and
  683.          * the last line was not empty and we have room in the buffer and
  684.          * the next line begins with a continuation character.
  685.          */
  686.     } while (fold && (retval != 1) && (n > 1)
  687.                   && (ap_blookc(&next, in) == 1)
  688.                   && ((next == ' ') || (next == '\t')));
  689.  
  690.     return total;
  691. }
  692.  
  693. /* parse_uri: break apart the uri
  694.  * Side Effects:
  695.  * - sets r->args to rest after '?' (or NULL if no '?')
  696.  * - sets r->uri to request uri (without r->args part)
  697.  * - sets r->hostname (if not set already) from request (scheme://host:port)
  698.  */
  699. CORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri)
  700. {
  701.     int status = HTTP_OK;
  702.  
  703.     r->unparsed_uri = ap_pstrdup(r->pool, uri);
  704.  
  705.     if (r->method_number == M_CONNECT) {
  706.     status = ap_parse_hostinfo_components(r->pool, uri, &r->parsed_uri);
  707.     } else {
  708.     /* Simple syntax Errors in URLs are trapped by parse_uri_components(). */
  709.     status = ap_parse_uri_components(r->pool, uri, &r->parsed_uri);
  710.     }
  711.  
  712.     if (ap_is_HTTP_SUCCESS(status)) {
  713.     /* if it has a scheme we may need to do absoluteURI vhost stuff */
  714.     if (r->parsed_uri.scheme
  715.         && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))) {
  716.         r->hostname = r->parsed_uri.hostname;
  717.     } else if (r->method_number == M_CONNECT) {
  718.         r->hostname = r->parsed_uri.hostname;
  719.     }
  720.     r->args = r->parsed_uri.query;
  721.     r->uri = r->parsed_uri.path ? r->parsed_uri.path
  722.                     : ap_pstrdup(r->pool, "/");
  723. #if defined(OS2) || defined(WIN32)
  724.     /* Handle path translations for OS/2 and plug security hole.
  725.      * This will prevent "http://www.wherever.com/..\..\/" from
  726.      * returning a directory for the root drive.
  727.      */
  728.     {
  729.         char *x;
  730.  
  731.         for (x = r->uri; (x = strchr(x, '\\')) != NULL; )
  732.         *x = '/';
  733. #ifndef WIN32   /* for OS/2 only: */
  734.         /* Fix OS/2 HPFS filename case problem. */
  735.         ap_str_tolower(r->uri);
  736. #endif
  737.     }
  738. #endif  /* OS2 || WIN32 */
  739.     }
  740.     else {
  741.     r->args = NULL;
  742.     r->hostname = NULL;
  743.     r->status = status;             /* set error status */
  744.     r->uri = ap_pstrdup(r->pool, uri);
  745.     }
  746. }
  747.  
  748. static int read_request_line(request_rec *r)
  749. {
  750.     char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */
  751.     const char *ll = l;
  752.     const char *uri;
  753.     conn_rec *conn = r->connection;
  754.     int major = 1, minor = 0;   /* Assume HTTP/1.0 if non-"HTTP" protocol */
  755.     int len;
  756.  
  757.     /* Read past empty lines until we get a real request line,
  758.      * a read error, the connection closes (EOF), or we timeout.
  759.      *
  760.      * We skip empty lines because browsers have to tack a CRLF on to the end
  761.      * of POSTs to support old CERN webservers.  But note that we may not
  762.      * have flushed any previous response completely to the client yet.
  763.      * We delay the flush as long as possible so that we can improve
  764.      * performance for clients that are pipelining requests.  If a request
  765.      * is pipelined then we won't block during the (implicit) read() below.
  766.      * If the requests aren't pipelined, then the client is still waiting
  767.      * for the final buffer flush from us, and we will block in the implicit
  768.      * read().  B_SAFEREAD ensures that the BUFF layer flushes if it will
  769.      * have to block during a read.
  770.      */
  771.     ap_bsetflag(conn->client, B_SAFEREAD, 1);
  772.     while ((len = getline(l, sizeof(l), conn->client, 0)) <= 0) {
  773.         if ((len < 0) || ap_bgetflag(conn->client, B_EOF)) {
  774.             ap_bsetflag(conn->client, B_SAFEREAD, 0);
  775.             return 0;
  776.         }
  777.     }
  778.     /* we've probably got something to do, ignore graceful restart requests */
  779. #ifdef SIGUSR1
  780.     signal(SIGUSR1, SIG_IGN);
  781. #endif
  782.  
  783.     ap_bsetflag(conn->client, B_SAFEREAD, 0);
  784.  
  785.     r->request_time = time(NULL);
  786.     r->the_request = ap_pstrdup(r->pool, l);
  787.     r->method = ap_getword_white(r->pool, &ll);
  788.     uri = ap_getword_white(r->pool, &ll);
  789.  
  790.     /* Provide quick information about the request method as soon as known */
  791.  
  792.     r->method_number = ap_method_number_of(r->method);
  793.     if (r->method_number == M_GET && r->method[0] == 'H') {
  794.         r->header_only = 1;
  795.     }
  796.  
  797.     ap_parse_uri(r, uri);
  798.  
  799.     /* getline returns (size of max buffer - 1) if it fills up the
  800.      * buffer before finding the end-of-line.  This is only going to
  801.      * happen if it exceeds the configured limit for a request-line.
  802.      */
  803.     if (len > r->server->limit_req_line) {
  804.         r->status    = HTTP_REQUEST_URI_TOO_LARGE;
  805.         r->proto_num = HTTP_VERSION(1,0);
  806.         r->protocol  = ap_pstrdup(r->pool, "HTTP/1.0");
  807.         return 0;
  808.     }
  809.  
  810.     r->assbackwards = (ll[0] == '\0');
  811.     r->protocol = ap_pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9");
  812.  
  813.     if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor)
  814.       && minor < HTTP_VERSION(1,0))    /* don't allow HTTP/0.1000 */
  815.     r->proto_num = HTTP_VERSION(major, minor);
  816.     else
  817.     r->proto_num = HTTP_VERSION(1,0);
  818.  
  819.     return 1;
  820. }
  821.  
  822. static void get_mime_headers(request_rec *r)
  823. {
  824.     char field[DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2]; /* getline's two extra */
  825.     conn_rec *c = r->connection;
  826.     char *value;
  827.     char *copy;
  828.     int len;
  829.     unsigned int fields_read = 0;
  830.     table *tmp_headers;
  831.  
  832.     /* We'll use ap_overlap_tables later to merge these into r->headers_in. */
  833.     tmp_headers = ap_make_table(r->pool, 50);
  834.  
  835.     /*
  836.      * Read header lines until we get the empty separator line, a read error,
  837.      * the connection closes (EOF), reach the server limit, or we timeout.
  838.      */
  839.     while ((len = getline(field, sizeof(field), c->client, 1)) > 0) {
  840.  
  841.         if (r->server->limit_req_fields &&
  842.             (++fields_read > r->server->limit_req_fields)) {
  843.             r->status = HTTP_BAD_REQUEST;
  844.             ap_table_setn(r->notes, "error-notes",
  845.                           "The number of request header fields exceeds "
  846.                           "this server's limit.<P>\n");
  847.             return;
  848.         }
  849.         /* getline returns (size of max buffer - 1) if it fills up the
  850.          * buffer before finding the end-of-line.  This is only going to
  851.          * happen if it exceeds the configured limit for a field size.
  852.          */
  853.         if (len > r->server->limit_req_fieldsize) {
  854.             r->status = HTTP_BAD_REQUEST;
  855.             ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
  856.                 "Size of a request header field exceeds server limit.<P>\n"
  857.                 "<PRE>\n", field, "</PRE>\n", NULL));
  858.             return;
  859.         }
  860.         copy = ap_palloc(r->pool, len + 1);
  861.         memcpy(copy, field, len + 1);
  862.  
  863.         if (!(value = strchr(copy, ':'))) {     /* Find the colon separator */
  864.             r->status = HTTP_BAD_REQUEST;       /* or abort the bad request */
  865.             ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
  866.                 "Request header field is missing colon separator.<P>\n"
  867.                 "<PRE>\n", copy, "</PRE>\n", NULL));
  868.             return;
  869.         }
  870.  
  871.         *value = '\0';
  872.         ++value;
  873.         while (*value == ' ' || *value == '\t')
  874.             ++value;            /* Skip to start of value   */
  875.  
  876.     ap_table_addn(tmp_headers, copy, value);
  877.     }
  878.  
  879.     ap_overlap_tables(r->headers_in, tmp_headers, AP_OVERLAP_TABLES_MERGE);
  880. }
  881.  
  882. request_rec *ap_read_request(conn_rec *conn)
  883. {
  884.     request_rec *r;
  885.     pool *p;
  886.     const char *expect;
  887.     int access_status;
  888.  
  889.     p = ap_make_sub_pool(conn->pool);
  890.     r = ap_pcalloc(p, sizeof(request_rec));
  891.     r->pool            = p;
  892.     r->connection      = conn;
  893.     conn->server       = conn->base_server;
  894.     r->server          = conn->server;
  895.  
  896.     conn->keptalive    = conn->keepalive == 1;
  897.     conn->keepalive    = 0;
  898.  
  899.     conn->user         = NULL;
  900.     conn->ap_auth_type    = NULL;
  901.  
  902.     r->headers_in      = ap_make_table(r->pool, 50);
  903.     r->subprocess_env  = ap_make_table(r->pool, 50);
  904.     r->headers_out     = ap_make_table(r->pool, 12);
  905.     r->err_headers_out = ap_make_table(r->pool, 5);
  906.     r->notes           = ap_make_table(r->pool, 5);
  907.  
  908.     r->request_config  = ap_create_request_config(r->pool);
  909.     r->per_dir_config  = r->server->lookup_defaults;
  910.  
  911.     r->sent_bodyct     = 0;                      /* bytect isn't for body */
  912.  
  913.     r->read_length     = 0;
  914.     r->read_body       = REQUEST_NO_BODY;
  915.  
  916.     r->status          = HTTP_REQUEST_TIME_OUT;  /* Until we get a request */
  917.     r->the_request     = NULL;
  918.  
  919. #ifdef CHARSET_EBCDIC
  920.     ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 1);
  921. #endif
  922.  
  923.     /* Get the request... */
  924.  
  925.     ap_keepalive_timeout("read request line", r);
  926.     if (!read_request_line(r)) {
  927.         ap_kill_timeout(r);
  928.         if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
  929.  
  930.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  931.                          "request failed: URI too long");
  932.             ap_send_error_response(r, 0);
  933.             ap_bflush(r->connection->client);
  934.             ap_log_transaction(r);
  935.             return r;
  936.         }
  937.         return NULL;
  938.     }
  939.     if (!r->assbackwards) {
  940.         ap_hard_timeout("read request headers", r);
  941.         get_mime_headers(r);
  942.         ap_kill_timeout(r);
  943.         if (r->status != HTTP_REQUEST_TIME_OUT) {
  944.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  945.                          "request failed: error reading the headers");
  946.             ap_send_error_response(r, 0);
  947.             ap_bflush(r->connection->client);
  948.             ap_log_transaction(r);
  949.             return r;
  950.         }
  951.     }
  952.     else {
  953.         ap_kill_timeout(r);
  954.  
  955.         if (r->header_only) {
  956.             /*
  957.              * Client asked for headers only with HTTP/0.9, which doesn't send
  958.              * headers! Have to dink things just to make sure the error message
  959.              * comes through...
  960.              */
  961.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  962.                           "client sent invalid HTTP/0.9 request: HEAD %s",
  963.                           r->uri);
  964.             r->header_only = 0;
  965.             r->status = HTTP_BAD_REQUEST;
  966.             ap_send_error_response(r, 0);
  967.             ap_bflush(r->connection->client);
  968.             ap_log_transaction(r);
  969.             return r;
  970.         }
  971.     }
  972.  
  973.     r->status = HTTP_OK;                         /* Until further notice. */
  974.  
  975.     /* update what we think the virtual host is based on the headers we've
  976.      * now read
  977.      */
  978.     ap_update_vhost_from_headers(r);
  979.  
  980.     /* we may have switched to another server */
  981.     r->per_dir_config = r->server->lookup_defaults;
  982.  
  983.     conn->keptalive = 0;        /* We now have a request to play with */
  984.  
  985.     if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) ||
  986.         ((r->proto_num == HTTP_VERSION(1,1)) &&
  987.          !ap_table_get(r->headers_in, "Host"))) {
  988.         /*
  989.          * Client sent us an HTTP/1.1 or later request without telling us the
  990.          * hostname, either with a full URL or a Host: header. We therefore
  991.          * need to (as per the 1.1 spec) send an error.  As a special case,
  992.          * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
  993.          * a Host: header, and the server MUST respond with 400 if it doesn't.
  994.          */
  995.         r->status = HTTP_BAD_REQUEST;
  996.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  997.                       "client sent HTTP/1.1 request without hostname "
  998.                       "(see RFC2068 section 9, and 14.23): %s", r->uri);
  999.         ap_send_error_response(r, 0);
  1000.         ap_bflush(r->connection->client);
  1001.         ap_log_transaction(r);
  1002.         return r;
  1003.     }
  1004.     if (((expect = ap_table_get(r->headers_in, "Expect")) != NULL) &&
  1005.         (expect[0] != '\0')) {
  1006.         /*
  1007.          * The Expect header field was added to HTTP/1.1 after RFC 2068
  1008.          * as a means to signal when a 100 response is desired and,
  1009.          * unfortunately, to signal a poor man's mandatory extension that
  1010.          * the server must understand or return 417 Expectation Failed.
  1011.          */
  1012.         if (strcasecmp(expect, "100-continue") == 0) {
  1013.             r->expecting_100 = 1;
  1014.         }
  1015.         else {
  1016.             r->status = HTTP_EXPECTATION_FAILED;
  1017.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r,
  1018.                           "client sent an unrecognized expectation value of "
  1019.                           "Expect: %s", expect);
  1020.             ap_send_error_response(r, 0);
  1021.             ap_bflush(r->connection->client);
  1022.             (void) ap_discard_request_body(r);
  1023.             ap_log_transaction(r);
  1024.             return r;
  1025.         }
  1026.     }
  1027.  
  1028.     if ((access_status = ap_run_post_read_request(r))) {
  1029.         ap_die(access_status, r);
  1030.         ap_log_transaction(r);
  1031.         return NULL;
  1032.     }
  1033.  
  1034.     return r;
  1035. }
  1036.  
  1037. /*
  1038.  * A couple of other functions which initialize some of the fields of
  1039.  * a request structure, as appropriate for adjuncts of one kind or another
  1040.  * to a request in progress.  Best here, rather than elsewhere, since
  1041.  * *someone* has to set the protocol-specific fields...
  1042.  */
  1043.  
  1044. void ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r)
  1045. {
  1046.     rnew->the_request     = r->the_request;  /* Keep original request-line */
  1047.  
  1048.     rnew->assbackwards    = 1;   /* Don't send headers from this. */
  1049.     rnew->no_local_copy   = 1;   /* Don't try to send USE_LOCAL_COPY for a
  1050.                                   * fragment. */
  1051.     rnew->method          = "GET";
  1052.     rnew->method_number   = M_GET;
  1053.     rnew->protocol        = "INCLUDED";
  1054.  
  1055.     rnew->status          = HTTP_OK;
  1056.  
  1057.     rnew->headers_in      = r->headers_in;
  1058.     rnew->subprocess_env  = ap_copy_table(rnew->pool, r->subprocess_env);
  1059.     rnew->headers_out     = ap_make_table(rnew->pool, 5);
  1060.     rnew->err_headers_out = ap_make_table(rnew->pool, 5);
  1061.     rnew->notes           = ap_make_table(rnew->pool, 5);
  1062.  
  1063.     rnew->expecting_100   = r->expecting_100;
  1064.     rnew->read_length     = r->read_length;
  1065.     rnew->read_body       = REQUEST_NO_BODY;
  1066.  
  1067.     rnew->main = (request_rec *) r;
  1068. }
  1069.  
  1070. void ap_finalize_sub_req_protocol(request_rec *sub)
  1071. {
  1072.     SET_BYTES_SENT(sub->main);
  1073. }
  1074.  
  1075. /*
  1076.  * Support for the Basic authentication protocol, and a bit for Digest.
  1077.  */
  1078.  
  1079. API_EXPORT(void) ap_note_auth_failure(request_rec *r)
  1080. {
  1081.     if (!strcasecmp(ap_auth_type(r), "Basic"))
  1082.         ap_note_basic_auth_failure(r);
  1083.     else if (!strcasecmp(ap_auth_type(r), "Digest"))
  1084.         ap_note_digest_auth_failure(r);
  1085. }
  1086.  
  1087. API_EXPORT(void) ap_note_basic_auth_failure(request_rec *r)
  1088. {
  1089.     if (strcasecmp(ap_auth_type(r), "Basic"))
  1090.         ap_note_auth_failure(r);
  1091.     else
  1092.         ap_table_setn(r->err_headers_out,
  1093.                   r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
  1094.                   ap_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r), "\"",
  1095.                           NULL));
  1096. }
  1097.  
  1098. API_EXPORT(void) ap_note_digest_auth_failure(request_rec *r)
  1099. {
  1100.     ap_table_setn(r->err_headers_out,
  1101.         r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
  1102.         ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%lu\"",
  1103.         ap_auth_name(r), r->request_time));
  1104. }
  1105.  
  1106. API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw)
  1107. {
  1108.     const char *auth_line = ap_table_get(r->headers_in,
  1109.                                       r->proxyreq ? "Proxy-Authorization"
  1110.                                                   : "Authorization");
  1111.     const char *t;
  1112.  
  1113.     if (!(t = ap_auth_type(r)) || strcasecmp(t, "Basic"))
  1114.         return DECLINED;
  1115.  
  1116.     if (!ap_auth_name(r)) {
  1117.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
  1118.             r, "need AuthName: %s", r->uri);
  1119.         return SERVER_ERROR;
  1120.     }
  1121.  
  1122.     if (!auth_line) {
  1123.         ap_note_basic_auth_failure(r);
  1124.         return AUTH_REQUIRED;
  1125.     }
  1126.  
  1127.     if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
  1128.         /* Client tried to authenticate using wrong auth scheme */
  1129.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  1130.                     "client used wrong authentication scheme: %s", r->uri);
  1131.         ap_note_basic_auth_failure(r);
  1132.         return AUTH_REQUIRED;
  1133.     }
  1134.  
  1135.     t = ap_uudecode(r->pool, auth_line);
  1136.     /* Note that this allocation has to be made from r->connection->pool
  1137.      * because it has the lifetime of the connection.  The other allocations
  1138.      * are temporary and can be tossed away any time.
  1139.      */
  1140.     r->connection->user = ap_getword_nulls (r->connection->pool, &t, ':');
  1141.     r->connection->ap_auth_type = "Basic";
  1142.  
  1143.     *pw = t;
  1144.  
  1145.     return OK;
  1146. }
  1147.  
  1148. /* New Apache routine to map status codes into array indicies
  1149.  *  e.g.  100 -> 0,  101 -> 1,  200 -> 2 ...
  1150.  * The number of status lines must equal the value of RESPONSE_CODES (httpd.h)
  1151.  * and must be listed in order.
  1152.  */
  1153.  
  1154. static char *status_lines[RESPONSE_CODES] = {
  1155.     "100 Continue",
  1156.     "101 Switching Protocols",
  1157.     "102 Processing",
  1158. #define LEVEL_200  3
  1159.     "200 OK",
  1160.     "201 Created",
  1161.     "202 Accepted",
  1162.     "203 Non-Authoritative Information",
  1163.     "204 No Content",
  1164.     "205 Reset Content",
  1165.     "206 Partial Content",
  1166.     "207 Multi-Status",
  1167. #define LEVEL_300 11
  1168.     "300 Multiple Choices",
  1169.     "301 Moved Permanently",
  1170.     "302 Found",
  1171.     "303 See Other",
  1172.     "304 Not Modified",
  1173.     "305 Use Proxy",
  1174.     "306 unused",
  1175.     "307 Temporary Redirect",
  1176. #define LEVEL_400 19
  1177.     "400 Bad Request",
  1178.     "401 Authorization Required",
  1179.     "402 Payment Required",
  1180.     "403 Forbidden",
  1181.     "404 Not Found",
  1182.     "405 Method Not Allowed",
  1183.     "406 Not Acceptable",
  1184.     "407 Proxy Authentication Required",
  1185.     "408 Request Time-out",
  1186.     "409 Conflict",
  1187.     "410 Gone",
  1188.     "411 Length Required",
  1189.     "412 Precondition Failed",
  1190.     "413 Request Entity Too Large",
  1191.     "414 Request-URI Too Large",
  1192.     "415 Unsupported Media Type",
  1193.     "416 Requested Range Not Satisfiable",
  1194.     "417 Expectation Failed",
  1195.     "418 unused",
  1196.     "419 unused",
  1197.     "420 unused",
  1198.     "421 unused",
  1199.     "422 Unprocessable Entity",
  1200.     "423 Locked",
  1201.     "424 Failed Dependency",
  1202. #define LEVEL_500 44
  1203.     "500 Internal Server Error",
  1204.     "501 Method Not Implemented",
  1205.     "502 Bad Gateway",
  1206.     "503 Service Temporarily Unavailable",
  1207.     "504 Gateway Time-out",
  1208.     "505 HTTP Version Not Supported",
  1209.     "506 Variant Also Negotiates",
  1210.     "507 Insufficient Storage",
  1211.     "508 unused",
  1212.     "509 unused",
  1213.     "510 Not Extended"
  1214. };
  1215.  
  1216. /* The index is found by its offset from the x00 code of each level.
  1217.  * Although this is fast, it will need to be replaced if some nutcase
  1218.  * decides to define a high-numbered code before the lower numbers.
  1219.  * If that sad event occurs, replace the code below with a linear search
  1220.  * from status_lines[shortcut[i]] to status_lines[shortcut[i+1]-1];
  1221.  */
  1222. API_EXPORT(int) ap_index_of_response(int status)
  1223. {
  1224.     static int shortcut[6] = {0, LEVEL_200, LEVEL_300, LEVEL_400,
  1225.     LEVEL_500, RESPONSE_CODES};
  1226.     int i, pos;
  1227.  
  1228.     if (status < 100)           /* Below 100 is illegal for HTTP status */
  1229.         return LEVEL_500;
  1230.  
  1231.     for (i = 0; i < 5; i++) {
  1232.         status -= 100;
  1233.         if (status < 100) {
  1234.             pos = (status + shortcut[i]);
  1235.             if (pos < shortcut[i + 1])
  1236.                 return pos;
  1237.             else
  1238.                 return LEVEL_500;       /* status unknown (falls in gap) */
  1239.         }
  1240.     }
  1241.     return LEVEL_500;           /* 600 or above is also illegal */
  1242. }
  1243.  
  1244. /* Send a single HTTP header field to the client.  Note that this function
  1245.  * is used in calls to table_do(), so their interfaces are co-dependent.
  1246.  * In other words, don't change this one without checking table_do in alloc.c.
  1247.  * It returns true unless there was a write error of some kind.
  1248.  */
  1249. API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r,
  1250.     const char *fieldname, const char *fieldval)
  1251. {
  1252.     return (0 < ap_bvputs(r->connection->client,
  1253.                        fieldname, ": ", fieldval, "\015\012", NULL));
  1254. }
  1255.  
  1256. API_EXPORT(void) ap_basic_http_header(request_rec *r)
  1257. {
  1258.     char *protocol;
  1259. #ifdef CHARSET_EBCDIC
  1260.     int convert = ap_bgetflag(r->connection->client, B_EBCDIC2ASCII);
  1261. #endif /*CHARSET_EBCDIC*/
  1262.  
  1263.     if (r->assbackwards)
  1264.         return;
  1265.  
  1266.     if (!r->status_line)
  1267.         r->status_line = status_lines[ap_index_of_response(r->status)];
  1268.  
  1269.     /* mod_proxy is only HTTP/1.0, so avoid sending HTTP/1.1 error response;
  1270.      * kluge around broken browsers when indicated by force-response-1.0
  1271.      */
  1272.     if (r->proxyreq
  1273.         || (r->proto_num == HTTP_VERSION(1,0)
  1274.             && ap_table_get(r->subprocess_env, "force-response-1.0"))) {
  1275.  
  1276.         protocol = "HTTP/1.0";
  1277.         r->connection->keepalive = -1;
  1278.     }
  1279.     else
  1280.         protocol = SERVER_PROTOCOL;
  1281.  
  1282. #ifdef CHARSET_EBCDIC
  1283.     ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, 1);
  1284. #endif /*CHARSET_EBCDIC*/
  1285.  
  1286.     /* Output the HTTP/1.x Status-Line and the Date and Server fields */
  1287.  
  1288.     ap_bvputs(r->connection->client,
  1289.            protocol, " ", r->status_line, "\015\012", NULL);
  1290.  
  1291.     ap_send_header_field(r, "Date", ap_gm_timestr_822(r->pool, r->request_time));
  1292.     ap_send_header_field(r, "Server", ap_get_server_version());
  1293.  
  1294.     ap_table_unset(r->headers_out, "Date");        /* Avoid bogosity */
  1295.     ap_table_unset(r->headers_out, "Server");
  1296. #ifdef CHARSET_EBCDIC
  1297.     if (!convert)
  1298.         ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, convert);
  1299. #endif /*CHARSET_EBCDIC*/
  1300. }
  1301.  
  1302. /* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2
  1303.  * have a header parsing bug.  If the terminating \r\n occur starting
  1304.  * at offset 256, 257 or 258 of output then it will not properly parse
  1305.  * the headers.  Curiously it doesn't exhibit this problem at 512, 513.
  1306.  * We are guessing that this is because their initial read of a new request
  1307.  * uses a 256 byte buffer, and subsequent reads use a larger buffer.
  1308.  * So the problem might exist at different offsets as well.
  1309.  *
  1310.  * This should also work on keepalive connections assuming they use the
  1311.  * same small buffer for the first read of each new request.
  1312.  *
  1313.  * At any rate, we check the bytes written so far and, if we are about to
  1314.  * tickle the bug, we instead insert a bogus padding header.  Since the bug
  1315.  * manifests as a broken image in Navigator, users blame the server.  :(
  1316.  * It is more expensive to check the User-Agent than it is to just add the
  1317.  * bytes, so we haven't used the BrowserMatch feature here.
  1318.  */
  1319. static void terminate_header(BUFF *client)
  1320. {
  1321.     long int bs;
  1322.  
  1323.     ap_bgetopt(client, BO_BYTECT, &bs);
  1324.     if (bs >= 255 && bs <= 257)
  1325.         ap_bputs("X-Pad: avoid browser bug\015\012", client);
  1326.  
  1327.     ap_bputs("\015\012", client);  /* Send the terminating empty line */
  1328. }
  1329.  
  1330. /* Build the Allow field-value from the request handler method mask.
  1331.  * Note that we always allow TRACE, since it is handled below.
  1332.  */
  1333. static char *make_allow(request_rec *r)
  1334. {
  1335.     return 2 + ap_pstrcat(r->pool,
  1336.                    (r->allowed & (1 << M_GET))       ? ", GET, HEAD" : "",
  1337.                    (r->allowed & (1 << M_POST))      ? ", POST"      : "",
  1338.                    (r->allowed & (1 << M_PUT))       ? ", PUT"       : "",
  1339.                    (r->allowed & (1 << M_DELETE))    ? ", DELETE"    : "",
  1340.                    (r->allowed & (1 << M_CONNECT))   ? ", CONNECT"   : "",
  1341.                    (r->allowed & (1 << M_OPTIONS))   ? ", OPTIONS"   : "",
  1342.                    (r->allowed & (1 << M_PATCH))     ? ", PATCH"     : "",
  1343.                    (r->allowed & (1 << M_PROPFIND))  ? ", PROPFIND"  : "",
  1344.                    (r->allowed & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "",
  1345.                    (r->allowed & (1 << M_MKCOL))     ? ", MKCOL"     : "",
  1346.                    (r->allowed & (1 << M_COPY))      ? ", COPY"      : "",
  1347.                    (r->allowed & (1 << M_MOVE))      ? ", MOVE"      : "",
  1348.                    (r->allowed & (1 << M_LOCK))      ? ", LOCK"      : "",
  1349.                    (r->allowed & (1 << M_UNLOCK))    ? ", UNLOCK"    : "",
  1350.                    ", TRACE",
  1351.                    NULL);
  1352. }
  1353.  
  1354. API_EXPORT(int) ap_send_http_trace(request_rec *r)
  1355. {
  1356.     int rv;
  1357.  
  1358.     /* Get the original request */
  1359.     while (r->prev)
  1360.         r = r->prev;
  1361.  
  1362.     if ((rv = ap_setup_client_block(r, REQUEST_NO_BODY)))
  1363.         return rv;
  1364.  
  1365.     ap_hard_timeout("send TRACE", r);
  1366.  
  1367.     r->content_type = "message/http";
  1368.     ap_send_http_header(r);
  1369.  
  1370.     /* Now we recreate the request, and echo it back */
  1371.  
  1372.     ap_rvputs(r, r->the_request, "\015\012", NULL);
  1373.  
  1374.     ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
  1375.              (void *) r, r->headers_in, NULL);
  1376.     ap_bputs("\015\012", r->connection->client);
  1377.  
  1378.     ap_kill_timeout(r);
  1379.     return OK;
  1380. }
  1381.  
  1382. int ap_send_http_options(request_rec *r)
  1383. {
  1384.     const long int zero = 0L;
  1385.  
  1386.     if (r->assbackwards)
  1387.         return DECLINED;
  1388.  
  1389.     ap_hard_timeout("send OPTIONS", r);
  1390.  
  1391.     ap_basic_http_header(r);
  1392.  
  1393.     ap_table_setn(r->headers_out, "Content-Length", "0");
  1394.     ap_table_setn(r->headers_out, "Allow", make_allow(r));
  1395.     ap_set_keepalive(r);
  1396.  
  1397.     ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
  1398.              (void *) r, r->headers_out, NULL);
  1399.  
  1400.     terminate_header(r->connection->client);
  1401.  
  1402.     ap_kill_timeout(r);
  1403.     ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
  1404.  
  1405.     return OK;
  1406. }
  1407.  
  1408. /*
  1409.  * Here we try to be compatible with clients that want multipart/x-byteranges
  1410.  * instead of multipart/byteranges (also see above), as per HTTP/1.1. We
  1411.  * look for the Request-Range header (e.g. Netscape 2 and 3) as an indication
  1412.  * that the browser supports an older protocol. We also check User-Agent
  1413.  * for Microsoft Internet Explorer 3, which needs this as well.
  1414.  */
  1415. static int use_range_x(request_rec *r)
  1416. {
  1417.     const char *ua;
  1418.     return (ap_table_get(r->headers_in, "Request-Range") ||
  1419.             ((ua = ap_table_get(r->headers_in, "User-Agent"))
  1420.              && strstr(ua, "MSIE 3")));
  1421. }
  1422.  
  1423. API_EXPORT(void) ap_send_http_header(request_rec *r)
  1424. {
  1425.     int i;
  1426.     const long int zero = 0L;
  1427. #ifdef CHARSET_EBCDIC
  1428.     int convert = ap_bgetflag(r->connection->client, B_EBCDIC2ASCII);
  1429. #endif /*CHARSET_EBCDIC*/
  1430.  
  1431.     if (r->assbackwards) {
  1432.         if (!r->main)
  1433.             ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
  1434.         r->sent_bodyct = 1;
  1435.         return;
  1436.     }
  1437.  
  1438.     /*
  1439.      * Now that we are ready to send a response, we need to combine the two
  1440.      * header field tables into a single table.  If we don't do this, our
  1441.      * later attempts to set or unset a given fieldname might be bypassed.
  1442.      */
  1443.     if (!ap_is_empty_table(r->err_headers_out))
  1444.         r->headers_out = ap_overlay_tables(r->pool, r->err_headers_out,
  1445.                                         r->headers_out);
  1446.  
  1447.     ap_hard_timeout("send headers", r);
  1448.  
  1449.     ap_basic_http_header(r);
  1450.  
  1451. #ifdef CHARSET_EBCDIC
  1452.     ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, 1);
  1453. #endif /*CHARSET_EBCDIC*/
  1454.  
  1455.     ap_set_keepalive(r);
  1456.  
  1457.     if (r->chunked) {
  1458.         ap_table_mergen(r->headers_out, "Transfer-Encoding", "chunked");
  1459.         ap_table_unset(r->headers_out, "Content-Length");
  1460.     }
  1461.  
  1462.     if (r->byterange > 1)
  1463.         ap_table_setn(r->headers_out, "Content-Type",
  1464.                   ap_pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/",
  1465.                           "byteranges; boundary=", r->boundary, NULL));
  1466.     else if (r->content_type)
  1467.         ap_table_setn(r->headers_out, "Content-Type", r->content_type);
  1468.     else
  1469.         ap_table_setn(r->headers_out, "Content-Type", ap_default_type(r));
  1470.  
  1471.     if (r->content_encoding)
  1472.         ap_table_setn(r->headers_out, "Content-Encoding", r->content_encoding);
  1473.  
  1474.     if (r->content_languages && r->content_languages->nelts) {
  1475.         for (i = 0; i < r->content_languages->nelts; ++i) {
  1476.             ap_table_mergen(r->headers_out, "Content-Language",
  1477.                         ((char **) (r->content_languages->elts))[i]);
  1478.         }
  1479.     }
  1480.     else if (r->content_language)
  1481.         ap_table_setn(r->headers_out, "Content-Language", r->content_language);
  1482.  
  1483.     /*
  1484.      * Control cachability for non-cachable responses if not already set by
  1485.      * some other part of the server configuration.
  1486.      */
  1487.     if (r->no_cache && !ap_table_get(r->headers_out, "Expires"))
  1488.         ap_table_addn(r->headers_out, "Expires",
  1489.                   ap_gm_timestr_822(r->pool, r->request_time));
  1490.  
  1491.     /* Send the entire table of header fields, terminated by an empty line. */
  1492.  
  1493.     ap_table_do((int (*) (void *, const char *, const char *)) ap_send_header_field,
  1494.              (void *) r, r->headers_out, NULL);
  1495.  
  1496.     terminate_header(r->connection->client);
  1497.  
  1498.     ap_kill_timeout(r);
  1499.  
  1500.     ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
  1501.     r->sent_bodyct = 1;         /* Whatever follows is real body stuff... */
  1502.  
  1503.     /* Set buffer flags for the body */
  1504.     if (r->chunked)
  1505.         ap_bsetflag(r->connection->client, B_CHUNK, 1);
  1506. #ifdef CHARSET_EBCDIC
  1507.     if (!convert)
  1508.         ap_bsetflag(r->connection->client, B_EBCDIC2ASCII, convert);
  1509. #endif /*CHARSET_EBCDIC*/
  1510. }
  1511.  
  1512. /* finalize_request_protocol is called at completion of sending the
  1513.  * response.  It's sole purpose is to send the terminating protocol
  1514.  * information for any wrappers around the response message body
  1515.  * (i.e., transfer encodings).  It should have been named finalize_response.
  1516.  */
  1517. API_EXPORT(void) ap_finalize_request_protocol(request_rec *r)
  1518. {
  1519.     if (r->chunked && !r->connection->aborted) {
  1520.         /*
  1521.          * Turn off chunked encoding --- we can only do this once.
  1522.          */
  1523.         r->chunked = 0;
  1524.         ap_bsetflag(r->connection->client, B_CHUNK, 0);
  1525.  
  1526.         ap_soft_timeout("send ending chunk", r);
  1527.         ap_bputs("0\015\012", r->connection->client);
  1528.         /* If we had footer "headers", we'd send them now */
  1529.         ap_bputs("\015\012", r->connection->client);
  1530.         ap_kill_timeout(r);
  1531.     }
  1532. }
  1533.  
  1534. /* Here we deal with getting the request message body from the client.
  1535.  * Whether or not the request contains a body is signaled by the presence
  1536.  * of a non-zero Content-Length or by a Transfer-Encoding: chunked.
  1537.  *
  1538.  * Note that this is more complicated than it was in Apache 1.1 and prior
  1539.  * versions, because chunked support means that the module does less.
  1540.  *
  1541.  * The proper procedure is this:
  1542.  *
  1543.  * 1. Call setup_client_block() near the beginning of the request
  1544.  *    handler. This will set up all the necessary properties, and will
  1545.  *    return either OK, or an error code. If the latter, the module should
  1546.  *    return that error code. The second parameter selects the policy to
  1547.  *    apply if the request message indicates a body, and how a chunked
  1548.  *    transfer-coding should be interpreted. Choose one of
  1549.  *
  1550.  *    REQUEST_NO_BODY          Send 413 error if message has any body
  1551.  *    REQUEST_CHUNKED_ERROR    Send 411 error if body without Content-Length
  1552.  *    REQUEST_CHUNKED_DECHUNK  If chunked, remove the chunks for me.
  1553.  *    REQUEST_CHUNKED_PASS     Pass the chunks to me without removal.
  1554.  *
  1555.  *    In order to use the last two options, the caller MUST provide a buffer
  1556.  *    large enough to hold a chunk-size line, including any extensions.
  1557.  *
  1558.  * 2. When you are ready to read a body (if any), call should_client_block().
  1559.  *    This will tell the module whether or not to read input. If it is 0,
  1560.  *    the module should assume that there is no message body to read.
  1561.  *    This step also sends a 100 Continue response to HTTP/1.1 clients,
  1562.  *    so should not be called until the module is *definitely* ready to
  1563.  *    read content. (otherwise, the point of the 100 response is defeated).
  1564.  *    Never call this function more than once.
  1565.  *
  1566.  * 3. Finally, call get_client_block in a loop. Pass it a buffer and its size.
  1567.  *    It will put data into the buffer (not necessarily a full buffer), and
  1568.  *    return the length of the input block. When it is done reading, it will
  1569.  *    return 0 if EOF, or -1 if there was an error.
  1570.  *    If an error occurs on input, we force an end to keepalive.
  1571.  */
  1572.  
  1573. API_EXPORT(int) ap_setup_client_block(request_rec *r, int read_policy)
  1574. {
  1575.     const char *tenc = ap_table_get(r->headers_in, "Transfer-Encoding");
  1576.     const char *lenp = ap_table_get(r->headers_in, "Content-Length");
  1577.     unsigned long max_body;
  1578.  
  1579.     r->read_body = read_policy;
  1580.     r->read_chunked = 0;
  1581.     r->remaining = 0;
  1582.  
  1583.     if (tenc) {
  1584.         if (strcasecmp(tenc, "chunked")) {
  1585.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  1586.                         "Unknown Transfer-Encoding %s", tenc);
  1587.             return HTTP_NOT_IMPLEMENTED;
  1588.         }
  1589.         if (r->read_body == REQUEST_CHUNKED_ERROR) {
  1590.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  1591.                         "chunked Transfer-Encoding forbidden: %s", r->uri);
  1592.             return (lenp) ? HTTP_BAD_REQUEST : HTTP_LENGTH_REQUIRED;
  1593.         }
  1594.  
  1595.         r->read_chunked = 1;
  1596.     }
  1597.     else if (lenp) {
  1598.         const char *pos = lenp;
  1599.  
  1600.         while (ap_isdigit(*pos) || ap_isspace(*pos))
  1601.             ++pos;
  1602.         if (*pos != '\0') {
  1603.             ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  1604.                         "Invalid Content-Length %s", lenp);
  1605.             return HTTP_BAD_REQUEST;
  1606.         }
  1607.  
  1608.         r->remaining = atol(lenp);
  1609.     }
  1610.  
  1611.     if ((r->read_body == REQUEST_NO_BODY) &&
  1612.         (r->read_chunked || (r->remaining > 0))) {
  1613.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  1614.                     "%s with body is not allowed for %s", r->method, r->uri);
  1615.         return HTTP_REQUEST_ENTITY_TOO_LARGE;
  1616.     }
  1617.  
  1618.     max_body = ap_get_limit_req_body(r);
  1619.     if (max_body && (r->remaining > max_body)) {
  1620.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  1621.           "Request content-length of %s is larger than the configured "
  1622.           "limit of %lu", lenp, max_body);
  1623.         return HTTP_REQUEST_ENTITY_TOO_LARGE;
  1624.     }
  1625.  
  1626.     return OK;
  1627. }
  1628.  
  1629. API_EXPORT(int) ap_should_client_block(request_rec *r)
  1630. {
  1631.     /* First check if we have already read the request body */
  1632.  
  1633.     if (r->read_length || (!r->read_chunked && (r->remaining <= 0)))
  1634.         return 0;
  1635.  
  1636.     if (r->expecting_100 && r->proto_num >= HTTP_VERSION(1,1)) {
  1637.         /* sending 100 Continue interim response */
  1638.         ap_bvputs(r->connection->client,
  1639.                SERVER_PROTOCOL, " ", status_lines[0], "\015\012\015\012",
  1640.                NULL);
  1641.         ap_bflush(r->connection->client);
  1642.     }
  1643.  
  1644.     return 1;
  1645. }
  1646.  
  1647. static long get_chunk_size(char *b)
  1648. {
  1649.     long chunksize = 0;
  1650.  
  1651.     while (isxdigit(*b)) {
  1652.         int xvalue = 0;
  1653.  
  1654.         if (*b >= '0' && *b <= '9')
  1655.             xvalue = *b - '0';
  1656.         else if (*b >= 'A' && *b <= 'F')
  1657.             xvalue = *b - 'A' + 0xa;
  1658.         else if (*b >= 'a' && *b <= 'f')
  1659.             xvalue = *b - 'a' + 0xa;
  1660.  
  1661.         chunksize = (chunksize << 4) | xvalue;
  1662.         ++b;
  1663.     }
  1664.  
  1665.     return chunksize;
  1666. }
  1667.  
  1668. /* get_client_block is called in a loop to get the request message body.
  1669.  * This is quite simple if the client includes a content-length
  1670.  * (the normal case), but gets messy if the body is chunked. Note that
  1671.  * r->remaining is used to maintain state across calls and that
  1672.  * r->read_length is the total number of bytes given to the caller
  1673.  * across all invocations.  It is messy because we have to be careful not
  1674.  * to read past the data provided by the client, since these reads block.
  1675.  * Returns 0 on End-of-body, -1 on error or premature chunk end.
  1676.  *
  1677.  * Reading the chunked encoding requires a buffer size large enough to
  1678.  * hold a chunk-size line, including any extensions. For now, we'll leave
  1679.  * that to the caller, at least until we can come up with a better solution.
  1680.  */
  1681. API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz)
  1682. {
  1683.     int c;
  1684.     long len_read, len_to_read;
  1685.     long chunk_start = 0;
  1686.     unsigned long max_body;
  1687.  
  1688.     if (!r->read_chunked) {     /* Content-length read */
  1689.         len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
  1690.         len_read = ap_bread(r->connection->client, buffer, len_to_read);
  1691.         if (len_read <= 0) {
  1692.             if (len_read < 0)
  1693.                 r->connection->keepalive = -1;
  1694.             return len_read;
  1695.         }
  1696.         r->read_length += len_read;
  1697.         r->remaining -= len_read;
  1698.         return len_read;
  1699.     }
  1700.  
  1701.     /*
  1702.      * Handle chunked reading Note: we are careful to shorten the input
  1703.      * bufsiz so that there will always be enough space for us to add a CRLF
  1704.      * (if necessary).
  1705.      */
  1706.     if (r->read_body == REQUEST_CHUNKED_PASS)
  1707.         bufsiz -= 2;
  1708.     if (bufsiz <= 0)
  1709.         return -1;              /* Cannot read chunked with a small buffer */
  1710.  
  1711.     /* Check to see if we have already read too much request data.
  1712.      * For efficiency reasons, we only check this at the top of each
  1713.      * caller read pass, since the limit exists just to stop infinite
  1714.      * length requests and nobody cares if it goes over by one buffer.
  1715.      */
  1716.     max_body = ap_get_limit_req_body(r);
  1717.     if (max_body && (r->read_length > max_body)) {
  1718.         ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
  1719.             "Chunked request body is larger than the configured limit of %lu",
  1720.             max_body);
  1721.         r->connection->keepalive = -1;
  1722.         return -1;
  1723.     }
  1724.  
  1725.     if (r->remaining == 0) {    /* Start of new chunk */
  1726.  
  1727.         chunk_start = getline(buffer, bufsiz, r->connection->client, 0);
  1728.         if ((chunk_start <= 0) || (chunk_start >= (bufsiz - 1))
  1729.             || !isxdigit(*buffer)) {
  1730.             r->connection->keepalive = -1;
  1731.             return -1;
  1732.         }
  1733.  
  1734.         len_to_read = get_chunk_size(buffer);
  1735.  
  1736.         if (len_to_read == 0) { /* Last chunk indicated, get footers */
  1737.             if (r->read_body == REQUEST_CHUNKED_DECHUNK) {
  1738.                 get_mime_headers(r);
  1739.                 ap_snprintf(buffer, bufsiz, "%ld", r->read_length);
  1740.                 ap_table_unset(r->headers_in, "Transfer-Encoding");
  1741.                 ap_table_setn(r->headers_in, "Content-Length",
  1742.                     ap_pstrdup(r->pool, buffer));
  1743.                 return 0;
  1744.             }
  1745.             r->remaining = -1;  /* Indicate footers in-progress */
  1746.         }
  1747.         else {
  1748.             r->remaining = len_to_read;
  1749.         }
  1750.         if (r->read_body == REQUEST_CHUNKED_PASS) {
  1751.             buffer[chunk_start++] = CR; /* Restore chunk-size line end  */
  1752.             buffer[chunk_start++] = LF;
  1753.             buffer += chunk_start;      /* and pass line on to caller   */
  1754.             bufsiz -= chunk_start;
  1755.         }
  1756.         else {
  1757.             /* REQUEST_CHUNKED_DECHUNK -- do not include the length of the
  1758.              * header in the return value
  1759.              */
  1760.             chunk_start = 0;
  1761.         }
  1762.     }
  1763.                                 /* When REQUEST_CHUNKED_PASS, we are */
  1764.     if (r->remaining == -1) {   /* reading footers until empty line  */
  1765.         len_read = chunk_start;
  1766.  
  1767.         while ((bufsiz > 1) && ((len_read =
  1768.                   getline(buffer, bufsiz, r->connection->client, 1)) > 0)) {
  1769.  
  1770.             if (len_read != (bufsiz - 1)) {
  1771.                 buffer[len_read++] = CR;        /* Restore footer line end  */
  1772.                 buffer[len_read++] = LF;
  1773.             }
  1774.             chunk_start += len_read;
  1775.             buffer += len_read;
  1776.             bufsiz -= len_read;
  1777.         }
  1778.         if (len_read < 0) {
  1779.             r->connection->keepalive = -1;
  1780.             return -1;
  1781.         }
  1782.  
  1783.         if (len_read == 0) {    /* Indicates an empty line */
  1784.             buffer[0] = CR;
  1785.             buffer[1] = LF;
  1786.             chunk_start += 2;
  1787.             r->remaining = -2;
  1788.         }
  1789.         r->read_length += chunk_start;
  1790.         return chunk_start;
  1791.     }
  1792.                                 /* When REQUEST_CHUNKED_PASS, we     */
  1793.     if (r->remaining == -2) {   /* finished footers when last called */
  1794.         r->remaining = 0;       /* so now we must signal EOF         */
  1795.         return 0;
  1796.     }
  1797.  
  1798.     /* Otherwise, we are in the midst of reading a chunk of data */
  1799.  
  1800.     len_to_read = (r->remaining > bufsiz) ? bufsiz : r->remaining;
  1801.  
  1802.     len_read = ap_bread(r->connection->client, buffer, len_to_read);
  1803.     if (len_read <= 0) {
  1804.         r->connection->keepalive = -1;
  1805.         return -1;
  1806.     }
  1807.  
  1808.     r->remaining -= len_read;
  1809.  
  1810.     if (r->remaining == 0) {    /* End of chunk, get trailing CRLF */
  1811.         if ((c = ap_bgetc(r->connection->client)) == CR) {
  1812.             c = ap_bgetc(r->connection->client);
  1813.         }
  1814.         if (c != LF) {
  1815.             r->connection->keepalive = -1;
  1816.             return -1;
  1817.         }
  1818.         if (r->read_body == REQUEST_CHUNKED_PASS) {
  1819.             buffer[len_read++] = CR;
  1820.             buffer[len_read++] = LF;
  1821.         }
  1822.     }
  1823.     r->read_length += (chunk_start + len_read);
  1824.  
  1825.     return (chunk_start + len_read);
  1826. }
  1827.  
  1828. /* In HTTP/1.1, any method can have a body.  However, most GET handlers
  1829.  * wouldn't know what to do with a request body if they received one.
  1830.  * This helper routine tests for and reads any message body in the request,
  1831.  * simply discarding whatever it receives.  We need to do this because
  1832.  * failing to read the request body would cause it to be interpreted
  1833.  * as the next request on a persistent connection.
  1834.  *
  1835.  * Since we return an error status if the request is malformed, this
  1836.  * routine should be called at the beginning of a no-body handler, e.g.,
  1837.  *
  1838.  *    if ((retval = ap_discard_request_body(r)) != OK)
  1839.  *        return retval;
  1840.  */
  1841. API_EXPORT(int) ap_discard_request_body(request_rec *r)
  1842. {
  1843.     int rv;
  1844.  
  1845.     if ((rv = ap_setup_client_block(r, REQUEST_CHUNKED_PASS)))
  1846.         return rv;
  1847.  
  1848.     /* If we are discarding the request body, then we must already know
  1849.      * the final status code, therefore disable the sending of 100 continue.
  1850.      */
  1851.     r->expecting_100 = 0;
  1852.  
  1853.     if (ap_should_client_block(r)) {
  1854.         char dumpbuf[HUGE_STRING_LEN];
  1855.  
  1856.         ap_hard_timeout("reading request body", r);
  1857.         while ((rv = ap_get_client_block(r, dumpbuf, HUGE_STRING_LEN)) > 0)
  1858.             continue;
  1859.         ap_kill_timeout(r);
  1860.  
  1861.         if (rv < 0)
  1862.             return HTTP_BAD_REQUEST;
  1863.     }
  1864.     return OK;
  1865. }
  1866.  
  1867. /*
  1868.  * Send the body of a response to the client.
  1869.  */
  1870. API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r)
  1871. {
  1872.     return ap_send_fd_length(f, r, -1);
  1873. }
  1874.  
  1875. API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length)
  1876. {
  1877.     char buf[IOBUFSIZE];
  1878.     long total_bytes_sent = 0;
  1879.     register int n, w, o, len;
  1880.  
  1881.     if (length == 0)
  1882.         return 0;
  1883.  
  1884.     ap_soft_timeout("send body", r);
  1885.  
  1886.     while (!r->connection->aborted) {
  1887.         if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
  1888.             len = length - total_bytes_sent;
  1889.         else
  1890.             len = IOBUFSIZE;
  1891.  
  1892.         while ((n = fread(buf, sizeof(char), len, f)) < 1
  1893.                && ferror(f) && errno == EINTR && !r->connection->aborted)
  1894.             continue;
  1895.  
  1896.         if (n < 1) {
  1897.             break;
  1898.         }
  1899.         o = 0;
  1900.  
  1901.         while (n && !r->connection->aborted) {
  1902.             w = ap_bwrite(r->connection->client, &buf[o], n);
  1903.             if (w > 0) {
  1904.                 ap_reset_timeout(r);   /* reset timeout after successful write */
  1905.         total_bytes_sent += w;
  1906.                 n -= w;
  1907.                 o += w;
  1908.             }
  1909.             else if (w < 0) {
  1910.                 if (r->connection->aborted)
  1911.                     break;
  1912.                 else if (errno == EAGAIN)
  1913.                     continue;
  1914.                 else {
  1915.                     ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
  1916.                      "client stopped connection before send body completed");
  1917.                     ap_bsetflag(r->connection->client, B_EOUT, 1);
  1918.                     r->connection->aborted = 1;
  1919.                     break;
  1920.                 }
  1921.             }
  1922.         }
  1923.     }
  1924.  
  1925.     ap_kill_timeout(r);
  1926.     SET_BYTES_SENT(r);
  1927.     return total_bytes_sent;
  1928. }
  1929.  
  1930. /*
  1931.  * Send the body of a response to the client.
  1932.  */
  1933. API_EXPORT(long) ap_send_fb(BUFF *fb, request_rec *r)
  1934. {
  1935.     return ap_send_fb_length(fb, r, -1);
  1936. }
  1937.  
  1938. API_EXPORT(long) ap_send_fb_length(BUFF *fb, request_rec *r, long length)
  1939. {
  1940.     char buf[IOBUFSIZE];
  1941.     long total_bytes_sent = 0;
  1942.     register int n, w, o, len, fd;
  1943.     fd_set fds;
  1944.  
  1945.     if (length == 0)
  1946.         return 0;
  1947.  
  1948.     /* Make fb unbuffered and non-blocking */
  1949.     ap_bsetflag(fb, B_RD, 0);
  1950.     ap_bnonblock(fb, B_RD);
  1951.     fd = ap_bfileno(fb, B_RD);
  1952. #ifndef WIN32
  1953.     if (fd >= FD_SETSIZE) {
  1954.     ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
  1955.         "send body: filedescriptor (%u) larger than FD_SETSIZE (%u) "
  1956.         "found, you probably need to rebuild Apache with a "
  1957.         "larger FD_SETSIZE", fd, FD_SETSIZE);
  1958.     return 0;
  1959.     }
  1960. #endif
  1961.  
  1962.     ap_soft_timeout("send body", r);
  1963.  
  1964.     FD_ZERO(&fds);
  1965.     while (!r->connection->aborted) {
  1966. #ifdef NDELAY_PIPE_RETURNS_ZERO
  1967.     /* Contributed by dwd@bell-labs.com for UTS 2.1.2, where the fcntl */
  1968.     /*   O_NDELAY flag causes read to return 0 when there's nothing */
  1969.     /*   available when reading from a pipe.  That makes it tricky */
  1970.     /*   to detect end-of-file :-(.  This stupid bug is even documented */
  1971.     /*   in the read(2) man page where it says that everything but */
  1972.     /*   pipes return -1 and EAGAIN.  That makes it a feature, right? */
  1973.     int afterselect = 0;
  1974. #endif
  1975.         if ((length > 0) && (total_bytes_sent + IOBUFSIZE) > length)
  1976.             len = length - total_bytes_sent;
  1977.         else
  1978.             len = IOBUFSIZE;
  1979.  
  1980.         do {
  1981.             n = ap_bread(fb, buf, len);
  1982. #ifdef NDELAY_PIPE_RETURNS_ZERO
  1983.         if ((n > 0) || (n == 0 && afterselect))
  1984.         break;
  1985. #else
  1986.             if (n >= 0)
  1987.                 break;
  1988. #endif
  1989.             if (r->connection->aborted)
  1990.                 break;
  1991.             if (n < 0 && errno != EAGAIN)
  1992.                 break;
  1993.             /* we need to block, so flush the output first */
  1994.             ap_bflush(r->connection->client);
  1995.             if (r->connection->aborted)
  1996.                 break;
  1997.             FD_SET(fd, &fds);
  1998.             /*
  1999.              * we don't care what select says, we might as well loop back
  2000.              * around and try another read
  2001.              */
  2002.             ap_select(fd + 1, &fds, NULL, NULL, NULL);
  2003. #ifdef NDELAY_PIPE_RETURNS_ZERO
  2004.         afterselect = 1;
  2005. #endif
  2006.         } while (!r->connection->aborted);
  2007.  
  2008.         if (n < 1 || r->connection->aborted) {
  2009.             break;
  2010.         }
  2011.  
  2012.         o = 0;
  2013.         total_bytes_sent += n;
  2014.  
  2015.         while (n && !r->connection->aborted) {
  2016.             w = ap_bwrite(r->connection->client, &buf[o], n);
  2017.             if (w > 0) {
  2018.                 ap_reset_timeout(r);       /* reset timeout after successful
  2019.                                          * write */
  2020.                 n -= w;
  2021.                 o += w;
  2022.             }
  2023.             else if (w < 0) {
  2024.                 if (r->connection->aborted)
  2025.                     break;
  2026.                 else if (errno == EAGAIN)
  2027.                     continue;
  2028.                 else {
  2029.                     ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
  2030.                      "client stopped connection before send body completed");
  2031.                     ap_bsetflag(r->connection->client, B_EOUT, 1);
  2032.                     r->connection->aborted = 1;
  2033.                     break;
  2034.                 }
  2035.             }
  2036.         }
  2037.     }
  2038.  
  2039.     ap_kill_timeout(r);
  2040.     SET_BYTES_SENT(r);
  2041.     return total_bytes_sent;
  2042. }
  2043.  
  2044.  
  2045.  
  2046. /* The code writes MMAP_SEGMENT_SIZE bytes at a time.  This is due to Apache's
  2047.  * timeout model, which is a timeout per-write rather than a time for the
  2048.  * entire transaction to complete.  Essentially this should be small enough
  2049.  * so that in one Timeout period, your slowest clients should be reasonably
  2050.  * able to receive this many bytes.
  2051.  *
  2052.  * To take advantage of zero-copy TCP under Solaris 2.6 this should be a
  2053.  * multiple of 16k.  (And you need a SunATM2.0 network card.)
  2054.  */
  2055. #ifndef MMAP_SEGMENT_SIZE
  2056. #define MMAP_SEGMENT_SIZE       32768
  2057. #endif
  2058.  
  2059. /* send data from an in-memory buffer */
  2060. API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset,
  2061.                              size_t length)
  2062. {
  2063.     size_t total_bytes_sent = 0;
  2064.     int n, w;
  2065.  
  2066.     if (length == 0)
  2067.         return 0;
  2068.  
  2069.     ap_soft_timeout("send mmap", r);
  2070.  
  2071.     length += offset;
  2072.     while (!r->connection->aborted && offset < length) {
  2073.         if (length - offset > MMAP_SEGMENT_SIZE) {
  2074.             n = MMAP_SEGMENT_SIZE;
  2075.         }
  2076.         else {
  2077.             n = length - offset;
  2078.         }
  2079.  
  2080.         while (n && !r->connection->aborted) {
  2081.             w = ap_bwrite(r->connection->client, (char *) mm + offset, n);
  2082.             if (w > 0) {
  2083.                 ap_reset_timeout(r);   /* reset timeout after successful write */
  2084.                 total_bytes_sent += w;
  2085.                 n -= w;
  2086.                 offset += w;
  2087.             }
  2088.             else if (w < 0) {
  2089.                 if (r->connection->aborted)
  2090.                     break;
  2091.                 else if (errno == EAGAIN)
  2092.                     continue;
  2093.                 else {
  2094.                     ap_log_rerror(APLOG_MARK, APLOG_INFO, r,
  2095.                      "client stopped connection before send mmap completed");
  2096.                     ap_bsetflag(r->connection->client, B_EOUT, 1);
  2097.                     r->connection->aborted = 1;
  2098.                     break;
  2099.                 }
  2100.             }
  2101.         }
  2102.     }
  2103.  
  2104.     ap_kill_timeout(r);
  2105.     SET_BYTES_SENT(r);
  2106.     return total_bytes_sent;
  2107. }
  2108.  
  2109. API_EXPORT(int) ap_rputc(int c, request_rec *r)
  2110. {
  2111.     if (r->connection->aborted)
  2112.         return EOF;
  2113.     ap_bputc(c, r->connection->client);
  2114.     SET_BYTES_SENT(r);
  2115.     return c;
  2116. }
  2117.  
  2118. API_EXPORT(int) ap_rputs(const char *str, request_rec *r)
  2119. {
  2120.     int rcode;
  2121.  
  2122.     if (r->connection->aborted)
  2123.         return EOF;
  2124.     rcode = ap_bputs(str, r->connection->client);
  2125.     SET_BYTES_SENT(r);
  2126.     return rcode;
  2127. }
  2128.  
  2129. API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
  2130. {
  2131.     int n;
  2132.     if (r->connection->aborted)
  2133.         return EOF;
  2134.     n = ap_bwrite(r->connection->client, buf, nbyte);
  2135.     SET_BYTES_SENT(r);
  2136.     return n;
  2137. }
  2138.  
  2139. API_EXPORT(int) ap_rprintf(request_rec *r, const char *fmt,...)
  2140. {
  2141.     va_list vlist;
  2142.     int n;
  2143.  
  2144.     if (r->connection->aborted)
  2145.         return EOF;
  2146.     va_start(vlist, fmt);
  2147.     n = ap_vbprintf(r->connection->client, fmt, vlist);
  2148.     va_end(vlist);
  2149.     SET_BYTES_SENT(r);
  2150.     return n;
  2151. }
  2152.  
  2153. API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...)
  2154. {
  2155.     va_list args;
  2156.     int i, j, k;
  2157.     const char *x;
  2158.     BUFF *fb = r->connection->client;
  2159.  
  2160.     if (r->connection->aborted)
  2161.         return EOF;
  2162.  
  2163.     va_start(args, r);
  2164.     for (k = 0;;) {
  2165.         x = va_arg(args, const char *);
  2166.         if (x == NULL)
  2167.             break;
  2168.         j = strlen(x);
  2169.         i = ap_bwrite(fb, x, j);
  2170.         if (i != j) {
  2171.             va_end(args);
  2172.             return -1;
  2173.         }
  2174.         k += i;
  2175.     }
  2176.     va_end(args);
  2177.  
  2178.     SET_BYTES_SENT(r);
  2179.     return k;
  2180. }
  2181.  
  2182. API_EXPORT(int) ap_rflush(request_rec *r)
  2183. {
  2184.     return ap_bflush(r->connection->client);
  2185. }
  2186.  
  2187. /* We should have named this send_canned_response, since it is used for any
  2188.  * response that can be generated by the server from the request record.
  2189.  * This includes all 204 (no content), 3xx (redirect), 4xx (client error),
  2190.  * and 5xx (server error) messages that have not been redirected to another
  2191.  * handler via the ErrorDocument feature.
  2192.  */
  2193. void ap_send_error_response(request_rec *r, int recursive_error)
  2194. {
  2195.     BUFF *fd = r->connection->client;
  2196.     int status = r->status;
  2197.     int idx = ap_index_of_response(status);
  2198.     char *custom_response;
  2199.     const char *location = ap_table_get(r->headers_out, "Location");
  2200.  
  2201.     /* We need to special-case the handling of 204 and 304 responses,
  2202.      * since they have specific HTTP requirements and do not include a
  2203.      * message body.  Note that being assbackwards here is not an option.
  2204.      */
  2205.     if (status == HTTP_NOT_MODIFIED) {
  2206.         if (!ap_is_empty_table(r->err_headers_out))
  2207.             r->headers_out = ap_overlay_tables(r->pool, r->err_headers_out,
  2208.                                                r->headers_out);
  2209.         ap_hard_timeout("send 304", r);
  2210.  
  2211.         ap_basic_http_header(r);
  2212.         ap_set_keepalive(r);
  2213.  
  2214.         ap_table_do((int (*)(void *, const char *, const char *)) ap_send_header_field,
  2215.                     (void *) r, r->headers_out,
  2216.                     "Connection",
  2217.                     "Keep-Alive",
  2218.                     "ETag",
  2219.                     "Content-Location",
  2220.                     "Expires",
  2221.                     "Cache-Control",
  2222.                     "Vary",
  2223.                     "Warning",
  2224.                     "WWW-Authenticate",
  2225.                     "Proxy-Authenticate",
  2226.                     NULL);
  2227.  
  2228.         terminate_header(r->connection->client);
  2229.  
  2230.         ap_kill_timeout(r);
  2231.         return;
  2232.     }
  2233.  
  2234.     if (status == HTTP_NO_CONTENT) {
  2235.         ap_send_http_header(r);
  2236.         ap_finalize_request_protocol(r);
  2237.         return;
  2238.     }
  2239.  
  2240.     if (!r->assbackwards) {
  2241.         table *tmp = r->headers_out;
  2242.  
  2243.         /* For all HTTP/1.x responses for which we generate the message,
  2244.          * we need to avoid inheriting the "normal status" header fields
  2245.          * that may have been set by the request handler before the
  2246.          * error or redirect, except for Location on external redirects.
  2247.          */
  2248.         r->headers_out = r->err_headers_out;
  2249.         r->err_headers_out = tmp;
  2250.         ap_clear_table(r->err_headers_out);
  2251.  
  2252.         if (location && *location
  2253.             && (ap_is_HTTP_REDIRECT(status) || status == HTTP_CREATED))
  2254.             ap_table_setn(r->headers_out, "Location", location);
  2255.  
  2256.         r->content_language = NULL;
  2257.         r->content_languages = NULL;
  2258.         r->content_encoding = NULL;
  2259.         r->clength = 0;
  2260.         r->content_type = "text/html";
  2261.  
  2262.         if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
  2263.             ap_table_setn(r->headers_out, "Allow", make_allow(r));
  2264.  
  2265.         ap_send_http_header(r);
  2266.  
  2267.         if (r->header_only) {
  2268.             ap_finalize_request_protocol(r);
  2269.             return;
  2270.         }
  2271.     }
  2272.  
  2273.     ap_hard_timeout("send error body", r);
  2274.  
  2275.     if ((custom_response = ap_response_code_string(r, idx))) {
  2276.         /*
  2277.          * We have a custom response output. This should only be
  2278.          * a text-string to write back. But if the ErrorDocument
  2279.          * was a local redirect and the requested resource failed
  2280.          * for any reason, the custom_response will still hold the
  2281.          * redirect URL. We don't really want to output this URL
  2282.          * as a text message, so first check the custom response
  2283.          * string to ensure that it is a text-string (using the
  2284.          * same test used in ap_die(), i.e. does it start with a ").
  2285.          * If it doesn't, we've got a recursive error, so find
  2286.          * the original error and output that as well.
  2287.          */
  2288.         if (custom_response[0] == '\"') {
  2289.             ap_bputs(custom_response + 1, fd);
  2290.             ap_kill_timeout(r);
  2291.             ap_finalize_request_protocol(r);
  2292.             return;
  2293.         }
  2294.         /*
  2295.          * Redirect failed, so get back the original error
  2296.          */
  2297.         while (r->prev && (r->prev->status != HTTP_OK))
  2298.             r = r->prev;
  2299.     }
  2300.     {
  2301.         char *title = status_lines[idx];
  2302.         char *h1;
  2303.         const char *error_notes;
  2304.  
  2305.         /* Accept a status_line set by a module, but only if it begins
  2306.          * with the 3 digit status code
  2307.          */
  2308.         if (r->status_line != NULL
  2309.             && strlen(r->status_line) > 4       /* long enough */
  2310.             && ap_isdigit(r->status_line[0])
  2311.             && ap_isdigit(r->status_line[1])
  2312.             && ap_isdigit(r->status_line[2])
  2313.             && ap_isspace(r->status_line[3])
  2314.             && ap_isalnum(r->status_line[4])) {
  2315.             title = r->status_line;
  2316.         }
  2317.  
  2318.         /* folks decided they didn't want the error code in the H1 text */
  2319.         h1 = &title[4];
  2320.  
  2321.         ap_bvputs(fd,
  2322.                   "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
  2323.                   "<HTML><HEAD>\n<TITLE>", title,
  2324.                   "</TITLE>\n</HEAD><BODY>\n<H1>", h1, "</H1>\n",
  2325.                   NULL);
  2326.  
  2327.     switch (status) {
  2328.     case HTTP_MOVED_PERMANENTLY:
  2329.     case HTTP_MOVED_TEMPORARILY:
  2330.     case HTTP_TEMPORARY_REDIRECT:
  2331.         ap_bvputs(fd, "The document has moved <A HREF=\"",
  2332.               ap_escape_html(r->pool, location), "\">here</A>.<P>\n",
  2333.               NULL);
  2334.         break;
  2335.     case HTTP_SEE_OTHER:
  2336.         ap_bvputs(fd, "The answer to your request is located <A HREF=\"",
  2337.               ap_escape_html(r->pool, location), "\">here</A>.<P>\n",
  2338.               NULL);
  2339.         break;
  2340.     case HTTP_USE_PROXY:
  2341.         ap_bvputs(fd, "This resource is only accessible "
  2342.               "through the proxy\n",
  2343.               ap_escape_html(r->pool, location),
  2344.               "<BR>\nYou will need to ",
  2345.               "configure your client to use that proxy.<P>\n", NULL);
  2346.         break;
  2347.     case HTTP_PROXY_AUTHENTICATION_REQUIRED:
  2348.     case AUTH_REQUIRED:
  2349.         ap_bputs("This server could not verify that you\n", fd);
  2350.         ap_bputs("are authorized to access the document you\n", fd);
  2351.         ap_bputs("requested.  Either you supplied the wrong\n", fd);
  2352.         ap_bputs("credentials (e.g., bad password), or your\n", fd);
  2353.         ap_bputs("browser doesn't understand how to supply\n", fd);
  2354.         ap_bputs("the credentials required.<P>\n", fd);
  2355.         break;
  2356.     case BAD_REQUEST:
  2357.         ap_bputs("Your browser sent a request that\n", fd);
  2358.         ap_bputs("this server could not understand.<P>\n", fd);
  2359.         if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
  2360.         ap_bvputs(fd, error_notes, "<P>\n", NULL);
  2361.         }
  2362.         break;
  2363.     case HTTP_FORBIDDEN:
  2364.         ap_bvputs(fd, "You don't have permission to access ",
  2365.               ap_escape_html(r->pool, r->uri),
  2366.               "\non this server.<P>\n", NULL);
  2367.         break;
  2368.     case NOT_FOUND:
  2369.         ap_bvputs(fd, "The requested URL ",
  2370.               ap_escape_html(r->pool, r->uri),
  2371.               " was not found on this server.<P>\n", NULL);
  2372.         break;
  2373.     case METHOD_NOT_ALLOWED:
  2374.         ap_bvputs(fd, "The requested method ", r->method,
  2375.               " is not allowed "
  2376.               "for the URL ", ap_escape_html(r->pool, r->uri),
  2377.               ".<P>\n", NULL);
  2378.         break;
  2379.     case NOT_ACCEPTABLE:
  2380.         ap_bvputs(fd,
  2381.               "An appropriate representation of the "
  2382.               "requested resource ",
  2383.               ap_escape_html(r->pool, r->uri),
  2384.               " could not be found on this server.<P>\n", NULL);
  2385.         /* fall through */
  2386.     case MULTIPLE_CHOICES:
  2387.         {
  2388.         const char *list;
  2389.         if ((list = ap_table_get(r->notes, "variant-list")))
  2390.             ap_bputs(list, fd);
  2391.         }
  2392.         break;
  2393.     case LENGTH_REQUIRED:
  2394.         ap_bvputs(fd, "A request of the requested method ", r->method,
  2395.               " requires a valid Content-length.<P>\n", NULL);
  2396.         if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
  2397.         ap_bvputs(fd, error_notes, "<P>\n", NULL);
  2398.         }
  2399.         break;
  2400.     case PRECONDITION_FAILED:
  2401.         ap_bvputs(fd, "The precondition on the request for the URL ",
  2402.               ap_escape_html(r->pool, r->uri),
  2403.               " evaluated to false.<P>\n", NULL);
  2404.         break;
  2405.     case HTTP_NOT_IMPLEMENTED:
  2406.         ap_bvputs(fd, ap_escape_html(r->pool, r->method), " to ",
  2407.               ap_escape_html(r->pool, r->uri),
  2408.               " not supported.<P>\n", NULL);
  2409.         if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
  2410.         ap_bvputs(fd, error_notes, "<P>\n", NULL);
  2411.         }
  2412.         break;
  2413.     case BAD_GATEWAY:
  2414.         ap_bputs("The proxy server received an invalid\015\012", fd);
  2415.         ap_bputs("response from an upstream server.<P>\015\012", fd);
  2416.         break;
  2417.     case VARIANT_ALSO_VARIES:
  2418.         ap_bvputs(fd, "A variant for the requested resource\n<PRE>\n",
  2419.               ap_escape_html(r->pool, r->uri),
  2420.               "\n</PRE>\nis itself a negotiable resource. "
  2421.               "This indicates a configuration error.<P>\n", NULL);
  2422.         break;
  2423.     case HTTP_REQUEST_TIME_OUT:
  2424.         ap_bputs("I'm tired of waiting for your request.\n", fd);
  2425.         break;
  2426.     case HTTP_GONE:
  2427.         ap_bvputs(fd, "The requested resource<BR>",
  2428.               ap_escape_html(r->pool, r->uri),
  2429.               "<BR>\nis no longer available on this server ",
  2430.               "and there is no forwarding address.\n",
  2431.               "Please remove all references to this resource.\n",
  2432.               NULL);
  2433.         break;
  2434.     case HTTP_REQUEST_ENTITY_TOO_LARGE:
  2435.         ap_bvputs(fd, "The requested resource<BR>",
  2436.               ap_escape_html(r->pool, r->uri), "<BR>\n",
  2437.               "does not allow request data with ", r->method,
  2438.               " requests, or the amount of data provided in\n",
  2439.               "the request exceeds the capacity limit.\n", NULL);
  2440.         break;
  2441.     case HTTP_REQUEST_URI_TOO_LARGE:
  2442.         ap_bputs("The requested URL's length exceeds the capacity\n"
  2443.                  "limit for this server.<P>\n", fd);
  2444.         if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
  2445.         ap_bvputs(fd, error_notes, "<P>\n", NULL);
  2446.         }
  2447.         break;
  2448.     case HTTP_UNSUPPORTED_MEDIA_TYPE:
  2449.         ap_bputs("The supplied request data is not in a format\n"
  2450.                  "acceptable for processing by this resource.\n", fd);
  2451.         break;
  2452.     case HTTP_RANGE_NOT_SATISFIABLE:
  2453.         ap_bputs("None of the range-specifier values in the Range\n"
  2454.                  "request-header field overlap the current extent\n"
  2455.                  "of the selected resource.\n", fd);
  2456.         break;
  2457.     case HTTP_EXPECTATION_FAILED:
  2458.         ap_bvputs(fd, "The expectation given in the Expect request-header"
  2459.                   "\nfield could not be met by this server.<P>\n"
  2460.                   "The client sent<PRE>\n    Expect: ",
  2461.                   ap_table_get(r->headers_in, "Expect"), "\n</PRE>\n"
  2462.                   "but we only allow the 100-continue expectation.\n",
  2463.                   NULL);
  2464.         break;
  2465.     case HTTP_UNPROCESSABLE_ENTITY:
  2466.         ap_bputs("The server understands the media type of the\n"
  2467.                  "request entity, but was unable to process the\n"
  2468.                  "contained instructions.\n", fd);
  2469.         break;
  2470.     case HTTP_LOCKED:
  2471.         ap_bputs("The requested resource is currently locked.\n"
  2472.                  "The lock must be released or proper identification\n"
  2473.                  "given before the method can be applied.\n", fd);
  2474.         break;
  2475.     case HTTP_FAILED_DEPENDENCY:
  2476.         ap_bputs("The method could not be performed on the resource\n"
  2477.                  "because the requested action depended on another\n"
  2478.                  "action and that other action failed.\n", fd);
  2479.         break;
  2480.     case HTTP_INSUFFICIENT_STORAGE:
  2481.         ap_bputs("The method could not be performed on the resource\n"
  2482.                  "because the server is unable to store the\n"
  2483.                  "representation needed to successfully complete the\n"
  2484.                  "request.  There is insufficient free space left in\n"
  2485.                  "your storage allocation.\n", fd);
  2486.         break;
  2487.     case HTTP_SERVICE_UNAVAILABLE:
  2488.         ap_bputs("The server is temporarily unable to service your\n"
  2489.                  "request due to maintenance downtime or capacity\n"
  2490.                  "problems. Please try again later.\n", fd);
  2491.         break;
  2492.     case HTTP_GATEWAY_TIME_OUT:
  2493.         ap_bputs("The proxy server did not receive a timely response\n"
  2494.                  "from the upstream server.\n", fd);
  2495.         break;
  2496.     case HTTP_NOT_EXTENDED:
  2497.         ap_bputs("A mandatory extension policy in the request is not\n"
  2498.                      "accepted by the server for this resource.\n", fd);
  2499.         break;
  2500.     default:            /* HTTP_INTERNAL_SERVER_ERROR */
  2501.         ap_bvputs(fd, "The server encountered an internal error or\n"
  2502.                  "misconfiguration and was unable to complete\n"
  2503.                  "your request.<P>\n"
  2504.                  "Please contact the server administrator,\n ",
  2505.                  ap_escape_html(r->pool, r->server->server_admin),
  2506.                  " and inform them of the time the error occurred,\n"
  2507.                  "and anything you might have done that may have\n"
  2508.                  "caused the error.<P>\n"
  2509.              "More information about this error may be available\n"
  2510.              "in the server error log.<P>\n", NULL);
  2511.      /*
  2512.       * It would be nice to give the user the information they need to
  2513.       * fix the problem directly since many users don't have access to
  2514.       * the error_log (think University sites) even though they can easily
  2515.       * get this error by misconfiguring an htaccess file.  However, the
  2516.       * error notes tend to include the real file pathname in this case,
  2517.       * which some people consider to be a breach of privacy.  Until we
  2518.       * can figure out a way to remove the pathname, leave this commented.
  2519.       *
  2520.       * if ((error_notes = ap_table_get(r->notes, "error-notes")) != NULL) {
  2521.       *     ap_bvputs(fd, error_notes, "<P>\n", NULL);
  2522.       * }
  2523.       */
  2524.         break;
  2525.     }
  2526.  
  2527.         if (recursive_error) {
  2528.             ap_bvputs(fd, "<P>Additionally, a ",
  2529.                       status_lines[ap_index_of_response(recursive_error)],
  2530.                       "\nerror was encountered while trying to use an "
  2531.                       "ErrorDocument to handle the request.\n", NULL);
  2532.         }
  2533.         ap_bputs(ap_psignature("<HR>\n", r), fd);
  2534.         ap_bputs("</BODY></HTML>\n", fd);
  2535.     }
  2536.     ap_kill_timeout(r);
  2537.     ap_finalize_request_protocol(r);
  2538. }
  2539.