core.c revision fde6633c32d88dbb31062017d13fac616fce41e5
/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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"
#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 "util_mutex.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 */
#if defined(RLIMIT_CPU) || defined (RLIMIT_DATA) || defined (RLIMIT_VMEM) || defined(RLIMIT_AS) || defined (RLIMIT_NPROC)
#include "unixd.h"
#endif
/* 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., to handle just enough
* to allow a server with the core module ONLY to actually serve documents.
*
* This file could almost be mod_core.c, except for the stuff which affects
* the http_conf_globals.
*/
/* Handles for core filters */
/* Provide ap_document_root_check storage and default value = true */
/* magic pointer for ErrorDocument xxx "default" */
static char errordocument_default;
{
/* conf->r and conf->d[_*] are initialized by dirsection() or left NULL */
#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;
/* If Includes was enabled with exec in the base config, but
* was enabled without exec in the new config, then disable
* exec in the merged set. */
== OPT_INCLUDES)) {
}
}
else {
/* otherwise we just copy, because an explicit opts setting
* overrides all earlier +/- modifiers
*/
}
}
}
}
/* 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
*/
}
}
/* 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;
}
#ifndef ACCEPT_FILTER_NAME
#define ACCEPT_FILTER_NAME "httpready"
#ifdef __FreeBSD_version
#define ACCEPT_FILTER_NAME "dataready"
#endif
#endif
#endif
#endif
{
int is_virtual = s->is_virtual;
/* global-default / global-only settings */
if (!is_virtual) {
/* A mapping only makes sense in the global context */
#else
#endif
}
/* pcalloc'ed - we have NULL's/0's
else ** is_virtual ** {
conf->ap_document_root = NULL;
conf->access_name = NULL;
conf->accf_map = NULL;
}
*/
/* initialization, no special case for global context */
/* pcalloc'ed - we have NULL's/0's
conf->gprof_dir = NULL;
** recursion stopper; 0 == unset
conf->redirect_limit = 0;
conf->subreq_limit = 0;
conf->protocol = NULL;
*/
return (void *)conf;
}
{
if (virt->ap_document_root)
if (virt->access_name)
/* XXX optimize to keep base->sec_ pointers if virt->sec_ array is empty */
if (virt->redirect_limit)
if (virt->subreq_limit)
/* no action for virt->accf_map, not allowed per-vhost */
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);
}
/*
* Optional function coming from mod_authn_core, used for
* retrieving the type of autorization
*/
{
if (authn_ap_auth_type) {
return authn_ap_auth_type(r);
}
return NULL;
}
/*
* Optional function coming from mod_authn_core, used for
* retrieving the authorization realm
*/
{
if (authn_ap_auth_name) {
return authn_ap_auth_name(r);
}
return NULL;
}
/*
* Optional function coming from mod_access_compat, used to determine how
access control interacts with authentication/authorization
*/
{
if (access_compat_ap_satisfies) {
return access_compat_ap_satisfies(r);
}
return SATISFY_NOSPEC;
}
{
&core_module);
return conf->ap_document_root;
}
/* 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.
*
* 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;
const char *retval;
&core_module);
switch (d->use_canonical_name) {
case USE_CANONICAL_NAME_ON:
break;
case USE_CANONICAL_NAME_DNS:
r->server->server_hostname);
else {
}
}
break;
case USE_CANONICAL_NAME_OFF:
case USE_CANONICAL_NAME_UNSET:
break;
default:
"ap_get_server_name: Invalid UCN Option somehow");
retval = "localhost";
break;
}
return retval;
}
/*
* 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]").
*/
{
const char *plain_server_name = ap_get_server_name(r);
#if APR_HAVE_IPV6
}
#endif
return plain_server_name;
}
{
core_dir_config *d =
switch (d->use_canonical_name) {
case USE_CANONICAL_NAME_OFF:
case USE_CANONICAL_NAME_DNS:
case USE_CANONICAL_NAME_UNSET:
ap_default_port(r);
else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
ap_default_port(r);
break;
case 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);
else /* USE_CANONICAL_PHYS_PORT_OFF or USE_CANONICAL_PHYS_PORT_UNSET */
ap_default_port(r);
break;
default:
"ap_get_server_port: Invalid UCN Option somehow");
port = ap_default_port(r);
break;
}
return port;
}
request_rec *r)
{
unsigned port = ap_get_server_port(r);
const char *host = ap_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> or <LimitExcept> "
"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;
}
const char *optarg)
{
char **newv;
return err;
}
return NULL;
}
#ifdef GPROF
{
return err;
}
return NULL;
}
#endif /*GPROF*/
{
core_dir_config *d = d_;
}
}
else {
d->add_default_charset_name = arg;
}
return NULL;
}
const char *arg)
{
return err;
}
/* When ap_document_root_check is false; skip all the stuff below */
if (!ap_document_root_check) {
return NULL;
}
/* Make it absolute, relative to ServerRoot */
return "DocumentRoot must be a directory";
}
/* TODO: ap_configtestonly */
"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,
}
}
{
/* 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")) {
/* If Includes is permitted, both Includes and
* IncludesNOEXEC may be changed. */
}
else if (!strcasecmp(w, "IncludesNOEXEC")) {
opt = OPT_INCLUDES;
}
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;
/* Throw a warning if we're in <Location> or <Files> */
"Useless use of AllowOverride in line %d of %s.",
}
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")) {
}
else if (!strcasecmp(w, "IncludesNOEXEC")) {
opt = OPT_INCLUDES;
}
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;
}
const char *arg)
{
"Ignoring deprecated use of DefaultType in line %d of %s.",
}
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_;
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_;
}
}
else {
return "parameter must be 'on' or 'off'";
}
return NULL;
}
/*
* Report a missing-'>' syntax error.
*/
{
"> directive missing closing '>'", NULL);
}
/*
* Report a missing args in '<Foo >' syntax error.
*/
{
"> directive requires additional arguments", NULL);
}
void *dummy,
const char *arg)
{
const char *limited_methods;
apr_int64_t limited = 0;
const char *errmsg;
return unclosed_directive(cmd);
}
if (!limited_methods[0]) {
return missing_container_arg(cmd);
}
while (limited_methods[0]) {
int methnum;
/* check for builtin or module registered method number */
return "TRACE cannot be controlled by <Limit>, see TraceEnable";
}
/* 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>
*/
if (!(old_limited & limited)) {
"> directive excludes all methods", NULL);
}
"> directive specifies methods already excluded",
NULL);
}
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
#define USE_ICASE AP_REG_ICASE
#else
#define USE_ICASE 0
#endif
{
const char *errmsg;
ap_regex_t *r = NULL;
return err;
}
return unclosed_directive(cmd);
}
if (!arg[0]) {
return missing_container_arg(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;
ap_regex_t *r = NULL;
return err;
}
return unclosed_directive(cmd);
}
if (!arg[0]) {
return missing_container_arg(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;
ap_regex_t *r = NULL;
core_dir_config *c = mconfig;
return err;
}
return unclosed_directive(cmd);
}
if (!arg[0]) {
return missing_container_arg(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;
}
{
const char *errmsg;
core_dir_config *c = mconfig;
const char *condition;
int expr_err = 0;
return err;
}
return unclosed_directive(cmd);
}
if (!arg[0]) {
return missing_container_arg(cmd);
}
/* Only if not an .htaccess file */
if (!old_path) {
}
/* initialize our config and fetch it */
if (expr_err) {
return "Cannot parse condition clause";
}
return errmsg;
conf->d_is_fnmatch = 0;
if (*arg != '\0') {
"> arguments not supported.", NULL);
}
return NULL;
}
{
return unclosed_directive(cmd);
}
if (not) {
arg++;
}
if (!arg[0]) {
return missing_container_arg(cmd);
}
/* 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++;
}
if (!arg[0]) {
return missing_container_arg(cmd);
}
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);
}
if (!arg[0]) {
return missing_container_arg(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;
}
{
&core_module);
char* proto;
char* accf;
return err;
}
return NULL;
}
{
&core_module);
}
{
&core_module);
}
const char *arg)
{
&core_module);
char* proto;
return err;
}
return NULL;
}
const char *arg)
{
/* This one's pretty generic... */
return err;
}
return NULL;
}
/*
* The ServerName directive takes one argument with format
* [scheme://]fully-qualified-domain-name[:port], for instance
* ServerName www.example.com
* ServerName www.example.com:80
* ServerName https://www.example.com:443
*/
{
char *scheme;
int port;
return err;
}
if (part) {
part += 3;
} else {
}
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_;
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_;
d->allow_encoded_slashes = arg != 0;
return NULL;
}
const char *arg)
{
core_dir_config *d = d_;
}
}
}
else {
return "parameter must be 'on', 'off', or 'double'";
}
return NULL;
}
const char *arg)
{
return err;
}
return NULL;
}
{
core_dir_config *d = d_;
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_;
}
}
}
else {
return "parameter must be 'on', 'off', or 'dns'";
}
return NULL;
}
const char *arg)
{
core_dir_config *d = d_;
}
}
else {
return "parameter must be 'on' or 'off'";
}
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);
}
/*
* 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_banner = NULL;
static int banner_locked = 0;
static const char *server_description = NULL;
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 */
};
{
banner_locked = 0;
return APR_SUCCESS;
}
{
}
AP_DECLARE(const char *) ap_get_server_description(void)
{
return server_description ? server_description :
}
AP_DECLARE(const char *) ap_get_server_banner(void)
{
}
{
if (! banner_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_banner == NULL) {
}
else {
/*
* Tack the given component identifier to the end of
* the existing string.
*/
}
}
}
/*
* This routine adds the real server base identity to the banner 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_banner string if we're not displaying
* the full set of tokens
*/
if (ap_server_tokens != SrvTk_FULL) {
}
}
{
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",
NULL);
}
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 "LimitRequestBody argument is not parsable.";
}
return "LimitRequestBody requires a non-negative integer.";
}
return NULL;
}
const char *arg)
{
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 configuration "
"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 no content-type or if we don't have a
* filter configured.
*/
return;
}
/* remove c-t decoration */
if (ctype) {
while (ct_filter) {
}
}
return;
}
const char *arg1)
{
&core_module);
}
}
}
else {
return "TraceEnable must be one of 'on', 'off', or 'extended'";
}
return NULL;
}
/* 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"),
#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"),
"Define the existance of a variable. Same as passing -D to the command line."),
"Container for directives to be conditionally applied"),
/* 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"),
"the default media type for otherwise untyped files (DEPRECATED)"),
"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 */
"Set the Protocol for httpd to use."),
"Set the Accept Filter to use for a protocol"),
"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"),
"Whether to use the physical 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), "
"Major, Minor, Prod, 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"),
"mutex (or \"default\") and mechanism"),
/* 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.
* XXX These are not for all platforms, and even some Unix MPMs might not want
* some directives.
*/
"A file for logging the server process ID"),
"A file for Apache to maintain runtime process management information"),
"Maximum number of requests a particular child serves before dying."),
"The location of the directory Apache changes to before dumping core"),
"Maximum number of 1k blocks a particular childs allocator may hold."),
"Size in bytes of stack used by threads handling client connections"),
"Controls whether exception hook may be called after a crash"),
#endif
"'on' (default), 'off' or 'extended' to trace request body content"),
{ 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);
if (bld_content_md5) {
}
}
else {
#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);
if (status == APR_SUCCESS
|| c->aborted) {
return OK;
}
else {
/* no way to know what type of error occurred */
"default_handler: ap_pass_brigade returned %i",
status);
return HTTP_INTERNAL_SERVER_ERROR;
}
}
else { /* unusual method (not GET or POST) */
if (r->method_number == M_INVALID) {
/* See if this looks like an undecrypted SSL handshake attempt.
* It's safe to look a couple bytes into the_request if it exists, as it's
* always allocated at least MIN_LINE_ALLOC (80) bytes.
*/
if (r->the_request
&& r->the_request[0] == 0x16
"Invalid method in request %s - possible attempt to establish SSL connection on non-SSL port", r->the_request);
} else {
"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
*/
/* Insist that at least one module will undertake to provide system
* security by dropping startup privileges.
*/
static int sys_privileges = 0;
{
sys_privileges += inc;
return sys_privileges;
}
{
if (!sys_privileges) {
"Server MUST relinquish startup privileges before "
"accepting connections. Please ensure mod_unixd "
"or other system security module is loaded.");
return !OK;
}
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 {
}
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;
c->cs->expiration_time = 0;
c->cs->c = c;
c->clogging_input_filters = 0;
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)");
}
/* The core filter requires the timeout mode to be set, which
* incidentally sets the socket to be nonblocking. If this
* is not initialized correctly, Linux - for example - will
* be initially blocking, while Solaris will be non blocking
* and any initial read will fail.
*/
if (rv != APR_SUCCESS) {
/* expected cause is that the client disconnected already */
"apr_socket_timeout_set");
}
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
*/
}
AP_PLATFORM_REWRITE_ARGS_HOOK, /* hook to run before apache parses args */
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 */
};