/* ====================================================================
* The Apache Software License, Version 1.1
*
- * Copyright (c) 2000-2002 The Apache Software Foundation. All rights
+ * Copyright (c) 2000-2003 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
#include "http_vhost.h"
#include "http_main.h" /* For the default_handler below... */
#include "http_log.h"
-#include "rfc1413.h"
#include "util_md5.h"
#include "http_connection.h"
#include "apr_buckets.h"
conf->use_canonical_name = USE_CANONICAL_NAME_UNSET;
conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET;
- conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */
conf->satisfy = SATISFY_NOSPEC;
#ifdef RLIMIT_CPU
conf->enable_mmap = ENABLE_MMAP_UNSET;
conf->enable_sendfile = ENABLE_SENDFILE_UNSET;
+ conf->allow_encoded_slashes = 0;
return (void *)conf;
}
conf->hostname_lookups = new->hostname_lookups;
}
- if ((new->do_rfc1413 & 2) == 0) {
- conf->do_rfc1413 = new->do_rfc1413;
- }
-
if ((new->content_md5 & 2) == 0) {
conf->content_md5 = new->content_md5;
}
conf->enable_sendfile = new->enable_sendfile;
}
+ conf->allow_encoded_slashes = new->allow_encoded_slashes;
+
return (void*)conf;
}
conf->sec_dir = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
conf->sec_url = apr_array_make(a, 40, sizeof(ap_conf_vector_t *));
+ /* recursion stopper */
+ conf->redirect_limit = 0; /* 0 == unset */
+ conf->subreq_limit = 0;
+
return (void *)conf;
}
conf->sec_dir = apr_array_append(p, base->sec_dir, virt->sec_dir);
conf->sec_url = apr_array_append(p, base->sec_url, virt->sec_url);
+ conf->redirect_limit = virt->redirect_limit
+ ? virt->redirect_limit
+ : base->redirect_limit;
+
+ conf->subreq_limit = virt->subreq_limit
+ ? virt->subreq_limit
+ : base->subreq_limit;
+
return conf;
}
}
}
+/*
+ * Optional function coming from mod_ident, used for looking up ident user
+ */
+static APR_OPTIONAL_FN_TYPE(ap_ident_lookup) *ident_lookup;
+
AP_DECLARE(const char *) ap_get_remote_logname(request_rec *r)
{
- core_dir_config *dir_conf;
-
if (r->connection->remote_logname != NULL) {
return r->connection->remote_logname;
}
- /* If we haven't checked the identity, and we want to */
- dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
- &core_module);
-
- if (dir_conf->do_rfc1413 & 1) {
- return ap_rfc1413(r->connection, r->server);
- }
- else {
- return NULL;
+ if (ident_lookup) {
+ return ident_lookup(r);
}
+
+ return NULL;
}
/* There are two options regarding what the "name" of a server is. The
return r->server->server_hostname;
}
+/*
+ * Get the current server name from the request for the purposes
+ * of using in a URL. If the server name is an IPv6 literal
+ * address, it will be returned in URL format (e.g., "[fe80::1]").
+ */
+static const char *get_server_name_for_url(request_rec *r)
+{
+ const char *plain_server_name = ap_get_server_name(r);
+
+#if APR_HAVE_IPV6
+ if (ap_strchr_c(plain_server_name, ':')) { /* IPv6 literal? */
+ return apr_psprintf(r->pool, "[%s]", plain_server_name);
+ }
+#endif
+ return plain_server_name;
+}
+
AP_DECLARE(apr_port_t) ap_get_server_port(const request_rec *r)
{
apr_port_t port;
request_rec *r)
{
unsigned port = ap_get_server_port(r);
- const char *host = ap_get_server_name(r);
+ const char *host = get_server_name_for_url(r);
if (ap_is_default_port(port, r)) {
return apr_pstrcat(p, ap_http_method(r), "://", host, uri, NULL);
return err;
}
+ /* Make it absolute, relative to ServerRoot */
+ arg = ap_server_root_relative(cmd->pool, arg);
+
/* TODO: ap_configtestonly && ap_docrootcheck && */
- /* XXX Shouldn't this be relative to ServerRoot ??? */
if (apr_filepath_merge((char**)&conf->ap_document_root, NULL, arg,
APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS
|| !ap_is_directory(cmd->pool, arg)) {
return err;
}
+ /* Throw a warning if we're in <Location> or <Files> */
+ if (ap_check_cmd_context(cmd, NOT_IN_LOCATION | NOT_IN_FILES)) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
+ "Useless use of AllowOverride in line %d.",
+ cmd->directive->line_num);
+ }
+
d->override = OR_NONE;
while (l[0]) {
w = ap_getword_conf(cmd->pool, &l);
/*
* Ensure that the pathname is canonical, and append the trailing /
*/
- if (apr_filepath_merge(&newpath, NULL, cmd->path,
- APR_FILEPATH_TRUENAME, cmd->pool) != APR_SUCCESS) {
+ apr_status_t rv = apr_filepath_merge(&newpath, NULL, cmd->path,
+ APR_FILEPATH_TRUENAME, cmd->pool);
+ if (rv != APR_SUCCESS && rv != APR_EPATHWILD) {
return apr_pstrcat(cmd->pool, "<Directory \"", cmd->path,
"\"> path is invalid.", NULL);
}
return NULL;
}
-static const char *set_idcheck(cmd_parms *cmd, void *d_, int arg)
+static const char *set_allow2f(cmd_parms *cmd, void *d_, int arg)
{
core_dir_config *d = d_;
const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
return err;
}
- d->do_rfc1413 = arg != 0;
+ d->allow_encoded_slashes = arg != 0;
return NULL;
}
{
ap_directive_t *conftree = NULL;
const char* conffile = ap_server_root_relative(cmd->pool, name);
-
+
if (!conffile) {
return apr_pstrcat(cmd->pool, "Invalid Include path ",
name, NULL);
return NULL;
}
-#ifdef _OSD_POSIX /* BS2000 Logon Passwd file */
-static const char *set_bs2000_account(cmd_parms *cmd, void *dummy, char *name)
-{
- const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY);
- if (err != NULL) {
- return err;
- }
-
- return os_set_account(cmd->pool, name);
-}
-#endif /*_OSD_POSIX*/
-
/*
* Handle a request to include the server's OS platform in the Server
* response header field (the ServerTokens directive). Unfortunately
}
#endif
+static const char *set_recursion_limit(cmd_parms *cmd, void *dummy,
+ const char *arg1, const char *arg2)
+{
+ core_server_config *conf = ap_get_module_config(cmd->server->module_config,
+ &core_module);
+ int limit = atoi(arg1);
+
+ if (limit <= 0) {
+ return "The recursion limit must be greater than zero.";
+ }
+ if (limit < 4) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
+ "Limiting internal redirects to very low numbers may "
+ "cause normal requests to fail.");
+ }
+
+ conf->redirect_limit = limit;
+
+ if (arg2) {
+ limit = atoi(arg2);
+
+ if (limit <= 0) {
+ return "The recursion limit must be greater than zero.";
+ }
+ if (limit < 4) {
+ ap_log_error(APLOG_MARK, APLOG_WARNING, 0, cmd->server,
+ "Limiting the subrequest depth to a very low level may"
+ " cause normal requests to fail.");
+ }
+ }
+
+ conf->subreq_limit = limit;
+
+ return NULL;
+}
+
+static void log_backtrace(const request_rec *r)
+{
+ const request_rec *top = r;
+
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "r->uri = %s", r->uri ? r->uri : "(unexpectedly NULL)");
+
+ while (top && (top->prev || top->main)) {
+ if (top->prev) {
+ top = top->prev;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "redirected from r->uri = %s",
+ top->uri ? top->uri : "(unexpectedly NULL)");
+ }
+
+ if (!top->prev && top->main) {
+ top = top->main;
+ ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
+ "subrequested from r->uri = %s",
+ top->uri ? top->uri : "(unexpectedly NULL)");
+ }
+ }
+}
+
+/*
+ * check whether redirect limit is reached
+ */
+AP_DECLARE(int) ap_is_recursion_limit_exceeded(const request_rec *r)
+{
+ core_server_config *conf = ap_get_module_config(r->server->module_config,
+ &core_module);
+ const request_rec *top = r;
+ int redirects = 0, subreqs = 0;
+ int rlimit = conf->redirect_limit
+ ? conf->redirect_limit
+ : AP_DEFAULT_MAX_INTERNAL_REDIRECTS;
+ int slimit = conf->subreq_limit
+ ? conf->subreq_limit
+ : AP_DEFAULT_MAX_SUBREQ_DEPTH;
+
+
+ while (top->prev || top->main) {
+ if (top->prev) {
+ if (++redirects >= rlimit) {
+ /* uuh, too much. */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Request exceeded the limit of %d internal "
+ "redirects due to probable configuration error. "
+ "Use 'LimitInternalRecursion' to increase the "
+ "limit if necessary. Use 'LogLevel debug' to get "
+ "a backtrace.", rlimit);
+
+ /* post backtrace */
+ log_backtrace(r);
+
+ /* return failure */
+ return 1;
+ }
+
+ top = top->prev;
+ }
+
+ if (!top->prev && top->main) {
+ if (++subreqs >= slimit) {
+ /* uuh, too much. */
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "Request exceeded the limit of %d subrequest "
+ "nesting levels due to probable confguration "
+ "error. Use 'LimitInternalRecursion' to increase "
+ "the limit if necessary. Use 'LogLevel debug' to "
+ "get a backtrace.", slimit);
+
+ /* post backtrace */
+ log_backtrace(r);
+
+ /* return failure */
+ return 1;
+ }
+
+ top = top->main;
+ }
+ }
+
+ /* recursion state: ok */
+ return 0;
+}
+
static const char *add_ct_output_filters(cmd_parms *cmd, void *conf_,
const char *arg, const char *arg2)
{
else {
old = (ap_filter_rec_t*) apr_hash_get(conf->ct_output_filters, arg2,
APR_HASH_KEY_STRING);
+ /* find last entry */
+ if (old) {
+ while (old->next) {
+ old = old->next;
+ }
+ }
}
while (*arg &&
/* We found something, so let's append it. */
if (old) {
- new->next = old;
+ old->next = new;
+ }
+ else {
+ apr_hash_set(conf->ct_output_filters, arg2,
+ APR_HASH_KEY_STRING, new);
}
old = new;
}
return "invalid filter name";
}
- apr_hash_set(conf->ct_output_filters, arg2, APR_HASH_KEY_STRING, new);
-
return NULL;
}
/*
void ap_add_output_filters_by_type(request_rec *r)
{
core_dir_config *conf;
- const char *ctype, *ctypes;
+ const char *ctype;
conf = (core_dir_config *)ap_get_module_config(r->per_dir_config,
&core_module);
return;
}
- ctypes = r->content_type;
-
- /* We must be able to handle decorated content-types. */
- while (*ctypes && (ctype = ap_getword(r->pool, &ctypes, ';'))) {
+ /* remove c-t decoration */
+ ctype = ap_field_noparam(r->pool, r->content_type);
+ if (ctype) {
ap_filter_rec_t *ct_filter;
ct_filter = apr_hash_get(conf->ct_output_filters, ctype,
APR_HASH_KEY_STRING);
/* XXX handle checking for non-blocking socket */
while (bytes_written != len) {
- rv = apr_sendv(s, vec + i, nvec - i, &n);
+ rv = apr_socket_sendv(s, vec + i, nvec - i, &n);
bytes_written += n;
if (rv != APR_SUCCESS)
return rv;
*nbytes += n;
/* If the write did not complete, adjust the iovecs and issue
- * apr_sendv again
+ * apr_socket_sendv again
*/
if (bytes_written < len) {
/* Skip over the vectors that have already been written */
do {
apr_size_t tmplen = file_bytes_left;
- rv = apr_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen,
- flags);
+ rv = apr_socket_sendfile(c->client_socket, fd, hdtr, &file_offset, &tmplen,
+ flags);
*bytes_sent += tmplen;
total_bytes_left -= tmplen;
if (!total_bytes_left || rv != APR_SUCCESS) {
rv = apr_file_read(fd, buffer, &sendlen);
while (rv == APR_SUCCESS && sendlen) {
bytes_sent = sendlen;
- rv = apr_send(c->client_socket, &buffer[o], &bytes_sent);
+ rv = apr_socket_send(c->client_socket, &buffer[o], &bytes_sent);
if (rv == APR_SUCCESS) {
sendlen -= bytes_sent; /* sendlen != bytes_sent ==> partial write */
o += bytes_sent; /* o is where we are in the buffer */
"The pathname the server can be reached at"),
AP_INIT_TAKE1("Timeout", set_timeout, NULL, RSRC_CONF,
"Timeout duration (sec)"),
-AP_INIT_FLAG("IdentityCheck", set_idcheck, NULL, RSRC_CONF|ACCESS_CONF,
- "Enable identd (RFC 1413) user lookups - SLOW"),
AP_INIT_FLAG("ContentDigest", set_content_md5, NULL, OR_OPTIONS,
"whether or not to send a Content-MD5 header with each request"),
AP_INIT_TAKE1("UseCanonicalName", set_use_canonical_name, NULL,
"Level of verbosity in error logging"),
AP_INIT_TAKE1("NameVirtualHost", ap_set_name_virtual_host, NULL, RSRC_CONF,
"A numeric IP address:port, or the name of a host"),
-#ifdef _OSD_POSIX
-AP_INIT_TAKE1("BS2000Account", set_bs2000_account, NULL, RSRC_CONF,
- "Name of server User's bs2000 logon account name"),
-#endif
AP_INIT_TAKE1("ServerTokens", set_serv_tokens, NULL, RSRC_CONF,
"Determine tokens displayed in the Server: header - Min(imal), OS or Full"),
AP_INIT_TAKE1("LimitRequestLine", set_limit_req_line, NULL, RSRC_CONF,
OR_ALL, "soft/hard limits for max number of processes per uid"),
#endif
+/* internal recursion stopper */
+AP_INIT_TAKE12("LimitInternalRecursion", set_recursion_limit, NULL, RSRC_CONF,
+ "maximum recursion depth of internal redirects and subrequests"),
+
AP_INIT_TAKE1("ForceType", ap_set_string_slot_lower,
(void *)APR_OFFSETOF(core_dir_config, mime_type), OR_FILEINFO,
"a mime type that overrides other configured type"),
AP_INIT_ITERATE2("AddOutputFilterByType", add_ct_output_filters,
(void *)APR_OFFSETOF(core_dir_config, ct_output_filters), OR_FILEINFO,
"output filter name followed by one or more content-types"),
+AP_INIT_FLAG("AllowEncodedSlashes", set_allow2f, NULL, RSRC_CONF,
+ "Allow URLs containing '/' encoded as '%2F'"),
/*
* These are default configuration directives that mpms can/should
static apr_status_t core_output_filter(ap_filter_t *f, apr_bucket_brigade *b)
{
apr_status_t rv;
- apr_bucket_brigade *more; /* definition moved to foil a gdb bug */
+ apr_bucket_brigade *more;
conn_rec *c = f->c;
core_net_rec *net = f->ctx;
core_output_filter_ctx_t *ctx = net->out_ctx;
apr_read_type_e eblock = APR_NONBLOCK_READ;
+ apr_pool_t *input_pool = b->p;
if (ctx == NULL) {
ctx = apr_pcalloc(c->pool, sizeof(*ctx));
apr_bucket *last_e = NULL; /* initialized for debugging */
apr_bucket *e;
- /* tail of brigade if we need another pass */
- more = NULL;
-
/* one group of iovecs per pass over the brigade */
apr_size_t nvec = 0;
apr_size_t nvec_trailers = 0;
*/
apr_bucket *last_merged_bucket = NULL;
+ /* tail of brigade if we need another pass */
+ more = NULL;
+
/* Iterate over the brigade: collect iovecs and/or a file */
APR_BRIGADE_FOREACH(e, b) {
/* keep track of the last bucket processed */
break;
}
if (APR_BUCKET_IS_FLUSH(e)) {
- more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
+ if (e != APR_BRIGADE_LAST(b)) {
+ more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
+ }
break;
}
}
- /* Completed iterating over the brigades, now determine if we want
+ /* Completed iterating over the brigade, now determine if we want
* to buffer the brigade or send the brigade out on the network.
*
* Save if we haven't accumulated enough bytes to send, and:
}
apr_brigade_destroy(b);
-
+
/* drive cleanups for resources which were set aside
* this may occur before or after termination of the request which
* created the resource
*/
if (ctx->deferred_write_pool) {
- if (more) {
+ if (more && more->p == ctx->deferred_write_pool) {
+ /* "more" belongs to the deferred_write_pool,
+ * which is about to be cleared.
+ */
if (APR_BRIGADE_EMPTY(more)) {
- /* the usual case - prevent the next loop iteration
- * from referencing a brigade which lives in a
- * cleared pool
- */
more = NULL;
}
else {
- /* change the lifetime of "more" to the connection's
- * lifetime
- *
- * XXX a shorter lifetime would be better for long-running
- * keep-alive connections...might be able to use the
- * input brigade's pool
+ /* uh oh... change more's lifetime
+ * to the input brigade's lifetime
*/
apr_bucket_brigade *tmp_more = more;
more = NULL;
- ap_save_brigade(f, &more, &tmp_more, c->pool);
+ ap_save_brigade(f, &more, &tmp_more, input_pool);
}
}
apr_pool_clear(ctx->deferred_write_pool);
}
+
if (rv != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_INFO, rv, c->base_server,
"core_output_filter: writing data to the network");
static int core_post_config(apr_pool_t *pconf, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
{
logio_add_bytes_out = APR_RETRIEVE_OPTIONAL_FN(ap_logio_add_bytes_out);
+ ident_lookup = APR_RETRIEVE_OPTIONAL_FN(ap_ident_lookup);
ap_set_version(pconf);
ap_setup_make_content_type(pconf);