http_protocol.c revision 48d7c43629323c8d5ee9f7bd0d194de0a376b391
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* ====================================================================
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The Apache Software License, Version 1.1
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Copyright (c) 2000 The Apache Software Foundation. All rights
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Redistribution and use in source and binary forms, with or without
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * modification, are permitted provided that the following conditions
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 1. Redistributions of source code must retain the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 2. Redistributions in binary form must reproduce the above copyright
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * notice, this list of conditions and the following disclaimer in
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the documentation and/or other materials provided with the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * distribution.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 3. The end-user documentation included with the redistribution,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if any, must include the following acknowledgment:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * "This product includes software developed by the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Apache Software Foundation (http://www.apache.org/)."
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Alternately, this acknowledgment may appear in the software itself,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * if and wherever such third-party acknowledgments normally appear.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 4. The names "Apache" and "Apache Software Foundation" must
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * not be used to endorse or promote products derived from this
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * software without prior written permission. For written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission, please contact apache@apache.org.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * 5. Products derived from this software may not be called "Apache",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * nor may "Apache" appear in their name, without prior written
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * permission of the Apache Software Foundation.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * SUCH DAMAGE.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * ====================================================================
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This software consists of voluntary contributions made by many
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * individuals on behalf of the Apache Software Foundation. For more
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * information on the Apache Software Foundation, please see
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Portions of this software are based upon public domain software
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * originally written at the National Center for Supercomputing Applications,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * University of Illinois, Urbana-Champaign.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * http_protocol.c --- routines which directly communicate with the client.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Code originally by Rob McCool; much redone by Robert S. Thau
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the Apache Software Foundation.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "http_log.h" /* For errors detected in basic auth common
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * support code... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#include "util_date.h" /* For parseHTTPdate and BAD_DATE */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes do { if (r->sent_bodyct) \
f8fc4173f3b9715e5945b668ba511b77573dc1d1minfrin ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
f8fc4173f3b9715e5945b668ba511b77573dc1d1minfrin } while (0)
f8fc4173f3b9715e5945b668ba511b77573dc1d1minfrin * Builds the content-type that should be sent to the client from the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * content-type specified. The following rules are followed:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - if type is NULL, type is set to ap_default_type(r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - if charset adding is disabled, stop processing and return type.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - then, if there are no parameters on type, add the default charset
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - return type
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char *make_content_type(request_rec *r, const char *type) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes core_dir_config *conf = (core_dir_config *)ap_get_module_config(
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (conf->add_default_charset != ADD_DEFAULT_CHARSET_ON) return type;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* already has parameter, do nothing */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* XXX we don't check the validity */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* see if it makes sense to add the charset. At present,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * we only add it if the Content-type is one of needcset[]
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int parse_byterange(char *range, long clength, long *start, long *end)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* In the form "-5" */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else /* "5-" */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int internal_byterange(int, long *, request_rec *, const char **,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Check for Range request-header (HTTP/1.1) or Request-Range for
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * backwards-compatibility with second-draft Luotonen/Franks
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * byte-ranges (e.g. Netscape Navigator 2-3).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * We support this form, with Request-Range, and (farther down) we
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * send multipart/x-byteranges instead of multipart/byteranges for
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Request-Range based requests to work around a bug in Netscape
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Navigator 2-3 and MSIE 3.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!(range = ap_table_get(r->headers_in, "Range")))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes range = ap_table_get(r->headers_in, "Request-Range");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Check the If-Range header for Etag or Date.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Note that this check will return false (as required) if either
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * of the two etags are weak.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((if_range = ap_table_get(r->headers_in, "If-Range"))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!(match = ap_table_get(r->headers_out, "Etag")) ||
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes else if (!(match = ap_table_get(r->headers_out, "Last-Modified")) ||
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* A single range */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!parse_byterange(ap_pstrdup(r->pool, range + 6), r->clength,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_psprintf(r->pool, "%ld", range_end - range_start + 1));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* a multiple range */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *r_range = ap_pstrdup(r->pool, range + 6);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(int) ap_each_byterange(request_rec *r, ap_off_t *offset,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return internal_byterange(1, NULL, r, &r->range, offset, length);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* If this function is called with realreq=1, it will spit out
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the correct headers for a byterange chunk, and set offset and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * length to the positions they should be.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If it is called with realreq=0, it will add to tlength the length
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * it *would* have used with realreq=1.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Either case will return 1 if it should be called again, and 0
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * when done.
e18ba90a1e610b43062e90cfa8bf0c1edcad7a49bnicholesstatic int internal_byterange(int realreq, long *tlength, request_rec *r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* determine current translation handle, set to the one for
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * protocol strings, and reset to original setting before
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_PUSH_OUTPUTCONVERSION_STATE(r->connection->client,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /*APACHE_XLATE*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_rvputs(r, CRLF "--", r->boundary, "--" CRLF, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_POP_OUTPUTCONVERSION_STATE(r->connection->client);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /*APACHE_XLATE*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!parse_byterange(range, r->clength, &range_start, &range_end))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_POP_OUTPUTCONVERSION_STATE(r->connection->client);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /*APACHE_XLATE*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Skip this one */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return internal_byterange(realreq, tlength, r, r_range, offset,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *ct = make_content_type(r, r->content_type);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_rvputs(r, CRLF "--", r->boundary, CRLF "Content-type: ",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_POP_OUTPUTCONVERSION_STATE(r->connection->client);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /*APACHE_XLATE*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_get(r->headers_out, "Connection"), "close");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *conn = ap_table_get(r->headers_in, "Connection");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Translation is not single-byte-only, so we don't know the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * content length. Zap the Content-Length header before the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * following logic, as the absence of the Content-Length header
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * may affect the decision on chunked encoding.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /* APACHE_XLATE */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* The following convoluted conditional determines whether or not
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the current connection should remain persistent after this response
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (a.k.a. HTTP Keep-Alive) and whether or not the output message
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * body should use the HTTP/1.1 chunked transfer-coding. In English,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * IF we have not marked this connection as errored;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the response body has a defined length due to the status code
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * being 304 or 204, the request method being HEAD, already
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * having defined Content-Length or Transfer-Encoding: chunked, or
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the request version being HTTP/1.1 and thus capable of being set
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * as chunked [we know the (r->chunked = 1) side-effect is ugly];
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the server configuration enables keep-alive;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the server configuration has a reasonable inter-request timeout;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and there is no maximum # requests or the max hasn't been reached;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the response status does not require a close;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the response generator has not already indicated close;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the client did not request non-persistence (Connection: close);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and we haven't been configured to ignore the buggy twit
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * or they're a buggy twit coming through a HTTP/1.1 proxy
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and the client is requesting an HTTP/1.0-style keep-alive
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * THEN we can be persistent, which requires more headers be output.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Note that the condition evaluation order is extremely important.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_get(r->headers_out, "Transfer-Encoding"),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "chunked") ||
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (r->chunked = 1))) && /* THIS CODE IS CORRECT, see comment above. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (r->server->keep_alive_max > r->connection->keepalives)) &&
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (!ap_table_get(r->subprocess_env, "nokeepalive") ||
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) ||
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int left = r->server->keep_alive_max - r->connection->keepalives;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If they sent a Keep-Alive token, send one back */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_mergen(r->headers_out, "Connection", "Keep-Alive");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Otherwise, we need to indicate that we will be closing this
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * connection immediately after the current response.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * We only really need to send "close" to HTTP/1.1 clients, but we
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * always send it anyway, because a broken proxy may identify itself
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * to a HTTP/1.1 client. Better safe than sorry.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_mergen(r->headers_out, "Connection", "close");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Return the latest rational time from a request/mtime (modification time)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * pair. We return the mtime unless it's in the future, in which case we
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * return the current time. We use the request time as a reference in order
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * to limit the number of calls to time(). We don't check for futurosity
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * unless the mtime is at least as new as the reference.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(ap_time_t) ap_rationalize_mtime(request_rec *r, ap_time_t mtime)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* For all static responses, it's almost certain that the file was
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * last modified before the beginning of the request. So there's
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * no reason to call time(NULL) again. But if the response has been
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * created on demand, then it might be newer than the time the request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * started. In this event we really have to call time(NULL) again
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * so that we can give the clients the most accurate Last-Modified. If we
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * were given a time in the future, we return the current time - the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Last-Modified can't be in the future.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes now = (mtime < r->request_time) ? r->request_time : ap_now();
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(int) ap_meets_conditions(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *etag = ap_table_get(r->headers_out, "ETag");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Check for conditional requests --- note that we only want to do
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * this if we are successful so far and we are not processing a
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * subrequest or an ErrorDocument.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The order of the checks is important, since ETag checks are supposed
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * to be more accurate than checks relative to the modification time.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * However, not all documents are guaranteed to *have* ETags, and some
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * might have Last-Modified values w/o ETags, so this gets a little
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * complicated.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* XXX: we should define a "time unset" constant */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If an If-Match request-header field was given
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * AND the field value is not "*" (meaning match anything)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * AND if our strong ETag does not match any entity tag in that field,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * respond with a status of 412 (Precondition Failed).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((if_match = ap_table_get(r->headers_in, "If-Match")) != NULL) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Else if a valid If-Unmodified-Since request-header field was given
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * AND the requested resource has been modified since the time
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * specified in this field, then the server MUST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * respond with a status of 412 (Precondition Failed).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if_unmodified = ap_table_get(r->headers_in, "If-Unmodified-Since");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If an If-None-Match request-header field was given
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * AND the field value is "*" (meaning match anything)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * OR our ETag matches any of the entity tags in that field, fail.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If the request method was GET or HEAD, failure means the server
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * SHOULD respond with a 304 (Not Modified) response.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * For all other request methods, failure means the server MUST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * respond with a status of 412 (Precondition Failed).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * GET or HEAD allow weak etag comparison, all other methods require
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * strong comparison. We can only use weak if it's not a range request.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if_nonematch = ap_table_get(r->headers_in, "If-None-Match");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_find_list_item(r->pool, if_nonematch, etag))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Else if a valid If-Modified-Since request-header field was given
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * AND it is a GET or HEAD request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * AND the requested resource has not been modified since the time
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * specified in this field, then the server MUST
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * respond with a status of 304 (Not Modified).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * A date later than the server's current request time is invalid.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_get(r->headers_in, "If-Modified-Since")) != NULL)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_time_t ims = ap_parseHTTPdate(if_modified_since);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Construct an entity tag (ETag) from resource information. If it's a real
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * file, build in some of the file characteristics. If the modification time
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * is newer than (request-time minus 1 second), mark the ETag as weak - it
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * could be modified again in as short an interval. We rationalize the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * modification time we're given to keep it from being in the future.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Make an ETag header out of various pieces of information. We use
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the last-modified date and, if we have a real file, the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * length and inode number - note that this doesn't have to match
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the content-length (i.e. includes), it just has to be unique
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * for the file.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If the request was made within a second of the last-modified date,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * we send a weak tag instead of a strong one, since it could
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * be modified again later in the second, and the validation
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * would be incorrect.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes weak = ((r->request_time - r->mtime > AP_USEC_PER_SEC) && !force_weak) ? "" : "W/";
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (unsigned long) r->mtime);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes (unsigned long) r->mtime);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* If we have a variant list validator (vlv) due to the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * response being negotiated, then we create a structured
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * entity tag which merges the variant etag with the variant
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * list validator (vlv). This merging makes revalidation
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * somewhat safer, ensures that caches which can deal with
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Vary will (eventually) be updated if the set of variants is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * changed, and is also a protocol requirement for transparent
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * content negotiation.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if the variant list validator is weak, we make the whole
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * structured etag weak. If we would not, then clients could
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * have problems merging range responses if we have different
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * variants with the same non-globally-unique strong etag.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* merge variant_etag and vlv into a structured etag */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes etag = ap_pstrcat(r->pool, variant_etag, ";", vlv, NULL);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This function sets the Last-Modified output header field to the value
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * of the mtime field in the request structure - rationalized to keep it from
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * being in the future.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(void) ap_set_last_modified(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_time_t mod_time = ap_rationalize_mtime(r, r->mtime);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char *datestr = ap_palloc(r->pool, AP_RFC822_DATE_LEN);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_setn(r->headers_out, "Last-Modified", datestr);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Get the method number associated with the given string, assumed to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * contain an HTTP method. Returns M_INVALID if not recognized.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This is the first step toward placing method names in a configurable
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * list. Hopefully it (and other routines) can eventually be moved to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * something like a mod_http_methods.c, complete with config stuff.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(int) ap_method_number_of(const char *method)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes return M_GET; /* see header_only in request_rec */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* Get a line of protocol input, including any continuation lines
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * caused by MIME folding (or broken clients) if fold != 0, and place it
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * in the buffer s, of size n bytes, without the ending newline.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Returns -1 on error, or the length of s.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Note: Because bgets uses 1 char for newline and 1 char for NUL,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the most we can get is (n - 2) actual characters if it
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * was ended by a newline, or (n - 1) characters if the line
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * length exceeded (n - 1). So, if the result == (n - 1),
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * then the actual input line exceeded the buffer length,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * and it would be a good idea for the caller to puke 400 or 414.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic int getline(char *s, int n, BUFF *in, int fold)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* When getline() is called, the HTTP protocol is in a state
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * where we MUST be reading "plain text" protocol stuff,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (Request line, MIME headers, Chunk sizes) regardless of
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the MIME type and conversion setting of the document itself.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Save the current setting of the translation handle for
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * uploads, then temporarily set it to the one used for headers
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * (and restore it before returning).
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes AP_PUSH_INPUTCONVERSION_STATE(in, ap_hdrs_from_ascii);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /*APACHE_XLATE*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* retval == -1 if error, 0 if EOF */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes total = ((retval < 0) && (total == 0)) ? -1 : total;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* retval is the number of characters read, not including NUL */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes n -= retval; /* Keep track of how much of s is full */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (*pos == '\n') { /* Did we get a full line of input? */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Trim any extra trailing spaces or tabs except for the first
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * space or tab at the beginning of a blank string. This makes
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * it much easier to check field values for exact matches, and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * saves memory as well. Terminate string at end of line.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while (pos > (s + 1) && (*(pos - 1) == ' ' || *(pos - 1) == '\t')) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes --total; /* but not one at the beginning of line */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes break; /* if not, input line exceeded buffer size */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Continue appending if line folding is desired and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the last line was not empty and we have room in the buffer and
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the next line begins with a continuation character.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* restore translation handle */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /*APACHE_XLATE*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* parse_uri: break apart the uri
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Side Effects:
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - sets r->args to rest after '?' (or NULL if no '?')
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - sets r->uri to request uri (without r->args part)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * - sets r->hostname (if not set already) from request (scheme://host:port)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesCORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes status = ap_parse_hostinfo_components(r->pool, uri, &r->parsed_uri);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Simple syntax Errors in URLs are trapped by parse_uri_components(). */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes status = ap_parse_uri_components(r->pool, uri, &r->parsed_uri);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* if it has a scheme we may need to do absoluteURI vhost stuff */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Handle path translations for OS/2 and plug security hole.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * This will prevent "http://www.wherever.com/..\..\/" from
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * returning a directory for the root drive.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#endif /* OS2 || WIN32 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *ll = l;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *uri;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Read past empty lines until we get a real request line,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a read error, the connection closes (EOF), or we timeout.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * We skip empty lines because browsers have to tack a CRLF on to the end
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * of POSTs to support old CERN webservers. But note that we may not
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * have flushed any previous response completely to the client yet.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * We delay the flush as long as possible so that we can improve
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * performance for clients that are pipelining requests. If a request
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * is pipelined then we won't block during the (implicit) read() below.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * If the requests aren't pipelined, then the client is still waiting
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * for the final buffer flush from us, and we will block in the implicit
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * have to block during a read.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while ((len = getline(l, sizeof(l), conn->client, 0)) <= 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((len < 0) || ap_bgetflag(conn->client, B_EOF)) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* this is a hack to make sure that request time is set,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * it's not perfect, but it's better than nothing
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* we've probably got something to do, ignore graceful restart requests */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* XXX - sigwait doesn't work if the signal has been SIG_IGNed (under
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * linux 2.0 w/ glibc 2.0, anyway), and this step isn't necessary when
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * we're running a sigwait thread anyway. If/when unthreaded mode is
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * put back in, we should make sure to ignore this signal iff a sigwait
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * thread isn't used. - mvsk
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes#ifdef SIGWINCH
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_signal(SIGWINCH, SIG_IGN);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_update_connection_status(conn->id, "Method", r->method);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Provide quick information about the request method as soon as known */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->method_number = ap_method_number_of(r->method);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (r->method_number == M_GET && r->method[0] == 'H') {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* getline returns (size of max buffer - 1) if it fills up the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * buffer before finding the end-of-line. This is only going to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * happen if it exceeds the configured limit for a request-line.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->protocol = ap_pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_update_connection_status(conn->id, "Protocol", r->protocol);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes && minor < HTTP_VERSION(1,0)) /* don't allow HTTP/0.1000 */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes char field[DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2]; /* getline's two extra */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes unsigned int fields_read = 0;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* We'll use ap_overlap_tables later to merge these into r->headers_in. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Read header lines until we get the empty separator line, a read error,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the connection closes (EOF), reach the server limit, or we timeout.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes while ((len = getline(field, sizeof(field), c->client, 1)) > 0) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "The number of request header fields exceeds "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "this server's limit.<P>\n");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* getline returns (size of max buffer - 1) if it fills up the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * buffer before finding the end-of-line. This is only going to
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * happen if it exceeds the configured limit for a field size.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Size of a request header field exceeds server limit.<P>\n"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<PRE>\n", ap_escape_html(r->pool, field), "</PRE>\n", NULL));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!(value = strchr(copy, ':'))) { /* Find the colon separator */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->status = HTTP_BAD_REQUEST; /* or abort the bad request */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "Request header field is missing colon separator.<P>\n"
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "<PRE>\n", ap_escape_html(r->pool, copy), "</PRE>\n", NULL));
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_overlap_tables(r->headers_in, tmp_headers, AP_OVERLAP_TABLES_MERGE);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *expect;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->request_config = ap_create_request_config(r->pool);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->rrx = ap_pcalloc(p, sizeof(struct ap_rr_xlate));
5aa455d45abacfa675c88d4ff53fbe97c44ce545bnicholes#endif /*APACHE_XLATE*/
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Get the request... */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "request failed: URI too long");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "request failed: error reading the headers");
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Client asked for headers only with HTTP/0.9, which doesn't send
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * headers! Have to dink things just to make sure the error message
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * comes through...
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "client sent invalid HTTP/0.9 request: HEAD %s",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* update what we think the virtual host is based on the headers we've
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * now read. may update status.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* we may have switched to another server */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes conn->keptalive = 0; /* We now have a request to play with */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) ||
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Client sent us an HTTP/1.1 or later request without telling us the
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * hostname, either with a full URL or a Host: header. We therefore
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * need to (as per the 1.1 spec) send an error. As a special case,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a Host: header, and the server MUST respond with 400 if it doesn't.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "client sent HTTP/1.1 request without hostname "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "(see RFC2068 section 9, and 14.23): %s", r->uri);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (((expect = ap_table_get(r->headers_in, "Expect")) != NULL) &&
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The Expect header field was added to HTTP/1.1 after RFC 2068
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * as a means to signal when a 100 response is desired and,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * unfortunately, to signal a poor man's mandatory extension that
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * the server must understand or return 417 Expectation Failed.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "client sent an unrecognized expectation value of "
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if ((access_status = ap_run_post_read_request(r))) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * A couple of other functions which initialize some of the fields of
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * a request structure, as appropriate for adjuncts of one kind or another
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * to a request in progress. Best here, rather than elsewhere, since
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * *someone* has to set the protocol-specific fields...
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesvoid ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rnew->the_request = r->the_request; /* Keep original request-line */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rnew->assbackwards = 1; /* Don't send headers from this. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rnew->no_local_copy = 1; /* Don't try to send USE_LOCAL_COPY for a
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * fragment. */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rnew->subprocess_env = ap_copy_table(rnew->pool, r->subprocess_env);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes rnew->err_headers_out = ap_make_table(rnew->pool, 5);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesvoid ap_finalize_sub_req_protocol(request_rec *sub)
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * Support for the Basic authentication protocol, and a bit for Digest.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(void) ap_note_basic_auth_failure(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_pstrcat(r->pool, "Basic realm=\"", ap_auth_name(r), "\"",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(void) ap_note_digest_auth_failure(request_rec *r)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_psprintf(r->pool, "Digest realm=\"%s\", nonce=\"%lu\"",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesAPI_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw)
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes const char *auth_line = ap_table_get(r->headers_in,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes : "Authorization");
3a11074e78d5961088e8f5520ba3cec163faed9cjorton const char *t;
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (!(t = ap_auth_type(r)) || strcasecmp(t, "Basic"))
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Client tried to authenticate using wrong auth scheme */
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "client used wrong authentication scheme: %s", r->uri);
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* APACHE_XLATE Issue's here ?!? Compare with 32/9 instead
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * as we are operating on an octed stream ?
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes /* Note that this allocation has to be made from r->connection->pool
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * because it has the lifetime of the connection. The other allocations
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * are temporary and can be tossed away any time.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* New Apache routine to map status codes into array indicies
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * e.g. 100 -> 0, 101 -> 1, 200 -> 2 ...
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * The number of status lines must equal the value of RESPONSE_CODES (httpd.h)
d266c3777146d36a4c23c17aad6f153aebea1bf4jorton * and must be listed in order.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes/* The second const triggers an assembler bug on UTS 2.1.
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes * Another workaround is to move some code out of this file into another,
af6d8b02b2fd4ea9a0f6bfb95940d6075030e9a7minfrin * but this is easier. Dave Dykstra, 3/31/99
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholesstatic const char * const status_lines[RESPONSE_CODES] =
af6d8b02b2fd4ea9a0f6bfb95940d6075030e9a7minfrin "100 Continue",
af6d8b02b2fd4ea9a0f6bfb95940d6075030e9a7minfrin "101 Switching Protocols",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "102 Processing",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "201 Created",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "202 Accepted",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "203 Non-Authoritative Information",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "204 No Content",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "205 Reset Content",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "206 Partial Content",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "207 Multi-Status",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "300 Multiple Choices",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "301 Moved Permanently",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "302 Found",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "303 See Other",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "304 Not Modified",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "305 Use Proxy",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "306 unused",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "307 Temporary Redirect",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "400 Bad Request",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "401 Authorization Required",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "402 Payment Required",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "403 Forbidden",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "404 Not Found",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "405 Method Not Allowed",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "406 Not Acceptable",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "407 Proxy Authentication Required",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "408 Request Time-out",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "409 Conflict",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "411 Length Required",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "412 Precondition Failed",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "413 Request Entity Too Large",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "414 Request-URI Too Large",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "415 Unsupported Media Type",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "416 Requested Range Not Satisfiable",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "417 Expectation Failed",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "418 unused",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "419 unused",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "420 unused",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "421 unused",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "422 Unprocessable Entity",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "423 Locked",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "424 Failed Dependency",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "500 Internal Server Error",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "501 Method Not Implemented",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "502 Bad Gateway",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "503 Service Temporarily Unavailable",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "504 Gateway Time-out",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "505 HTTP Version Not Supported",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "506 Variant Also Negotiates",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "507 Insufficient Storage",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "508 unused",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "509 unused",
d5b12fe8ae917e654a33247fd4e59dc9e75170aebnicholes "510 Not Extended"
int i, pos;
return LEVEL_500;
return pos;
* In other words, don't change this one without checking table_do in alloc.c.
char *protocol;
if (r->assbackwards)
if (!r->status_line)
if (r->proxyreq
#ifdef APACHE_XLATE
#ifdef APACHE_XLATE
long int bs;
NULL);
int rv;
while (r->prev)
r = r->prev;
return rv;
ap_table_do((int (*) (void *, const char *, const char *))
return OK;
const long int zero = 0L;
if (r->assbackwards)
return DECLINED;
ap_set_keepalive(r);
terminate_header(r);
return OK;
* Here we try to be compatible with clients that want multipart/x-byteranges
* instead of multipart/byteranges (also see above), as per HTTP/1.1. We
const char *ua;
* consisting of comma/space-separated tokens.
char *start;
char **strpp;
start = e;
++i, ++strpp) {
const long int zero = 0L;
if (r->assbackwards) {
if (!r->main)
#ifdef CHARSET_EBCDIC
ap_checkconv(r);
r->headers_out);
fixup_vary(r);
#ifdef APACHE_XLATE
ap_set_keepalive(r);
if (r->chunked) {
r->content_type));
if (r->content_encoding)
else if (r->content_language)
terminate_header(r);
if (r->chunked)
#ifdef APACHE_XLATE
#ifdef APACHE_XLATE
r->chunked = 0;
#ifdef APACHE_XLATE
unsigned long max_body;
r->read_chunked = 0;
r->remaining = 0;
if (tenc) {
return HTTP_NOT_IMPLEMENTED;
else if (lenp) {
++pos;
return HTTP_BAD_REQUEST;
return HTTP_REQUEST_ENTITY_TOO_LARGE;
return HTTP_REQUEST_ENTITY_TOO_LARGE;
#ifdef CHARSET_EBCDIC
if (!convert_in) {
return OK;
NULL);
ap_rflush(r);
static long get_chunk_size(char *b)
long chunksize = 0;
while (ap_isxdigit(*b)) {
int xvalue = 0;
return chunksize;
long chunk_start = 0;
unsigned long max_body;
return len_read;
if (bufsiz <= 0)
max_body);
get_mime_headers(r);
chunk_start = 0;
if (len_read < 0) {
return chunk_start;
#ifdef APACHE_XLATE
#ifdef APACHE_XLATE
if (c != LF) {
int rv;
return rv;
if (r->expecting_100) {
return OK;
if (rv < 0)
return HTTP_BAD_REQUEST;
return OK;
#ifdef HAVE_SENDFILE
if (!r->chunked) {
&len,
return len;
long total_bytes_sent = 0;
ap_ssize_t w;
ap_ssize_t n;
if (length == 0)
o = IOBUFSIZE;
total_bytes_sent += w;
SET_BYTES_SENT(r);
return total_bytes_sent;
long total_bytes_sent = 0;
long zero_timeout = 0;
ap_ssize_t w;
ap_ssize_t n;
if (length == 0) {
bytes_read = n;
total_bytes_sent += w;
if (bytes_read == 0) {
(void) ap_rflush(r);
(void) ap_rflush(r);
goto got_read;
SET_BYTES_SENT(r);
return total_bytes_sent;
#ifdef USE_MMAP_FILES
#ifndef MMAP_SEGMENT_SIZE
ap_ssize_t w;
char *addr;
if (length == 0)
n = MMAP_SEGMENT_SIZE;
total_bytes_sent += w;
offset += w;
SET_BYTES_SENT(r);
return total_bytes_sent;
return EOF;
return EOF;
SET_BYTES_SENT(r);
int rcode;
return EOF;
if (rcode < 0) {
return EOF;
SET_BYTES_SENT(r);
return rcode;
ap_ssize_t n;
return EOF;
return EOF;
SET_BYTES_SENT(r);
SET_BYTES_SENT(r);
SET_BYTES_SENT(r);
ap_ssize_t i;
return EOF;
if (x == NULL)
j = strlen(x);
return EOF;
SET_BYTES_SENT(r);
return EOF;
char *custom_response;
r->headers_out);
ap_set_keepalive(r);
(void *) r, r->headers_out,
NULL);
terminate_header(r);
if (!r->assbackwards) {
r->clength = 0;
if (r->header_only) {
ap_rflush(r);
#ifdef APACHE_XLATE
ap_rflush(r);
r = r->prev;
const char *h1;
const char *error_notes;
ap_rvputs(r,
NULL);
switch (status) {
case HTTP_MOVED_PERMANENTLY:
case HTTP_MOVED_TEMPORARILY:
case HTTP_TEMPORARY_REDIRECT:
NULL);
case HTTP_SEE_OTHER:
NULL);
case HTTP_USE_PROXY:
case AUTH_REQUIRED:
case BAD_REQUEST:
case HTTP_FORBIDDEN:
case NOT_FOUND:
case METHOD_NOT_ALLOWED:
case NOT_ACCEPTABLE:
ap_rvputs(r,
case MULTIPLE_CHOICES:
const char *list;
case LENGTH_REQUIRED:
case PRECONDITION_FAILED:
case HTTP_NOT_IMPLEMENTED:
case BAD_GATEWAY:
case VARIANT_ALSO_VARIES:
case HTTP_REQUEST_TIME_OUT:
case HTTP_GONE:
NULL);
case HTTP_EXPECTATION_FAILED:
NULL);
case HTTP_LOCKED:
case HTTP_FAILED_DEPENDENCY:
case HTTP_SERVICE_UNAVAILABLE:
case HTTP_GATEWAY_TIME_OUT:
case HTTP_NOT_EXTENDED:
if (recursive_error) {
ap_rflush(r);
(const request_rec *r),(r),0)