protocol.c revision 6af61679f5d25e77f0d34112d714f9ae4cc666e3
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2001 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
/*
* http_protocol.c --- routines which directly communicate with the client.
*
* Code originally by Rob McCool; much redone by Robert S. Thau
* and the Apache Software Foundation.
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_buckets.h"
#include "apr_lib.h"
#include "apr_signal.h"
#define APR_WANT_STDIO /* for sscanf */
#define APR_WANT_STRFUNC
#define APR_WANT_MEMFUNC
#include "apr_want.h"
#define CORE_PRIVATE
#include "util_filter.h"
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_main.h"
#include "http_request.h"
#include "http_vhost.h"
#include "http_log.h" /* For errors detected in basic auth common
* support code... */
#include "util_date.h" /* For parseHTTPdate and BAD_DATE */
#include "util_charset.h"
#include "util_ebcdic.h"
#include <stdarg.h>
#endif
#include <unistd.h>
#endif
)
/*
* Builds the content-type that should be sent to the client from the
* content-type specified. The following rules are followed:
* - if type is NULL, type is set to ap_default_type(r)
* - if charset adding is disabled, stop processing and return type.
* - then, if there are no parameters on type, add the default charset
* - return type
*/
{
static const char *needcset[] = {
NULL };
const char **pcset;
&core_module);
if (!type) {
type = ap_default_type(r);
}
return type;
}
/* already has parameter, do nothing */
/* XXX we don't check the validity */
;
}
else {
/* see if it makes sense to add the charset. At present,
* we only add it if the Content-type is one of needcset[]
*/
break;
}
}
}
return type;
}
{
}
/*
* pair. We return the mtime unless it's in the future, in which case we
* return the current time. We use the request time as a reference in order
* to limit the number of calls to time(). We don't check for futurosity
* unless the mtime is at least as new as the reference.
*/
{
/* For all static responses, it's almost certain that the file was
* last modified before the beginning of the request. So there's
* no reason to call time(NULL) again. But if the response has been
* created on demand, then it might be newer than the time the request
* started. In this event we really have to call time(NULL) again
* so that we can give the clients the most accurate Last-Modified. If we
* were given a time in the future, we return the current time - the
* Last-Modified can't be in the future.
*/
}
/* Get a line of protocol input, including any continuation lines
* caused by MIME folding (or broken clients) if fold != 0, and place it
* in the buffer s, of size n bytes, without the ending newline.
*
* Returns -1 on error, or the length of s.
*
* Notes: Because the buffer uses 1 char for NUL, the most we can return is
* (n - 1) actual characters.
*
* If no LF is detected on the last line due to a dropped connection
* or a full buffer, that's considered an error.
*/
{
char *pos = s;
char *last_char;
char *beyond_buff = s + n;
const char *temp;
int retval;
int total = 0;
int looking_ahead = 0;
conn_rec *c = r->connection;
apr_bucket *e;
req_cfg = (core_request_config *)
/* make sure it's empty unless we're folding */
while (1) {
if (APR_BRIGADE_EMPTY(b)) {
int zero = 0;
APR_BRIGADE_EMPTY(b)) {
return -1;
}
}
e = APR_BRIGADE_FIRST(b);
if (e->length == 0) {
continue;
}
if (retval != APR_SUCCESS) {
if (total) {
break; /* report previously-read data to caller, do ap_xlate_proto_to_ascii() */
}
else {
return -1;
}
}
/* can't fold because next line isn't indented,
* so return what we have. lookahead brigade is
* stashed on req_cfg->bb
*/
break;
}
if (last_char < beyond_buff) {
}
else {
/* input line was larger than the caller's buffer */
/* don't need to worry about req_cfg->bb being bogus.
* the request is about to die, and ErrorDocument
* redirects get a new req_cfg->bb
*/
return -1;
}
--pos; /* zap optional CR before LF */
}
/*
* Trim any extra trailing spaces or tabs except for the first
* space or tab at the beginning of a blank string. This makes
* it much easier to check field values for exact matches, and
* saves memory as well. Terminate string at end of line.
*/
while (pos > (s + 1) &&
--pos; /* trim extra trailing spaces or tabs */
}
/* look ahead another line if line folding is desired
* and this line isn't empty
*/
looking_ahead = 1;
}
else {
break;
}
}
else {
/* no LF yet...character mode client (telnet)...keep going
* bump past last character read,
* and set total in case we bail before finding a LF
*/
looking_ahead = 0; /* only appropriate right after LF */
}
}
return total;
}
/* parse_uri: break apart the uri
* Side Effects:
* - sets r->args to rest after '?' (or NULL if no '?')
* - sets r->uri to request uri (without r->args part)
* - sets r->hostname (if not set already) from request (scheme://host:port)
*/
{
if (r->method_number == M_CONNECT) {
}
else {
/* Simple syntax Errors in URLs are trapped by parse_uri_components(). */
}
if (ap_is_HTTP_SUCCESS(status)) {
/* if it has a scheme we may need to do absoluteURI vhost stuff */
if (r->parsed_uri.scheme
}
else if (r->method_number == M_CONNECT) {
}
/* Handle path translations for OS/2 and plug security hole.
* This will prevent "http://www.wherever.com/..\..\/" from
* returning a directory for the root drive.
*/
{
char *x;
*x = '/';
}
#endif /* OS2 || WIN32 */
}
else {
}
}
static int read_request_line(request_rec *r)
{
const char *ll = l;
const char *uri;
const char *pro;
#if 0
#endif
int len;
/* Read past empty lines until we get a real request line,
* a read error, the connection closes (EOF), or we timeout.
*
* We skip empty lines because browsers have to tack a CRLF on to the end
* of POSTs to support old CERN webservers. But note that we may not
* have flushed any previous response completely to the client yet.
* We delay the flush as long as possible so that we can improve
* performance for clients that are pipelining requests. If a request
* is pipelined then we won't block during the (implicit) read() below.
* If the requests aren't pipelined, then the client is still waiting
* for the final buffer flush from us, and we will block in the implicit
* read(). B_SAFEREAD ensures that the BUFF layer flushes if it will
* have to block during a read.
*/
while ((len = ap_getline(l, sizeof(l), r, 0)) <= 0) {
if (len < 0) { /* includes EOF */
/* this is a hack to make sure that request time is set,
* it's not perfect, but it's better than nothing
*/
r->request_time = apr_time_now();
return 0;
}
}
/* we've probably got something to do, ignore graceful restart requests */
/* XXX - sigwait doesn't work if the signal has been SIG_IGNed (under
* linux 2.0 w/ glibc 2.0, anyway), and this step isn't necessary when
* put back in, we should make sure to ignore this signal iff a sigwait
* thread isn't used. - mvsk
#ifdef SIGWINCH
apr_signal(SIGWINCH, SIG_IGN);
#endif
*/
r->request_time = apr_time_now();
#if 0
/* XXX If we want to keep track of the Method, the protocol module should do
* it. That support isn't in the scoreboard yet. Hopefully next week
* sometime. rbb */
#endif
/* Provide quick information about the request method as soon as known */
r->header_only = 1;
}
ap_parse_uri(r, uri);
/* ap_getline returns (size of max buffer - 1) if it fills up the
* buffer before finding the end-of-line. This is only going to
* happen if it exceeds the configured limit for a request-line.
*/
return 0;
}
if (ll[0]) {
r->assbackwards = 0;
} else {
r->assbackwards = 1;
pro = "HTTP/0.9";
len = 8;
}
/* XXX ap_update_connection_status(conn->id, "Protocol", r->protocol); */
/* Avoid sscanf in the common case */
if (len == 8 &&
else
return 1;
}
static void get_mime_headers(request_rec *r)
{
char *value;
char *copy;
int len;
int fields_read = 0;
/* We'll use apr_table_overlap later to merge these into r->headers_in. */
/*
* Read header lines until we get the empty separator line, a read error,
* the connection closes (EOF), reach the server limit, or we timeout.
*/
if (r->server->limit_req_fields &&
r->status = HTTP_BAD_REQUEST;
"The number of request header fields exceeds "
"this server's limit.<P>\n");
return;
}
/* ap_getline returns (size of max buffer - 1) if it fills up the
* buffer before finding the end-of-line. This is only going to
* happen if it exceeds the configured limit for a field size.
*/
r->status = HTTP_BAD_REQUEST;
apr_pstrcat(r->pool,
"Size of a request header field "
"exceeds server limit.<P>\n"
"<PRE>\n",
"</PRE>\n", NULL));
return;
}
apr_pstrcat(r->pool,
"Request header field is missing "
"colon separator.<P>\n"
"<PRE>\n",
"</PRE>\n", NULL));
return;
}
*value = '\0';
++value;
++value; /* Skip to start of value */
}
}
}
{
request_rec *r;
apr_pool_t *p;
const char *expect;
int access_status, keptalive;
r = apr_pcalloc(p, sizeof(request_rec));
r->pool = p;
r->connection = conn;
r->ap_auth_type = NULL;
r->sent_bodyct = 0; /* bytect isn't for body */
r->read_length = 0;
r->read_body = REQUEST_NO_BODY;
r->the_request = NULL;
(int)(keptalive
/* Get the request... */
if (!read_request_line(r)) {
if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
"request failed: URI too long");
ap_send_error_response(r, 0);
return r;
}
return NULL;
}
if (keptalive) {
}
if (!r->assbackwards) {
get_mime_headers(r);
if (r->status != HTTP_REQUEST_TIME_OUT) {
"request failed: error reading the headers");
ap_send_error_response(r, 0);
return r;
}
}
else {
if (r->header_only) {
/*
* Client asked for headers only with HTTP/0.9, which doesn't send
* headers! Have to dink things just to make sure the error message
* comes through...
*/
"client sent invalid HTTP/0.9 request: HEAD %s",
r->uri);
r->header_only = 0;
r->status = HTTP_BAD_REQUEST;
ap_send_error_response(r, 0);
return r;
}
}
/* update what we think the virtual host is based on the headers we've
* now read. may update status.
*/
/* we may have switched to another server */
/*
* Client sent us an HTTP/1.1 or later request without telling us the
* hostname, either with a full URL or a Host: header. We therefore
* need to (as per the 1.1 spec) send an error. As a special case,
* HTTP/1.1 mentions twice (S9, S14.23) that a request MUST contain
* a Host: header, and the server MUST respond with 400 if it doesn't.
*/
r->status = HTTP_BAD_REQUEST;
"client sent HTTP/1.1 request without hostname "
"(see RFC2616 section 14.23): %s", r->uri);
}
ap_send_error_response(r, 0);
return r;
}
(expect[0] != '\0')) {
/*
* The Expect header field was added to HTTP/1.1 after RFC 2068
* as a means to signal when a 100 response is desired and,
* unfortunately, to signal a poor man's mandatory extension that
* the server must understand or return 417 Expectation Failed.
*/
r->expecting_100 = 1;
}
else {
"client sent an unrecognized expectation value of "
"Expect: %s", expect);
ap_send_error_response(r, 0);
(void) ap_discard_request_body(r);
return r;
}
}
if ((access_status = ap_run_post_read_request(r))) {
ap_die(access_status, r);
return NULL;
}
return r;
}
/*
* A couple of other functions which initialize some of the fields of
* a request structure, as appropriate for adjuncts of one kind or another
* to a request in progress. Best here, rather than elsewhere, since
* *someone* has to set the protocol-specific fields...
*/
{
* fragment. */
}
static void end_output_stream(request_rec *r)
{
apr_bucket *b;
b = apr_bucket_eos_create();
}
{
}
/* finalize_request_protocol is called at completion of sending the
* response. Its sole purpose is to send the terminating protocol
* information for any wrappers around the response message body
* (i.e., transfer encodings). It should have been named finalize_response.
*/
{
while (r->next) {
r = r->next;
}
/* tell the filter chain there is no more content coming */
if (!r->eos_sent) {
}
}
/*
* Support for the Basic authentication protocol, and a bit for Digest.
*/
{
}
{
else
NULL));
}
{
ap_auth_name(r), r->request_time));
}
{
: "Authorization");
const char *t;
return DECLINED;
if (!ap_auth_name(r)) {
0, r, "need AuthName: %s", r->uri);
return HTTP_INTERNAL_SERVER_ERROR;
}
if (!auth_line) {
return HTTP_UNAUTHORIZED;
}
/* Client tried to authenticate using wrong auth scheme */
"client used wrong authentication scheme: %s", r->uri);
return HTTP_UNAUTHORIZED;
}
auth_line++;
}
/* Note that this allocation has to be made from r->connection->pool
* because it has the lifetime of the connection. The other allocations
* are temporary and can be tossed away any time.
*/
r->ap_auth_type = "Basic";
*pw = t;
return OK;
}
struct content_length_ctx {
int compute_len;
};
/* This filter computes the content length, but it also computes the number
* of bytes sent to the client. This means that this filter will always run
* through all of the buckets in all brigades
*/
{
request_rec *r = f->r;
struct content_length_ctx *ctx;
apr_bucket *e;
int send_it = 0;
if (!ctx) { /* first time through */
}
APR_BRIGADE_FOREACH(e, b) {
const char *ignored;
if (APR_BUCKET_IS_EOS(e) || APR_BUCKET_IS_FLUSH(e)) {
send_it = 1;
}
if (rv != APR_SUCCESS) {
return rv;
}
}
else {
}
r->bytes_sent += length;
}
}
/* We will compute a content length if:
* The protocol is < 1.1
* and We can not chunk
* and this is a keepalive request.
* or We already have all the data
* This is a bit confusing, because we will always buffer up
* to AP_MIN_BYTES_TO_WRITE, so if we get all the data while
* we are buffering that much data, we set the c-l.
*/
&& (!ap_find_last_token(f->r->pool,
"Transfer-Encoding"),
"chunked")
&& (f->r->connection->keepalive)))
|| (APR_BUCKET_IS_EOS(APR_BRIGADE_LAST(b)))) {
}
else {
ctx->compute_len = 0;
}
if (ctx->compute_len) {
/* save the brigade; we can't pass any data to the next
* filter until we have the entire content length
*/
if (!send_it) {
return APR_SUCCESS;
}
ap_set_content_length(r, r->bytes_sent);
}
}
return ap_pass_brigade(f->next, b);
}
/*
* Send the body of a response to the client.
*/
{
apr_bucket *b;
if (rv != APR_SUCCESS) {
*nbytes = 0; /* no way to tell how many were actually sent */
}
else {
}
return rv;
}
#if APR_HAS_MMAP
/* send data from an in-memory buffer */
{
apr_bucket *b;
}
#endif /* APR_HAS_MMAP */
typedef struct {
{
/* whatever is coming down the pipe (we don't care), we
* can simply insert our buffered data at the front and
* pass the whole bundle down the chain.
*/
}
}
{
ap_filter_t *f;
if (len == 0)
return APR_SUCCESS;
/* future optimization: record some flags in the request_rec to
* say whether we've added our filter, and whether it is first.
*/
/* this will typically exit on the first test */
break;
if (f == NULL) {
/* our filter hasn't been added yet */
f = r->output_filters;
}
/* if the first filter is not our buffering filter, then we have to
* deliver the content through the normal filter chain */
if (f != r->output_filters) {
}
/* grab the context from our filter */
}
return APR_SUCCESS;
}
{
char c2 = (char)c;
if (r->connection->aborted) {
return -1;
}
return -1;
return c;
}
{
if (r->connection->aborted)
return -1;
return -1;
return len;
}
{
if (r->connection->aborted)
return -1;
return -1;
return nbyte;
}
{
char buf[4096];
if (r->connection->aborted)
return -1;
/* ### fix this mechanism to allow more than 4K of output */
return -1;
return written;
}
{
int n;
if (r->connection->aborted)
return -1;
return n;
}
{
const char *s;
apr_size_t written = 0;
if (r->connection->aborted)
return -1;
/* ### TODO: if the total output is large, put all the strings
### into a single brigade, rather than flushing each time we
### fill the buffer */
while (1) {
if (s == NULL)
break;
return -1;
}
}
return written;
}
{
apr_bucket *b;
b = apr_bucket_flush_create();
return -1;
return 0;
}
/*
* This function sets the Last-Modified output header field to the value
* of the mtime field in the request structure - rationalized to keep it from
* being in the future.
*/
{
}
AP_IMPLEMENT_HOOK_RUN_FIRST(const char *,http_method,
(const request_rec *r),(r),NULL)
AP_IMPLEMENT_HOOK_RUN_FIRST(unsigned short,default_port,
(const request_rec *r),(r),0)