core.c revision 99a041314eb3db0b0cca325c9c40d0a6c5fdf04f
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2000-2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software itself,
* if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Apache" and "Apache Software Foundation" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
*
* Portions of this software are based upon public domain software
* originally written at the National Center for Supercomputing Applications,
* University of Illinois, Urbana-Champaign.
*/
#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 "rfc1413.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"
/* LimitXMLRequestBody handling */
#define AP_LIMIT_UNSET ((long) -1)
#define AP_MIN_SENDFILE_BYTES (256)
)
/* 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 */
{
/* conf->r and conf->d[_*] are initialized by dirsection() or left NULL */
#ifdef RLIMIT_CPU
#endif
#endif
#ifdef RLIMIT_NPROC
#endif
conf->limit_req_body = 0;
/* Overriding all negotiation
*/
/*
* Flag for use of inodes in ETags.
*/
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
if (new->limit_req_body) {
}
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;
}
{
int is_virtual = s->is_virtual;
#ifdef GPROF
#endif
return (void *)conf;
}
{
if (!conf->access_name) {
}
if (!conf->ap_document_root) {
}
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).
*/
{
&core_module);
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;
if (str_is_ip) { /* if caller wants 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 {
if (str_is_ip) { /* if caller wants to know */
*str_is_ip = 1;
}
}
}
}
{
return r->connection->remote_logname;
}
/* If we haven't checked the identity, and we want to */
&core_module);
}
else {
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;
}
{
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 = ap_get_server_name(r);
if (ap_is_default_port(port, r)) {
}
}
{
core_dir_config *d =
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;
}
/* TODO: ap_configtestonly && ap_docrootcheck && */
/* XXX Shouldn't this be relative to ServerRoot ??? */
"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) *
}
/* 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;
}
{
core_dir_config *d = d_;
char *w;
return err;
}
while (l[0]) {
if (!strcasecmp(w, "Limit")) {
}
else if (!strcasecmp(w, "Options")) {
d->override |= OR_OPTIONS;
}
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 {
}
/* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */
if (action == '-') {
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;
}
{
core_dir_config *c = c_;
c->satisfy = SATISFY_ALL;
}
c->satisfy = SATISFY_ANY;
}
else {
return "Satisfy either 'any' or 'all'.";
}
return NULL;
}
{
require_line *r;
core_dir_config *c = c_;
if (!c->ap_requires) {
}
return NULL;
}
void *dummy,
const char *arg)
{
apr_int64_t limited = 0;
const char *errmsg;
return err;
}
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
/*
* Report a missing-'>' syntax error.
*/
{
"> directive missing closing '>'", NULL);
}
{
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";
}
}
{
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);
}
}
}
/* 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) {
}
}
}
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++;
}
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->do_rfc1413 = 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)
{
if (!conffile) {
}
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=\"mailto:",
"</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;
}
#ifdef _OSD_POSIX /* BS2000 Logon Passwd file */
{
return err;
}
}
#endif /*_OSD_POSIX*/
/*
* 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);
}
if (lim > DEFAULT_LIMIT_REQUEST_LINE) {
"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);
}
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;
}
/* WTF: If strtoul is not portable, then write a replacement.
* Instead we have an idiotic define in httpd.h that prevents
* it from being used even when it is available. Sheesh.
*/
if (*errp != '\0') {
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
{
const char *filter_name;
if (!conf->ct_output_filters) {
}
else {
}
while (*arg &&
/* We found something, so let's append it. */
if (old) {
}
}
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)
{
&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;
}
ctypes = r->content_type;
/* We must be able to handle decorated content-types. */
while (ct_filter) {
}
}
return;
}
{
apr_size_t bytes_written = 0;
apr_size_t n = len;
int i = 0;
*nbytes = 0;
/* XXX handle checking for non-blocking socket */
while (bytes_written != len) {
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
*/
if (bytes_written < len) {
/* Skip over the vectors that have already been written */
i++;
}
if (n < cnt) {
/* Handle partial write of vec i */
}
}
n = len - bytes_written;
}
return APR_SUCCESS;
}
/* sendfile_it_all()
* send the entire file using sendfile()
* handle partial writes
* return only when all bytes have been sent or an error is encountered.
*/
#if APR_HAS_SENDFILE
apr_file_t *fd,
{
#ifdef AP_DEBUG
#endif
== APR_SUCCESS)
&& timeout > 0); /* socket must be in timeout mode */
do {
flags);
return rv; /* normal case & error exit */
}
/* partial write, oooh noooo...
* Skip over any header data which was written
*/
--hdtr->numheaders;
}
else {
tmplen = 0;
}
}
/* Skip over any file data which was written */
if (tmplen <= file_bytes_left) {
file_offset += tmplen;
continue;
}
file_bytes_left = 0;
file_offset = 0;
/* Skip over any trailer data which was written */
--hdtr->numtrailers;
}
else {
tmplen = 0;
}
}
} while (1);
}
#endif
/*
* emulate_sendfile()
* to the network. emulate_sendfile will return only when all the bytes have been
* sent (i.e., it handles partial writes) or on a network error condition.
*/
{
apr_size_t sendlen = 0;
apr_int32_t i;
apr_off_t o; /* Track the file offset for partial writes */
char buffer[8192];
*nbytes = 0;
/* Send the headers
* writev_it_all handles partial writes.
* XXX: optimization... if headers are less than MIN_WRITE_SIZE, copy
* them into buffer
*/
for (i = 0; i < hdtr->numheaders; i++) {
}
sendlen, &bytes_sent);
if (rv == APR_SUCCESS)
}
/* Seek the file to 'offset' */
}
/* Send the file, making sure to handle partial writes */
o = 0;
if (rv == APR_SUCCESS) {
o += bytes_sent; /* o is where we are in the buffer */
*nbytes += bytes_sent;
}
}
}
/* Send the trailers
* XXX: optimization... if it will fit, send this on the last send in the
* loop above
*/
sendlen = 0;
for (i = 0; i < hdtr->numtrailers; i++) {
}
sendlen, &bytes_sent);
if (rv == APR_SUCCESS)
*nbytes += bytes_sent;
}
return rv;
}
/* 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"),
/* 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)"),
"Enable identd (RFC 1413) user lookups - SLOW"),
"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"),
#ifdef _OSD_POSIX
"Name of server User's bs2000 logon account name"),
#endif
"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
"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"),
/*
* 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
{ 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) {
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) {
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;
}
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) {
}
/* APR_HAS_LARGE_FILES issue; must split into mutiple buckets,
* no greater than MAX(apr_size_t), and more granular than that
*/
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
#endif
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;
}
}
{
int *first_line = f->ctx;
if (!f->ctx) {
*first_line = 1;
}
if (*first_line) {
? f->c->base_server->keep_alive_timeout
: f->c->base_server->timeout);
*first_line = 0;
}
else {
if (keptalive) {
}
}
}
}
/**
* Remove all zero length buckets from the brigade.
*/
#define BRIGADE_NORMALIZE(b) \
do { \
apr_bucket *e = APR_BRIGADE_FIRST(b); \
do { \
if (e->length == 0 && !APR_BUCKET_IS_METADATA(e)) { \
apr_bucket *d; \
d = APR_BUCKET_NEXT(e); \
apr_bucket_delete(e); \
e = d; \
} \
e = APR_BUCKET_NEXT(e); \
} while (!APR_BRIGADE_EMPTY(b) && (e != APR_BRIGADE_SENTINEL(b))); \
} while (0)
{
apr_bucket *e;
const char *str;
if (mode == AP_MODE_INIT) {
/*
* this mode is for filters that might need to 'initialize'
* a connection before reading request data from a client.
* NNTP over SSL for example needs to handshake before the
* server sends the welcome message.
* such filters would have changed the mode before this point
* is reached. however, protocol modules such as NNTP should
* not need to know anything about SSL. given the example, if
* SSL is not in the filter chain, AP_MODE_INIT is a noop.
*/
return APR_SUCCESS;
}
if (!ctx)
{
/* seed the brigade with the client socket. */
APR_BRIGADE_INSERT_TAIL(ctx->b, e);
}
else if (APR_BRIGADE_EMPTY(ctx->b)) {
return APR_EOF;
}
/* ### This is bad. */
BRIGADE_NORMALIZE(ctx->b);
/* check for empty brigade again *AFTER* BRIGADE_NORMALIZE()
* If we have lost our socket bucket (see above), we are EOF.
*
* Ideally, this should be returning SUCCESS with EOS bucket, but
* some higher-up APIs (spec. read_request_line via ap_rgetline)
* want an error code. */
if (APR_BRIGADE_EMPTY(ctx->b)) {
return APR_EOF;
}
/* ### AP_MODE_PEEK is a horrific name for this mode because we also
* eat any CRLFs that we see. That's not the obvious intention of
* this mode. Determine whether anyone actually uses this or not. */
if (mode == AP_MODE_EATCRLF) {
apr_bucket *e;
const char *c;
/* The purpose of this loop is to ignore any CRLF (or LF) at the end
* of a request. Many browsers send extra lines at the end of POST
* requests. We use the PEEK method to determine if there is more
* data on the socket, so that we know if we should delay sending the
* end of one request until we have served the second request in a
* pipelined situation. We don't want to actually delay sending a
* response if the server finds a CRLF (or LF), becuause that doesn't
* mean that there is another request, just a blank line.
*/
while (1) {
if (APR_BRIGADE_EMPTY(ctx->b))
return APR_EOF;
e = APR_BRIGADE_FIRST(ctx->b);
if (rv != APR_SUCCESS)
return rv;
c = str;
if (*c == APR_ASCII_LF)
c++;
c += 2;
else
return APR_SUCCESS;
}
/* If we reach here, we were a bucket just full of CRLFs, so
* just toss the bucket. */
/* FIXME: Is this the right thing to do in the core? */
}
}
/* If mode is EXHAUSTIVE, we want to just read everything until the end
* of the brigade, which in this case means the end of the socket.
* To do this, we attach the brigade that has currently been setaside to
* the brigade that was passed down, and send that brigade back.
*
* NOTE: This is VERY dangerous to use, and should only be done with
* extreme caution. However, the Perchild MPM needs this feature
* if it is ever going to work correctly again. With this, the Perchild
* MPM can easily request the socket and all data that has been read,
* which means that it can pass it to the correct child process.
*/
if (mode == AP_MODE_EXHAUSTIVE) {
apr_bucket *e;
/* Tack on any buckets that were set aside. */
APR_BRIGADE_CONCAT(b, ctx->b);
/* Since we've just added all potential buckets (which will most
* likely simply be the socket bucket) we know this is the end,
* so tack on an EOS too. */
/* We have read until the brigade was empty, so we know that we
* must be EOS. */
e = apr_bucket_eos_create(f->c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(b, e);
return APR_SUCCESS;
}
/* read up to the amount they specified. */
apr_bucket *e;
AP_DEBUG_ASSERT(readbytes > 0);
e = APR_BRIGADE_FIRST(ctx->b);
if (APR_STATUS_IS_EAGAIN(rv)) {
return APR_SUCCESS;
}
else if (rv != APR_SUCCESS) {
return rv;
}
/* We wanted to read some bytes in blocking mode. We read
* 0 bytes. Hence, we now assume we are EOS.
*
* When we are in normal mode, return an EOS bucket to the
* caller.
* When we are in speculative mode, leave ctx->b empty, so
* that the next call returns an EOS bucket.
*/
if (mode == AP_MODE_READBYTES) {
e = apr_bucket_eos_create(f->c->bucket_alloc);
APR_BRIGADE_INSERT_TAIL(b, e);
}
return APR_SUCCESS;
}
/* We can only return at most what we read. */
}
if (rv != APR_SUCCESS) {
return rv;
}
/* Must do split before CONCAT */
if (mode == AP_MODE_READBYTES) {
APR_BRIGADE_CONCAT(b, ctx->b);
}
else if (mode == AP_MODE_SPECULATIVE) {
APR_BRIGADE_FOREACH(e, ctx->b) {
if (rv != APR_SUCCESS) {
return rv;
}
}
}
/* Take what was originally there and place it back on ctx->b */
return APR_SUCCESS;
}
/* we are reading a single LF line, e.g. the HTTP headers */
/* We should treat EAGAIN here the same as we do for EOF (brigade is
* empty). We do this by returning whatever we have read. This may
* or may not be bogus, but is consistent (for now) with EOF logic.
*/
if (APR_STATUS_IS_EAGAIN(rv)) {
rv = APR_SUCCESS;
}
return rv;
}
/* Default filter. This filter should almost always be used. Its only job
* is to send the headers if they haven't already been sent, and then send
* the actual data.
*/
#define MAX_IOVEC_TO_WRITE 16
{
conn_rec *c = f->c;
}
/* If we have a saved brigade, concatenate the new brigade to it */
if (ctx->b) {
APR_BRIGADE_CONCAT(ctx->b, b);
b = ctx->b;
}
/* Perform multiple passes over the brigade, sending batches of output
to the connection. */
while (b && !APR_BRIGADE_EMPTY(b)) {
apr_size_t nbytes = 0;
apr_bucket *e;
/* tail of brigade if we need another pass */
/* one group of iovecs per pass over the brigade */
apr_size_t nvec = 0;
apr_size_t nvec_trailers = 0;
/* one file per pass over the brigade */
apr_size_t flen = 0;
/* keep track of buckets that we've concatenated
* to avoid small writes
*/
APR_BRIGADE_FOREACH(e, b) {
/* keep track of the last bucket processed */
last_e = e;
if (APR_BUCKET_IS_EOS(e)) {
break;
}
if (APR_BUCKET_IS_FLUSH(e)) {
break;
}
/* It doesn't make any sense to use sendfile for a file bucket
* that represents 10 bytes.
*/
else if (APR_BUCKET_IS_FILE(e)
&& (e->length >= AP_MIN_SENDFILE_BYTES)) {
apr_bucket_file *a = e->data;
/* We can't handle more than one file bucket at a time
* so we split here and send the file we have already
* found.
*/
if (fd) {
more = apr_brigade_split(b, e);
break;
}
}
else {
const char *str;
apr_size_t n;
if (n) {
if (!fd) {
if (nvec == MAX_IOVEC_TO_WRITE) {
/* woah! too many. buffer them up, for use later. */
if (nbytes >= AP_MIN_BYTES_TO_WRITE) {
/* We have enough data in the iovec
* to justify doing a writev
*/
more = apr_brigade_split(b, e);
break;
}
/* Create a temporary brigade as a means
* of concatenating a bunch of buckets together
*/
if (last_merged_bucket) {
/* If we've concatenated together small
* buckets already in a previous pass,
* the initial buckets in this brigade
* are heap buckets that may have extra
* space left in them (because they
* were created by apr_brigade_write()).
* We can take advantage of this by
* building the new temp brigade out of
* these buckets, so that the content
* in them doesn't have to be copied again.
*/
bb = apr_brigade_split(b,
temp_brig = b;
b = bb;
}
else {
f->c->bucket_alloc);
}
temp = APR_BRIGADE_FIRST(b);
while (temp != e) {
apr_bucket *d;
d = temp;
}
nvec = 0;
nbytes = 0;
nvec++;
/* Just in case the temporary brigade has
* multiple buckets, recover the rest of
* them and put them in the brigade that
* we're sending.
*/
nvec++;
}
e = temp;
last_e = e;
}
else {
nvec++;
}
}
else {
/* The bucket is a trailer to a file bucket */
if (nvec_trailers == MAX_IOVEC_TO_WRITE) {
/* woah! too many. stop now. */
more = apr_brigade_split(b, e);
break;
}
}
nbytes += n;
}
}
}
/* Completed iterating over the brigades, now determine if we want
* to buffer the brigade or send the brigade out on the network.
*
* Save if:
*
* 1) we didn't see a file, we don't have more passes over the
* brigade to perform, we haven't accumulated enough bytes to
* send, AND we didn't stop at a FLUSH bucket.
* (IOW, we will save away plain old bytes)
* or
* 2) we hit the EOS and have a keep-alive connection
* (IOW, this response is a bit more complex, but we save it
* with the hope of concatenating with another response)
*/
&& !APR_BUCKET_IS_FLUSH(last_e))
&& c->keepalive == AP_CONN_KEEPALIVE)) {
/* NEVER save an EOS in here. If we are saving a brigade with
* an EOS bucket, then we are doing keepalive connections, and
* we want to process to second request fully.
*/
if (APR_BUCKET_IS_EOS(last_e)) {
int file_bucket_saved = 0;
for (bucket = APR_BRIGADE_FIRST(b);
bucket != APR_BRIGADE_SENTINEL(b);
/* Do a read on each bucket to pull in the
* data from pipe and socket buckets, so
* that we don't leave their file descriptors
* open indefinitely. Do the same for file
* buckets, with one exception: allow the
* first file bucket in the brigade to remain
* a file bucket, so that we don't end up
* doing an mmap+memcpy every time a client
* requests a <8KB file over a keepalive
* connection.
*/
file_bucket_saved = 1;
}
else {
const char *buf;
apr_size_t len = 0;
if (rv != APR_SUCCESS) {
c->base_server, "core_output_filter:"
" Error reading from bucket.");
return HTTP_INTERNAL_SERVER_ERROR;
}
}
}
}
return APR_SUCCESS;
}
if (fd) {
#if APR_HAS_SENDFILE
apr_int32_t flags = 0;
#endif
if (nvec) {
}
if (nvec_trailers) {
}
#if APR_HAS_SENDFILE
/* Prepare the socket to be reused */
}
fd, /* the file to send */
&hdtr, /* header and trailer iovecs */
foffset, /* offset in the file to begin
sending from */
flen, /* length of file */
headers */
flags); /* apr_sendfile flags */
/* If apr_sendfile() returns APR_ENOTIMPL, call emulate_sendfile().
* emulate_sendfile() is useful to enable the same Apache binary
* distribution to support Windows NT/2000 (supports TransmitFile)
* and Win95/98 (do not support TransmitFile)
*/
if (rv == APR_ENOTIMPL)
#endif
{
}
}
else {
}
if (rv != APR_SUCCESS) {
"core_output_filter: writing data to the network");
if (more)
/* No need to check for SUCCESS, we did that above. */
if (!APR_STATUS_IS_EAGAIN(rv)) {
c->aborted = 1;
}
/* The client has aborted, but the request was successful. We
* will report success, and leave it to the access and error
* logs to note that the connection was aborted.
*/
return APR_SUCCESS;
}
b = more;
} /* end while () */
return APR_SUCCESS;
}
{
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);
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;
}
{
/* BillS says perhaps this should be moved to the MPMs. Some OSes
* allow listening socket attributes to be inherited by the
* accept sockets which means this call only needs to be made
* once on the listener
*/
#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 */
};