Binary files apache_1.3.33/src/ap/.ap_strtoll.c.swp and apache_1.3.33-mod/src/ap/.ap_strtoll.c.swp differ diff -udrN apache_1.3.33/src/ap/Makefile.tmpl apache_1.3.33-mod/src/ap/Makefile.tmpl --- apache_1.3.33/src/ap/Makefile.tmpl Mon Jun 17 17:34:35 2002 +++ apache_1.3.33-mod/src/ap/Makefile.tmpl Fri Apr 1 10:06:37 2005 @@ -7,7 +7,7 @@ OBJS=ap_cpystrn.o ap_execve.o ap_fnmatch.o ap_getpass.o ap_md5c.o ap_signal.o \ ap_slack.o ap_snprintf.o ap_sha1.o ap_checkpass.o ap_base64.o ap_ebcdic.o \ - ap_strtol.o + ap_strtol.o ap_strtoll.o .c.o: $(CC) -c $(INCLUDES) $(CFLAGS) $< diff -udrN apache_1.3.33/src/ap/ap_strtoll.c apache_1.3.33-mod/src/ap/ap_strtoll.c --- apache_1.3.33/src/ap/ap_strtoll.c Wed Dec 31 16:00:00 1969 +++ apache_1.3.33-mod/src/ap/ap_strtoll.c Fri Apr 1 10:16:06 2005 @@ -0,0 +1,142 @@ +/*- + * Copyright (c) 1992, 1993 + * The Regents of the University of California. 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 the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS 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 REGENTS OR 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93"; +#endif /* LIBC_SCCS and not lint */ +#include +#if 0 +__FBSDID("$FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.19 2002/09/06 11:23:59 tjr Exp $"); +#endif + +#include +#include +#include +#include + +/* + * Convert a string to a long long integer. + * + * Assumes that the upper and lower case + * alphabets and digits are each contiguous. + */ +long long ap_strtoll(const char * nptr, char ** endptr, int base) +{ + const char *s; + unsigned long long acc; + char c; + unsigned long long cutoff; + int neg, any, cutlim; + + /* + * Skip white space and pick up leading +/- sign if any. + * If base is 0, allow 0x for hex and 0 for octal, else + * assume decimal; if base is already 16, allow 0x. + */ + s = nptr; + do { + c = *s++; + } while (isspace((unsigned char)c)); + if (c == '-') { + neg = 1; + c = *s++; + } else { + neg = 0; + if (c == '+') + c = *s++; + } + if ((base == 0 || base == 16) && + c == '0' && (*s == 'x' || *s == 'X')) { + c = s[1]; + s += 2; + base = 16; + } + if (base == 0) + base = c == '0' ? 8 : 10; + acc = any = 0; + if (base < 2 || base > 36) + goto noconv; + + /* + * Compute the cutoff value between legal numbers and illegal + * numbers. That is the largest legal value, divided by the + * base. An input number that is greater than this value, if + * followed by a legal input character, is too big. One that + * is equal to this value may be valid or not; the limit + * between valid and invalid numbers is then based on the last + * digit. For instance, if the range for quads is + * [-9223372036854775808..9223372036854775807] and the input base + * is 10, cutoff will be set to 922337203685477580 and cutlim to + * either 7 (neg==0) or 8 (neg==1), meaning that if we have + * accumulated a value > 922337203685477580, or equal but the + * next digit is > 7 (or 8), the number is too big, and we will + * return a range error. + * + * Set 'any' if any `digits' consumed; make it negative to indicate + * overflow. + */ + cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX + : LLONG_MAX; + cutlim = cutoff % base; + cutoff /= base; + for ( ; ; c = *s++) { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'A' && c <= 'Z') + c -= 'A' - 10; + else if (c >= 'a' && c <= 'z') + c -= 'a' - 10; + else + break; + if (c >= base) + break; + if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + if (any < 0) { + acc = neg ? LLONG_MIN : LLONG_MAX; + errno = ERANGE; + } else if (!any) { +noconv: + errno = EINVAL; + } else if (neg) + acc = -acc; + if (endptr != NULL) + *endptr = (char *)(any ? s - 1 : nptr); + return (acc); +} diff -udrN apache_1.3.33/src/include/ap.h apache_1.3.33-mod/src/include/ap.h --- apache_1.3.33/src/include/ap.h Mon Feb 16 14:25:08 2004 +++ apache_1.3.33-mod/src/include/ap.h Fri Apr 1 10:06:37 2005 @@ -34,6 +34,7 @@ #ifndef ap_strtol API_EXPORT(long) ap_strtol(const char *nptr, char **endptr, int base); +API_EXPORT(int64_t) ap_strtoll(const char *nptr, char **endptr, int base); #endif /* small utility macros to make things easier to read */ diff -udrN apache_1.3.33/src/include/ap.h.orig apache_1.3.33-mod/src/include/ap.h.orig --- apache_1.3.33/src/include/ap.h.orig Wed Dec 31 16:00:00 1969 +++ apache_1.3.33-mod/src/include/ap.h.orig Mon Feb 16 14:25:08 2004 @@ -0,0 +1,159 @@ +/* Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +/* + * The ap_vsnprintf/ap_snprintf functions are based on, and used with the + * permission of, the SIO stdio-replacement strx_* functions by Panos + * Tsirigotis for xinetd. + */ + +#ifndef APACHE_AP_H +#define APACHE_AP_H + +#ifdef __cplusplus +extern "C" { +#endif + +API_EXPORT(char *) ap_cpystrn(char *, const char *, size_t); +int ap_slack(int, int); +int ap_execle(const char *, const char *, ...); +int ap_execve(const char *, char * const argv[], char * const envp[]); +API_EXPORT(int) ap_getpass(const char *prompt, char *pwbuf, size_t bufsiz); + +#ifndef ap_strtol +API_EXPORT(long) ap_strtol(const char *nptr, char **endptr, int base); +#endif + +/* small utility macros to make things easier to read */ + +#ifdef WIN32 +#define ap_killpg(x, y) +#else +#ifdef NO_KILLPG +#define ap_killpg(x, y) (kill (-(x), (y))) +#else +#define ap_killpg(x, y) (killpg ((x), (y))) +#endif +#endif /* WIN32 */ + +/* ap_vformatter() is a generic printf-style formatting routine + * with some extensions. The extensions are: + * + * %pA takes a struct in_addr *, and prints it as a.b.c.d + * %pI takes a struct sockaddr_in * and prints it as a.b.c.d:port + * %pp takes a void * and outputs it in hex + * + * The %p hacks are to force gcc's printf warning code to skip + * over a pointer argument without complaining. This does + * mean that the ANSI-style %p (output a void * in hex format) won't + * work as expected at all, but that seems to be a fair trade-off + * for the increased robustness of having printf-warnings work. + * + * Additionally, ap_vformatter allows for arbitrary output methods + * using the ap_vformatter_buff and flush_func. + * + * The ap_vformatter_buff has two elements curpos and endpos. + * curpos is where ap_vformatter will write the next byte of output. + * It proceeds writing output to curpos, and updating curpos, until + * either the end of output is reached, or curpos == endpos (i.e. the + * buffer is full). + * + * If the end of output is reached, ap_vformatter returns the + * number of bytes written. + * + * When the buffer is full, the flush_func is called. The flush_func + * can return -1 to indicate that no further output should be attempted, + * and ap_vformatter will return immediately with -1. Otherwise + * the flush_func should flush the buffer in whatever manner is + * appropriate, re-initialize curpos and endpos, and return 0. + * + * Note that flush_func is only invoked as a result of attempting to + * write another byte at curpos when curpos >= endpos. So for + * example, it's possible when the output exactly matches the buffer + * space available that curpos == endpos will be true when + * ap_vformatter returns. + * + * ap_vformatter does not call out to any other code, it is entirely + * self-contained. This allows the callers to do things which are + * otherwise "unsafe". For example, ap_psprintf uses the "scratch" + * space at the unallocated end of a block, and doesn't actually + * complete the allocation until ap_vformatter returns. ap_psprintf + * would be completely broken if ap_vformatter were to call anything + * that used a pool. Similarly http_bprintf() uses the "scratch" + * space at the end of its output buffer, and doesn't actually note + * that the space is in use until it either has to flush the buffer + * or until ap_vformatter returns. + */ + +typedef struct { + char *curpos; + char *endpos; +} ap_vformatter_buff; + +API_EXPORT(int) ap_vformatter(int (*flush_func)(ap_vformatter_buff *), + ap_vformatter_buff *, const char *fmt, va_list ap); + +/* These are snprintf implementations based on ap_vformatter(). + * + * Note that various standards and implementations disagree on the return + * value of snprintf, and side-effects due to %n in the formatting string. + * ap_snprintf behaves as follows: + * + * Process the format string until the entire string is exhausted, or + * the buffer fills. If the buffer fills then stop processing immediately + * (so no further %n arguments are processed), and return the buffer + * length. In all cases the buffer is NUL terminated. The return value + * is the number of characters placed in the buffer, excluding the + * terminating NUL. All this implies that, at most, (len-1) characters + * will be copied over; if the return value is >= len, then truncation + * occured. + * + * In no event does ap_snprintf return a negative number. + */ +API_EXPORT_NONSTD(int) ap_snprintf(char *buf, size_t len, const char *format,...) + __attribute__((format(printf,3,4))); +API_EXPORT(int) ap_vsnprintf(char *buf, size_t len, const char *format, + va_list ap); +/* Simple BASE64 encode/decode functions. + * + * As we might encode binary strings, hence we require the length of + * the incoming plain source. And return the length of what we decoded. + * + * The decoding function takes any non valid char (i.e. whitespace, \0 + * or anything non A-Z,0-9 etc as terminal. + * + * plain strings/binary sequences are not assumed '\0' terminated. Encoded + * strings are neither. But propably should. + * + */ +API_EXPORT(int) ap_base64encode_len(int len); +API_EXPORT(int) ap_base64encode(char * coded_dst, const char *plain_src,int len_plain_src); +API_EXPORT(int) ap_base64encode_binary(char * coded_dst, const unsigned char *plain_src,int len_plain_src); + +API_EXPORT(int) ap_base64decode_len(const char * coded_src); +API_EXPORT(int) ap_base64decode(char * plain_dst, const char *coded_src); +API_EXPORT(int) ap_base64decode_binary(unsigned char * plain_dst, const char *coded_src); + +/* Password validation, as used in AuthType Basic which is able to cope + * (based on the prefix) with the SHA1, Apache's internal MD5 and (depending + * on your platform either plain or crypt(3) passwords. + */ +API_EXPORT(char *) ap_validate_password(const char *passwd, const char *hash); + +#ifdef __cplusplus +} +#endif + +#endif /* !APACHE_AP_H */ diff -udrN apache_1.3.33/src/include/http_protocol.h apache_1.3.33-mod/src/include/http_protocol.h --- apache_1.3.33/src/include/http_protocol.h Mon Feb 16 14:25:08 2004 +++ apache_1.3.33-mod/src/include/http_protocol.h Fri Apr 1 10:06:37 2005 @@ -70,7 +70,7 @@ * permit_cache argument is set to one). */ -API_EXPORT(int) ap_set_content_length(request_rec *r, long length); +API_EXPORT(int64_t) ap_set_content_length(request_rec *r, int64_t length); API_EXPORT(int) ap_set_keepalive(request_rec *r); API_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime); API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak); @@ -89,14 +89,13 @@ * (Ditto the send_header stuff). */ -API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r); -API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length); +API_EXPORT(int64_t) ap_send_fd(FILE *f, request_rec *r); +API_EXPORT(int64_t) ap_send_fd_length(FILE *f, request_rec *r, int64_t length); -API_EXPORT(long) ap_send_fb(BUFF *f, request_rec *r); -API_EXPORT(long) ap_send_fb_length(BUFF *f, request_rec *r, long length); +API_EXPORT(int64_t) ap_send_fb(BUFF *f, request_rec *r); +API_EXPORT(int64_t) ap_send_fb_length(BUFF *f, request_rec *r, int64_t length); -API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset, - size_t length); +API_EXPORT(int64_t) ap_send_mmap(void *mm, request_rec *r, off_t offset, int64_t length); /* Hmmm... could macrofy these for now, and maybe forever, though the * definitions of the macros would get a whole lot hairier. @@ -128,7 +127,7 @@ /* Sending a byterange */ API_EXPORT(int) ap_set_byterange(request_rec *r); -API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length); +API_EXPORT(int64_t) ap_each_byterange(request_rec *r, int64_t *offset, int64_t *length); /* Support for the Basic authentication protocol. Note that there's * nothing that prevents these from being in mod_auth.c, except that other diff -udrN apache_1.3.33/src/include/http_protocol.h.orig apache_1.3.33-mod/src/include/http_protocol.h.orig --- apache_1.3.33/src/include/http_protocol.h.orig Wed Dec 31 16:00:00 1969 +++ apache_1.3.33-mod/src/include/http_protocol.h.orig Mon Feb 16 14:25:08 2004 @@ -0,0 +1,186 @@ +/* Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef APACHE_HTTP_PROTOCOL_H +#define APACHE_HTTP_PROTOCOL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Prototypes for routines which either talk directly back to the user, + * or control the ones that eventually do. + */ + +/* Read a request and fill in the fields. */ + +API_EXPORT(request_rec *) ap_read_request(conn_rec *c); + +/* Send a single HTTP header field */ + +API_EXPORT_NONSTD(int) ap_send_header_field(request_rec *r, const char *fieldname, + const char *fieldval); + +/* Send the minimal part of an HTTP response header... but modules should be + * very careful about using this, and should prefer ap_send_http_header(). + * Much of the HTTP/1.1 implementation correctness depends on code in + * ap_send_http_header(). + */ +API_EXPORT(void) ap_basic_http_header(request_rec *r); + +/* Send the Status-Line and header fields for HTTP response */ + +API_EXPORT(void) ap_send_http_header(request_rec *l); + +/* Send the response to special method requests */ + +API_EXPORT(int) ap_send_http_trace(request_rec *r); +API_EXPORT(int) ap_send_http_options(request_rec *r); + +/* Finish up stuff after a request */ + +API_EXPORT(void) ap_finalize_request_protocol(request_rec *r); + +/* Send error back to client... last arg indicates error status in case + * we get an error in the process of trying to deal with an ErrorDocument + * to handle some other error. In that case, we print the default report + * for the first thing that went wrong, and more briefly report on the + * problem with the ErrorDocument. + */ + +API_EXPORT(void) ap_send_error_response(request_rec *r, int recursive_error); + +/* Set last modified header line from the lastmod date of the associated file. + * Also, set content length. + * + * May return an error status, typically USE_LOCAL_COPY (that when the + * permit_cache argument is set to one). + */ + +API_EXPORT(int) ap_set_content_length(request_rec *r, long length); +API_EXPORT(int) ap_set_keepalive(request_rec *r); +API_EXPORT(time_t) ap_rationalize_mtime(request_rec *r, time_t mtime); +API_EXPORT(char *) ap_make_etag(request_rec *r, int force_weak); +API_EXPORT(void) ap_set_etag(request_rec *r); +API_EXPORT(void) ap_set_last_modified(request_rec *r); +API_EXPORT(int) ap_meets_conditions(request_rec *r); + +/* Other ways to send stuff at the client. All of these keep track + * of bytes_sent automatically. This indirection is intended to make + * it a little more painless to slide things like HTTP-NG packetization + * underneath the main body of the code later. In the meantime, it lets + * us centralize a bit of accounting (bytes_sent). + * + * These also return the number of bytes written by the call. + * They should only be called with a timeout registered, for obvious reaasons. + * (Ditto the send_header stuff). + */ + +API_EXPORT(long) ap_send_fd(FILE *f, request_rec *r); +API_EXPORT(long) ap_send_fd_length(FILE *f, request_rec *r, long length); + +API_EXPORT(long) ap_send_fb(BUFF *f, request_rec *r); +API_EXPORT(long) ap_send_fb_length(BUFF *f, request_rec *r, long length); + +API_EXPORT(size_t) ap_send_mmap(void *mm, request_rec *r, size_t offset, + size_t length); + +/* Hmmm... could macrofy these for now, and maybe forever, though the + * definitions of the macros would get a whole lot hairier. + */ + +API_EXPORT(int) ap_rputc(int c, request_rec *r); +API_EXPORT(int) ap_rputs(const char *str, request_rec *r); +API_EXPORT(int) ap_rwrite(const void *buf, int nbyte, request_rec *r); +API_EXPORT_NONSTD(int) ap_rvputs(request_rec *r,...); +API_EXPORT(int) ap_vrprintf(request_rec *r, const char *fmt, va_list vlist); +API_EXPORT_NONSTD(int) ap_rprintf(request_rec *r, const char *fmt,...) + __attribute__((format(printf,2,3))); +API_EXPORT(int) ap_rflush(request_rec *r); + +/* + * Index used in custom_responses array for a specific error code + * (only use outside protocol.c is in getting them configured). + */ + +API_EXPORT(int) ap_index_of_response(int status); + +/* Reading a block of data from the client connection (e.g., POST arg) */ + +API_EXPORT(int) ap_setup_client_block(request_rec *r, int read_policy); +API_EXPORT(int) ap_should_client_block(request_rec *r); +API_EXPORT(long) ap_get_client_block(request_rec *r, char *buffer, int bufsiz); +API_EXPORT(int) ap_discard_request_body(request_rec *r); + +/* Sending a byterange */ + +API_EXPORT(int) ap_set_byterange(request_rec *r); +API_EXPORT(int) ap_each_byterange(request_rec *r, long *offset, long *length); + +/* Support for the Basic authentication protocol. Note that there's + * nothing that prevents these from being in mod_auth.c, except that other + * modules which wanted to provide their own variants on finding users and + * passwords for Basic auth (a fairly common request) would then require + * mod_auth to be loaded or they wouldn't work. + * + * get_basic_auth_pw returns 0 (OK) if it set the 'pw' argument (and assured + * a correct value in r->connection->user); otherwise it returns an error + * code, either SERVER_ERROR if things are really confused, AUTH_REQUIRED + * if no authentication at all seemed to be in use, or DECLINED if there + * was authentication but it wasn't Basic (in which case, the caller should + * presumably decline as well). + * + * note_basic_auth_failure arranges for the right stuff to be scribbled on + * the HTTP return so that the client knows how to authenticate itself the + * next time. As does note_digest_auth_failure for Digest auth. + * + * note_auth_failure does the same thing, but will call the correct one + * based on the authentication type in use. + * + */ + +API_EXPORT(void) ap_note_auth_failure(request_rec *r); +API_EXPORT(void) ap_note_basic_auth_failure(request_rec *r); +API_EXPORT(void) ap_note_digest_auth_failure(request_rec *r); +API_EXPORT(int) ap_get_basic_auth_pw(request_rec *r, const char **pw); + +/* + * Setting up the protocol fields for subsidiary requests... + * Also, a wrapup function to keep the internal accounting straight. + */ + +API_EXPORT(void) ap_set_sub_req_protocol(request_rec *rnew, const request_rec *r); +API_EXPORT(void) ap_finalize_sub_req_protocol(request_rec *sub_r); + +/* This is also useful for putting sub_reqs and internal_redirects together */ + +CORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri); + +/* Get the method number associated with the given string, assumed to + * contain an HTTP method. Returns M_INVALID if not recognized. + */ +API_EXPORT(int) ap_method_number_of(const char *method); + +API_EXPORT(int) ap_getline(char *s, int n, BUFF *in, int fold); + +API_EXPORT(long) ap_get_chunk_size(char *b); + + +#ifdef __cplusplus +} +#endif + +#endif /* !APACHE_HTTP_PROTOCOL_H */ diff -udrN apache_1.3.33/src/include/httpd.h apache_1.3.33-mod/src/include/httpd.h --- apache_1.3.33/src/include/httpd.h Wed Oct 27 09:34:01 2004 +++ apache_1.3.33-mod/src/include/httpd.h Fri Apr 1 10:06:37 2005 @@ -700,20 +700,20 @@ */ int allowed; /* Allowed methods - for 405, OPTIONS, etc */ - int sent_bodyct; /* byte count in stream is for body */ - long bytes_sent; /* body byte count, for easy access */ + int64_t sent_bodyct; /* byte count in stream is for body */ + int64_t bytes_sent; /* body byte count, for easy access */ time_t mtime; /* Time the resource was last modified */ /* HTTP/1.1 connection-level features */ int chunked; /* sending chunked transfer-coding */ - int byterange; /* number of byte ranges */ + int64_t byterange; /* number of byte ranges */ char *boundary; /* multipart/byteranges boundary */ const char *range; /* The Range: header */ - long clength; /* The "real" content length */ + int64_t clength; /* The "real" content length */ - long remaining; /* bytes left to read */ - long read_length; /* bytes that have been read */ + int64_t remaining; /* bytes left to read */ + int64_t read_length; /* bytes that have been read */ int read_body; /* how the request body should be read */ int read_chunked; /* reading chunked transfer-coding */ unsigned expecting_100; /* is client waiting for a 100 response? */ diff -udrN apache_1.3.33/src/include/httpd.h.orig apache_1.3.33-mod/src/include/httpd.h.orig --- apache_1.3.33/src/include/httpd.h.orig Wed Dec 31 16:00:00 1969 +++ apache_1.3.33-mod/src/include/httpd.h.orig Wed Oct 27 09:34:01 2004 @@ -0,0 +1,1216 @@ +/* Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#ifndef APACHE_HTTPD_H +#define APACHE_HTTPD_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * httpd.h: header for simple (ha! not anymore) http daemon + */ + +/* Headers in which EVERYONE has an interest... */ + +#include "ap_config.h" +#include "ap_alloc.h" +#include "buff.h" +#include "ap.h" + +/* ----------------------------- config dir ------------------------------ */ + +/* Define this to be the default server home dir. Most things later in this + * file with a relative pathname will have this added. + */ +#ifndef HTTPD_ROOT +#ifdef OS2 +/* Set default for OS/2 file system */ +#define HTTPD_ROOT "/os2httpd" +#elif defined(WIN32) +/* Set default for Windows file system */ +#define HTTPD_ROOT "/apache" +#elif defined(BEOS) || defined(BONE) +#define HTTPD_ROOT "/boot/home/apache" +#elif defined(NETWARE) +#define HTTPD_ROOT "sys:/apache" +#else +#define HTTPD_ROOT "/usr/local/apache" +#endif +#endif /* HTTPD_ROOT */ + +/* Default location of documents. Can be overridden by the DocumentRoot + * directive. + */ +#ifndef DOCUMENT_LOCATION +#ifdef OS2 +/* Set default for OS/2 file system */ +#define DOCUMENT_LOCATION HTTPD_ROOT "/docs" +#else +#define DOCUMENT_LOCATION HTTPD_ROOT "/htdocs" +#endif +#endif /* DOCUMENT_LOCATION */ + +/* Max. number of dynamically loaded modules */ +#ifndef DYNAMIC_MODULE_LIMIT +#define DYNAMIC_MODULE_LIMIT 64 +#endif + +/* Default administrator's address */ +#define DEFAULT_ADMIN "[no address given]" + +/* The target name of the installed Apache */ +#ifndef TARGET +#define TARGET "httpd" +#endif + +/* + * --------- You shouldn't have to edit anything below this line ---------- + * + * Any modifications to any defaults not defined above should be done in the + * respective config. file. + * + */ + + +/* -- Internal representation for a HTTP protocol number, e.g., HTTP/1.1 -- */ + +#define HTTP_VERSION(major,minor) (1000*(major)+(minor)) +#define HTTP_VERSION_MAJOR(number) ((number)/1000) +#define HTTP_VERSION_MINOR(number) ((number)%1000) + + +/* -------------- Port number for server running standalone --------------- */ + +#define DEFAULT_HTTP_PORT 80 +#define DEFAULT_HTTPS_PORT 443 +#define ap_is_default_port(port,r) ((port) == ap_default_port(r)) +#ifdef NETWARE +#define ap_http_method(r) ap_os_http_method((void*)r) +#define ap_default_port(r) ap_os_default_port((void*)r) +#else +#define ap_http_method(r) "http" +#define ap_default_port(r) DEFAULT_HTTP_PORT +#endif + +/* --------- Default user name and group name running standalone ---------- */ +/* --- These may be specified as numbers by placing a # before a number --- */ + +#ifndef DEFAULT_USER +#define DEFAULT_USER "#-1" +#endif +#ifndef DEFAULT_GROUP +#define DEFAULT_GROUP "#-1" +#endif + +#ifndef DEFAULT_ERRORLOG +#if defined(OS2) || defined(WIN32) +#define DEFAULT_ERRORLOG "logs/error.log" +#else +#define DEFAULT_ERRORLOG "logs/error_log" +#endif +#endif /* DEFAULT_ERRORLOG */ + +#ifndef DEFAULT_PIDLOG +#define DEFAULT_PIDLOG "logs/httpd.pid" +#endif +#ifndef DEFAULT_SCOREBOARD +#define DEFAULT_SCOREBOARD "logs/apache_runtime_status" +#endif +#ifndef DEFAULT_LOCKFILE +#define DEFAULT_LOCKFILE "logs/accept.lock" +#endif + +/* Define this to be what your HTML directory content files are called */ +#ifndef DEFAULT_INDEX +#define DEFAULT_INDEX "index.html" +#endif + +/* Define this to 1 if you want fancy indexing, 0 otherwise */ +#ifndef DEFAULT_INDEXING +#define DEFAULT_INDEXING 0 +#endif + +/* Define this to be what type you'd like returned for files with unknown */ +/* suffixes. MUST be all lower case. */ +#ifndef DEFAULT_CONTENT_TYPE +#define DEFAULT_CONTENT_TYPE "text/plain" +#endif + +/* Define this to be what your per-directory security files are called */ +#ifndef DEFAULT_ACCESS_FNAME +#ifdef OS2 +/* Set default for OS/2 file system */ +#define DEFAULT_ACCESS_FNAME "htaccess" +#else +#define DEFAULT_ACCESS_FNAME ".htaccess" +#endif +#endif /* DEFAULT_ACCESS_FNAME */ + +/* The name of the server config file */ +#ifndef SERVER_CONFIG_FILE +#define SERVER_CONFIG_FILE "conf/httpd.conf" +#endif + +/* The name of the document config file */ +#ifndef RESOURCE_CONFIG_FILE +#define RESOURCE_CONFIG_FILE "conf/srm.conf" +#endif + +/* The name of the MIME types file */ +#ifndef TYPES_CONFIG_FILE +#define TYPES_CONFIG_FILE "conf/mime.types" +#endif + +/* The name of the access file */ +#ifndef ACCESS_CONFIG_FILE +#define ACCESS_CONFIG_FILE "conf/access.conf" +#endif + +/* Whether we should enable rfc1413 identity checking */ +#ifndef DEFAULT_RFC1413 +#define DEFAULT_RFC1413 0 +#endif +/* The default directory in user's home dir */ +#ifndef DEFAULT_USER_DIR +#define DEFAULT_USER_DIR "public_html" +#endif + +/* The default path for CGI scripts if none is currently set */ +#ifndef DEFAULT_PATH +#define DEFAULT_PATH "/bin:/usr/bin:/usr/ucb:/usr/bsd:/usr/local/bin" +#endif + +/* The path to the shell interpreter, for parsed docs */ +#ifndef SHELL_PATH +#if defined(OS2) || defined(WIN32) +/* Set default for OS/2 and Windows file system */ +#define SHELL_PATH "CMD.EXE" +#else +#define SHELL_PATH "/bin/sh" +#endif +#endif /* SHELL_PATH */ + +/* The path to the suExec wrapper, can be overridden in Configuration */ +#ifndef SUEXEC_BIN +#define SUEXEC_BIN HTTPD_ROOT "/bin/suexec" +#endif + +/* The default string lengths */ +#define MAX_STRING_LEN HUGE_STRING_LEN +#define HUGE_STRING_LEN 8192 + +/* The timeout for waiting for messages */ +#ifndef DEFAULT_TIMEOUT +#define DEFAULT_TIMEOUT 300 +#endif + +/* The timeout for waiting for keepalive timeout until next request */ +#ifndef DEFAULT_KEEPALIVE_TIMEOUT +#define DEFAULT_KEEPALIVE_TIMEOUT 15 +#endif + +/* The number of requests to entertain per connection */ +#ifndef DEFAULT_KEEPALIVE +#define DEFAULT_KEEPALIVE 100 +#endif + +/* The size of the server's internal read-write buffers */ +#define IOBUFSIZE 8192 + +/* The max number of regex captures that can be expanded by ap_pregsub */ +#define AP_MAX_REG_MATCH 10 + +/* Number of servers to spawn off by default --- also, if fewer than + * this free when the caretaker checks, it will spawn more. + */ +#ifndef DEFAULT_START_DAEMON +#define DEFAULT_START_DAEMON 5 +#endif + +/* Maximum number of *free* server processes --- more than this, and + * they will die off. + */ + +#ifndef DEFAULT_MAX_FREE_DAEMON +#define DEFAULT_MAX_FREE_DAEMON 10 +#endif + +/* Minimum --- fewer than this, and more will be created */ + +#ifndef DEFAULT_MIN_FREE_DAEMON +#define DEFAULT_MIN_FREE_DAEMON 5 +#endif + +/* Limit on the total --- clients will be locked out if more servers than + * this are needed. It is intended solely to keep the server from crashing + * when things get out of hand. + * + * We keep a hard maximum number of servers, for two reasons --- first off, + * in case something goes seriously wrong, we want to stop the fork bomb + * short of actually crashing the machine we're running on by filling some + * kernel table. Secondly, it keeps the size of the scoreboard file small + * enough that we can read the whole thing without worrying too much about + * the overhead. + */ +#ifndef HARD_SERVER_LIMIT +#ifdef WIN32 +#define HARD_SERVER_LIMIT 1024 +#elif defined(NETWARE) +#define HARD_SERVER_LIMIT 2048 +#else +#define HARD_SERVER_LIMIT 256 +#endif +#endif + +/* + * Special Apache error codes. These are basically used + * in http_main.c so we can keep track of various errors. + * + * APEXIT_OK: + * A normal exit + * APEXIT_INIT: + * A fatal error arising during the server's init sequence + * APEXIT_CHILDINIT: + * The child died during it's init sequence + * APEXIT_CHILDFATAL: + * A fatal error, resulting in the whole server aborting. + * If a child exits with this error, the parent process + * considers this a server-wide fatal error and aborts. + * + */ +#define APEXIT_OK 0x0 +#define APEXIT_INIT 0x2 +#define APEXIT_CHILDINIT 0x3 +#define APEXIT_CHILDFATAL 0xf + +/* + * (Unix, OS/2 only) + * Interval, in microseconds, between scoreboard maintenance. During + * each scoreboard maintenance cycle the parent decides if it needs to + * spawn a new child (to meet MinSpareServers requirements), or kill off + * a child (to meet MaxSpareServers requirements). It will only spawn or + * kill one child per cycle. Setting this too low will chew cpu. The + * default is probably sufficient for everyone. But some people may want + * to raise this on servers which aren't dedicated to httpd and where they + * don't like the httpd waking up each second to see what's going on. + */ +#ifndef SCOREBOARD_MAINTENANCE_INTERVAL +#define SCOREBOARD_MAINTENANCE_INTERVAL 1000000 +#endif + +/* Number of requests to try to handle in a single process. If <= 0, + * the children don't die off. That's the default here, since I'm still + * interested in finding and stanching leaks. + */ + +#ifndef DEFAULT_MAX_REQUESTS_PER_CHILD +#define DEFAULT_MAX_REQUESTS_PER_CHILD 0 +#endif + +#ifndef DEFAULT_THREADS_PER_CHILD +#define DEFAULT_THREADS_PER_CHILD 50 +#endif +#ifndef DEFAULT_EXCESS_REQUESTS_PER_CHILD +#define DEFAULT_EXCESS_REQUESTS_PER_CHILD 0 +#endif + +/* The maximum length of the queue of pending connections, as defined + * by listen(2). Under some systems, it should be increased if you + * are experiencing a heavy TCP SYN flood attack. + * + * It defaults to 511 instead of 512 because some systems store it + * as an 8-bit datatype; 512 truncated to 8-bits is 0, while 511 is + * 255 when truncated. + */ + +#ifndef DEFAULT_LISTENBACKLOG +#define DEFAULT_LISTENBACKLOG 511 +#endif + +/* Limits on the size of various request items. These limits primarily + * exist to prevent simple denial-of-service attacks on a server based + * on misuse of the protocol. The recommended values will depend on the + * nature of the server resources -- CGI scripts and database backends + * might require large values, but most servers could get by with much + * smaller limits than we use below. The request message body size can + * be limited by the per-dir config directive LimitRequestBody. + * + * Internal buffer sizes are two bytes more than the DEFAULT_LIMIT_REQUEST_LINE + * and DEFAULT_LIMIT_REQUEST_FIELDSIZE below, which explains the 8190. + * These two limits can be lowered (but not raised) by the server config + * directives LimitRequestLine and LimitRequestFieldsize, respectively. + * + * DEFAULT_LIMIT_REQUEST_FIELDS can be modified or disabled (set = 0) by + * the server config directive LimitRequestFields. + */ +#ifndef DEFAULT_LIMIT_REQUEST_LINE +#define DEFAULT_LIMIT_REQUEST_LINE 8190 +#endif /* default limit on bytes in Request-Line (Method+URI+HTTP-version) */ +#ifndef DEFAULT_LIMIT_REQUEST_FIELDSIZE +#define DEFAULT_LIMIT_REQUEST_FIELDSIZE 8190 +#endif /* default limit on bytes in any one header field */ +#ifndef DEFAULT_LIMIT_REQUEST_FIELDS +#define DEFAULT_LIMIT_REQUEST_FIELDS 100 +#endif /* default limit on number of request header fields */ + +/* + * The default default character set name to add if AddDefaultCharset is + * enabled. Overridden with AddDefaultCharsetName. + */ +#define DEFAULT_ADD_DEFAULT_CHARSET_NAME "iso-8859-1" + +/* + * The below defines the base string of the Server: header. Additional + * tokens can be added via the ap_add_version_component() API call. + * + * The tokens are listed in order of their significance for identifying the + * application. + * + * "Product tokens should be short and to the point -- use of them for + * advertizing or other non-essential information is explicitly forbidden." + * + * Example: "Apache/1.1.0 MrWidget/0.1-alpha" + */ + +#define SERVER_BASEVENDOR "Apache Group" +#define SERVER_BASEPRODUCT "Apache" +#define SERVER_BASEREVISION "1.3.33" +#define SERVER_BASEVERSION SERVER_BASEPRODUCT "/" SERVER_BASEREVISION + +#define SERVER_PRODUCT SERVER_BASEPRODUCT +#define SERVER_REVISION SERVER_BASEREVISION +#define SERVER_VERSION SERVER_PRODUCT "/" SERVER_REVISION +enum server_token_type { + SrvTk_MIN, /* eg: Apache/1.3.0 */ + SrvTk_OS, /* eg: Apache/1.3.0 (UNIX) */ + SrvTk_FULL, /* eg: Apache/1.3.0 (UNIX) PHP/3.0 FooBar/1.2b */ + SrvTk_PRODUCT_ONLY /* eg: Apache */ +}; + +API_EXPORT(const char *) ap_get_server_version(void); +API_EXPORT(void) ap_add_version_component(const char *component); +API_EXPORT(const char *) ap_get_server_built(void); + +/* Numeric release version identifier: MMNNFFRBB: major minor fix final beta + * Always increases along the same track as the source branch. + * For example, Apache 1.4.2 would be '10402100', 2.5b7 would be '20500007'. + */ +#define APACHE_RELEASE 10333100 + +#define SERVER_PROTOCOL "HTTP/1.1" +#ifndef SERVER_SUPPORT +#define SERVER_SUPPORT "http://www.apache.org/" +#endif + +#define DECLINED -1 /* Module declines to handle */ +#define DONE -2 /* Module has served the response completely + * - it's safe to die() with no more output + */ +#define OK 0 /* Module has handled this stage. */ + + +/* ----------------------- HTTP Status Codes ------------------------- */ + +/* The size of the static array in http_protocol.c for storing + * all of the potential response status-lines (a sparse table). + * A future version should dynamically generate the table at startup. + */ +#define RESPONSE_CODES 55 + +#define HTTP_CONTINUE 100 +#define HTTP_SWITCHING_PROTOCOLS 101 +#define HTTP_PROCESSING 102 +#define HTTP_OK 200 +#define HTTP_CREATED 201 +#define HTTP_ACCEPTED 202 +#define HTTP_NON_AUTHORITATIVE 203 +#define HTTP_NO_CONTENT 204 +#define HTTP_RESET_CONTENT 205 +#define HTTP_PARTIAL_CONTENT 206 +#define HTTP_MULTI_STATUS 207 +#define HTTP_MULTIPLE_CHOICES 300 +#define HTTP_MOVED_PERMANENTLY 301 +#define HTTP_MOVED_TEMPORARILY 302 +#define HTTP_SEE_OTHER 303 +#define HTTP_NOT_MODIFIED 304 +#define HTTP_USE_PROXY 305 +#define HTTP_TEMPORARY_REDIRECT 307 +#define HTTP_BAD_REQUEST 400 +#define HTTP_UNAUTHORIZED 401 +#define HTTP_PAYMENT_REQUIRED 402 +#define HTTP_FORBIDDEN 403 +#define HTTP_NOT_FOUND 404 +#define HTTP_METHOD_NOT_ALLOWED 405 +#define HTTP_NOT_ACCEPTABLE 406 +#define HTTP_PROXY_AUTHENTICATION_REQUIRED 407 +#define HTTP_REQUEST_TIME_OUT 408 +#define HTTP_CONFLICT 409 +#define HTTP_GONE 410 +#define HTTP_LENGTH_REQUIRED 411 +#define HTTP_PRECONDITION_FAILED 412 +#define HTTP_REQUEST_ENTITY_TOO_LARGE 413 +#define HTTP_REQUEST_URI_TOO_LARGE 414 +#define HTTP_UNSUPPORTED_MEDIA_TYPE 415 +#define HTTP_RANGE_NOT_SATISFIABLE 416 +#define HTTP_EXPECTATION_FAILED 417 +#define HTTP_UNPROCESSABLE_ENTITY 422 +#define HTTP_LOCKED 423 +#define HTTP_FAILED_DEPENDENCY 424 +#define HTTP_INTERNAL_SERVER_ERROR 500 +#define HTTP_NOT_IMPLEMENTED 501 +#define HTTP_BAD_GATEWAY 502 +#define HTTP_SERVICE_UNAVAILABLE 503 +#define HTTP_GATEWAY_TIME_OUT 504 +#define HTTP_VERSION_NOT_SUPPORTED 505 +#define HTTP_VARIANT_ALSO_VARIES 506 +#define HTTP_INSUFFICIENT_STORAGE 507 +#define HTTP_NOT_EXTENDED 510 + +#define DOCUMENT_FOLLOWS HTTP_OK +#define PARTIAL_CONTENT HTTP_PARTIAL_CONTENT +#define MULTIPLE_CHOICES HTTP_MULTIPLE_CHOICES +#define MOVED HTTP_MOVED_PERMANENTLY +#define REDIRECT HTTP_MOVED_TEMPORARILY +#define USE_LOCAL_COPY HTTP_NOT_MODIFIED +#define BAD_REQUEST HTTP_BAD_REQUEST +#define AUTH_REQUIRED HTTP_UNAUTHORIZED +#define FORBIDDEN HTTP_FORBIDDEN +#define NOT_FOUND HTTP_NOT_FOUND +#define METHOD_NOT_ALLOWED HTTP_METHOD_NOT_ALLOWED +#define NOT_ACCEPTABLE HTTP_NOT_ACCEPTABLE +#define LENGTH_REQUIRED HTTP_LENGTH_REQUIRED +#define PRECONDITION_FAILED HTTP_PRECONDITION_FAILED +#define SERVER_ERROR HTTP_INTERNAL_SERVER_ERROR +#define NOT_IMPLEMENTED HTTP_NOT_IMPLEMENTED +#define BAD_GATEWAY HTTP_BAD_GATEWAY +#define VARIANT_ALSO_VARIES HTTP_VARIANT_ALSO_VARIES + +#define ap_is_HTTP_INFO(x) (((x) >= 100)&&((x) < 200)) +#define ap_is_HTTP_SUCCESS(x) (((x) >= 200)&&((x) < 300)) +#define ap_is_HTTP_REDIRECT(x) (((x) >= 300)&&((x) < 400)) +#define ap_is_HTTP_ERROR(x) (((x) >= 400)&&((x) < 600)) +#define ap_is_HTTP_CLIENT_ERROR(x) (((x) >= 400)&&((x) < 500)) +#define ap_is_HTTP_SERVER_ERROR(x) (((x) >= 500)&&((x) < 600)) + +#define ap_status_drops_connection(x) \ + (((x) == HTTP_BAD_REQUEST) || \ + ((x) == HTTP_REQUEST_TIME_OUT) || \ + ((x) == HTTP_LENGTH_REQUIRED) || \ + ((x) == HTTP_REQUEST_ENTITY_TOO_LARGE) || \ + ((x) == HTTP_REQUEST_URI_TOO_LARGE) || \ + ((x) == HTTP_INTERNAL_SERVER_ERROR) || \ + ((x) == HTTP_SERVICE_UNAVAILABLE) || \ + ((x) == HTTP_NOT_IMPLEMENTED)) + +/* Methods recognized (but not necessarily handled) by the server. + * These constants are used in bit shifting masks of size int, so it is + * unsafe to have more methods than bits in an int. HEAD == M_GET. + */ +#define M_GET 0 +#define M_PUT 1 +#define M_POST 2 +#define M_DELETE 3 +#define M_CONNECT 4 +#define M_OPTIONS 5 +#define M_TRACE 6 +#define M_PATCH 7 +#define M_PROPFIND 8 +#define M_PROPPATCH 9 +#define M_MKCOL 10 +#define M_COPY 11 +#define M_MOVE 12 +#define M_LOCK 13 +#define M_UNLOCK 14 +#define M_INVALID 15 + +#define METHODS 16 + +#define CGI_MAGIC_TYPE "application/x-httpd-cgi" +#define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html" +#define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3" +#ifdef CHARSET_EBCDIC +#define ASCIITEXT_MAGIC_TYPE_PREFIX "text/x-ascii-" /* Text files whose content-type starts with this are passed thru unconverted */ +#endif /*CHARSET_EBCDIC*/ +#define MAP_FILE_MAGIC_TYPE "application/x-type-map" +#define ASIS_MAGIC_TYPE "httpd/send-as-is" +#define DIR_MAGIC_TYPE "httpd/unix-directory" +#define STATUS_MAGIC_TYPE "application/x-httpd-status" + +/* + * Define the HTML doctype strings centrally. + */ +#define DOCTYPE_HTML_2_0 "\n" +#define DOCTYPE_HTML_3_2 "\n" +#define DOCTYPE_HTML_4_0S "\n" +#define DOCTYPE_HTML_4_0T "\n" +#define DOCTYPE_HTML_4_0F "\n" + +/* Just in case your linefeed isn't the one the other end is expecting. */ +#ifndef CHARSET_EBCDIC +#define LF 10 +#define CR 13 +#define CRLF "\015\012" +#define OS_ASC(c) (c) +#else /* CHARSET_EBCDIC */ +#include "ap_ebcdic.h" +/* OSD_POSIX uses the EBCDIC charset. The transition ASCII->EBCDIC is done in + * the buff package (bread/bputs/bwrite), so everywhere else, we use + * "native EBCDIC" CR and NL characters. These are therefore defined as + * '\r' and '\n'. + * NB: this is not the whole truth - sometimes \015 and \012 are contained + * in literal (EBCDIC!) strings, so these are not converted but passed. + */ +#define CR '\r' +#define LF '\n' +#define CRLF "\r\n" +#define OS_ASC(c) (os_toascii[c]) +#endif /* CHARSET_EBCDIC */ + +/* Possible values for request_rec.read_body (set by handling module): + * REQUEST_NO_BODY Send 413 error if message has any body + * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length + * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. + * REQUEST_CHUNKED_PASS Pass the chunks to me without removal. + */ +#define REQUEST_NO_BODY 0 +#define REQUEST_CHUNKED_ERROR 1 +#define REQUEST_CHUNKED_DECHUNK 2 +#define REQUEST_CHUNKED_PASS 3 + +/* Things which may vary per file-lookup WITHIN a request --- + * e.g., state of MIME config. Basically, the name of an object, info + * about the object, and any other info we may ahve which may need to + * change as we go poking around looking for it (e.g., overridden by + * .htaccess files). + * + * Note how the default state of almost all these things is properly + * zero, so that allocating it with pcalloc does the right thing without + * a whole lot of hairy initialization... so long as we are willing to + * make the (fairly) portable assumption that the bit pattern of a NULL + * pointer is, in fact, zero. + */ + +/* This represents the result of calling htaccess; these are cached for + * each request. + */ +struct htaccess_result { + char *dir; /* the directory to which this applies */ + int override; /* the overrides allowed for the .htaccess file */ + void *htaccess; /* the configuration directives */ +/* the next one, or NULL if no more; N.B. never change this */ + const struct htaccess_result *next; +}; + +typedef struct conn_rec conn_rec; +typedef struct server_rec server_rec; +typedef struct request_rec request_rec; +typedef struct listen_rec listen_rec; + +#include "util_uri.h" + +enum proxyreqtype { + NOT_PROXY=0, + STD_PROXY, + PROXY_PASS +}; + +struct request_rec { + + ap_pool *pool; + conn_rec *connection; + server_rec *server; + + request_rec *next; /* If we wind up getting redirected, + * pointer to the request we redirected to. + */ + request_rec *prev; /* If this is an internal redirect, + * pointer to where we redirected *from*. + */ + + request_rec *main; /* If this is a sub_request (see request.h) + * pointer back to the main request. + */ + + /* Info about the request itself... we begin with stuff that only + * protocol.c should ever touch... + */ + + char *the_request; /* First line of request, so we can log it */ + int assbackwards; /* HTTP/0.9, "simple" request */ + enum proxyreqtype proxyreq;/* A proxy request (calculated during + * post_read_request or translate_name) */ + int header_only; /* HEAD request, as opposed to GET */ + char *protocol; /* Protocol, as given to us, or HTTP/0.9 */ + int proto_num; /* Number version of protocol; 1.1 = 1001 */ + const char *hostname; /* Host, as set by full URI or Host: */ + + time_t request_time; /* When the request started */ + + const char *status_line; /* Status line, if set by script */ + int status; /* In any case */ + + /* Request method, two ways; also, protocol, etc.. Outside of protocol.c, + * look, but don't touch. + */ + + const char *method; /* GET, HEAD, POST, etc. */ + int method_number; /* M_GET, M_POST, etc. */ + + /* + allowed is a bitvector of the allowed methods. + + A handler must ensure that the request method is one that + it is capable of handling. Generally modules should DECLINE + any request methods they do not handle. Prior to aborting the + handler like this the handler should set r->allowed to the list + of methods that it is willing to handle. This bitvector is used + to construct the "Allow:" header required for OPTIONS requests, + and METHOD_NOT_ALLOWED and NOT_IMPLEMENTED status codes. + + Since the default_handler deals with OPTIONS, all modules can + usually decline to deal with OPTIONS. TRACE is always allowed, + modules don't need to set it explicitly. + + Since the default_handler will always handle a GET, a + module which does *not* implement GET should probably return + METHOD_NOT_ALLOWED. Unfortunately this means that a Script GET + handler can't be installed by mod_actions. + */ + int allowed; /* Allowed methods - for 405, OPTIONS, etc */ + + int sent_bodyct; /* byte count in stream is for body */ + long bytes_sent; /* body byte count, for easy access */ + time_t mtime; /* Time the resource was last modified */ + + /* HTTP/1.1 connection-level features */ + + int chunked; /* sending chunked transfer-coding */ + int byterange; /* number of byte ranges */ + char *boundary; /* multipart/byteranges boundary */ + const char *range; /* The Range: header */ + long clength; /* The "real" content length */ + + long remaining; /* bytes left to read */ + long read_length; /* bytes that have been read */ + int read_body; /* how the request body should be read */ + int read_chunked; /* reading chunked transfer-coding */ + unsigned expecting_100; /* is client waiting for a 100 response? */ + + /* MIME header environments, in and out. Also, an array containing + * environment variables to be passed to subprocesses, so people can + * write modules to add to that environment. + * + * The difference between headers_out and err_headers_out is that the + * latter are printed even on error, and persist across internal redirects + * (so the headers printed for ErrorDocument handlers will have them). + * + * The 'notes' table is for notes from one module to another, with no + * other set purpose in mind... + */ + + table *headers_in; + table *headers_out; + table *err_headers_out; + table *subprocess_env; + table *notes; + + /* content_type, handler, content_encoding, content_language, and all + * content_languages MUST be lowercased strings. They may be pointers + * to static strings; they should not be modified in place. + */ + const char *content_type; /* Break these out --- we dispatch on 'em */ + const char *handler; /* What we *really* dispatch on */ + + const char *content_encoding; + const char *content_language; /* for back-compat. only -- do not use */ + array_header *content_languages; /* array of (char*) */ + + char *vlist_validator; /* variant list validator (if negotiated) */ + + int no_cache; + int no_local_copy; + + /* What object is being requested (either directly, or via include + * or content-negotiation mapping). + */ + + char *unparsed_uri; /* the uri without any parsing performed */ + char *uri; /* the path portion of the URI */ + char *filename; /* filename if found, otherwise NULL */ + char *path_info; + char *args; /* QUERY_ARGS, if any */ + struct stat finfo; /* ST_MODE set to zero if no such file */ + uri_components parsed_uri; /* components of uri, dismantled */ + + /* Various other config info which may change with .htaccess files + * These are config vectors, with one void* pointer for each module + * (the thing pointed to being the module's business). + */ + + void *per_dir_config; /* Options set in config files, etc. */ + void *request_config; /* Notes on *this* request */ + +/* + * a linked list of the configuration directives in the .htaccess files + * accessed by this request. + * N.B. always add to the head of the list, _never_ to the end. + * that way, a sub request's list can (temporarily) point to a parent's list + */ + const struct htaccess_result *htaccess; + + /* On systems with case insensitive file systems (Windows, OS/2, etc.), + * r->filename is case canonicalized (folded to either lower or upper + * case, depending on the specific system) to accomodate file access + * checking. case_preserved_filename is the same as r->filename + * except case is preserved. There is at least one instance where Apache + * needs access to the case preserved filename: Java class files published + * with WebDAV need to preserve filename case to make the Java compiler + * happy. + */ + char *case_preserved_filename; + +#ifdef CHARSET_EBCDIC + /* We don't want subrequests to modify our current conversion flags. + * These flags save the state of the conversion flags when subrequests + * are run. + */ + struct { + unsigned conv_in:1; /* convert ASCII->EBCDIC when read()ing? */ + unsigned conv_out:1; /* convert EBCDIC->ASCII when write()ing? */ + } ebcdic; +#endif + +/* Things placed at the end of the record to avoid breaking binary + * compatibility. It would be nice to remember to reorder the entire + * record to improve 64bit alignment the next time we need to break + * binary compatibility for some other reason. + */ +}; + + +/* Things which are per connection + */ + +struct conn_rec { + + ap_pool *pool; + server_rec *server; + server_rec *base_server; /* Physical vhost this conn come in on */ + void *vhost_lookup_data; /* used by http_vhost.c */ + + /* Information about the connection itself */ + + int child_num; /* The number of the child handling conn_rec */ + BUFF *client; /* Connection to the guy */ + + /* Who is the client? */ + + struct sockaddr_in local_addr; /* local address */ + struct sockaddr_in remote_addr; /* remote address */ + char *remote_ip; /* Client's IP address */ + char *remote_host; /* Client's DNS name, if known. + * NULL if DNS hasn't been checked, + * "" if it has and no address was found. + * N.B. Only access this though + * get_remote_host() */ + char *remote_logname; /* Only ever set if doing rfc1413 lookups. + * N.B. Only access this through + * get_remote_logname() */ + char *user; /* If an authentication check was made, + * this gets set to the user name. We assume + * that there's only one user per connection(!) + */ + char *ap_auth_type; /* Ditto. */ + + unsigned aborted:1; /* Are we still talking? */ + signed int keepalive:2; /* Are we using HTTP Keep-Alive? + * -1 fatal error, 0 undecided, 1 yes */ + unsigned keptalive:1; /* Did we use HTTP Keep-Alive? */ + signed int double_reverse:2;/* have we done double-reverse DNS? + * -1 yes/failure, 0 not yet, 1 yes/success */ + int keepalives; /* How many times have we used it? */ + char *local_ip; /* server IP address */ + char *local_host; /* used for ap_get_server_name when + * UseCanonicalName is set to DNS + * (ignores setting of HostnameLookups) */ +}; + +/* Per-vhost config... */ + +/* The address 255.255.255.255, when used as a virtualhost address, + * will become the "default" server when the ip doesn't match other vhosts. + */ +#define DEFAULT_VHOST_ADDR 0xfffffffful + +typedef struct server_addr_rec server_addr_rec; +struct server_addr_rec { + server_addr_rec *next; + struct in_addr host_addr; /* The bound address, for this server */ + unsigned short host_port; /* The bound port, for this server */ + char *virthost; /* The name given in */ +}; + +struct server_rec { + + server_rec *next; + + /* description of where the definition came from */ + const char *defn_name; + unsigned defn_line_number; + + /* Full locations of server config info */ + + char *srm_confname; + char *access_confname; + + /* Contact information */ + + char *server_admin; + char *server_hostname; + unsigned short port; /* for redirects, etc. */ + + /* Log files --- note that transfer log is now in the modules... */ + + char *error_fname; + FILE *error_log; + int loglevel; + + /* Module-specific configuration for server, and defaults... */ + + int is_virtual; /* true if this is the virtual server */ + void *module_config; /* Config vector containing pointers to + * modules' per-server config structures. + */ + void *lookup_defaults; /* MIME type info, etc., before we start + * checking per-directory info. + */ + /* Transaction handling */ + + server_addr_rec *addrs; + int timeout; /* Timeout, in seconds, before we give up */ + int keep_alive_timeout; /* Seconds we'll wait for another request */ + int keep_alive_max; /* Maximum requests per connection */ + int keep_alive; /* Use persistent connections? */ + int send_buffer_size; /* size of TCP send buffer (in bytes) */ + + char *path; /* Pathname for ServerPath */ + int pathlen; /* Length of path */ + + array_header *names; /* Normal names for ServerAlias servers */ + array_header *wild_names; /* Wildcarded names for ServerAlias servers */ + + uid_t server_uid; /* effective user id when calling exec wrapper */ + gid_t server_gid; /* effective group id when calling exec wrapper */ + + int limit_req_line; /* limit on size of the HTTP request line */ + int limit_req_fieldsize; /* limit on size of any request header field */ + int limit_req_fields; /* limit on number of request header fields */ +}; + +/* These are more like real hosts than virtual hosts */ +struct listen_rec { + listen_rec *next; + struct sockaddr_in local_addr; /* local IP address and port */ + int fd; + int used; /* Only used during restart */ +/* more stuff here, like which protocol is bound to the port */ +}; + +/* Prototypes for utilities... util.c. + */ + +extern void ap_util_init(void); + +/* Time */ +extern API_VAR_EXPORT const char ap_month_snames[12][4]; +extern API_VAR_EXPORT const char ap_day_snames[7][4]; + +API_EXPORT(struct tm *) ap_get_gmtoff(int *tz); +API_EXPORT(char *) ap_get_time(void); +API_EXPORT(char *) ap_field_noparam(pool *p, const char *intype); +API_EXPORT(char *) ap_ht_time(pool *p, time_t t, const char *fmt, int gmt); +API_EXPORT(char *) ap_gm_timestr_822(pool *p, time_t t); + +/* String handling. The *_nc variants allow you to use non-const char **s as + arguments (unfortunately C won't automatically convert a char ** to a const + char **) */ + +API_EXPORT(char *) ap_getword(pool *p, const char **line, char stop); +API_EXPORT(char *) ap_getword_nc(pool *p, char **line, char stop); +API_EXPORT(char *) ap_getword_white(pool *p, const char **line); +API_EXPORT(char *) ap_getword_white_nc(pool *p, char **line); +API_EXPORT(char *) ap_getword_nulls(pool *p, const char **line, char stop); +API_EXPORT(char *) ap_getword_nulls_nc(pool *p, char **line, char stop); +API_EXPORT(char *) ap_getword_conf(pool *p, const char **line); +API_EXPORT(char *) ap_getword_conf_nc(pool *p, char **line); + +API_EXPORT(const char *) ap_size_list_item(const char **field, int *len); +API_EXPORT(char *) ap_get_list_item(pool *p, const char **field); +API_EXPORT(int) ap_find_list_item(pool *p, const char *line, const char *tok); + +API_EXPORT(char *) ap_get_token(pool *p, const char **accept_line, int accept_white); +API_EXPORT(int) ap_find_token(pool *p, const char *line, const char *tok); +API_EXPORT(int) ap_find_last_token(pool *p, const char *line, const char *tok); + +API_EXPORT(int) ap_is_url(const char *u); +API_EXPORT(int) ap_unescape_url(char *url); +API_EXPORT(void) ap_no2slash(char *name); +API_EXPORT(void) ap_getparents(char *name); +API_EXPORT(char *) ap_escape_path_segment(pool *p, const char *s); +API_EXPORT(char *) ap_os_escape_path(pool *p, const char *path, int partial); +#define ap_escape_uri(ppool,path) ap_os_escape_path(ppool,path,1) +API_EXPORT(char *) ap_escape_html(pool *p, const char *s); +API_EXPORT(char *) ap_construct_server(pool *p, const char *hostname, + unsigned port, const request_rec *r); +API_EXPORT(char *) ap_escape_logitem(pool *p, const char *str); +API_EXPORT(size_t) ap_escape_errorlog_item(char *dest, const char *source, + size_t buflen); +API_EXPORT(char *) ap_escape_shell_cmd(pool *p, const char *s); + +API_EXPORT(int) ap_count_dirs(const char *path); +API_EXPORT(char *) ap_make_dirstr_prefix(char *d, const char *s, int n); +API_EXPORT(char *) ap_make_dirstr_parent(pool *p, const char *s); +/* deprecated. The previous two routines are preferred. */ +API_EXPORT(char *) ap_make_dirstr(pool *a, const char *s, int n); +API_EXPORT(char *) ap_make_full_path(pool *a, const char *dir, const char *f); + +API_EXPORT(int) ap_is_matchexp(const char *str); +API_EXPORT(int) ap_strcmp_match(const char *str, const char *exp); +API_EXPORT(int) ap_strcasecmp_match(const char *str, const char *exp); +API_EXPORT(char *) ap_stripprefix(const char *bigstring, const char *prefix); +API_EXPORT(char *) ap_strcasestr(const char *s1, const char *s2); +API_EXPORT(char *) ap_pbase64decode(pool *p, const char *bufcoded); +API_EXPORT(char *) ap_pbase64encode(pool *p, char *string); +API_EXPORT(char *) ap_uudecode(pool *p, const char *bufcoded); +API_EXPORT(char *) ap_uuencode(pool *p, char *string); + +#if defined(OS2) || defined(WIN32) +API_EXPORT(char *) ap_double_quotes(pool *p, const char *str); +API_EXPORT(char *) ap_caret_escape_args(pool *p, const char *str); +#endif + +#ifdef OS2 +void os2pathname(char *path); +#endif + +API_EXPORT(int) ap_regexec(const regex_t *preg, const char *string, + size_t nmatch, regmatch_t pmatch[], int eflags); +API_EXPORT(size_t) ap_regerror(int errcode, const regex_t *preg, + char *errbuf, size_t errbuf_size); +API_EXPORT(char *) ap_pregsub(pool *p, const char *input, const char *source, + size_t nmatch, regmatch_t pmatch[]); + +API_EXPORT(void) ap_content_type_tolower(char *); +API_EXPORT(void) ap_str_tolower(char *); +API_EXPORT(int) ap_ind(const char *, char); /* Sigh... */ +API_EXPORT(int) ap_rind(const char *, char); + +API_EXPORT(char *) ap_escape_quotes (pool *p, const char *instring); +API_EXPORT(void) ap_remove_spaces(char *dest, char *src); + +/* Common structure for reading of config files / passwd files etc. */ +typedef struct { + int (*getch) (void *param); /* a getc()-like function */ + void *(*getstr) (void *buf, size_t bufsiz, void *param); /* a fgets()-like function */ + int (*close) (void *param); /* a close hander function */ + void *param; /* the argument passed to getch/getstr/close */ + const char *name; /* the filename / description */ + unsigned line_number; /* current line number, starting at 1 */ +} configfile_t; + +/* Open a configfile_t as FILE, return open configfile_t struct pointer */ +API_EXPORT(configfile_t *) ap_pcfg_openfile(pool *p, const char *name); + +/* Allocate a configfile_t handle with user defined functions and params */ +API_EXPORT(configfile_t *) ap_pcfg_open_custom(pool *p, const char *descr, + void *param, + int(*getc_func)(void*), + void *(*gets_func) (void *buf, size_t bufsiz, void *param), + int(*close_func)(void *param)); + +/* Read one line from open configfile_t, strip LF, increase line number */ +API_EXPORT(int) ap_cfg_getline(char *buf, size_t bufsize, configfile_t *cfp); + +/* Read one char from open configfile_t, increase line number upon LF */ +API_EXPORT(int) ap_cfg_getc(configfile_t *cfp); + +/* Detach from open configfile_t, calling the close handler */ +API_EXPORT(int) ap_cfg_closefile(configfile_t *cfp); + +#ifdef NEED_STRERROR +char *strerror(int err); +#endif + +/* Misc system hackery */ + +API_EXPORT(uid_t) ap_uname2id(const char *name); +API_EXPORT(gid_t) ap_gname2id(const char *name); +API_EXPORT(int) ap_is_directory(const char *name); +API_EXPORT(int) ap_is_rdirectory(const char *name); +API_EXPORT(int) ap_can_exec(const struct stat *); +API_EXPORT(void) ap_chdir_file(const char *file); + +#ifndef HAVE_CANONICAL_FILENAME +/* + * We can't define these in os.h because of dependence on pool pointer. + */ +#define ap_os_canonical_filename(p,f) (f) +#define ap_os_case_canonical_filename(p,f) (f) +#define ap_os_systemcase_filename(p,f) (f) +#else +API_EXPORT(char *) ap_os_canonical_filename(pool *p, const char *file); +#ifdef WIN32 +API_EXPORT(char *) ap_os_case_canonical_filename(pool *pPool, const char *szFile); +API_EXPORT(char *) ap_os_systemcase_filename(pool *pPool, const char *szFile); +#elif defined(OS2) +API_EXPORT(char *) ap_os_case_canonical_filename(pool *pPool, const char *szFile); +API_EXPORT(char *) ap_os_systemcase_filename(pool *pPool, const char *szFile); +#elif defined(NETWARE) +API_EXPORT(char *) ap_os_case_canonical_filename(pool *pPool, const char *szFile); +#define ap_os_systemcase_filename(p,f) ap_os_case_canonical_filename(p,f) +#else +#define ap_os_case_canonical_filename(p,f) ap_os_canonical_filename(p,f) +#define ap_os_systemcase_filename(p,f) ap_os_canonical_filename(p,f) +#endif +#endif + +#ifdef CHARSET_EBCDIC +API_EXPORT(int) ap_checkconv(struct request_rec *r); /* for downloads */ +API_EXPORT(int) ap_checkconv_in(struct request_rec *r); /* for uploads */ +#endif /*#ifdef CHARSET_EBCDIC*/ + +API_EXPORT(char *) ap_get_local_host(pool *); +API_EXPORT(unsigned long) ap_get_virthost_addr(char *hostname, unsigned short *port); + +extern API_VAR_EXPORT time_t ap_restart_time; + +/* + * Apache tries to keep all of its long term filehandles (such as log files, + * and sockets) above this number. This is to workaround problems in many + * third party libraries that are compiled with a small FD_SETSIZE. There + * should be no reason to lower this, because it's only advisory. If a file + * can't be allocated above this number then it will remain in the "slack" + * area. + * + * Only the low slack line is used by default. If HIGH_SLACK_LINE is defined + * then an attempt is also made to keep all non-FILE * files above the high + * slack line. This is to work around a Solaris C library limitation, where it + * uses an unsigned char to store the file descriptor. + */ +#ifndef LOW_SLACK_LINE +#define LOW_SLACK_LINE 15 +#endif +/* #define HIGH_SLACK_LINE 255 */ + +/* + * The ap_slack() function takes a fd, and tries to move it above the indicated + * line. It returns an fd which may or may not have moved above the line, and + * never fails. If the high line was requested and it fails it will also try + * the low line. + */ +#ifdef NO_SLACK +#define ap_slack(fd,line) (fd) +#else +int ap_slack(int fd, int line); +#define AP_SLACK_LOW 1 +#define AP_SLACK_HIGH 2 +#endif + +API_EXPORT(char *) ap_escape_quotes(pool *p, const char *instr); + +/* + * Redefine assert() to something more useful for an Apache... + */ +API_EXPORT(void) ap_log_assert(const char *szExp, const char *szFile, int nLine) + __attribute__((noreturn)); +#define ap_assert(exp) ((exp) ? (void)0 : ap_log_assert(#exp,__FILE__,__LINE__)) + +/* The optimized timeout code only works if we're not MULTITHREAD and we're + * also not using a scoreboard file + */ +#if !defined (MULTITHREAD) && \ + (defined (USE_MMAP_SCOREBOARD) || defined (USE_SHMGET_SCOREBOARD)) +#define OPTIMIZE_TIMEOUTS +#endif + +/* A set of flags which indicate places where the server should raise(SIGSTOP). + * This is useful for debugging, because you can then attach to that process + * with gdb and continue. This is important in cases where one_process + * debugging isn't possible. + */ +#define SIGSTOP_DETACH 1 +#define SIGSTOP_MAKE_CHILD 2 +#define SIGSTOP_SPAWN_CHILD 4 +#define SIGSTOP_PIPED_LOG_SPAWN 8 +#define SIGSTOP_CGI_CHILD 16 + +#ifdef DEBUG_SIGSTOP +extern int raise_sigstop_flags; +#define RAISE_SIGSTOP(x) do { \ + if (raise_sigstop_flags & SIGSTOP_##x) raise(SIGSTOP);\ + } while (0) +#else +#define RAISE_SIGSTOP(x) +#endif + +API_EXPORT(extern const char *) ap_psignature(const char *prefix, request_rec *r); + +/* strtoul does not exist on sunos4. */ +#ifdef strtoul +#undef strtoul +#endif +#define strtoul strtoul_is_not_a_portable_function_use_strtol_instead + +#ifdef AP_ENABLE_EXCEPTION_HOOK +/* The exception hook allows a module to run from the server's signal + * handler, and perform tasks such as logging the current request or + * getting a backtrace or performing other diagnostic functions. All + * operating system requirements for running in a signal handler must + * be respected, or the process may not exit properly. + * + * AP_ENABLE_EXCEPTION_HOOK is already defined for platforms that have + * been tested. It likely will work on other platforms. In order to + * test, define AP_ENABLE_EXCEPTION_HOOK at configure time. + */ +typedef struct ap_exception_info_t { + int sig; + pid_t pid; +} ap_exception_info_t; + +/* Register a function to be called after a fatal exception (on *X systems, a + * "synchronous signal" such as SIGSEGV, SIGILL, etc.). + * + * Returns 0 on success, non-zero on failure. + * If EnableExceptionHook directive is not set to "on", this function will + * report failure and no such hooks will be called. + */ +API_EXPORT(extern int) ap_add_fatal_exception_hook(void (*fn)(ap_exception_info_t *)); +#endif /* AP_ENABLE_EXCEPTION_HOOK */ + +#ifdef __cplusplus +} +#endif + +#endif /* !APACHE_HTTPD_H */ diff -udrN apache_1.3.33/src/main/http_core.c apache_1.3.33-mod/src/main/http_core.c --- apache_1.3.33/src/main/http_core.c Thu Sep 30 03:23:35 2004 +++ apache_1.3.33-mod/src/main/http_core.c Fri Apr 1 10:08:13 2005 @@ -4181,15 +4181,15 @@ ap_send_fd(f, r); } else { - long offset, length; + int64_t offset, length; while (ap_each_byterange(r, &offset, &length)) { /* * Non zero returns are more portable than checking * for a return of -1. */ - if (fseek(f, offset, SEEK_SET)) { + if (fseeko(f, offset, SEEK_SET)) { ap_log_error(APLOG_MARK, APLOG_ERR, r->server, - "Failed to fseek for byterange (%ld, %ld): %s", + "Failed to fseeko for byterange (%qd, %qd): %s", offset, length, r->filename); } else { @@ -4227,7 +4227,7 @@ ap_send_mmap(mm, r, 0, r->finfo.st_size); } else { - long offset, length; + int64_t offset, length; while (ap_each_byterange(r, &offset, &length)) { ap_send_mmap(mm, r, offset, length); } diff -udrN apache_1.3.33/src/main/http_core.c.orig apache_1.3.33-mod/src/main/http_core.c.orig --- apache_1.3.33/src/main/http_core.c.orig Wed Dec 31 16:00:00 1969 +++ apache_1.3.33-mod/src/main/http_core.c.orig Thu Sep 30 03:23:35 2004 @@ -0,0 +1,4269 @@ +/* Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +#define CORE_PRIVATE +#define ADD_EBCDICCONVERT_DEBUG_HEADER 0 +#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_conf_globals.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 "scoreboard.h" +#include "fnmatch.h" + +#ifdef USE_MMAP_FILES +#include + +/* mmap support for static files based on ideas from John Heidemann's + * patch against 1.0.5. See + * . + */ + +/* Files have to be at least this big before they're mmap()d. This is to deal + * with systems where the expense of doing an mmap() and an munmap() outweighs + * the benefit for small files. It shouldn't be set lower than 1. + */ +#ifndef MMAP_THRESHOLD +#ifdef SUNOS4 +#define MMAP_THRESHOLD (8*1024) +#else +#define MMAP_THRESHOLD 1 +#endif +#endif +#endif +#ifndef MMAP_LIMIT +#define MMAP_LIMIT (4*1024*1024) +#endif + +typedef struct { + /* Custom response strings registered via ap_custom_response(), + * or NULL; check per-dir config if nothing found here + */ + char **response_code_strings; /* from ap_custom_response(), not from + * ErrorDocument + */ +} core_request_config; + +/* 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. + */ + +static void *create_core_dir_config(pool *a, char *dir) +{ + core_dir_config *conf; + + conf = (core_dir_config *)ap_pcalloc(a, sizeof(core_dir_config)); + if (!dir || dir[strlen(dir) - 1] == '/') { + conf->d = dir; + } + else if (strncmp(dir, "proxy:", 6) == 0) { + conf->d = ap_pstrdup(a, dir); + } + else { + conf->d = ap_pstrcat(a, dir, "/", NULL); + } + conf->d_is_fnmatch = conf->d ? (ap_is_fnmatch(conf->d) != 0) : 0; + conf->d_components = conf->d ? ap_count_dirs(conf->d) : 0; + + conf->opts = dir ? OPT_UNSET : OPT_UNSET|OPT_ALL; + conf->opts_add = conf->opts_remove = OPT_NONE; + conf->override = dir ? OR_UNSET : OR_UNSET|OR_ALL; + + conf->content_md5 = 2; + + conf->use_canonical_name = USE_CANONICAL_NAME_UNSET; + + conf->hostname_lookups = HOSTNAME_LOOKUP_UNSET; + conf->do_rfc1413 = DEFAULT_RFC1413 | 2; /* set bit 1 to indicate default */ + conf->satisfy = SATISFY_NOSPEC; + +#ifdef RLIMIT_CPU + conf->limit_cpu = NULL; +#endif +#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) + conf->limit_mem = NULL; +#endif +#ifdef RLIMIT_NPROC + conf->limit_nproc = NULL; +#endif + + conf->limit_req_body = 0; + conf->sec = ap_make_array(a, 2, sizeof(void *)); +#ifdef WIN32 + conf->script_interpreter_source = INTERPRETER_SOURCE_UNSET; +#endif + + conf->server_signature = srv_sig_unset; + + conf->add_default_charset = ADD_DEFAULT_CHARSET_UNSET; + conf->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME; + +#ifdef CHARSET_EBCDIC + conf->ebcdicconversion_by_ext_in = ap_make_table(a, 4); + conf->ebcdicconversion_by_ext_out = ap_make_table(a, 4); + conf->ebcdicconversion_by_type_in = ap_make_table(a, 4); + conf->ebcdicconversion_by_type_out = ap_make_table(a, 4); + conf->x_ascii_magic_kludge = 0; +#if ADD_EBCDICCONVERT_DEBUG_HEADER + conf->ebcdicconversion_debug_header = 0; +#endif +#endif /* CHARSET_EBCDIC */ + + /* + * Flag for use of inodes in ETags. + */ + conf->etag_bits = ETAG_UNSET; + conf->etag_add = ETAG_UNSET; + conf->etag_remove = ETAG_UNSET; + + return (void *)conf; +} + +static void *merge_core_dir_configs(pool *a, void *basev, void *newv) +{ + core_dir_config *base = (core_dir_config *)basev; + core_dir_config *new = (core_dir_config *)newv; + core_dir_config *conf; + int i; + + conf = (core_dir_config *)ap_palloc(a, sizeof(core_dir_config)); + memcpy((char *)conf, (const char *)base, sizeof(core_dir_config)); + if (base->response_code_strings) { + conf->response_code_strings = + ap_palloc(a, sizeof(*conf->response_code_strings) + * RESPONSE_CODES); + memcpy(conf->response_code_strings, base->response_code_strings, + sizeof(*conf->response_code_strings) * RESPONSE_CODES); + } + + conf->d = new->d; + conf->d_is_fnmatch = new->d_is_fnmatch; + conf->d_components = new->d_components; + conf->r = new->r; + + if (new->opts & OPT_UNSET) { + /* there was no explicit setting of new->opts, so we merge + * preserve the invariant (opts_add & opts_remove) == 0 + */ + conf->opts_add = (conf->opts_add & ~new->opts_remove) | new->opts_add; + conf->opts_remove = (conf->opts_remove & ~new->opts_add) + | new->opts_remove; + conf->opts = (conf->opts & ~conf->opts_remove) | conf->opts_add; + if ((base->opts & OPT_INCNOEXEC) && (new->opts & OPT_INCLUDES)) { + conf->opts = (conf->opts & ~OPT_INCNOEXEC) | OPT_INCLUDES; + } + } + else { + /* otherwise we just copy, because an explicit opts setting + * overrides all earlier +/- modifiers + */ + conf->opts = new->opts; + conf->opts_add = new->opts_add; + conf->opts_remove = new->opts_remove; + } + + if (!(new->override & OR_UNSET)) { + conf->override = new->override; + } + if (new->ap_default_type) { + conf->ap_default_type = new->ap_default_type; + } + + if (new->ap_auth_type) { + conf->ap_auth_type = new->ap_auth_type; + } + if (new->ap_auth_name) { + conf->ap_auth_name = new->ap_auth_name; + } + if (new->ap_auth_nonce) { + conf->ap_auth_nonce = new->ap_auth_nonce; + } + if (new->ap_requires) { + conf->ap_requires = new->ap_requires; + } + + if (new->response_code_strings) { + if (conf->response_code_strings == NULL) { + conf->response_code_strings = ap_palloc(a, + sizeof(*conf->response_code_strings) * RESPONSE_CODES); + memcpy(conf->response_code_strings, new->response_code_strings, + sizeof(*conf->response_code_strings) * RESPONSE_CODES); + } + else { + for (i = 0; i < RESPONSE_CODES; ++i) { + if (new->response_code_strings[i] != NULL) { + conf->response_code_strings[i] + = new->response_code_strings[i]; + } + } + } + } + if (new->hostname_lookups != HOSTNAME_LOOKUP_UNSET) { + conf->hostname_lookups = new->hostname_lookups; + } + if ((new->do_rfc1413 & 2) == 0) { + conf->do_rfc1413 = new->do_rfc1413; + } + if ((new->content_md5 & 2) == 0) { + conf->content_md5 = new->content_md5; + } + if (new->use_canonical_name != USE_CANONICAL_NAME_UNSET) { + conf->use_canonical_name = new->use_canonical_name; + } + +#ifdef RLIMIT_CPU + if (new->limit_cpu) { + conf->limit_cpu = new->limit_cpu; + } +#endif +#if defined(RLIMIT_DATA) || defined(RLIMIT_VMEM) || defined(RLIMIT_AS) + if (new->limit_mem) { + conf->limit_mem = new->limit_mem; + } +#endif +#ifdef RLIMIT_NPROC + if (new->limit_nproc) { + conf->limit_nproc = new->limit_nproc; + } +#endif + + if (new->limit_req_body) { + conf->limit_req_body = new->limit_req_body; + } + conf->sec = ap_append_arrays(a, base->sec, new->sec); + + if (new->satisfy != SATISFY_NOSPEC) { + conf->satisfy = new->satisfy; + } + +#ifdef WIN32 + if (new->script_interpreter_source != INTERPRETER_SOURCE_UNSET) { + conf->script_interpreter_source = new->script_interpreter_source; + } +#endif + + if (new->server_signature != srv_sig_unset) { + conf->server_signature = new->server_signature; + } + + if (new->add_default_charset != ADD_DEFAULT_CHARSET_UNSET) { + conf->add_default_charset = new->add_default_charset; + if (new->add_default_charset_name) { + conf->add_default_charset_name = new->add_default_charset_name; + } + } + +#ifdef CHARSET_EBCDIC + conf->ebcdicconversion_by_ext_in = ap_overlay_tables(a, new->ebcdicconversion_by_ext_in, + base->ebcdicconversion_by_ext_in); + conf->ebcdicconversion_by_ext_out = ap_overlay_tables(a, new->ebcdicconversion_by_ext_out, + base->ebcdicconversion_by_ext_out); + conf->ebcdicconversion_by_type_in = ap_overlay_tables(a, new->ebcdicconversion_by_type_in, + base->ebcdicconversion_by_type_in); + conf->ebcdicconversion_by_type_out = ap_overlay_tables(a, new->ebcdicconversion_by_type_out, + base->ebcdicconversion_by_type_out); + conf->x_ascii_magic_kludge = new->x_ascii_magic_kludge ? new->x_ascii_magic_kludge : base->x_ascii_magic_kludge; +#if ADD_EBCDICCONVERT_DEBUG_HEADER + conf->ebcdicconversion_debug_header = new->ebcdicconversion_debug_header ? new->ebcdicconversion_debug_header : base->ebcdicconversion_debug_header; +#endif +#endif /* CHARSET_EBCDIC */ + + /* + * Now merge the setting of the FileETag directive. + */ + if (new->etag_bits == ETAG_UNSET) { + conf->etag_add = + (conf->etag_add & (~ new->etag_remove)) | new->etag_add; + conf->etag_remove = + (conf->opts_remove & (~ new->etag_add)) | new->etag_remove; + conf->etag_bits = + (conf->etag_bits & (~ conf->etag_remove)) | conf->etag_add; + } + else { + conf->etag_bits = new->etag_bits; + conf->etag_add = new->etag_add; + conf->etag_remove = new->etag_remove; + } + if (conf->etag_bits != ETAG_NONE) { + conf->etag_bits &= (~ ETAG_NONE); + } + + if (new->cgi_command_args != AP_FLAG_UNSET) { + conf->cgi_command_args = new->cgi_command_args; + } + + return (void*)conf; +} + +static void *create_core_server_config(pool *a, server_rec *s) +{ + core_server_config *conf; + int is_virtual = s->is_virtual; + + conf = (core_server_config *)ap_pcalloc(a, sizeof(core_server_config)); +#ifdef GPROF + conf->gprof_dir = NULL; +#endif + conf->access_name = is_virtual ? NULL : DEFAULT_ACCESS_FNAME; + conf->ap_document_root = is_virtual ? NULL : DOCUMENT_LOCATION; + conf->sec = ap_make_array(a, 40, sizeof(void *)); + conf->sec_url = ap_make_array(a, 40, sizeof(void *)); + + /* recursion stopper */ + conf->redirect_limit = 0; + conf->subreq_limit = 0; + conf->recursion_limit_set = 0; + + return (void *)conf; +} + +static void *merge_core_server_configs(pool *p, void *basev, void *virtv) +{ + core_server_config *base = (core_server_config *)basev; + core_server_config *virt = (core_server_config *)virtv; + core_server_config *conf; + + conf = (core_server_config *)ap_pcalloc(p, sizeof(core_server_config)); + *conf = *virt; + if (!conf->access_name) { + conf->access_name = base->access_name; + } + if (!conf->ap_document_root) { + conf->ap_document_root = base->ap_document_root; + } + conf->sec = ap_append_arrays(p, base->sec, virt->sec); + conf->sec_url = ap_append_arrays(p, base->sec_url, virt->sec_url); + + conf->redirect_limit = virt->recursion_limit_set + ? virt->redirect_limit + : base->redirect_limit; + + conf->subreq_limit = virt->recursion_limit_set + ? virt->subreq_limit + : base->subreq_limit; + + return conf; +} + +/* Add per-directory configuration entry (for section); + * these are part of the core server config. + */ + +CORE_EXPORT(void) ap_add_per_dir_conf(server_rec *s, void *dir_config) +{ + core_server_config *sconf = ap_get_module_config(s->module_config, + &core_module); + void **new_space = (void **)ap_push_array(sconf->sec); + + *new_space = dir_config; +} + +CORE_EXPORT(void) ap_add_per_url_conf(server_rec *s, void *url_config) +{ + core_server_config *sconf = ap_get_module_config(s->module_config, + &core_module); + void **new_space = (void **)ap_push_array(sconf->sec_url); + + *new_space = url_config; +} + +CORE_EXPORT(void) ap_add_file_conf(core_dir_config *conf, void *url_config) +{ + void **new_space = (void **)ap_push_array(conf->sec); + + *new_space = url_config; +} + +/* core_reorder_directories reorders the directory sections such that the + * 1-component sections come first, then the 2-component, and so on, finally + * followed by the "special" sections. A section is "special" if it's a regex, + * or if it doesn't start with / -- consider proxy: matching. All movements + * are in-order to preserve the ordering of the sections from the config files. + * See directory_walk(). + */ + +#if defined(HAVE_DRIVE_LETTERS) +#define IS_SPECIAL(entry_core) \ + ((entry_core)->r != NULL \ + || ((entry_core)->d[0] != '/' && (entry_core)->d[1] != ':')) +#elif defined(NETWARE) +/* XXX: Fairly certain this is correct... '/' must prefix the path + * or else in the case xyz:/ or abc/xyz:/, '/' must follow the ':'. + * If there is no leading '/' or embedded ':/', then we are special. + */ +#define IS_SPECIAL(entry_core) \ + ((entry_core)->r != NULL \ + || ((entry_core)->d[0] != '/' \ + && strchr((entry_core)->d, ':') \ + && *(strchr((entry_core)->d, ':') + 1) != '/')) +#else +#define IS_SPECIAL(entry_core) \ + ((entry_core)->r != NULL || (entry_core)->d[0] != '/') +#endif + +/* 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 a "special" section has infinite components). + */ +struct reorder_sort_rec { + void *elt; + int orig_index; +}; + +static int reorder_sorter(const void *va, const void *vb) +{ + const struct reorder_sort_rec *a = va; + const struct reorder_sort_rec *b = vb; + core_dir_config *core_a; + core_dir_config *core_b; + + core_a = (core_dir_config *)ap_get_module_config(a->elt, &core_module); + core_b = (core_dir_config *)ap_get_module_config(b->elt, &core_module); + if (IS_SPECIAL(core_a)) { + if (!IS_SPECIAL(core_b)) { + return 1; + } + } + else if (IS_SPECIAL(core_b)) { + return -1; + } + else { + /* we know they're both not special */ + if (core_a->d_components < core_b->d_components) { + return -1; + } + else if (core_a->d_components > core_b->d_components) { + return 1; + } + } + /* Either they're both special, or they're both not special and have the + * same number of components. In any event, we now have to compare + * the minor key. */ + return a->orig_index - b->orig_index; +} + +CORE_EXPORT(void) ap_core_reorder_directories(pool *p, server_rec *s) +{ + core_server_config *sconf; + array_header *sec; + struct reorder_sort_rec *sortbin; + int nelts; + void **elts; + int i; + pool *tmp; + + sconf = ap_get_module_config(s->module_config, &core_module); + sec = sconf->sec; + nelts = sec->nelts; + elts = (void **)sec->elts; + + /* we have to allocate tmp space to do a stable sort */ + tmp = ap_make_sub_pool(p); + sortbin = ap_palloc(tmp, sec->nelts * sizeof(*sortbin)); + for (i = 0; i < nelts; ++i) { + sortbin[i].orig_index = i; + sortbin[i].elt = elts[i]; + } + + qsort(sortbin, nelts, sizeof(*sortbin), reorder_sorter); + + /* and now copy back to the original array */ + for (i = 0; i < nelts; ++i) { + elts[i] = sortbin[i].elt; + } + + ap_destroy_pool(tmp); +} + +/***************************************************************** + * + * 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... + */ + +API_EXPORT(int) ap_allow_options(request_rec *r) +{ + core_dir_config *conf = + (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); + + return conf->opts; +} + +API_EXPORT(int) ap_allow_overrides(request_rec *r) +{ + core_dir_config *conf; + conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + + return conf->override; +} + +API_EXPORT(const char *) ap_auth_type(request_rec *r) +{ + core_dir_config *conf; + + conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + return conf->ap_auth_type; +} + +API_EXPORT(const char *) ap_auth_name(request_rec *r) +{ + core_dir_config *conf; + + conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + return conf->ap_auth_name; +} + +API_EXPORT(const char *) ap_auth_nonce(request_rec *r) +{ + core_dir_config *conf; + conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + if (conf->ap_auth_nonce) + return conf->ap_auth_nonce; + + /* Ideally we'd want to mix in some per-directory style + * information; as we are likely to want to detect replay + * across those boundaries and some randomness. But that + * is harder due to the adhoc nature of .htaccess memory + * structures, restarts and forks. + * + * But then again - you should use AuthDigestRealmSeed in your config + * file if you care. So the adhoc value should do. + */ + return ap_psprintf(r->pool,"%pI%pp%pp%pp%pp", + &r->connection->local_addr.sin_addr, + (void *)ap_user_name, + (void *)ap_listeners, + (void *)ap_server_argv0, + (void *)ap_pid_fname); +} + +API_EXPORT(const char *) ap_default_type(request_rec *r) +{ + core_dir_config *conf; + + conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + return conf->ap_default_type + ? conf->ap_default_type + : DEFAULT_CONTENT_TYPE; +} + +API_EXPORT(const char *) ap_document_root(request_rec *r) /* Don't use this! */ +{ + core_server_config *conf; + + conf = (core_server_config *)ap_get_module_config(r->server->module_config, + &core_module); + return conf->ap_document_root; +} + +API_EXPORT(const array_header *) ap_requires(request_rec *r) +{ + core_dir_config *conf; + + conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + return conf->ap_requires; +} + +API_EXPORT(int) ap_satisfies(request_rec *r) +{ + core_dir_config *conf; + + conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + + return conf->satisfy; +} + +/* 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). + */ + +API_EXPORT(char *) ap_response_code_string(request_rec *r, int error_index) +{ + core_request_config *reqconf; + core_dir_config *dirconf; + + /* prefer per-request settings, which are created by calls to + * ap_custom_response() + */ + reqconf = (core_request_config *)ap_get_module_config(r->request_config, + &core_module); + + if (reqconf != NULL && + reqconf->response_code_strings != NULL && + reqconf->response_code_strings[error_index] != NULL) { + return reqconf->response_code_strings[error_index]; + } + + /* check for string specified via ErrorDocument */ + dirconf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + + if (dirconf->response_code_strings == NULL) { + return NULL; + } + + return dirconf->response_code_strings[error_index]; +} + + +/* Code from Harald Hanche-Olsen */ +/* Note: the function returns its result in conn->double_reverse: + * +1: forward lookup of the previously reverse-looked-up + * hostname in conn->remote_host succeeded, and at + * least one of its IP addresses matches the client. + * -1: forward lookup of conn->remote_host failed, or + * none of the addresses found matches the client connection + * (possible DNS spoof in the reverse zone!) + * If do_double_reverse() returns -1, then it also invalidates + * conn->remote_host to prevent an invalid name from appearing + * in the log files. Conn->remote_host is set to "", because + * a setting of NULL would allow another reverse lookup, + * depending on the flags given to ap_get_remote_host(). + */ +static ap_inline void do_double_reverse (conn_rec *conn) +{ + struct hostent *hptr; + + if (conn->double_reverse) { + /* already done */ + return; + } + if (conn->remote_host == NULL || conn->remote_host[0] == '\0') { + /* single reverse failed, so don't bother */ + conn->double_reverse = -1; + conn->remote_host = ""; /* prevent another lookup */ + return; + } + hptr = gethostbyname(conn->remote_host); + if (hptr) { + char **haddr; + + for (haddr = hptr->h_addr_list; *haddr; haddr++) { + if (((struct in_addr *)(*haddr))->s_addr + == conn->remote_addr.sin_addr.s_addr) { + conn->double_reverse = 1; + return; + } + } + } + conn->double_reverse = -1; + /* invalidate possible reverse-resolved hostname if forward lookup fails */ + conn->remote_host = ""; +} + +API_EXPORT(const char *) ap_get_remote_host(conn_rec *conn, void *dir_config, + int type) +{ + struct in_addr *iaddr; + struct hostent *hptr; + int hostname_lookups; + int old_stat = SERVER_DEAD; /* we shouldn't ever be in this state */ + + /* If we haven't checked the host name, and we want to */ + if (dir_config) { + hostname_lookups = + ((core_dir_config *)ap_get_module_config(dir_config, &core_module)) + ->hostname_lookups; + if (hostname_lookups == HOSTNAME_LOOKUP_UNSET) { + hostname_lookups = HOSTNAME_LOOKUP_OFF; + } + } + else { + /* the default */ + hostname_lookups = HOSTNAME_LOOKUP_OFF; + } + + if (type != REMOTE_NOLOOKUP + && conn->remote_host == NULL + && (type == REMOTE_DOUBLE_REV + || hostname_lookups != HOSTNAME_LOOKUP_OFF)) { + old_stat = ap_update_child_status(conn->child_num, SERVER_BUSY_DNS, + (request_rec*)NULL); + iaddr = &(conn->remote_addr.sin_addr); + hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), AF_INET); + if (hptr != NULL) { + conn->remote_host = ap_pstrdup(conn->pool, (void *)hptr->h_name); + ap_str_tolower(conn->remote_host); + + if (hostname_lookups == HOSTNAME_LOOKUP_DOUBLE) { + do_double_reverse(conn); + } + } + /* if failed, set it to the NULL string to indicate error */ + if (conn->remote_host == NULL) { + conn->remote_host = ""; + } + } + if (type == REMOTE_DOUBLE_REV) { + do_double_reverse(conn); + if (conn->double_reverse == -1) { + return NULL; + } + } + if (old_stat != SERVER_DEAD) { + (void)ap_update_child_status(conn->child_num, old_stat, + (request_rec*)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). + */ + if (conn->remote_host != NULL && conn->remote_host[0] != '\0') { + return conn->remote_host; + } + else { + if (type == REMOTE_HOST || type == REMOTE_DOUBLE_REV) { + return NULL; + } + else { + return conn->remote_ip; + } + } +} + +API_EXPORT(const char *) ap_get_remote_logname(request_rec *r) +{ + core_dir_config *dir_conf; + + if (r->connection->remote_logname != NULL) { + return r->connection->remote_logname; + } + +/* If we haven't checked the identity, and we want to */ + dir_conf = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + + if (dir_conf->do_rfc1413 & 1) { + return ap_rfc1413(r->connection, r->server); + } + else { + return NULL; + } +} + +/* 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 connectiona 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 + */ +API_EXPORT(const char *) ap_get_server_name(request_rec *r) +{ + conn_rec *conn = r->connection; + core_dir_config *d; + + d = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + + if (d->use_canonical_name == USE_CANONICAL_NAME_OFF) { + return r->hostname ? r->hostname : r->server->server_hostname; + } + if (d->use_canonical_name == USE_CANONICAL_NAME_DNS) { + if (conn->local_host == NULL) { + struct in_addr *iaddr; + struct hostent *hptr; + int old_stat; + old_stat = ap_update_child_status(conn->child_num, + SERVER_BUSY_DNS, r); + iaddr = &(conn->local_addr.sin_addr); + hptr = gethostbyaddr((char *)iaddr, sizeof(struct in_addr), + AF_INET); + if (hptr != NULL) { + conn->local_host = ap_pstrdup(conn->pool, + (void *)hptr->h_name); + ap_str_tolower(conn->local_host); + } + else { + conn->local_host = ap_pstrdup(conn->pool, + r->server->server_hostname); + } + (void) ap_update_child_status(conn->child_num, old_stat, r); + } + return conn->local_host; + } + /* default */ + return r->server->server_hostname; +} + +API_EXPORT(unsigned) ap_get_server_port(const request_rec *r) +{ + unsigned port; + unsigned cport = ntohs(r->connection->local_addr.sin_port); + core_dir_config *d = + (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); + + 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). + */ + port = r->parsed_uri.port_str ? r->parsed_uri.port : +#ifdef UCN_OFF_HONOR_PHYSICAL_PORT + cport ? cport : +#endif + r->server->port ? r->server->port : + ap_default_port(r); + } else { /* d->use_canonical_name == USE_CANONICAL_NAME_ON */ + port = r->server->port ? r->server->port : + cport ? cport : + ap_default_port(r); + } + + /* default */ + return port; +} + +API_EXPORT(char *) ap_construct_url(pool *p, const char *uri, + 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)) { + return ap_pstrcat(p, ap_http_method(r), "://", host, uri, NULL); + } + return ap_psprintf(p, "%s://%s:%u%s", ap_http_method(r), host, port, uri); +} + +API_EXPORT(unsigned long) ap_get_limit_req_body(const request_rec *r) +{ + core_dir_config *d = + (core_dir_config *)ap_get_module_config(r->per_dir_config, &core_module); + + return d->limit_req_body; +} + +#ifdef WIN32 +static char* get_interpreter_from_win32_registry(pool *p, const char* ext) +{ + char extension_path[] = "SOFTWARE\\Classes\\"; + char executable_path[] = "\\SHELL\\OPEN\\COMMAND"; + + HKEY hkeyOpen; + DWORD type; + int size; + int result; + char *keyName; + char *buffer; + char *s; + + if (!ext) + return NULL; + /* + * Future optimization: + * When the registry is successfully searched, store the interpreter + * string in a table to make subsequent look-ups faster + */ + + /* Open the key associated with the script extension */ + keyName = ap_pstrcat(p, extension_path, ext, NULL); + + result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, + &hkeyOpen); + + if (result != ERROR_SUCCESS) + return NULL; + + /* Read to NULL buffer to find value size */ + size = 0; + result = RegQueryValueEx(hkeyOpen, "", NULL, &type, NULL, &size); + + if (result == ERROR_SUCCESS) { + buffer = ap_palloc(p, size); + result = RegQueryValueEx(hkeyOpen, "", NULL, &type, buffer, &size); + } + + RegCloseKey(hkeyOpen); + + if (result != ERROR_SUCCESS) + return NULL; + + /* Open the key associated with the interpreter path */ + keyName = ap_pstrcat(p, extension_path, buffer, executable_path, NULL); + + result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, + &hkeyOpen); + + if (result != ERROR_SUCCESS) + return NULL; + + /* Read to NULL buffer to find value size */ + size = 0; + result = RegQueryValueEx(hkeyOpen, "", 0, &type, NULL, &size); + + if (result == ERROR_SUCCESS) { + buffer = ap_palloc(p, size); + result = RegQueryValueEx(hkeyOpen, "", 0, &type, buffer, &size); + } + + RegCloseKey(hkeyOpen); + + if (result != ERROR_SUCCESS) + return NULL; + + /* + * The command entry may contain embedded %envvar% entries, + * e.g. %winsysdir%\somecommand.exe %1 + * + * Resolve them here + */ + size = ExpandEnvironmentStrings(buffer, NULL, 0); + if (size) { + s = ap_palloc(p, size); + if (ExpandEnvironmentStrings(buffer, s, size)) + buffer = s; + } + + /* + * The canonical way shell command entries are entered in the Win32 + * registry is as follows: + * shell [options] "%1" [options] [%*] + * where + * shell - full path name to interpreter or shell to run. + * E.g., c:\usr\local\ntreskit\perl\bin\perl.exe + * options - optional switches + * E.g., /C or -w + * "%1" - Place holder for file to run the shell against. + * Quoted for if long path names are accepted. + * Not quoted if only short paths are acceptd + * + * %* - additional arguments + * + * Effective in v. 1.3.15, the responsibility is the consumer's + * to make these substitutions. + */ + + return buffer; +} + +API_EXPORT (file_type_e) ap_get_win32_interpreter(const request_rec *r, + char** interpreter ) +{ + HANDLE hFile; + DWORD nBytesRead; + BOOLEAN bResult; + char buffer[1024]; + core_dir_config *d; + int i; + file_type_e fileType = eFileTypeUNKNOWN; + char *ext = NULL; + char *exename = NULL; + + d = (core_dir_config *)ap_get_module_config(r->per_dir_config, + &core_module); + + /* Find the file extension */ + exename = strrchr(r->filename, '/'); + if (!exename) { + exename = strrchr(r->filename, '\\'); + } + if (!exename) { + exename = r->filename; + } + else { + exename++; + } + ext = strrchr(exename, '.'); + + if (ext && (!strcasecmp(ext,".bat") || !strcasecmp(ext,".cmd"))) + { + char *p, *shellcmd = getenv("COMSPEC"); + if (!shellcmd) + return eFileTypeUNKNOWN; + p = strchr(shellcmd, '\0'); + if ((p - shellcmd >= 11) && !strcasecmp(p - 11, "command.com")) + { + /* Command.com doesn't like long paths, doesn't do .cmd + */ + if (!strcasecmp(ext,".cmd")) + return eFileTypeUNKNOWN; + *interpreter = ap_pstrcat(r->pool, "\"", shellcmd, "\" /C %1", NULL); + return eCommandShell16; + } + else { + /* Assume any other likes long paths, and knows .cmd, + * but the entire /c arg should be double quoted, e.g. + * "c:\path\cmd.exe" /c ""prog" "arg" "arg"" + */ + *interpreter = ap_pstrcat(r->pool, "\"", shellcmd, "\" /C \"\"%1\" %*\"", NULL); + return eCommandShell32; + } + } + + /* If the file has an extension and it is not .com and not .exe and + * we've been instructed to search the registry, then do it! + */ + if (ext && strcasecmp(ext,".exe") && strcasecmp(ext,".com") && + d->script_interpreter_source == INTERPRETER_SOURCE_REGISTRY) { + /* Check the registry */ + *interpreter = get_interpreter_from_win32_registry(r->pool, ext); + if (*interpreter) + return eFileTypeSCRIPT; + else { + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_INFO, r->server, + "ScriptInterpreterSource config directive set to \"registry\".\n\t" + "Registry was searched but interpreter not found. Trying the shebang line."); + } + } + + /* Need to peek into the file figure out what it really is... */ + hFile = CreateFile(r->filename, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (hFile == INVALID_HANDLE_VALUE) { + return eFileTypeUNKNOWN; + } + bResult = ReadFile(hFile, (void*) &buffer, sizeof(buffer) - 1, + &nBytesRead, NULL); + if (!bResult || (nBytesRead == 0)) { + ap_log_rerror(APLOG_MARK, APLOG_ERR, r, + "ReadFile(%s) failed", r->filename); + CloseHandle(hFile); + return eFileTypeUNKNOWN; + } + CloseHandle(hFile); + buffer[nBytesRead] = '\0'; + + /* Script or executable, that is the question... */ + if ((buffer[0] == '#') && (buffer[1] == '!')) { + /* Assuming file is a script since it starts with a shebang */ + fileType = eFileTypeSCRIPT; + for (i = 2; i < (sizeof(buffer) - 1); i++) { + if ((buffer[i] == '\r') + || (buffer[i] == '\n')) { + break; + } + } + buffer[i] = '\0'; + for (i = 2; buffer[i] == ' ' ; ++i) + ; + *interpreter = ap_pstrdup(r->pool, buffer + i ); + } + else { + /* Not a script, is it an executable? */ + IMAGE_DOS_HEADER *hdr = (IMAGE_DOS_HEADER*)buffer; + if ((nBytesRead >= sizeof(IMAGE_DOS_HEADER)) && (hdr->e_magic == IMAGE_DOS_SIGNATURE)) { + if (hdr->e_lfarlc < 0x40) + fileType = eFileTypeEXE16; + else + fileType = eFileTypeEXE32; + } + else + fileType = eFileTypeUNKNOWN; + } + + return fileType; +} +#endif + +/***************************************************************** + * + * Commands... this module handles almost all of the NCSA httpd.conf + * commands, but most of the old srm.conf is in the the modules. + */ + +static const char end_directory_section[] = ""; +static const char end_directorymatch_section[] = ""; +static const char end_location_section[] = ""; +static const char end_locationmatch_section[] = ""; +static const char end_files_section[] = ""; +static const char end_filesmatch_section[] = ""; +static const char end_virtualhost_section[] = ""; +static const char end_ifmodule_section[] = ""; +static const char end_ifdefine_section[] = ""; + + +API_EXPORT(const char *) ap_check_cmd_context(cmd_parms *cmd, + unsigned forbidden) +{ + const char *gt = (cmd->cmd->name[0] == '<' + && cmd->cmd->name[strlen(cmd->cmd->name)-1] != '>') + ? ">" : ""; + + if ((forbidden & NOT_IN_VIRTUALHOST) && cmd->server->is_virtual) { + return ap_pstrcat(cmd->pool, cmd->cmd->name, gt, + " cannot occur within section", NULL); + } + + if ((forbidden & NOT_IN_LIMIT) && cmd->limited != -1) { + return ap_pstrcat(cmd->pool, cmd->cmd->name, gt, + " cannot occur within section", NULL); + } + + if ((forbidden & NOT_IN_DIR_LOC_FILE) == NOT_IN_DIR_LOC_FILE + && cmd->path != NULL) { + return ap_pstrcat(cmd->pool, cmd->cmd->name, gt, + " cannot occur within " + "section", NULL); + } + + if (((forbidden & NOT_IN_DIRECTORY) + && (cmd->end_token == end_directory_section + || cmd->end_token == end_directorymatch_section)) + || ((forbidden & NOT_IN_LOCATION) + && (cmd->end_token == end_location_section + || cmd->end_token == end_locationmatch_section)) + || ((forbidden & NOT_IN_FILES) + && (cmd->end_token == end_files_section + || cmd->end_token == end_filesmatch_section))) { + return ap_pstrcat(cmd->pool, cmd->cmd->name, gt, + " cannot occur within <", cmd->end_token+2, + " section", NULL); + } + + return NULL; +} + +static const char *set_access_name(cmd_parms *cmd, void *dummy, char *arg) +{ + void *sconf = cmd->server->module_config; + core_server_config *conf = ap_get_module_config(sconf, &core_module); + + const char *err = ap_check_cmd_context(cmd, + NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + conf->access_name = ap_pstrdup(cmd->pool, arg); + return NULL; +} + +#ifdef GPROF +static const char *set_gprof_dir(cmd_parms *cmd, void *dummy, char *arg) +{ + void *sconf = cmd->server->module_config; + core_server_config *conf = ap_get_module_config(sconf, &core_module); + + const char *err = ap_check_cmd_context(cmd, + NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + conf->gprof_dir = ap_pstrdup(cmd->pool, arg); + return NULL; +} +#endif /*GPROF*/ + +static const char *set_add_default_charset(cmd_parms *cmd, + core_dir_config *d, char *arg) +{ + const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + if (!strcasecmp(arg, "Off")) { + d->add_default_charset = ADD_DEFAULT_CHARSET_OFF; + } + else if (!strcasecmp(arg, "On")) { + d->add_default_charset = ADD_DEFAULT_CHARSET_ON; + d->add_default_charset_name = DEFAULT_ADD_DEFAULT_CHARSET_NAME; + } + else { + d->add_default_charset = ADD_DEFAULT_CHARSET_ON; + d->add_default_charset_name = arg; + } + return NULL; +} +static const char *set_accept_mutex(cmd_parms *cmd, void *dummy, char *arg) +{ + return ap_init_mutex_method(arg); +} + +static const char *set_document_root(cmd_parms *cmd, void *dummy, char *arg) +{ + void *sconf = cmd->server->module_config; + core_server_config *conf = ap_get_module_config(sconf, &core_module); + + const char *err = ap_check_cmd_context(cmd, + NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + arg = ap_os_canonical_filename(cmd->pool, arg); + if (ap_configtestonly && ap_docrootcheck && !ap_is_directory(arg)) { + if (cmd->server->is_virtual) { + fprintf(stderr, "Warning: DocumentRoot [%s] does not exist\n", + arg); + } + else { + return "DocumentRoot must be a directory"; + } + } + + conf->ap_document_root = arg; + return NULL; +} + +API_EXPORT(void) ap_custom_response(request_rec *r, int status, char *string) +{ + core_request_config *reqconf = + ap_get_module_config(r->request_config, &core_module); + int idx; + + if (reqconf == NULL) { + reqconf = (core_request_config *)ap_pcalloc(r->pool, + sizeof(core_request_config)); + ap_set_module_config(r->request_config, &core_module, reqconf); + } + + if (reqconf->response_code_strings == NULL) { + reqconf->response_code_strings = + ap_pcalloc(r->pool, + sizeof(reqconf->response_code_strings) * + RESPONSE_CODES); + } + + idx = ap_index_of_response(status); + + reqconf->response_code_strings[idx] = + ((ap_is_url(string) || (*string == '/')) && (*string != '"')) ? + ap_pstrdup(r->pool, string) : ap_pstrcat(r->pool, "\"", string, NULL); +} + +static const char *set_error_document(cmd_parms *cmd, core_dir_config *conf, + char *line) +{ + int error_number, index_number, idx500; + char *w; + + const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + /* 1st parameter should be a 3 digit number, which we recognize; + * convert it into an array index + */ + + w = ap_getword_conf_nc(cmd->pool, &line); + error_number = atoi(w); + + idx500 = ap_index_of_response(HTTP_INTERNAL_SERVER_ERROR); + + if (error_number == HTTP_INTERNAL_SERVER_ERROR) { + index_number = idx500; + } + else if ((index_number = ap_index_of_response(error_number)) == idx500) { + return ap_pstrcat(cmd->pool, "Unsupported HTTP response code ", + w, NULL); + } + + /* The entry should be ignored if it is a full URL for a 401 error */ + + if (error_number == 401 && + line[0] != '/' && line[0] != '"') { /* Ignore it... */ + ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_NOTICE, cmd->server, + "cannot use a full URL in a 401 ErrorDocument " + "directive --- ignoring!"); + } + else { /* Store it... */ + if (conf->response_code_strings == NULL) { + conf->response_code_strings = + ap_pcalloc(cmd->pool, + sizeof(*conf->response_code_strings) * RESPONSE_CODES); + } + conf->response_code_strings[index_number] = ap_pstrdup(cmd->pool, line); + } + + return NULL; +} + +/* access.conf commands... + * + * The *only* thing that can appear in access.conf at top level is a + * section. NB we need to have a way to cut the srm_command_loop + * invoked by dirsection (i.e., ) short when is seen. + * We do that by returning an error, which dirsection itself recognizes and + * discards as harmless. Cheesy, but it works. + */ + +static const char *set_override(cmd_parms *cmd, core_dir_config *d, + const char *l) +{ + char *w; + + const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + d->override = OR_NONE; + while (l[0]) { + w = ap_getword_conf(cmd->pool, &l); + if (!strcasecmp(w, "Limit")) { + d->override |= OR_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")) { + d->override = OR_NONE; + } + else if (!strcasecmp(w, "All")) { + d->override = OR_ALL; + } + else { + return ap_pstrcat(cmd->pool, "Illegal override option ", w, NULL); + } + d->override &= ~OR_UNSET; + } + + return NULL; +} + +static const char *set_options(cmd_parms *cmd, core_dir_config *d, + const char *l) +{ + allow_options_t opt; + int first = 1; + char action; + + while (l[0]) { + char *w = ap_getword_conf(cmd->pool, &l); + action = '\0'; + + if (*w == '+' || *w == '-') { + action = *(w++); + } + else if (first) { + d->opts = OPT_NONE; + first = 0; + } + + if (!strcasecmp(w, "Indexes")) { + opt = OPT_INDEXES; + } + else if (!strcasecmp(w, "Includes")) { + opt = OPT_INCLUDES; + } + else if (!strcasecmp(w, "IncludesNOEXEC")) { + opt = (OPT_INCLUDES | OPT_INCNOEXEC); + } + 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")) { + opt = OPT_MULTI; + } + else if (!strcasecmp(w, "RunScripts")) { /* AI backcompat. Yuck */ + opt = OPT_MULTI|OPT_EXECCGI; + } + else if (!strcasecmp(w, "None")) { + opt = OPT_NONE; + } + else if (!strcasecmp(w, "All")) { + opt = OPT_ALL; + } + else { + return ap_pstrcat(cmd->pool, "Illegal option ", w, NULL); + } + + /* we ensure the invariant (d->opts_add & d->opts_remove) == 0 */ + if (action == '-') { + d->opts_remove |= opt; + d->opts_add &= ~opt; + d->opts &= ~opt; + } + else if (action == '+') { + d->opts_add |= opt; + d->opts_remove &= ~opt; + d->opts |= opt; + } + else { + d->opts |= opt; + } + } + + return NULL; +} + +static const char *satisfy(cmd_parms *cmd, core_dir_config *c, char *arg) +{ + if (!strcasecmp(arg, "all")) { + c->satisfy = SATISFY_ALL; + } + else if (!strcasecmp(arg, "any")) { + c->satisfy = SATISFY_ANY; + } + else { + return "Satisfy either 'any' or 'all'."; + } + return NULL; +} + +static const char *require(cmd_parms *cmd, core_dir_config *c, char *arg) +{ + require_line *r; + + if (!c->ap_requires) { + c->ap_requires = ap_make_array(cmd->pool, 2, sizeof(require_line)); + } + r = (require_line *)ap_push_array(c->ap_requires); + r->requirement = ap_pstrdup(cmd->pool, arg); + r->method_mask = cmd->limited; + return NULL; +} + +CORE_EXPORT_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy, + const char *arg) +{ + const char *limited_methods = ap_getword(cmd->pool, &arg, '>'); + void *tog = cmd->cmd->cmd_data; + int limited = 0; + + const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + /* XXX: NB: Currently, we have no way of checking + * whether or sections are closed properly. + * (If we would add a srm_command_loop() here we might...) + */ + + while (limited_methods[0]) { + char *method = ap_getword_conf(cmd->pool, &limited_methods); + int methnum = ap_method_number_of(method); + + if (methnum == M_TRACE && !tog) { + return "TRACE cannot be controlled by "; + } + else if (methnum == M_INVALID) { + return ap_pstrcat(cmd->pool, "unknown method \"", method, + "\" in " : ">", NULL); + } + else { + limited |= (1 << methnum); + } + } + + /* Killing two features with one function, + * if (tog == NULL) , else + */ + cmd->limited = tog ? ~limited : limited; + return NULL; +} + +static const char *endlimit_section(cmd_parms *cmd, void *dummy, void *dummy2) +{ + void *tog = cmd->cmd->cmd_data; + + if (cmd->limited == -1) { + return tog ? " unexpected" : " unexpected"; + } + + cmd->limited = -1; + return NULL; +} + +/* + * When a section is not closed properly when end-of-file is reached, + * then an error message should be printed: + */ +static const char *missing_endsection(cmd_parms *cmd, int nest) +{ + if (nest < 2) { + return ap_psprintf(cmd->pool, "Missing %s directive at end-of-file", + cmd->end_token); + } + return ap_psprintf(cmd->pool, "%d missing %s directives at end-of-file", + nest, cmd->end_token); +} + +/* We use this in and , to ensure that + * people don't get bitten by wrong-cased regex matches + */ + +#ifdef WIN32 +#define USE_ICASE REG_ICASE +#else +#define USE_ICASE 0 +#endif + +static const char *end_nested_section(cmd_parms *cmd, void *dummy) +{ + if (cmd->end_token == NULL) { + return ap_pstrcat(cmd->pool, cmd->cmd->name, + " without matching <", cmd->cmd->name + 2, + " section", NULL); + } + /* + * This '!=' may look weird on a string comparison, but it's correct -- + * it's been set up so that checking for two pointers to the same datum + * is valid here. And faster. + */ + if (cmd->cmd->name != cmd->end_token) { + return ap_pstrcat(cmd->pool, "Expected ", cmd->end_token, " but saw ", + cmd->cmd->name, NULL); + } + return cmd->end_token; +} + +/* + * Report a missing-'>' syntax error. + */ +static char *unclosed_directive(cmd_parms *cmd) +{ + return ap_pstrcat(cmd->pool, cmd->cmd->name, + "> directive missing closing '>'", NULL); +} + +static const char *dirsection(cmd_parms *cmd, void *dummy, const char *arg) +{ + const char *errmsg; + char *endp = strrchr(arg, '>'); + int old_overrides = cmd->override; + char *old_path = cmd->path; + core_dir_config *conf; + void *new_dir_conf = ap_create_per_dir_config(cmd->pool); + regex_t *r = NULL; + const char *old_end_token; + const command_rec *thiscmd = cmd->cmd; + + const char *err = ap_check_cmd_context(cmd, + NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + if (endp == NULL) { + return unclosed_directive(cmd); + } + + *endp = '\0'; + + cmd->path = ap_getword_conf(cmd->pool, &arg); + cmd->override = OR_ALL|ACCESS_CONF; + + if (thiscmd->cmd_data) { /* */ + r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); + if (!r) { + return "Regex could not be compiled"; + } + } + else if (!strcmp(cmd->path, "~")) { + cmd->path = ap_getword_conf(cmd->pool, &arg); + r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); + if (!r) { + return "Regex could not be compiled"; + } + } +#if defined(HAVE_DRIVE_LETTERS) || defined(NETWARE) + else if (strcmp(cmd->path, "/") == 0) { + /* Treat 'default' path / as an inalienable root */ + cmd->path = ap_pstrdup(cmd->pool, cmd->path); + } +#endif +#if defined(HAVE_UNC_PATHS) + else if (strcmp(cmd->path, "//") == 0) { + /* Treat UNC path // as an inalienable root */ + cmd->path = ap_pstrdup(cmd->pool, cmd->path); + } +#endif + else { + /* Ensure that the pathname is canonical */ + cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path); + } + + old_end_token = cmd->end_token; + cmd->end_token = thiscmd->cmd_data ? end_directorymatch_section : end_directory_section; + errmsg = ap_srm_command_loop(cmd, new_dir_conf); + if (errmsg == NULL) { + errmsg = missing_endsection(cmd, 1); + } + cmd->end_token = old_end_token; + if (errmsg != (thiscmd->cmd_data + ? end_directorymatch_section + : end_directory_section)) { + return errmsg; + } + + conf = (core_dir_config *)ap_get_module_config(new_dir_conf, &core_module); + conf->r = r; + + ap_add_per_dir_conf(cmd->server, new_dir_conf); + + if (*arg != '\0') { + return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name, + "> arguments not (yet) supported.", NULL); + } + + cmd->path = old_path; + cmd->override = old_overrides; + + return NULL; +} + +static const char *urlsection(cmd_parms *cmd, void *dummy, const char *arg) +{ + const char *errmsg; + char *endp = strrchr(arg, '>'); + int old_overrides = cmd->override; + char *old_path = cmd->path; + core_dir_config *conf; + regex_t *r = NULL; + const char *old_end_token; + const command_rec *thiscmd = cmd->cmd; + + void *new_url_conf = ap_create_per_dir_config(cmd->pool); + + const char *err = ap_check_cmd_context(cmd, + NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT); + if (err != NULL) { + return err; + } + + if (endp == NULL) { + return unclosed_directive(cmd); + } + + *endp = '\0'; + + cmd->path = ap_getword_conf(cmd->pool, &arg); + cmd->override = OR_ALL|ACCESS_CONF; + + if (thiscmd->cmd_data) { /* */ + r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED); + if (!r) { + return "Regex could not be compiled"; + } + } + else if (!strcmp(cmd->path, "~")) { + cmd->path = ap_getword_conf(cmd->pool, &arg); + r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED); + if (!r) { + return "Regex could not be compiled"; + } + } + + old_end_token = cmd->end_token; + cmd->end_token = thiscmd->cmd_data ? end_locationmatch_section + : end_location_section; + errmsg = ap_srm_command_loop(cmd, new_url_conf); + if (errmsg == NULL) { + errmsg = missing_endsection(cmd, 1); + } + cmd->end_token = old_end_token; + if (errmsg != (thiscmd->cmd_data + ? end_locationmatch_section + : end_location_section)) { + return errmsg; + } + + conf = (core_dir_config *)ap_get_module_config(new_url_conf, &core_module); + conf->d = ap_pstrdup(cmd->pool, cmd->path); /* No mangling, please */ + conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0; + conf->r = r; + + ap_add_per_url_conf(cmd->server, new_url_conf); + + if (*arg != '\0') { + return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name, + "> arguments not (yet) supported.", NULL); + } + + cmd->path = old_path; + cmd->override = old_overrides; + + return NULL; +} + +static const char *filesection(cmd_parms *cmd, core_dir_config *c, + const char *arg) +{ + const char *errmsg; + char *endp = strrchr(arg, '>'); + int old_overrides = cmd->override; + char *old_path = cmd->path; + core_dir_config *conf; + regex_t *r = NULL; + const char *old_end_token; + const command_rec *thiscmd = cmd->cmd; + + void *new_file_conf = ap_create_per_dir_config(cmd->pool); + + const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT|NOT_IN_LOCATION); + if (err != NULL) { + return err; + } + + if (endp == NULL) { + return unclosed_directive(cmd); + } + + *endp = '\0'; + + cmd->path = ap_getword_conf(cmd->pool, &arg); + /* Only if not an .htaccess file */ + if (!old_path) { + cmd->override = OR_ALL|ACCESS_CONF; + } + + if (thiscmd->cmd_data) { /* */ + r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); + if (!r) { + return "Regex could not be compiled"; + } + } + else if (!strcmp(cmd->path, "~")) { + cmd->path = ap_getword_conf(cmd->pool, &arg); + r = ap_pregcomp(cmd->pool, cmd->path, REG_EXTENDED|USE_ICASE); + if (!r) { + return "Regex could not be compiled"; + } + } + else { + /* Ensure that the pathname is canonical */ + cmd->path = ap_os_canonical_filename(cmd->pool, cmd->path); + } + + old_end_token = cmd->end_token; + cmd->end_token = thiscmd->cmd_data ? end_filesmatch_section : end_files_section; + errmsg = ap_srm_command_loop(cmd, new_file_conf); + if (errmsg == NULL) { + errmsg = missing_endsection(cmd, 1); + } + cmd->end_token = old_end_token; + if (errmsg != (thiscmd->cmd_data + ? end_filesmatch_section + : end_files_section)) { + return errmsg; + } + + conf = (core_dir_config *)ap_get_module_config(new_file_conf, + &core_module); + conf->d = cmd->path; + conf->d_is_fnmatch = ap_is_fnmatch(conf->d) != 0; + conf->r = r; + + ap_add_file_conf(c, new_file_conf); + + if (*arg != '\0') { + return ap_pstrcat(cmd->pool, "Multiple ", thiscmd->name, + "> arguments not (yet) supported.", NULL); + } + + cmd->path = old_path; + cmd->override = old_overrides; + + return NULL; +} + +/* XXX: NB: Currently, we have no way of checking + * whether sections are closed properly. + * Extra (redundant, unpaired) directives are + * simply silently ignored. + */ +static const char *end_ifmod(cmd_parms *cmd, void *dummy) +{ + return NULL; +} + +static const char *start_ifmod(cmd_parms *cmd, void *dummy, char *arg) +{ + char *endp = strrchr(arg, '>'); + char l[MAX_STRING_LEN]; + int not = (arg[0] == '!'); + module *found; + int nest = 1; + + if (endp == NULL) { + return unclosed_directive(cmd); + } + + *endp = '\0'; + + if (not) { + arg++; + } + + found = ap_find_linked_module(arg); + + if ((!not && found) || (not && !found)) { + return NULL; + } + + while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) { + if (!strncasecmp(l, "")) { + nest--; + } + } + + if (nest) { + cmd->end_token = end_ifmodule_section; + return missing_endsection(cmd, nest); + } + return NULL; +} + +API_EXPORT(int) ap_exists_config_define(char *name) +{ + char **defines; + int i; + + defines = (char **)ap_server_config_defines->elts; + for (i = 0; i < ap_server_config_defines->nelts; i++) { + if (strcmp(defines[i], name) == 0) { + return 1; + } + } + return 0; +} + +static const char *end_ifdefine(cmd_parms *cmd, void *dummy) +{ + return NULL; +} + +static const char *start_ifdefine(cmd_parms *cmd, void *dummy, char *arg) +{ + char *endp; + char l[MAX_STRING_LEN]; + int defined; + int not = 0; + int nest = 1; + + endp = strrchr(arg, '>'); + if (endp == NULL) { + return unclosed_directive(cmd); + } + + *endp = '\0'; + + if (arg[0] == '!') { + not = 1; + arg++; + } + + defined = ap_exists_config_define(arg); + + if ((!not && defined) || (not && !defined)) { + return NULL; + } + + while (nest && !(ap_cfg_getline(l, MAX_STRING_LEN, cmd->config_file))) { + if (!strncasecmp(l, "