core.c revision 56ab8639aed4d3b2f031d9c1160c5f40af01bdeb
/* Copyright 2001-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_lib.h"
#include "apr_fnmatch.h"
#include "apr_hash.h"
#include "apr_thread_proc.h" /* for RLIMIT stuff */
#include "apr_hooks.h"
#define APR_WANT_IOVEC
#define APR_WANT_STRFUNC
#define APR_WANT_MEMFUNC
#include "apr_want.h"
#define CORE_PRIVATE
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_protocol.h" /* For index_of_response(). Grump. */
#include "http_request.h"
#include "http_vhost.h"
#include "http_main.h" /* For the default_handler below... */
#include "http_log.h"
#include "util_md5.h"
#include "http_connection.h"
#include "apr_buckets.h"
#include "util_filter.h"
#include "util_ebcdic.h"
#include "mpm.h"
#include "mpm_common.h"
#include "scoreboard.h"
#include "mod_core.h"
#include "mod_proxy.h"
#include "ap_listen.h"
#include "mod_so.h" /* for ap_find_loaded_module_symbol */
/* LimitRequestBody handling */
#define AP_DEFAULT_LIMIT_REQ_BODY ((apr_off_t) 0)
/* LimitXMLRequestBody handling */
#define AP_LIMIT_UNSET ((long) -1)
#define AP_MIN_SENDFILE_BYTES (256)
/* maximum include nesting level */
#ifndef AP_MAX_INCLUDE_DEPTH
#define AP_MAX_INCLUDE_DEPTH (128)
#endif
)
/* Server core module... This module provides support for really basic
* server operations, including options and commands which control the
* operation of other modules. Consider this the bureaucracy module.
*
* The core module also defines handlers, etc., do handle just enough
* to allow a server with the core module ONLY to actually serve documents
* (though it slaps DefaultType on all of 'em); this was useful in testing,
* but may not be worth preserving.
*
* This file could almost be mod_core.c, except for the stuff which affects
* the http_conf_globals.
*/
/* Handles for core filters */
/* magic pointer for ErrorDocument xxx "default" */
static char errordocument_default;
{
int i;
/* conf->r and conf->d[_*] are initialized by dirsection() or left NULL */
| OPT_MULTI;
for (i = 0; i < METHODS; ++i) {
}
#ifdef RLIMIT_CPU
#endif
#endif
#ifdef RLIMIT_NPROC
#endif
/* Overriding all negotiation
*/
/*
* Flag for use of inodes in ETags.
*/
conf->allow_encoded_slashes = 0;
return (void *)conf;
}
/*
* Overlay one hash table of ct_output_filters onto another
*/
static void *merge_ct_filters(apr_pool_t *p,
const void *key,
const void *overlay_val,
const void *base_val,
const void *data)
{
while (overlay_info) {
}
while (base_info) {
ap_filter_rec_t *f;
int found = 0;
/* We can't have dups. */
f = cur;
while (f) {
found = 1;
break;
}
f = f->next;
}
if (!found) {
f = apr_pcalloc(p, sizeof(ap_filter_rec_t));
cur = f;
}
}
return cur;
}
{
int i;
/* Create this conf by duplicating the base, replacing elements
* (or creating copies for merging) where new-> values exist.
*/
/* there was no explicit setting of new->opts, so we merge
* preserve the invariant (opts_add & opts_remove) == 0
*/
| new->opts_remove;
}
}
else {
/* otherwise we just copy, because an explicit opts setting
* overrides all earlier +/- modifiers
*/
}
}
}
if (new->ap_default_type) {
}
if (new->ap_auth_type) {
}
if (new->ap_auth_name) {
}
if (new->ap_requires) {
}
}
/* If we merge, the merge-result must have it's own array
*/
for (i = 0; i < RESPONSE_CODES; ++i) {
}
}
}
/* Otherwise we simply use the base->response_code_strings array
*/
}
}
}
}
#ifdef RLIMIT_CPU
}
#endif
}
#endif
#ifdef RLIMIT_NPROC
if (new->limit_nproc) {
}
#endif
}
else
}
/* If we merge, the merge-result must have it's own array
*/
}
/* Otherwise we simply use the base->sec_file array
*/
/* use a separate ->satisfy[] array either way */
for (i = 0; i < METHODS; ++i) {
} else {
}
}
}
}
/* Overriding all negotiation
*/
}
}
if (new->output_filters) {
}
if (new->input_filters) {
}
NULL);
}
else if (new->ct_output_filters) {
}
else if (conf->ct_output_filters) {
/* That memcpy above isn't enough. */
}
/*
* Now merge the setting of the FileETag directive.
*/
conf->etag_remove =
}
else {
}
}
}
}
return (void*)conf;
}
{
int is_virtual = s->is_virtual;
#ifdef GPROF
#endif
/* recursion stopper */
conf->subreq_limit = 0;
return (void *)conf;
}
{
if (!conf->access_name) {
}
if (!conf->ap_document_root) {
}
: base->redirect_limit;
? virt->subreq_limit
: base->subreq_limit;
return conf;
}
/* Add per-directory configuration entry (for <directory> section);
* these are part of the core server config.
*/
{
&core_module);
*new_space = dir_config;
}
{
&core_module);
*new_space = url_config;
}
{
*new_space = url_config;
}
/* We need to do a stable sort, qsort isn't stable. So to make it stable
* we'll be maintaining the original index into the list, and using it
* as the minor key during sorting. The major key is the number of
* components (where the root component is zero).
*/
struct reorder_sort_rec {
int orig_index;
};
{
const struct reorder_sort_rec *a = va;
const struct reorder_sort_rec *b = vb;
/* a regex always sorts after a non-regex
*/
return -1;
}
return 1;
}
/* we always sort next by the number of components
*/
return -1;
}
return 1;
}
/* They have the same number of components, we now have to compare
* the minor key to maintain the original order (from the config.)
*/
return a->orig_index - b->orig_index;
}
{
struct reorder_sort_rec *sortbin;
int nelts;
int i;
if (!nelts) {
/* simple case of already being sorted... */
/* We're not checking this condition to be fast... we're checking
* it to avoid trying to palloc zero bytes, which can trigger some
* memory debuggers to barf
*/
return;
}
/* we have to allocate tmp space to do a stable sort */
apr_pool_create(&tmp, p);
for (i = 0; i < nelts; ++i) {
sortbin[i].orig_index = i;
}
/* and now copy back to the original array */
for (i = 0; i < nelts; ++i) {
}
}
/*****************************************************************
*
* There are some elements of the core config structures in which
* other modules have a legitimate interest (this is ugly, but necessary
* to preserve NCSA back-compatibility). So, we have a bunch of accessors
* here...
*/
{
}
{
&core_module);
}
{
&core_module);
return conf->ap_auth_type;
}
{
&core_module);
return conf->ap_auth_name;
}
{
&core_module);
return conf->ap_default_type
}
{
&core_module);
return conf->ap_document_root;
}
{
&core_module);
return conf->ap_requires;
}
{
&core_module);
}
/* Should probably just get rid of this... the only code that cares is
* part of the core anyway (and in fact, it isn't publicised to other
* modules).
*/
{
/* check for string registered via ap_custom_response() first */
&core_module);
}
/* check for string specified via ErrorDocument */
&core_module);
return NULL;
}
return NULL;
}
}
/* Code from Harald Hanche-Olsen <hanche@imf.unit.no> */
{
if (conn->double_reverse) {
/* already done */
return;
}
/* single reverse failed, so don't bother */
return;
}
if (rv == APR_SUCCESS) {
while (sa) {
return;
}
}
}
}
{
int hostname_lookups;
int ignored_str_is_ip;
if (!str_is_ip) { /* caller doesn't want to know */
}
*str_is_ip = 0;
/* If we haven't checked the host name, and we want to */
if (dir_config) {
if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) {
}
}
else {
/* the default */
}
if (type != REMOTE_NOLOOKUP
&& (type == REMOTE_DOUBLE_REV
|| hostname_lookups != HOSTNAME_LOOKUP_OFF)) {
== APR_SUCCESS) {
if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) {
}
}
}
/* if failed, set it to the NULL string to indicate error */
}
}
if (type == REMOTE_DOUBLE_REV) {
return NULL;
}
}
/*
* Return the desired information; either the remote DNS name, if found,
* or either NULL (if the hostname was requested) or the IP address
* (if any identifier was requested).
*/
return conn->remote_host;
}
else {
return NULL;
}
else {
*str_is_ip = 1;
}
}
}
/*
* Optional function coming from mod_ident, used for looking up ident user
*/
{
return r->connection->remote_logname;
}
if (ident_lookup) {
return ident_lookup(r);
}
return NULL;
}
/* There are two options regarding what the "name" of a server is. The
* "canonical" name as defined by ServerName and Port, or the "client's
* name" as supplied by a possible Host: header or full URI. We never
* trust the port passed in the client's headers, we always use the
* port of the actual socket.
*
* The DNS option to UseCanonicalName causes this routine to do a
* reverse lookup on the local IP address of the connection and use
* that for the ServerName. This makes its value more reliable while
* at the same time allowing Demon's magic virtual hosting to work.
* The assumption is that DNS lookups are sufficiently quick...
* -- fanf 1998-10-03
*/
{
core_dir_config *d;
&core_module);
if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) {
}
if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
r->server->server_hostname);
else {
}
}
return conn->local_host;
}
/* default */
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
}
#endif
return plain_server_name;
}
{
core_dir_config *d =
if (d->use_canonical_name == USE_CANONICAL_NAME_OFF
|| d->use_canonical_name == USE_CANONICAL_NAME_DNS) {
/* With UseCanonicalName off Apache will form self-referential
* URLs using the hostname and port supplied by the client if
* any are supplied (otherwise it will use the canonical name).
*/
ap_default_port(r);
}
else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */
/* With UseCanonicalName on (and in all versions prior to 1.3)
* Apache will use the hostname and port specified in the
* ServerName directive to construct a canonical name for the
* server. (If no port was specified in the ServerName
* directive, Apache uses the port supplied by the client if
* any is supplied, and finally the default port for the protocol
* used.
*/
ap_default_port(r);
}
/* default */
return port;
}
request_rec *r)
{
unsigned port = ap_get_server_port(r);
const char *host = get_server_name_for_url(r);
if (ap_is_default_port(port, r)) {
}
}
{
core_dir_config *d =
if (d->limit_req_body == AP_LIMIT_REQ_BODY_UNSET) {
return AP_DEFAULT_LIMIT_REQ_BODY;
}
return d->limit_req_body;
}
/*****************************************************************
*
* Commands... this module handles almost all of the NCSA httpd.conf
* commands, but most of the old srm.conf is in the the modules.
*/
/* returns a parent if it matches the given directive */
const char *what)
{
/* ### it would be nice to have atom-ized directives */
return dirp;
}
return NULL;
}
unsigned forbidden)
{
? ">" : "";
const ap_directive_t *found;
" cannot occur within <VirtualHost> section", NULL);
}
" cannot occur within <Limit> section", NULL);
}
"section", NULL);
}
/* EXEC_ON_READ must be NOT_IN_DIR_LOC_FILE, if not, it will
* (deliberately) segfault below in the individual tests...
*/
return NULL;
}
}
if (((forbidden & NOT_IN_DIRECTORY)
|| ((forbidden & NOT_IN_LOCATION)
|| ((forbidden & NOT_IN_FILES)
"> section", NULL);
}
return NULL;
}
const char *arg)
{
return err;
}
return NULL;
}
#ifdef GPROF
{
return err;
}
return NULL;
}
#endif /*GPROF*/
{
core_dir_config *d = d_;
return err;
}
}
}
else {
d->add_default_charset_name = arg;
}
return NULL;
}
const char *arg)
{
return err;
}
/* Make it absolute, relative to ServerRoot */
/* TODO: ap_configtestonly && ap_docrootcheck && */
"Warning: DocumentRoot [%s] does not exist",
arg);
}
else {
return "DocumentRoot must be a directory";
}
}
return NULL;
}
const char *string)
{
int idx;
apr_pcalloc(r->pool,
}
}
{
return err;
}
/* 1st parameter should be a 3 digit number, which we recognize;
* convert it into an array index
*/
if (error_number == HTTP_INTERNAL_SERVER_ERROR) {
}
}
/* Heuristic to determine second argument. */
else if (msg[0] == '/')
what = LOCAL_PATH;
what = REMOTE_PATH;
else
/* The entry should be ignored if it is a full URL for a 401 error */
"cannot use a full URL in a 401 ErrorDocument "
"directive --- ignoring!");
}
else { /* Store it... */
sizeof(*conf->response_code_strings) *
}
/* special case: ErrorDocument 404 default restores the
* canned server error response
*/
}
else {
/* hack. Prefix a " if it is a msg; as that is what
* http_protocol.c relies on to distinguish between
* a msg and a (local) path.
*/
}
}
return NULL;
}
const char *l)
{
int first = 1;
char *w, *p = (char *) l;
char *tok_state;
if (first) {
p = NULL;
first = 0;
}
if (!strcasecmp(w, "Indexes")) {
opt = OPT_INDEXES;
}
else if (!strcasecmp(w, "Includes")) {
opt = OPT_INCLUDES;
}
else if (!strcasecmp(w, "IncludesNOEXEC")) {
}
else if (!strcasecmp(w, "FollowSymLinks")) {
opt = OPT_SYM_LINKS;
}
else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
opt = OPT_SYM_OWNER;
}
else if (!strcasecmp(w, "ExecCGI")) {
opt = OPT_EXECCGI;
}
else if (!strcasecmp(w, "MultiViews")) {
}
}
else if (!strcasecmp(w, "None")) {
}
else if (!strcasecmp(w, "All")) {
}
else {
}
}
return NULL;
}
{
core_dir_config *d = d_;
char *w;
char *k, *v;
return err;
}
/* Throw a warning if we're in <Location> or <Files> */
"Useless use of AllowOverride in line %d.",
}
while (l[0]) {
k = w;
v = strchr(k, '=');
if (v) {
*v++ = '\0';
}
if (!strcasecmp(w, "Limit")) {
}
else if (!strcasecmp(k, "Options")) {
d->override |= OR_OPTIONS;
if (v)
else
d->override_opts = OPT_ALL;
}
else if (!strcasecmp(w, "FileInfo")) {
d->override |= OR_FILEINFO;
}
else if (!strcasecmp(w, "AuthConfig")) {
d->override |= OR_AUTHCFG;
}
else if (!strcasecmp(w, "Indexes")) {
d->override |= OR_INDEXES;
}
else if (!strcasecmp(w, "None")) {
}
else if (!strcasecmp(w, "All")) {
}
else {
}
}
return NULL;
}
{
core_dir_config *d = d_;
int first = 1;
char action;
while (l[0]) {
action = '\0';
if (*w == '+' || *w == '-') {
action = *(w++);
}
else if (first) {
first = 0;
}
if (!strcasecmp(w, "Indexes")) {
opt = OPT_INDEXES;
}
else if (!strcasecmp(w, "Includes")) {
opt = OPT_INCLUDES;
}
else if (!strcasecmp(w, "IncludesNOEXEC")) {
}
else if (!strcasecmp(w, "FollowSymLinks")) {
opt = OPT_SYM_LINKS;
}
else if (!strcasecmp(w, "SymLinksIfOwnerMatch")) {
opt = OPT_SYM_OWNER;
}
else if (!strcasecmp(w, "ExecCGI")) {
opt = OPT_EXECCGI;
}
else if (!strcasecmp(w, "MultiViews")) {
}
}
else if (!strcasecmp(w, "None")) {
}
else if (!strcasecmp(w, "All")) {
}
else {
}
}
else if (action == '-') {
/* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
d->opts_remove |= opt;
}
else if (action == '+') {
d->opts_remove &= ~opt;
}
else {
}
}
return NULL;
}
/*
* Note what data should be used when forming file ETag values.
* It would be nicer to do this as an ITERATE, but then we couldn't
* remember the +/- state properly.
*/
const char *args_p)
{
char action;
char *token;
const char *args;
int valid;
int first;
int explicit;
first = 1;
explicit = 0;
while (args[0] != '\0') {
action = '*';
bit = ETAG_UNSET;
valid = 1;
token++;
}
else {
/*
* The occurrence of an absolute setting wipes
* out any previous relative ones. The first such
* occurrence forgets any inherited ones, too.
*/
if (first) {
first = 0;
}
}
if (action != '*') {
valid = 0;
}
else {
explicit = 1;
}
}
if (action != '*') {
valid = 0;
}
else {
explicit = 1;
}
}
}
bit = ETAG_MTIME;
}
bit = ETAG_INODE;
}
else {
" directive", NULL);
}
if (! valid) {
token, "' cannot be used with '+' or '-'",
NULL);
}
if (action == '+') {
/*
* Make sure it's in the 'add' list and absent from the
* 'subtract' list.
*/
}
else if (action == '-') {
}
else {
/*
* Non-relative values wipe out any + or - values
* accumulated so far.
*/
explicit = 1;
}
}
/*
* Any setting at all will clear the 'None' and 'Unset' bits.
*/
}
}
if (explicit) {
}
}
return NULL;
}
const char *arg)
{
core_dir_config *d = d_;
return err;
}
d->enable_mmap = ENABLE_MMAP_ON;
}
d->enable_mmap = ENABLE_MMAP_OFF;
}
else {
return "parameter must be 'on' or 'off'";
}
return NULL;
}
const char *arg)
{
core_dir_config *d = d_;
return err;
}
}
}
else {
return "parameter must be 'on' or 'off'";
}
return NULL;
}
{
core_dir_config *c = c_;
int satisfy = SATISFY_NOSPEC;
int i;
}
}
else {
return "Satisfy either 'any' or 'all'.";
}
for (i = 0; i < METHODS; ++i) {
}
}
return NULL;
}
{
require_line *r;
core_dir_config *c = c_;
if (!c->ap_requires) {
}
return NULL;
}
/*
* Report a missing-'>' syntax error.
*/
{
"> directive missing closing '>'", NULL);
}
void *dummy,
const char *arg)
{
const char *limited_methods;
apr_int64_t limited = 0;
const char *errmsg;
return err;
}
return unclosed_directive(cmd);
}
while (limited_methods[0]) {
int methnum;
/* check for builtin or module registered method number */
return "TRACE cannot be controlled by <Limit>";
}
/* method has not been registered yet, but resorce restriction
* is always checked before method handling, so register it.
*/
}
}
/* Killing two features with one function,
* if (tog == NULL) <Limit>, else <LimitExcept>
*/
return errmsg;
}
* the same problem!!!
* We use this in <DirectoryMatch> and <FilesMatch>, to ensure that
* people don't get bitten by wrong-cased regex matches
*/
#ifdef WIN32
#else
#define USE_ICASE 0
#endif
{
const char *errmsg;
return err;
}
return unclosed_directive(cmd);
}
if (!arg) {
return "<DirectoryMatch > block must specify a path";
else
return "<Directory > block must specify a path";
}
return "<Directory ~ > block must specify a path";
if (!r) {
return "Regex could not be compiled";
}
}
if (!r) {
return "Regex could not be compiled";
}
}
{
char *newpath;
/*
* Ensure that the pathname is canonical, and append the trailing /
*/
"\"> path is invalid.", NULL);
}
}
/* initialize our config and fetch it */
return errmsg;
conf->r = r;
/* Make this explicit - the "/" root has 0 elements, that is, we
* will always merge it, and it will always sort and merge first.
* All others are sorted and tested by the number of slashes.
*/
conf->d_components = 0;
else
if (*arg != '\0') {
"> arguments not (yet) supported.", NULL);
}
return NULL;
}
{
const char *errmsg;
return err;
}
return unclosed_directive(cmd);
}
if (!r) {
return "Regex could not be compiled";
}
}
if (!r) {
return "Regex could not be compiled";
}
}
/* initialize our config and fetch it */
return errmsg;
conf->r = r;
if (*arg != '\0') {
"> arguments not (yet) supported.", NULL);
}
return NULL;
}
{
const char *errmsg;
core_dir_config *c = mconfig;
return err;
}
return unclosed_directive(cmd);
}
/* Only if not an .htaccess file */
if (!old_path) {
}
if (!r) {
return "Regex could not be compiled";
}
}
if (!r) {
return "Regex could not be compiled";
}
}
else {
char *newpath;
/* Ensure that the pathname is canonical, but we
"\"> is invalid.", NULL);
}
/* initialize our config and fetch it */
return errmsg;
conf->r = r;
if (*arg != '\0') {
"> arguments not (yet) supported.", NULL);
}
return NULL;
}
{
return unclosed_directive(cmd);
}
if (not) {
arg++;
}
/* search prelinked stuff */
if (!found) {
break;
}
}
}
/* search dynamic stuff */
if (!found) {
if (check_symbol) {
}
}
const char *retval;
return retval;
}
else {
}
}
{
char **defines;
int i;
for (i = 0; i < ap_server_config_defines->nelts; i++) {
return 1;
}
}
return 0;
}
{
const char *endp;
int defined;
int not = 0;
return unclosed_directive(cmd);
}
if (arg[0] == '!') {
not = 1;
arg++;
}
defined = ap_exists_config_define(arg);
const char *retval;
return retval;
}
else {
}
}
/* httpd.conf commands... beginning with the <VirtualHost> business */
const char *arg)
{
const char *errmsg;
return err;
}
return unclosed_directive(cmd);
}
/* FIXME: There's another feature waiting to happen here -- since you
you might want to use it to group common definitions and then
define other "subhosts" with their individual differences. But
personally I'd rather just do it with a macro preprocessor. -djg */
if (main_server->is_virtual) {
return "<VirtualHost> doesn't nest!";
}
if (errmsg) {
return errmsg;
}
main_server->next = s;
s->lookup_defaults);
return errmsg;
}
const char *arg)
{
return "ServerAlias only used in <VirtualHost>";
}
while (*arg) {
if (ap_is_matchexp(name)) {
}
else {
}
}
return NULL;
}
const char *arg)
{
/* This one's pretty generic... */
return err;
}
return NULL;
}
{
const char *portstr;
int port;
return err;
}
if (portstr) {
portstr++;
"\" is outside the appropriate range "
"(i.e., 1..65535).", NULL);
}
}
else {
port = 0;
}
return NULL;
}
const char *arg)
{
core_dir_config *d = d_;
return err;
}
d->server_signature = srv_sig_on;
}
d->server_signature = srv_sig_off;
}
}
else {
return "ServerSignature: use one of: off | on | email";
}
return NULL;
}
const char *arg)
{
return err;
}
return "ServerRoot must be a valid directory";
}
return NULL;
}
{
return err;
}
return NULL;
}
{
core_dir_config *d = d_;
return err;
}
d->allow_encoded_slashes = arg != 0;
return NULL;
}
const char *arg)
{
core_dir_config *d = d_;
return err;
}
}
}
}
else {
return "parameter must be 'on', 'off', or 'double'";
}
return NULL;
}
const char *arg)
{
return err;
}
return NULL;
}
{
core_dir_config *d = d_;
return err;
}
d->content_md5 = arg != 0;
return NULL;
}
{
core_dir_config *d = d_;
}
}
}
else {
return "AcceptPathInfo must be set to on, off or default";
}
return NULL;
}
const char *arg)
{
core_dir_config *d = d_;
return err;
}
}
}
}
else {
return "parameter must be 'on', 'off', or 'dns'";
}
return NULL;
}
const char *name)
{
unsigned *recursion;
void *data;
if (data) {
}
else {
*recursion = 0;
}
if (++*recursion > AP_MAX_INCLUDE_DEPTH) {
*recursion = 0;
"You have probably a recursion somewhere.",
}
if (!conffile) {
*recursion = 0;
}
if (error) {
*recursion = 0;
return error;
}
/* recursion level done */
if (*recursion) {
--*recursion;
}
return NULL;
}
{
char *str;
return err;
}
}
}
}
}
}
}
}
}
else {
return "LogLevel requires level keyword: one of "
}
}
else {
return "LogLevel requires level keyword";
}
return NULL;
}
{
char sport[20];
&core_module);
return "";
}
" Server at <a href=\"",
"\">",
"</a> Port ", sport,
"</address>\n", NULL);
}
" Server at ",
" Port ", sport,
"</address>\n", NULL);
}
/*
* Load an authorisation realm into our location configuration, applying the
* usual rules that apply to realms.
*/
const char *word1)
{
return NULL;
}
/*
* Handle a request to include the server's OS platform in the Server
* response header field (the ServerTokens directive). Unfortunately
* this requires a new global in order to communicate the setting back to
* http_main so it can insert the information in the right place in the
* string.
*/
static char *server_version = NULL;
static int version_locked = 0;
enum server_token_type {
SrvTk_MAJOR, /* eg: Apache/2 */
SrvTk_MINOR, /* eg. Apache/2.0 */
SrvTk_MINIMAL, /* eg: Apache/2.0.41 */
SrvTk_OS, /* eg: Apache/2.0.41 (UNIX) */
SrvTk_FULL, /* eg: Apache/2.0.41 (UNIX) PHP/4.2.2 FooBar/1.2b */
SrvTk_PRODUCT_ONLY /* eg: Apache */
};
{
version_locked = 0;
return APR_SUCCESS;
}
{
}
AP_DECLARE(const char *) ap_get_server_version(void)
{
}
{
if (! version_locked) {
/*
* If the version string is null, register our cleanup to reset the
* pointer on pool destruction. We also know that, if NULL,
* we are adding the original SERVER_BASEVERSION string.
*/
if (server_version == NULL) {
}
else {
/*
* Tack the given component identifier to the end of
* the existing string.
*/
}
}
}
/*
* This routine adds the real server base identity to the version string,
* and then locks out changes until the next reconfig.
*/
{
if (ap_server_tokens == SrvTk_PRODUCT_ONLY) {
}
else if (ap_server_tokens == SrvTk_MINIMAL) {
}
else if (ap_server_tokens == SrvTk_MINOR) {
}
else if (ap_server_tokens == SrvTk_MAJOR) {
}
else {
}
/*
* Lock the server_version string if we're not displaying
* the full set of tokens
*/
if (ap_server_tokens != SrvTk_FULL) {
}
}
const char *arg)
{
return err;
}
}
}
}
}
}
else {
}
return NULL;
}
const char *arg)
{
int lim;
return err;
}
if (lim < 0) {
"\" must be a non-negative integer", NULL);
}
return NULL;
}
const char *arg)
{
int lim;
return err;
}
if (lim < 0) {
"\" must be a non-negative integer (0 = no limit)",
NULL);
}
if (lim > DEFAULT_LIMIT_REQUEST_FIELDSIZE) {
"must not exceed the precompiled maximum of %d",
}
return NULL;
}
const char *arg)
{
int lim;
return err;
}
if (lim < 0) {
"\" must be a non-negative integer (0 = no limit)",
NULL);
}
return NULL;
}
const char *arg)
{
char *errp;
return err;
}
return "LimitRequestBody argument is not parsable.";
}
return "LimitRequestBody requires a non-negative integer.";
}
return NULL;
}
const char *arg)
{
return err;
}
if (conf->limit_xml_body < 0)
return "LimitXMLRequestBody requires a non-negative integer.";
return NULL;
}
{
return AP_DEFAULT_LIMIT_XML_BODY;
}
#if !defined (RLIMIT_CPU) || !(defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS)) || !defined (RLIMIT_NPROC)
{
return NULL;
}
#endif
#ifdef RLIMIT_CPU
{
return NULL;
}
#endif
{
#if defined(RLIMIT_AS)
#elif defined(RLIMIT_DATA)
#elif defined(RLIMIT_VMEM)
#endif
return NULL;
}
#endif
#ifdef RLIMIT_NPROC
{
return NULL;
}
#endif
{
&core_module);
if (limit <= 0) {
return "The recursion limit must be greater than zero.";
}
if (limit < 4) {
"Limiting internal redirects to very low numbers may "
"cause normal requests to fail.");
}
if (arg2) {
if (limit <= 0) {
return "The recursion limit must be greater than zero.";
}
if (limit < 4) {
"Limiting the subrequest depth to a very low level may"
" cause normal requests to fail.");
}
}
return NULL;
}
static void log_backtrace(const request_rec *r)
{
const request_rec *top = r;
"redirected from r->uri = %s",
}
"subrequested from r->uri = %s",
}
}
}
/*
* check whether redirect limit is reached
*/
{
&core_module);
const request_rec *top = r;
? conf->subreq_limit
/* uuh, too much. */
"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;
}
}
/* uuh, too much. */
"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;
}
}
}
/* recursion state: ok */
return 0;
}
{
const char *filter_name;
if (!conf->ct_output_filters) {
}
else {
/* find last entry */
if (old) {
}
}
}
while (*arg &&
/* We found something, so let's append it. */
if (old) {
}
else {
}
}
if (!new) {
return "invalid filter name";
}
return NULL;
}
/*
* Insert filters requested by the AddOutputFilterByType
* configuration directive. We cannot add filters based
* on content-type until after the handler has started
* to run. Only then do we reliably know the content-type.
*/
void ap_add_output_filters_by_type(request_rec *r)
{
const char *ctype;
&core_module);
/* We can't do anything with proxy requests, no content-types or if
* we don't have a filter configured.
*/
!conf->ct_output_filters) {
return;
}
/* remove c-t decoration */
if (ctype) {
while (ct_filter) {
}
}
return;
}
/* Note --- ErrorDocument will now work from .htaccess files.
* The AllowOverride of Fileinfo allows webmasters to turn it off
*/
static const command_rec core_cmds[] = {
/* Old access config file commands */
"Container for directives affecting resources located in the specified "
"directories"),
"Container for directives affecting resources accessed through the "
"specified URL paths"),
"Container to map directives to a particular virtual host, takes one or "
"more host addresses"),
"Container for directives affecting files matching specified patterns"),
"Container for authentication directives when accessed using specified HTTP "
"methods"),
"Container for authentication directives to be applied when any HTTP "
"method other than those specified is used to access the resource"),
"Container for directives based on existance of specified modules"),
"Container for directives based on existance of command line defines"),
"Container for directives affecting resources located in the "
"specified directories"),
"Container for directives affecting resources accessed through the "
"specified URL paths"),
"Container for directives affecting files matching specified patterns"),
"An HTTP authorization type (e.g., \"Basic\")"),
"The authentication realm (e.g. \"Members Only\")"),
"Selects which authenticated users or groups may access a protected space"),
"access policy if both allow and require used ('all' or 'any')"),
#ifdef GPROF
"Directory to plop gmon.out files"),
#endif
"The name of the default charset to add to any Content-Type without one or 'Off' to disable"),
"Set to on or off for PATH_INFO to be accepted by handlers, or default for the per-handler preference"),
/* Old resource config file commands */
"Name(s) of per-directory config files (default: .htaccess)"),
"Root directory of the document tree"),
"Change responses for HTTP errors"),
"Controls what groups of directives can be configured by per-directory "
"config files"),
"Set a number of attributes for a given directory"),
OR_FILEINFO, "the default MIME type for untypable files"),
"Specify components used to construct a file's ETag"),
"Controls whether memory-mapping may be used to read files"),
"Controls whether sendfile may be used to transmit files"),
/* Old server config file commands */
"Port was replaced with Listen in Apache 2.0"),
"\"on\" to enable, \"off\" to disable reverse DNS lookups, or \"double\" to "
"enable double-reverse DNS lookups"),
"The email address of the server administrator"),
"The hostname and port of the server"),
"Common directory of server-related files (logs, confs, etc.)"),
"The filename of the error log"),
"A name or names alternately used to access the server"),
"The pathname the server can be reached at"),
"Timeout duration (sec)"),
"whether or not to send a Content-MD5 header with each request"),
"How to work out the ServerName : Port when constructing URLs"),
/* TODO: RlimitFoo should all be part of mod_cgi, not in the core */
/* TODO: ListenBacklog in MPM */
"Name of the config file to be included"),
"Level of verbosity in error logging"),
"A numeric IP address:port, or the name of a host"),
"Determine tokens displayed in the Server: header - Min(imal), OS or Full"),
"Limit on maximum size of an HTTP request line"),
"Limit on maximum size of an HTTP request header field"),
"Limit (0 = unlimited) on max number of header fields in a request message"),
"Limit (in bytes) on maximum size of request message body"),
"Limit (in bytes) on maximum size of an XML-based request "
"body"),
/* System Resource Controls */
#ifdef RLIMIT_CPU
#else
#endif
#else
#endif
#ifdef RLIMIT_NPROC
#else
#endif
/* internal recursion stopper */
"maximum recursion depth of internal redirects and subrequests"),
"a mime type that overrides other configured type"),
"a handler name that overrides any other configured handler"),
"filter (or ; delimited list of filters) to be run on the request content"),
"filter (or ; delimited list of filters) to be run on the request body"),
"output filter name followed by one or more content-types"),
"Allow URLs containing '/' encoded as '%2F'"),
/*
* pay attention to. If an mpm wishes to use these, they should
* #defined them in mpm.h.
*/
#ifdef AP_MPM_WANT_SET_PIDFILE
"A file for logging the server process ID"),
#endif
#ifdef AP_MPM_WANT_SET_SCOREBOARD
"A file for Apache to maintain runtime process management information"),
#endif
#ifdef AP_MPM_WANT_SET_LOCKFILE
"The lockfile used when Apache needs to lock the accept() call"),
#endif
#ifdef AP_MPM_WANT_SET_MAX_REQUESTS
"Maximum number of requests a particular child serves before dying."),
#endif
#ifdef AP_MPM_WANT_SET_COREDUMPDIR
"The location of the directory Apache changes to before dumping core"),
#endif
#endif
#ifdef AP_MPM_WANT_SET_MAX_MEM_FREE
"Maximum number of 1k blocks a particular childs allocator may hold."),
#endif
#ifdef AP_MPM_WANT_SET_STACKSIZE
"Size in bytes of stack used by threads handling client connections"),
#endif
"Controls whether exception hook may be called after a crash"),
#endif
{ NULL }
};
/*****************************************************************
*
* Core handlers for various phases of server operation...
*/
{
/* XXX this seems too specific, this should probably become
* some general-case test
*/
if (r->proxyreq) {
return HTTP_FORBIDDEN;
}
"Invalid URI in request %s", r->the_request);
return HTTP_BAD_REQUEST;
}
{
/* skip all leading /'s (e.g. http://localhost///foo)
* so we are looking at only the relative path.
*/
while (*path == '/') {
++path;
}
| APR_FILEPATH_SECUREROOT, r->pool))
!= APR_SUCCESS) {
"Cannot map %s to file", r->the_request);
return HTTP_FORBIDDEN;
}
r->canonical_filename = r->filename;
}
else {
/*
* Make sure that we do not mess up the translation by adding two
* /'s in a row. This happens under windows when the document
* root ends with a /
*/
/* skip all leading /'s (e.g. http://localhost///foo)
* so we are looking at only the relative path.
*/
while (*path == '/') {
++path;
}
| APR_FILEPATH_SECUREROOT, r->pool))
!= APR_SUCCESS) {
"Cannot map %s to file", r->the_request);
return HTTP_FORBIDDEN;
}
r->canonical_filename = r->filename;
}
return OK;
}
/*****************************************************************
*
* Test the filesystem name through directory_walk and file_walk
*/
static int core_map_to_storage(request_rec *r)
{
int access_status;
if ((access_status = ap_directory_walk(r))) {
return access_status;
}
if ((access_status = ap_file_walk(r))) {
return access_status;
}
return OK;
}
static int core_override_type(request_rec *r)
{
&core_module);
/* Check for overrides with ForceType / SetHandler
*/
/* Deal with the poor soul who is trying to force path_info to be
* accepted within the core_handler, where they will let the subreq
* address its contents. This is toggled by the user in the very
* beginning of the fixup phase, so modules should override the user's
* discretion in their own module fixup phase. It is tristate, if
* the user doesn't specify, the result is 2 (which the module may
* interpret to its own customary behavior.) It won't be touched
* if the value is no longer undefined (2), so any module changing
* the value prior to the fixup phase OVERRIDES the user's choice.
*/
if ((r->used_path_info == AP_REQ_DEFAULT_PATH_INFO)
}
return OK;
}
static int default_handler(request_rec *r)
{
conn_rec *c = r->connection;
apr_bucket *e;
core_dir_config *d;
int errstatus;
* remove this support or coordinate when to use the filter vs.
* when to use this code
* The current choice of when to compute the md5 here matches the 1.3
* support fairly closely (unlike 1.3, we don't handle computing md5
* when the charset is translated).
*/
int bld_content_md5;
&core_module);
/* If filters intend to consume the request body, they must
* register an InputFilter to slurp the contents of the POST
* data from the POST input stream. It no longer exists when
* the output filters are invoked by the default handler.
*/
return errstatus;
}
"File does not exist: %s", r->filename);
return HTTP_NOT_FOUND;
}
/* Don't try to serve a dir. Some OSs do weird things with
* raw I/O on a dir.
*/
"Attempt to serve directory: %s", r->filename);
return HTTP_NOT_FOUND;
}
if ((r->used_path_info != AP_REQ_ACCEPT_PATH_INFO) &&
{
/* default to reject */
"File does not exist: %s",
return HTTP_NOT_FOUND;
}
/* We understood the (non-GET) method, but it might not be legal for
this particular resource. Check to see if the 'deliver_script'
flag is set. If so, then we go ahead and deliver the file since
it isn't really content (only GET normally returns content).
Note: based on logic further above, the only possible non-GET
method at this point is POST. In the future, we should enable
script delivery for all methods. */
if (r->method_number != M_GET) {
if (!req_cfg->deliver_script) {
/* The flag hasn't been set for this request. Punt. */
"This resource does not accept the %s method.",
r->method);
return HTTP_METHOD_NOT_ALLOWED;
}
}
#if APR_HAS_SENDFILE
| ((d->enable_sendfile == ENABLE_SENDFILE_OFF)
? 0 : APR_SENDFILE_ENABLED)
#endif
, 0, r->pool)) != APR_SUCCESS) {
"file permissions deny server access: %s", r->filename);
return HTTP_FORBIDDEN;
}
ap_set_etag(r);
return errstatus;
}
if (bld_content_md5) {
}
/* For platforms where the size of the file may be larger than
* that which can be stored in a single bucket (where the
* length field is an apr_size_t), split it into several
* buckets: */
if (sizeof(apr_off_t) > sizeof(apr_size_t)
c->bucket_alloc);
while (fsize > AP_MAX_SENDFILE) {
apr_bucket *ce;
apr_bucket_copy(e, &ce);
e->start += AP_MAX_SENDFILE;
fsize -= AP_MAX_SENDFILE;
}
}
else
r->pool, c->bucket_alloc);
#if APR_HAS_MMAP
if (d->enable_mmap == ENABLE_MMAP_OFF) {
(void)apr_bucket_file_enable_mmap(e, 0);
}
#endif
e = apr_bucket_eos_create(c->bucket_alloc);
}
else { /* unusual method (not GET or POST) */
if (r->method_number == M_INVALID) {
"Invalid method in request %s", r->the_request);
return HTTP_NOT_IMPLEMENTED;
}
if (r->method_number == M_OPTIONS) {
return ap_send_http_options(r);
}
return HTTP_METHOD_NOT_ALLOWED;
}
}
/* Optional function coming from mod_logio, used for logging of output
* traffic
*/
{
return OK;
}
static void core_insert_filter(request_rec *r)
{
&core_module);
if (filters) {
}
}
if (filters) {
}
}
}
{
return APR_SUCCESS;
}
{
return num_request_notes++;
}
{
if (note_num >= num_request_notes) {
return NULL;
}
req_cfg = (core_request_config *)
if (!req_cfg) {
return NULL;
}
}
static int core_create_req(request_rec *r)
{
/* Alloc the config struct and the array of request notes in
* a single block for efficiency
*/
sizeof(void *) * num_request_notes);
/* ### temporarily enable script delivery as the default */
if (r->main) {
}
else {
if (!r->prev) {
NULL, r, r->connection);
}
}
/* Begin by presuming any module can make its own path_info assumptions,
* until some module interjects and changes the value.
*/
return OK;
}
{
return core_create_req(pr);
}
{
/* Got a connection structure, so initialize what fields we can
* (the rest are zeroed out by pcalloc).
*/
!= APR_SUCCESS) {
"apr_socket_addr_get(APR_LOCAL)");
return NULL;
}
!= APR_SUCCESS) {
"apr_socket_addr_get(APR_REMOTE)");
return NULL;
}
c->base_server = server;
c->bucket_alloc = alloc;
return c;
}
{
/* The Nagle algorithm says that we should delay sending partial
* packets in hopes of getting more data. We don't want to do
* this; we are not telnet. There are bad interactions between
* persistent connections and Nagle's algorithm that have very severe
* performance penalties. (Failing to disable Nagle is not much of a
* problem with simple HTTP.)
*/
/* expected cause is that the client disconnected already,
* hence the debug level
*/
"apr_socket_opt_set(APR_TCP_NODELAY)");
}
#endif
net->c = c;
return DONE;
}
static void register_hooks(apr_pool_t *p)
{
/* create_connection and install_transport_filters are
* hooks that should always be APR_HOOK_REALLY_LAST to give other
* modules the opportunity to install alternate network transports
* and stop other functions from being run.
*/
/* FIXME: I suspect we can eliminate the need for these do_nothings - Ben */
/* register the core's insert_filter hook and register core-provided
* filters
*/
}
create_core_dir_config, /* create per-directory config structure */
merge_core_dir_configs, /* merge per-directory config structures */
create_core_server_config, /* create per-server config structure */
merge_core_server_configs, /* merge per-server config structures */
core_cmds, /* command apr_table_t */
register_hooks /* register hooks */
};