http_protocol.c revision ebc2d0583ce25c4d7894da8392ca57ccc608ce49
08cb74ca432a8c24e39f17dedce527e6a47b8001jerenkrantz/* ====================================================================
08cb74ca432a8c24e39f17dedce527e6a47b8001jerenkrantz * Copyright (c) 1995-1999 The Apache Group. All rights reserved.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * Redistribution and use in source and binary forms, with or without
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * modification, are permitted provided that the following conditions
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * are met:
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * 1. Redistributions of source code must retain the above copyright
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * notice, this list of conditions and the following disclaimer.
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * 2. Redistributions in binary form must reproduce the above copyright
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * notice, this list of conditions and the following disclaimer in
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * the documentation and/or other materials provided with the
ce9621257ef9e54c1bbe5ad8a5f445a1f211c2dcnd * distribution.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * 3. All advertising materials mentioning features or use of this
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * software must display the following acknowledgment:
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * "This product includes software developed by the Apache Group
785be1b6298010956622771c870ab3cd8ca57a2faaron * for use in the Apache HTTP server project (http://www.apache.org/)."
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * 4. The names "Apache Server" and "Apache Group" must not be used to
1b21d7b3d97def358b2e923655edeb16613a1c31gstein * endorse or promote products derived from this software without
1b21d7b3d97def358b2e923655edeb16613a1c31gstein * prior written permission. For written permission, please contact
1b21d7b3d97def358b2e923655edeb16613a1c31gstein * apache@apache.org.
1b21d7b3d97def358b2e923655edeb16613a1c31gstein * 5. Products derived from this software may not be called "Apache"
1b21d7b3d97def358b2e923655edeb16613a1c31gstein * nor may "Apache" appear in their names without prior written
1b21d7b3d97def358b2e923655edeb16613a1c31gstein * permission of the Apache Group.
2d71630471d1c23f0137309e3c3957c633ecbfd6rbb * 6. Redistributions of any form whatsoever must retain the following
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * acknowledgment:
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * "This product includes software developed by the Apache Group
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * for use in the Apache HTTP server project (http://www.apache.org/)."
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
51af95bb51b5084e883bad250b2afa2838e9ceebfielding * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
d4f1d9c1ff112a8ab9bee31f196973761329b236rbb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
7fae9cc4639013f3c04c085547256c68814aee8ftrawick * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
7fae9cc4639013f3c04c085547256c68814aee8ftrawick * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
7fae9cc4639013f3c04c085547256c68814aee8ftrawick * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
7fae9cc4639013f3c04c085547256c68814aee8ftrawick * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * OF THE POSSIBILITY OF SUCH DAMAGE.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * ====================================================================
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * This software consists of voluntary contributions made by many
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * individuals on behalf of the Apache Group and was originally based
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * on public domain software written at the National Center for
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Supercomputing Applications, University of Illinois, Urbana-Champaign.
785be1b6298010956622771c870ab3cd8ca57a2faaron * For more information on the Apache Group and the Apache HTTP server
785be1b6298010956622771c870ab3cd8ca57a2faaron * project, please see <http://www.apache.org/>.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * http_protocol.c --- routines which directly communicate with the client.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Code originally by Rob McCool; much redone by Robert S. Thau
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * and the Apache Group.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding#include "http_log.h" /* For errors detected in basic auth common
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * support code... */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding#include "util_date.h" /* For parseHTTPdate and BAD_DATE */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding do { if (r->sent_bodyct) \
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_bgetopt (r->connection->client, BO_BYTECT, &r->bytes_sent); \
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding } while (0)
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fieldingstatic int parse_byterange(char *range, long clength, long *start, long *end)
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* In the form "-5" */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding else /* "5-" */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fieldingstatic int internal_byterange(int, long *, request_rec *, const char **,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* Check for Range request-header (HTTP/1.1) or Request-Range for
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * backwards-compatibility with second-draft Luotonen/Franks
785be1b6298010956622771c870ab3cd8ca57a2faaron * byte-ranges (e.g. Netscape Navigator 2-3).
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * We support this form, with Request-Range, and (farther down) we
8a261a9f7d18d1e862d63f68e93f288d3e1f0d94trawick * send multipart/x-byteranges instead of multipart/byteranges for
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Request-Range based requests to work around a bug in Netscape
6b38fca3ec543a0f72efd5683e91a0b30fc752d1trawick * Navigator 2-3 and MSIE 3.
6b38fca3ec543a0f72efd5683e91a0b30fc752d1trawick if (!(range = ap_table_get(r->headers_in, "Range")))
8a261a9f7d18d1e862d63f68e93f288d3e1f0d94trawick range = ap_table_get(r->headers_in, "Request-Range");
6b38fca3ec543a0f72efd5683e91a0b30fc752d1trawick /* Check the If-Range header for Etag or Date.
e160b861b50a3a8dcc013b8cd3ef849fe777e52fgregames * Note that this check will return false (as required) if either
e160b861b50a3a8dcc013b8cd3ef849fe777e52fgregames * of the two etags are weak.
e160b861b50a3a8dcc013b8cd3ef849fe777e52fgregames if ((if_range = ap_table_get(r->headers_in, "If-Range"))) {
e160b861b50a3a8dcc013b8cd3ef849fe777e52fgregames if (!(match = ap_table_get(r->headers_out, "Etag")) ||
e160b861b50a3a8dcc013b8cd3ef849fe777e52fgregames else if (!(match = ap_table_get(r->headers_out, "Last-Modified")) ||
6b38fca3ec543a0f72efd5683e91a0b30fc752d1trawick /* A single range */
6b38fca3ec543a0f72efd5683e91a0b30fc752d1trawick if (!parse_byterange(ap_pstrdup(r->pool, range + 6), r->clength,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_psprintf(r->pool, "%ld", range_end - range_start + 1));
39b76a07959a0a332366c735a23894d9e8ed6872trawick /* a multiple range */
39b76a07959a0a332366c735a23894d9e8ed6872trawick const char *r_range = ap_pstrdup(r->pool, range + 6);
785be1b6298010956622771c870ab3cd8ca57a2faaron while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL));
97c78987224dcd037076d393aad1867c26b2c8cftrawickAPI_EXPORT(int) ap_each_byterange(request_rec *r, ap_off_t *offset,
97c78987224dcd037076d393aad1867c26b2c8cftrawick return internal_byterange(1, NULL, r, &r->range, offset, length);
97c78987224dcd037076d393aad1867c26b2c8cftrawick/* If this function is called with realreq=1, it will spit out
97c78987224dcd037076d393aad1867c26b2c8cftrawick * the correct headers for a byterange chunk, and set offset and
97c78987224dcd037076d393aad1867c26b2c8cftrawick * length to the positions they should be.
97c78987224dcd037076d393aad1867c26b2c8cftrawick * If it is called with realreq=0, it will add to tlength the length
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * it *would* have used with realreq=1.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Either case will return 1 if it should be called again, and 0
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * when done.
785be1b6298010956622771c870ab3cd8ca57a2faaronstatic int internal_byterange(int realreq, long *tlength, request_rec *r,
785be1b6298010956622771c870ab3cd8ca57a2faaron ap_rvputs(r, "\015\012--", r->boundary, "--\015\012", NULL);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding if (!parse_byterange(range, r->clength, &range_start, &range_end))
785be1b6298010956622771c870ab3cd8ca57a2faaron /* Skip this one */
785be1b6298010956622771c870ab3cd8ca57a2faaron return internal_byterange(realreq, tlength, r, r_range, offset,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding const char *ct = r->content_type ? r->content_type : ap_default_type(r);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_snprintf(ts, sizeof(ts), "%ld-%ld/%ld", range_start, range_end,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_rvputs(r, "\015\012--", r->boundary, "\015\012Content-type: ",
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ct, "\015\012Content-range: bytes ", ts, "\015\012\015\012",
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding *tlength += 4 + strlen(r->boundary) + 16 + strlen(ct) + 23 +
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fieldingAPI_EXPORT(int) ap_set_content_length(request_rec *r, long clength)
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_table_setn(r->headers_out, "Content-Length", ap_psprintf(r->pool, "%ld", clength));
785be1b6298010956622771c870ab3cd8ca57a2faaron const char *conn = ap_table_get(r->headers_in, "Connection");
785be1b6298010956622771c870ab3cd8ca57a2faaron /* The following convoluted conditional determines whether or not
785be1b6298010956622771c870ab3cd8ca57a2faaron * the current connection should remain persistent after this response
785be1b6298010956622771c870ab3cd8ca57a2faaron * (a.k.a. HTTP Keep-Alive) and whether or not the output message
785be1b6298010956622771c870ab3cd8ca57a2faaron * body should use the HTTP/1.1 chunked transfer-coding. In English,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * IF we have not marked this connection as errored;
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * and the response body has a defined length due to the status code
785be1b6298010956622771c870ab3cd8ca57a2faaron * being 304 or 204, the request method being HEAD, already
785be1b6298010956622771c870ab3cd8ca57a2faaron * having defined Content-Length or Transfer-Encoding: chunked, or
785be1b6298010956622771c870ab3cd8ca57a2faaron * the request version being HTTP/1.1 and thus capable of being set
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * as chunked [we know the (r->chunked = 1) side-effect is ugly];
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * and the server configuration enables keep-alive;
785be1b6298010956622771c870ab3cd8ca57a2faaron * and the server configuration has a reasonable inter-request timeout;
785be1b6298010956622771c870ab3cd8ca57a2faaron * and there is no maximum # requests or the max hasn't been reached;
785be1b6298010956622771c870ab3cd8ca57a2faaron * and the response status does not require a close;
785be1b6298010956622771c870ab3cd8ca57a2faaron * and the response generator has not already indicated close;
785be1b6298010956622771c870ab3cd8ca57a2faaron * and the client did not request non-persistence (Connection: close);
785be1b6298010956622771c870ab3cd8ca57a2faaron * and we haven't been configured to ignore the buggy twit
785be1b6298010956622771c870ab3cd8ca57a2faaron * or they're a buggy twit coming through a HTTP/1.1 proxy
785be1b6298010956622771c870ab3cd8ca57a2faaron * and the client is requesting an HTTP/1.0-style keep-alive
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * or the client claims to be HTTP/1.1 compliant (perhaps a proxy);
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * THEN we can be persistent, which requires more headers be output.
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick * Note that the condition evaluation order is extremely important.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding "chunked") ||
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding (r->chunked = 1))) && /* THIS CODE IS CORRECT, see comment above. */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* ZZZ change to APR keepalive timeout defined value */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding (r->server->keep_alive_max > r->connection->keepalives)) &&
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding (!ap_table_get(r->subprocess_env, "nokeepalive") ||
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawick ((ka_sent = ap_find_token(r->pool, conn, "keep-alive")) ||
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawick int left = r->server->keep_alive_max - r->connection->keepalives;
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawick /* If they sent a Keep-Alive token, send one back */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_table_mergen(r->headers_out, "Connection", "Keep-Alive");
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* Otherwise, we need to indicate that we will be closing this
785be1b6298010956622771c870ab3cd8ca57a2faaron * connection immediately after the current response.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * We only really need to send "close" to HTTP/1.1 clients, but we
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * always send it anyway, because a broken proxy may identify itself
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * as HTTP/1.0, but pass our request along with our HTTP/1.1 tag
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * to a HTTP/1.1 client. Better safe than sorry.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_table_mergen(r->headers_out, "Connection", "close");
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Return the latest rational time from a request/mtime (modification time)
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * pair. We return the mtime unless it's in the future, in which case we
f4b96a996afbc46872f57ad1450e6ee1c8f13707jorton * return the current time. We use the request time as a reference in order
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawick * to limit the number of calls to time(). We don't check for futurosity
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * unless the mtime is at least as new as the reference.
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawickAPI_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime)
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawick /* For all static responses, it's almost certain that the file was
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawick * last modified before the beginning of the request. So there's
17f3ba69f65182426ad4e568bb2d6f192ccd2ed5trawick * no reason to call time(NULL) again. But if the response has been
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * created on demand, then it might be newer than the time the request
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * started. In this event we really have to call time(NULL) again
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * so that we can give the clients the most accurate Last-Modified. If we
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * were given a time in the future, we return the current time - the
8f8ec0957334f50b7ac11359f90490ee467258eedreid * Last-Modified can't be in the future.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* ZZZ Change time call to use time AP time thread functions. */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding now = (mtime < r->request_time) ? r->request_time : time(NULL);
785be1b6298010956622771c870ab3cd8ca57a2faaron const char *etag = ap_table_get(r->headers_out, "ETag");
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding const char *if_match, *if_modified_since, *if_unmodified, *if_nonematch;
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* Check for conditional requests --- note that we only want to do
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * this if we are successful so far and we are not processing a
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * subrequest or an ErrorDocument.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * The order of the checks is important, since ETag checks are supposed
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * to be more accurate than checks relative to the modification time.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * However, not all documents are guaranteed to *have* ETags, and some
6b38fca3ec543a0f72efd5683e91a0b30fc752d1trawick * might have Last-Modified values w/o ETags, so this gets a little
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * complicated.
785be1b6298010956622771c870ab3cd8ca57a2faaron if (!ap_is_HTTP_SUCCESS(r->status) || r->no_local_copy) {
6b38fca3ec543a0f72efd5683e91a0b30fc752d1trawick /* ZZZ We are changing time(NULL) to AP time thread functions. */
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf /* If an If-Match request-header field was given
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * AND the field value is not "*" (meaning match anything)
785be1b6298010956622771c870ab3cd8ca57a2faaron * AND if our strong ETag does not match any entity tag in that field,
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * respond with a status of 412 (Precondition Failed).
785be1b6298010956622771c870ab3cd8ca57a2faaron if ((if_match = ap_table_get(r->headers_in, "If-Match")) != NULL) {
066877f1a045103acfdd376d48cdd473c33f409bdougm /* Else if a valid If-Unmodified-Since request-header field was given
785be1b6298010956622771c870ab3cd8ca57a2faaron * AND the requested resource has been modified since the time
785be1b6298010956622771c870ab3cd8ca57a2faaron * specified in this field, then the server MUST
785be1b6298010956622771c870ab3cd8ca57a2faaron * respond with a status of 412 (Precondition Failed).
785be1b6298010956622771c870ab3cd8ca57a2faaron if_unmodified = ap_table_get(r->headers_in, "If-Unmodified-Since");
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf /* If an If-None-Match request-header field was given
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * AND the field value is "*" (meaning match anything)
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * OR our ETag matches any of the entity tags in that field, fail.
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * If the request method was GET or HEAD, failure means the server
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * SHOULD respond with a 304 (Not Modified) response.
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * For all other request methods, failure means the server MUST
066877f1a045103acfdd376d48cdd473c33f409bdougm * respond with a status of 412 (Precondition Failed).
785be1b6298010956622771c870ab3cd8ca57a2faaron * GET or HEAD allow weak etag comparison, all other methods require
785be1b6298010956622771c870ab3cd8ca57a2faaron * strong comparison. We can only use weak if it's not a range request.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding if_nonematch = ap_table_get(r->headers_in, "If-None-Match");
785be1b6298010956622771c870ab3cd8ca57a2faaron /* Else if a valid If-Modified-Since request-header field was given
785be1b6298010956622771c870ab3cd8ca57a2faaron * AND it is a GET or HEAD request
785be1b6298010956622771c870ab3cd8ca57a2faaron * AND the requested resource has not been modified since the time
785be1b6298010956622771c870ab3cd8ca57a2faaron * specified in this field, then the server MUST
2d399cd7535887fceaa9f8f116eb98ce68ddd602trawick * respond with a status of 304 (Not Modified).
785be1b6298010956622771c870ab3cd8ca57a2faaron * A date later than the server's current request time is invalid.
785be1b6298010956622771c870ab3cd8ca57a2faaron ap_table_get(r->headers_in, "If-Modified-Since")) != NULL)) {
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * Construct an entity tag (ETag) from resource information. If it's a real
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * file, build in some of the file characteristics. If the modification time
785be1b6298010956622771c870ab3cd8ca57a2faaron * is newer than (request-time minus 1 second), mark the ETag as weak - it
785be1b6298010956622771c870ab3cd8ca57a2faaron * could be modified again in as short an interval. We rationalize the
785be1b6298010956622771c870ab3cd8ca57a2faaron * modification time we're given to keep it from being in the future.
785be1b6298010956622771c870ab3cd8ca57a2faaronAPI_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak)
785be1b6298010956622771c870ab3cd8ca57a2faaron * Make an ETag header out of various pieces of information. We use
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * the last-modified date and, if we have a real file, the
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * length and inode number - note that this doesn't have to match
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * the content-length (i.e. includes), it just has to be unique
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * for the file.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * If the request was made within a second of the last-modified date,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * we send a weak tag instead of a strong one, since it could
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * be modified again later in the second, and the validation
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * would be incorrect.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding weak = ((r->request_time - r->mtime > 1) && !force_weak) ? "" : "W/";
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding (unsigned long) r->mtime);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding (unsigned long) r->mtime);
785be1b6298010956622771c870ab3cd8ca57a2faaron /* If we have a variant list validator (vlv) due to the
785be1b6298010956622771c870ab3cd8ca57a2faaron * response being negotiated, then we create a structured
785be1b6298010956622771c870ab3cd8ca57a2faaron * entity tag which merges the variant etag with the variant
785be1b6298010956622771c870ab3cd8ca57a2faaron * list validator (vlv). This merging makes revalidation
785be1b6298010956622771c870ab3cd8ca57a2faaron * somewhat safer, ensures that caches which can deal with
785be1b6298010956622771c870ab3cd8ca57a2faaron * Vary will (eventually) be updated if the set of variants is
785be1b6298010956622771c870ab3cd8ca57a2faaron * changed, and is also a protocol requirement for transparent
785be1b6298010956622771c870ab3cd8ca57a2faaron * content negotiation.
785be1b6298010956622771c870ab3cd8ca57a2faaron /* if the variant list validator is weak, we make the whole
785be1b6298010956622771c870ab3cd8ca57a2faaron * structured etag weak. If we would not, then clients could
785be1b6298010956622771c870ab3cd8ca57a2faaron * have problems merging range responses if we have different
785be1b6298010956622771c870ab3cd8ca57a2faaron * variants with the same non-globally-unique strong etag.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* merge variant_etag and vlv into a structured etag */
900127764fb985c340ee4979cac97146a330c694trawick etag = ap_pstrcat(r->pool, variant_etag, ";", vlv, NULL);
785be1b6298010956622771c870ab3cd8ca57a2faaron * This function sets the Last-Modified output header field to the value
785be1b6298010956622771c870ab3cd8ca57a2faaron * of the mtime field in the request structure - rationalized to keep it from
785be1b6298010956622771c870ab3cd8ca57a2faaron * being in the future.
785be1b6298010956622771c870ab3cd8ca57a2faaron/* Get the method number associated with the given string, assumed to
785be1b6298010956622771c870ab3cd8ca57a2faaron * contain an HTTP method. Returns M_INVALID if not recognized.
785be1b6298010956622771c870ab3cd8ca57a2faaron * This is the first step toward placing method names in a configurable
785be1b6298010956622771c870ab3cd8ca57a2faaron * list. Hopefully it (and other routines) can eventually be moved to
785be1b6298010956622771c870ab3cd8ca57a2faaron * something like a mod_http_methods.c, complete with config stuff.
785be1b6298010956622771c870ab3cd8ca57a2faaronAPI_EXPORT(int) ap_method_number_of(const char *method)
785be1b6298010956622771c870ab3cd8ca57a2faaron switch (*method) {
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding/* Get a line of protocol input, including any continuation lines
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * caused by MIME folding (or broken clients) if fold != 0, and place it
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * in the buffer s, of size n bytes, without the ending newline.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Returns -1 on error, or the length of s.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Note: Because bgets uses 1 char for newline and 1 char for NUL,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * the most we can get is (n - 2) actual characters if it
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * was ended by a newline, or (n - 1) characters if the line
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * length exceeded (n - 1). So, if the result == (n - 1),
bbbf8f0e622ad5a37ccf70f35660fc755575278arbb * then the actual input line exceeded the buffer length,
1ccd992d37d62c8cb2056126f2234f64ec189bfddougm * and it would be a good idea for the caller to puke 400 or 414.
3926b3b7716683a1241c1ff6f8dd2f9c5073665afanf /* retval == -1 if error, 0 if EOF */
91583d2e9c0550f539ea6f4dedf051979ad1ad88fanf /* retval is the number of characters read, not including NUL */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding if (*pos == '\n') { /* Did we get a full line of input? */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Trim any extra trailing spaces or tabs except for the first
3c48210f662a2ab8ed90708989e04c09aae33cb2trawick * space or tab at the beginning of a blank string. This makes
3926b3b7716683a1241c1ff6f8dd2f9c5073665afanf * it much easier to check field values for exact matches, and
3c48210f662a2ab8ed90708989e04c09aae33cb2trawick * saves memory as well. Terminate string at end of line.
3926b3b7716683a1241c1ff6f8dd2f9c5073665afanf while (pos > (s + 1) && (*(pos - 1) == ' ' || *(pos - 1) == '\t')) {
9c518951a46c7a12e20876827bb2e84ef87d3c11jerenkrantz --total; /* but not one at the beginning of line */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding return total; /* if not, input line exceeded buffer size */
0db1b9810f06c0e3c537e0e0dfbc30160c308526trawick /* Continue appending if line folding is desired and
0db1b9810f06c0e3c537e0e0dfbc30160c308526trawick * the last line was not empty and we have room in the buffer and
0db1b9810f06c0e3c537e0e0dfbc30160c308526trawick * the next line begins with a continuation character.
644be6f54749d2d9950d2c4d2ac448f7af016d26martin/* parse_uri: break apart the uri
644be6f54749d2d9950d2c4d2ac448f7af016d26martin * Side Effects:
d40fc22d54d5969fa330e4983cf07f450f7029cebrianp * - sets r->args to rest after '?' (or NULL if no '?')
644be6f54749d2d9950d2c4d2ac448f7af016d26martin * - sets r->uri to request uri (without r->args part)
0db1b9810f06c0e3c537e0e0dfbc30160c308526trawick * - sets r->hostname (if not set already) from request (scheme://host:port)
3c48210f662a2ab8ed90708989e04c09aae33cb2trawickCORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri)
3c8b3749225668f06abbb2b023a833a2cef46931brianp status = ap_parse_hostinfo_components(r->pool, uri, &r->parsed_uri);
785be1b6298010956622771c870ab3cd8ca57a2faaron /* Simple syntax Errors in URLs are trapped by parse_uri_components(). */
ccad4fdc6c75a352157a413bd3bbaf4d0c8a6f72brianp status = ap_parse_uri_components(r->pool, uri, &r->parsed_uri);
3c8b3749225668f06abbb2b023a833a2cef46931brianp /* if it has a scheme we may need to do absoluteURI vhost stuff */
785be1b6298010956622771c870ab3cd8ca57a2faaron && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))) {
3926b3b7716683a1241c1ff6f8dd2f9c5073665afanf /* Handle path translations for OS/2 and plug security hole.
3926b3b7716683a1241c1ff6f8dd2f9c5073665afanf * This will prevent "http://www.wherever.com/..\..\/" from
3926b3b7716683a1241c1ff6f8dd2f9c5073665afanf * returning a directory for the root drive.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding#endif /* OS2 || WIN32 */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding const char *ll = l;
785be1b6298010956622771c870ab3cd8ca57a2faaron const char *uri;
785be1b6298010956622771c870ab3cd8ca57a2faaron int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */
785be1b6298010956622771c870ab3cd8ca57a2faaron /* Read past empty lines until we get a real request line,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * a read error, the connection closes (EOF), or we timeout.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * We skip empty lines because browsers have to tack a CRLF on to the end
785be1b6298010956622771c870ab3cd8ca57a2faaron * of POSTs to support old CERN webservers. But note that we may not
785be1b6298010956622771c870ab3cd8ca57a2faaron * have flushed any previous response completely to the client yet.
785be1b6298010956622771c870ab3cd8ca57a2faaron * We delay the flush as long as possible so that we can improve
785be1b6298010956622771c870ab3cd8ca57a2faaron * performance for clients that are pipelining requests. If a request
785be1b6298010956622771c870ab3cd8ca57a2faaron * is pipelined then we won't block during the (implicit) read() below.
785be1b6298010956622771c870ab3cd8ca57a2faaron * If the requests aren't pipelined, then the client is still waiting
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * for the final buffer flush from us, and we will block in the implicit
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * have to block during a read.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* TODO: reimplement SAFEREAD external to BUFF using a layer */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* //ap_bsetflag(conn->client, B_SAFEREAD, 1); */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding while ((len = getline(l, sizeof(l), conn->client, 0)) <= 0) {
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding if ((len < 0) || ap_bgetflag(conn->client, B_EOF)) {
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* //ap_bsetflag(conn->client, B_SAFEREAD, 0); */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* this is a hack to make sure that request time is set,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * it's not perfect, but it's better than nothing
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* we've probably got something to do, ignore graceful restart requests */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* XXX - sigwait doesn't work if the signal has been SIG_IGNed (under
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * linux 2.0 w/ glibc 2.0, anyway), and this step isn't necessary when
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * we're running a sigwait thread anyway. If/when unthreaded mode is
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * put back in, we should make sure to ignore this signal iff a sigwait
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * thread isn't used. - mvsk
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding#ifdef SIGWINCH
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding signal(SIGWINCH, SIG_IGN);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* //ap_bsetflag(conn->client, B_SAFEREAD, 0); */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_update_connection_status(conn->id, "Method", r->method);
785be1b6298010956622771c870ab3cd8ca57a2faaron /* Provide quick information about the request method as soon as known */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding if (r->method_number == M_GET && r->method[0] == 'H') {
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* getline returns (size of max buffer - 1) if it fills up the
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * buffer before finding the end-of-line. This is only going to
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * happen if it exceeds the configured limit for a request-line.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding r->protocol = ap_pstrdup(r->pool, ll[0] ? ll : "HTTP/0.9");
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_update_connection_status(conn->id, "Protocol", r->protocol);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor)
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding && minor < HTTP_VERSION(1,0)) /* don't allow HTTP/0.1000 */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding char field[DEFAULT_LIMIT_REQUEST_FIELDSIZE + 2]; /* getline's two extra */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding unsigned int fields_read = 0;
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* We'll use ap_overlap_tables later to merge these into r->headers_in. */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Read header lines until we get the empty separator line, a read error,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * the connection closes (EOF), reach the server limit, or we timeout.
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding while ((len = getline(field, sizeof(field), c->client, 1)) > 0) {
785be1b6298010956622771c870ab3cd8ca57a2faaron "The number of request header fields exceeds "
785be1b6298010956622771c870ab3cd8ca57a2faaron "this server's limit.<P>\n");
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* getline returns (size of max buffer - 1) if it fills up the
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * buffer before finding the end-of-line. This is only going to
785be1b6298010956622771c870ab3cd8ca57a2faaron * happen if it exceeds the configured limit for a field size.
785be1b6298010956622771c870ab3cd8ca57a2faaron ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
785be1b6298010956622771c870ab3cd8ca57a2faaron "Size of a request header field exceeds server limit.<P>\n"
785be1b6298010956622771c870ab3cd8ca57a2faaron if (!(value = strchr(copy, ':'))) { /* Find the colon separator */
785be1b6298010956622771c870ab3cd8ca57a2faaron r->status = HTTP_BAD_REQUEST; /* or abort the bad request */
785be1b6298010956622771c870ab3cd8ca57a2faaron ap_table_setn(r->notes, "error-notes", ap_pstrcat(r->pool,
785be1b6298010956622771c870ab3cd8ca57a2faaron "Request header field is missing colon separator.<P>\n"
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_overlap_tables(r->headers_in, tmp_headers, AP_OVERLAP_TABLES_MERGE);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding const char *expect;
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding r->request_config = ap_create_request_config(r->pool);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding r->status = HTTP_REQUEST_TIME_OUT; /* Until we get a request */
45acd673a68181802b112e97e84fa3813ddd3ec1stoddard ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 1);
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding /* Get the request... */
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding "request failed: URI too long");
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna "request failed: error reading the headers");
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna * Client asked for headers only with HTTP/0.9, which doesn't send
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna * headers! Have to dink things just to make sure the error message
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna * comes through...
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna "client sent invalid HTTP/0.9 request: HEAD %s",
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna /* update what we think the virtual host is based on the headers we've
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna /* we may have switched to another server */
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna conn->keptalive = 0; /* We now have a request to play with */
20f1b1a67eef5ab0f3295608c89964a7dca4fdd1pquerna if ((!r->hostname && (r->proto_num >= HTTP_VERSION(1,1))) ||
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * Client sent us an HTTP/1.1 or later request without telling us the
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * hostname, either with a full URL or a Host: header. We therefore
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * need to (as per the 1.1 spec) send an error. As a special case,
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
45acd673a68181802b112e97e84fa3813ddd3ec1stoddard * a Host: header, and the server MUST respond with 400 if it doesn't.
8f8ec0957334f50b7ac11359f90490ee467258eedreid ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
382fa07a63096c4a1aabfed36433ea5ac9c40ad0trawick "client sent HTTP/1.1 request without hostname "
785be1b6298010956622771c870ab3cd8ca57a2faaron if (((expect = ap_table_get(r->headers_in, "Expect")) != NULL) &&
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * The Expect header field was added to HTTP/1.1 after RFC 2068
09fe0b69d3d1e8c8041c9ce99ee77b8b44b5e3b1fielding * as a means to signal when a 100 response is desired and,
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * unfortunately, to signal a poor man's mandatory extension that
b88f887ed5554d9050d97f9a56a89ae62bdbd906fanf * the server must understand or return 417 Expectation Failed.
785be1b6298010956622771c870ab3cd8ca57a2faaron ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, 0, r,
785be1b6298010956622771c870ab3cd8ca57a2faaron "client sent an unrecognized expectation value of "
return NULL;
NULL));
return DECLINED;
if (!ap_auth_name(r)) {
return SERVER_ERROR;
if (!auth_line) {
return AUTH_REQUIRED;
return AUTH_REQUIRED;
auth_line++;
*pw = t;
return OK;
* The number of status lines must equal the value of RESPONSE_CODES (httpd.h)
#ifdef UTS21
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;
#ifdef CHARSET_EBCDIC
if (r->assbackwards)
if (!r->status_line)
if (r->proxyreq
#ifdef CHARSET_EBCDIC
#ifdef CHARSET_EBCDIC
if (!convert)
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;
#ifdef CHARSET_EBCDIC
if (r->assbackwards) {
if (!r->main)
r->headers_out);
fixup_vary(r);
#ifdef CHARSET_EBCDIC
ap_set_keepalive(r);
if (r->chunked) {
else if (r->content_type)
if (r->content_encoding)
else if (r->content_language)
terminate_header(r);
if (r->chunked)
#ifdef CHARSET_EBCDIC
if (!convert)
r->chunked = 0;
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;
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;
if (c != LF) {
int rv;
return rv;
if (r->expecting_100) {
return OK;
if (rv < 0)
return HTTP_BAD_REQUEST;
return OK;
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) {
(void) ap_rflush(r);
(void) ap_rflush(r);
total_bytes_sent += w;
SET_BYTES_SENT(r);
return total_bytes_sent;
#ifndef MMAP_SEGMENT_SIZE
ap_ssize_t w;
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);
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);
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);
NULL)