joes 2002/12/18 22:15:04
Added: patches README apache-1.3+apreq.patch
Log:
Add apache-1.3+apreq.patch for OS X support.
Revision Changes Path
1.1 httpd-apreq/patches/README
Index: README
===================================================================
Experimental Patches:
apache-1.3+apreq-1.1.patch
patches apache-1.3 source to build libapreq directly into httpd.
To apply:
% cd ../../apache-1.3/
% patch -p0 < ../httpd-apreq/patches/apache-1.3+apreq-1.1.patch
Then build and install apache (+modperl) as normal. If you want to
use Apache::Request and Apache::Cookie, you'll also need to remove
the -lapreq linking flags within Request/Makefile.PL and
Cookie/Makefile.PL, before doing the perl build of libapreq.
The following commands should do the trick:
% cd ..
% perl -pi.bak -e 's/-lapreq//' Request/Makefile.PL Cookie/Makefile.PL
% perl Makefile.PL
...
% make && make test && make install
1.1 httpd-apreq/patches/apache-1.3+apreq.patch
Index: apache-1.3+apreq.patch
===================================================================
diff -urN ../apache-1.3/Makefile.tmpl ./Makefile.tmpl
--- ../apache-1.3/Makefile.tmpl Wed Mar 13 16:05:27 2002
+++ ./Makefile.tmpl Thu Dec 19 00:19:20 2002
@@ -447,6 +447,7 @@
@echo "===> [include: Installing Apache C header files]"
$(CP) $(TOP)/$(SRC)/include/*.h $(root)$(includedir)/
$(CP) $(TOP)/$(SRC)/lib/expat-lite/*.h $(root)$(includedir)/xml/
+ $(CP) $(TOP)/$(SRC)/lib/apreq/*.h $(root)$(includedir)/
@osdir=`grep '^OSDIR=' $(TOP)/$(SRC)/Makefile.config | sed -e
's:^OSDIR=.*/os/:os/:'`; \
echo "$(CP) $(TOP)/$(SRC)/$${osdir}/os.h
$(root)$(includedir)/"; \
$(CP) $(TOP)/$(SRC)/$${osdir}/os.h $(root)$(includedir)/; \
diff -urN ../apache-1.3/src/Configuration.tmpl ./src/Configuration.tmpl
--- ../apache-1.3/src/Configuration.tmpl Thu Jan 17 08:20:50 2002
+++ ./src/Configuration.tmpl Thu Dec 19 00:19:20 2002
@@ -187,6 +187,7 @@
Rule IRIXN32=yes
Rule PARANOID=no
Rule EXPAT=default
+Rule APREQ=yes
Rule CYGWIN_WINSOCK=no
# DEV_RANDOM:
diff -urN ../apache-1.3/src/Configure ./src/Configure
--- ../apache-1.3/src/Configure Thu Oct 10 12:36:21 2002
+++ ./src/Configure Thu Dec 19 00:19:21 2002
@@ -235,6 +235,7 @@
RULE_IRIXN32=`./helpers/CutRule IRIXN32 $file`
RULE_PARANOID=`./helpers/CutRule PARANOID $file`
RULE_EXPAT=`./helpers/CutRule EXPAT $file`
+RULE_APREQ=`./helpers/CutRule APREQ $file`
RULE_CYGWIN_WINSOCK=`./helpers/CutRule CYGWIN_WINSOCK $file`
RULE_SHARED_CORE=`./helpers/CutRule SHARED_CORE $file`
RULE_SHARED_CHAIN=`./helpers/CutRule SHARED_CHAIN $file`
@@ -1921,6 +1922,14 @@
fi
fi
+#APREQ HACK
+if [ "x$RULE_APREQ" = "xyes" ]; then
+ echo " + building with static apreq"
+ APREQLIB="lib/apreq/libapreq.a"
+ APLIBDIRS="apreq $APLIBDIRS"
+ CFLAGS="$CFLAGS -DUSE_APREQ -I\$(SRCDIR)/lib/apreq"
+fi
+
####################################################################
## Now the SHARED_CHAIN stuff
##
@@ -2182,6 +2191,7 @@
echo "MFLAGS_STATIC=$MFLAGS_STATIC" >>Makefile.config
echo "REGLIB=$REGLIB" >>Makefile.config
echo "EXPATLIB=$EXPATLIB" >>Makefile.config
+echo "APREQLIB=$APREQLIB" >>Makefile.config
echo "RANLIB=$RANLIB" >>Makefile.config
####################################################################
diff -urN ../apache-1.3/src/Makefile.tmpl ./src/Makefile.tmpl
--- ../apache-1.3/src/Makefile.tmpl Mon May 13 04:13:06 2002
+++ ./src/Makefile.tmpl Thu Dec 19 00:19:21 2002
@@ -33,7 +33,7 @@
target_static: subdirs modules.o
$(CC) -c $(INCLUDES) $(CFLAGS) buildmark.c
$(CC) $(CFLAGS) $(LDFLAGS) $(LDFLAGS_SHLIB_EXPORT) \
- -o $(TARGET) buildmark.o $(OBJS) $(REGLIB) $(EXPATLIB) $(LIBS)
+ -o $(TARGET) buildmark.o $(OBJS) $(REGLIB) $(EXPATLIB)
$(APREQLIB) $(LIBS)
target_compile_only: subdirs modules.o
$(CC) -c $(INCLUDES) $(CFLAGS) buildmark.c
@@ -50,7 +50,7 @@
lib$(TARGET).$(SHLIB_SUFFIX_NAME): subdirs modules.o
$(CC) -c $(INCLUDES) $(CFLAGS) buildmark.c
- $(LD_SHLIB) $(LDFLAGS_SHLIB) -o lib$(TARGET).$(SHLIB_SUFFIX_NAME)
buildmark.o $(OBJS) $(REGLIB) $(EXPATLIB) $(LD_SHCORE_DEF) $(LD_SHCORE_LIBS)
+ $(LD_SHLIB) $(LDFLAGS_SHLIB) -o lib$(TARGET).$(SHLIB_SUFFIX_NAME)
buildmark.o $(OBJS) $(REGLIB) $(EXPATLIB) $(APREQLIB) $(LD_SHCORE_DEF)
$(LD_SHCORE_LIBS)
@if [ ".$(SHLIB_SUFFIX_LIST)" != . ]; then \
rm -f lib$(TARGET).$(SHLIB_SUFFIX_NAME).*; \
for suffix in $(SHLIB_SUFFIX_LIST) ""; do \
diff -urN ../apache-1.3/src/lib/apreq/Makefile.tmpl
./src/lib/apreq/Makefile.tmpl
--- ../apache-1.3/src/lib/apreq/Makefile.tmpl Wed Dec 31 19:00:00 1969
+++ ./src/lib/apreq/Makefile.tmpl Thu Dec 19 00:19:21 2002
@@ -0,0 +1,26 @@
+#
+# default definition of these two. dunno how to get it prepended when the
+# Makefile is built, so we do it manually
+#
+CFLAGS=$(OPTIM) $(CFLAGS1) $(EXTRA_CFLAGS) -DAPACHE
+INCLUDES=$(INCLUDES1) $(INCLUDES0) $(EXTRA_INCLUDES)
+
+OBJS=apache_request.o apache_multipart_buffer.o apache_cookie.o
+
+all lib: libapreq.a
+
+libapreq.a: $(OBJS)
+ rm -f libapreq.a
+ ar cr libapreq.a $(OBJS)
+ $(RANLIB) libapreq.a
+
+clean:
+ rm -f $(OBJS) libapreq.a
+
+distclean: clean
+ -rm -f Makefile
+
+.SUFFIXES: .o
+
+.c.o:
+ $(CC) -c $(INCLUDES) $(CFLAGS) $<
diff -urN ../apache-1.3/src/lib/apreq/apache_cookie.c
./src/lib/apreq/apache_cookie.c
--- ../apache-1.3/src/lib/apreq/apache_cookie.c Wed Dec 31 19:00:00 1969
+++ ./src/lib/apreq/apache_cookie.c Thu Dec 19 00:22:38 2002
@@ -0,0 +1,269 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#include "apache_cookie.h"
+
+char *ApacheCookie_expires(ApacheCookie *c, char *time_str)
+{
+ char *expires;
+
+ expires = ApacheUtil_expires(c->r->pool, time_str, EXPIRES_COOKIE);
+ if (expires)
+ c->expires = expires;
+
+ return c->expires;
+}
+
+#define cookie_get_set(thing,val) \
+ retval = thing; \
+ if(val) thing = ap_pstrdup(c->r->pool, val)
+
+char *ApacheCookie_attr(ApacheCookie *c, char *key, char *val)
+{
+ char *retval = NULL;
+ int ix = key[0] == '-' ? 1 : 0;
+
+ switch (key[ix]) {
+ case 'n':
+ cookie_get_set(c->name, val);
+ break;
+ case 'v':
+ ApacheCookieAdd(c, val);
+ break;
+ case 'e':
+ retval = ApacheCookie_expires(c, val);
+ break;
+ case 'd':
+ cookie_get_set(c->domain, val);
+ break;
+ case 'p':
+ cookie_get_set(c->path, val);
+ break;
+ case 's':
+ if(val) {
+ c->secure =
+ !strcaseEQ(val, "off") &&
+ !strcaseEQ(val, "0");
+ }
+ retval = c->secure ? "on" : "";
+ break;
+ default:
+ ap_log_rerror(APC_ERROR,
+ "[libapreq] unknown cookie pair: `%s' => `%s'", key, val);
+ };
+
+ return retval;
+}
+
+ApacheCookie *ApacheCookie_new(request_rec *r, ...)
+{
+ va_list args;
+ ApacheRequest req;
+ ApacheCookie *c =
+ ap_pcalloc(r->pool, sizeof(ApacheCookie));
+
+ req.r = r;
+ c->r = r;
+ c->values = ap_make_array(r->pool, 1, sizeof(char *));
+ c->secure = 0;
+ c->name = c->expires = NULL;
+
+ c->domain = NULL;
+ c->path = ApacheRequest_script_path(&req);
+
+ va_start(args, r);
+ for(;;) {
+ char *key, *val;
+ key = va_arg(args, char *);
+ if (key == NULL)
+ break;
+
+ val = va_arg(args, char *);
+ (void)ApacheCookie_attr(c, key, val);
+ }
+ va_end(args);
+
+ return c;
+}
+
+ApacheCookieJar *ApacheCookie_parse(request_rec *r, const char *data)
+{
+ const char *pair;
+ ApacheCookieJar *retval =
+ ap_make_array(r->pool, 1, sizeof(ApacheCookie *));
+
+ if (!data)
+ if (!(data = ap_table_get(r->headers_in, "Cookie")))
+ return retval;
+
+ while (*data && (pair = ap_getword(r->pool, &data, ';'))) {
+ const char *key, *val;
+ ApacheCookie *c;
+
+ while (ap_isspace(*data))
+ ++data;
+
+ key = ap_getword(r->pool, &pair, '=');
+ ap_unescape_url((char *)key);
+ c = ApacheCookie_new(r, "-name", key, NULL);
+
+ if (c->values)
+ c->values->nelts = 0;
+ else
+ c->values = ap_make_array(r->pool, 4, sizeof(char *));
+
+ if (!*pair)
+ ApacheCookieAdd(c, "");
+
+
+ while (*pair && (val = ap_getword_nulls(r->pool, &pair, '&'))) {
+ ap_unescape_url((char *)val);
+#ifdef DEBUG
+ ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r,
+ "[apache_cookie] added (%s)", val);
+#endif
+ ApacheCookieAdd(c, val);
+ }
+ ApacheCookieJarAdd(retval, c);
+ }
+
+ return retval;
+}
+
+#define cookie_push_arr(arr, val) \
+ *(char **)ap_push_array(arr) = (char *)val
+
+#define cookie_push_named(arr, name, val) \
+ if(val && strlen(val) > 0) { \
+ cookie_push_arr(arr, ap_pstrcat(p, name, "=", val, NULL)); \
+ }
+
+static char * escape_url(pool *p, char *val)
+{
+ char *result = ap_os_escape_path(p, val?val:"", 1);
+ char *end = result + strlen(result);
+ char *seek;
+
+ /* touchup result to ensure that special chars are escaped */
+ for ( seek = end-1; seek >= result; --seek) {
+ char *ptr, *replacement;
+
+ switch (*seek) {
+
+ case '&':
+ replacement = "%26";
+ break;
+ case '=':
+ replacement = "%3d";
+ break;
+ /* additional cases here */
+
+ default:
+ continue; /* next for() */
+ }
+
+ for (ptr = end; ptr > seek; --ptr)
+ ptr[2] = ptr[0];
+
+ strncpy(seek, replacement, 3);
+ end += 2;
+ }
+
+ return(result);
+}
+
+char *ApacheCookie_as_string(ApacheCookie *c)
+{
+ array_header *values;
+ pool *p = c->r->pool;
+ char *cookie, *retval;
+ int i;
+
+ if (!c->name)
+ return "";
+
+ values = ap_make_array(p, 6, sizeof(char *));
+ cookie_push_named(values, "domain", c->domain);
+ cookie_push_named(values, "path", c->path);
+ cookie_push_named(values, "expires", c->expires);
+ if (c->secure) {
+ cookie_push_arr(values, "secure");
+ }
+
+ cookie = ap_pstrcat(p, escape_url(p, c->name), "=", NULL);
+ for (i=0; i<c->values->nelts; i++) {
+ cookie = ap_pstrcat(p, cookie,
+ escape_url(p, ((char**)c->values->elts)[i]),
+ (i < (c->values->nelts -1) ? "&" : NULL),
+ NULL);
+ }
+
+ retval = cookie;
+ for (i=0; i<values->nelts; i++) {
+ retval = ap_pstrcat(p, retval, "; ",
+ ((char**)values->elts)[i], NULL);
+ }
+
+ return retval;
+}
+
+void ApacheCookie_bake(ApacheCookie *c)
+{
+ ap_table_add(c->r->err_headers_out, "Set-Cookie",
+ ApacheCookie_as_string(c));
+}
diff -urN ../apache-1.3/src/lib/apreq/apache_cookie.h
./src/lib/apreq/apache_cookie.h
--- ../apache-1.3/src/lib/apreq/apache_cookie.h Wed Dec 31 19:00:00 1969
+++ ./src/lib/apreq/apache_cookie.h Thu Dec 19 00:22:38 2002
@@ -0,0 +1,57 @@
+#ifndef _APACHE_COOKIE_H
+#define _APACHE_COOKIE_H
+
+#include "apache_request.h"
+
+typedef array_header ApacheCookieJar;
+
+typedef struct {
+ request_rec *r;
+ char *name;
+ array_header *values;
+ char *domain;
+ char *expires;
+ char *path;
+ int secure;
+} ApacheCookie;
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#define ApacheCookieJarItems(arr) arr->nelts
+
+#define ApacheCookieJarFetch(arr,i) \
+((ApacheCookie *)(((ApacheCookie **)arr->elts)[i]))
+
+#define ApacheCookieJarAdd(arr,c) \
+*(ApacheCookie **)ap_push_array(arr) = c
+
+#define ApacheCookieItems(c) c->values->nelts
+
+#define ApacheCookieFetch(c,i) \
+((char *)(((char **)c->values->elts)[i]))
+
+#define ApacheCookieAddn(c,val) \
+ if(val) *(char **)ap_push_array(c->values) = (char *)val
+
+#define ApacheCookieAdd(c,val) \
+ ApacheCookieAddn(c, ap_pstrdup(c->r->pool, val))
+
+#define ApacheCookieAddLen(c,val,len) \
+ ApacheCookieAddn(c, ap_pstrndup(c->r->pool, val, len))
+
+ApacheCookie *ApacheCookie_new(request_rec *r, ...);
+ApacheCookieJar *ApacheCookie_parse(request_rec *r, const char *data);
+char *ApacheCookie_as_string(ApacheCookie *c);
+char *ApacheCookie_attr(ApacheCookie *c, char *key, char *val);
+char *ApacheCookie_expires(ApacheCookie *c, char *time_str);
+void ApacheCookie_bake(ApacheCookie *c);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define APC_ERROR APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, c->r
+
+#endif
diff -urN ../apache-1.3/src/lib/apreq/apache_multipart_buffer.c
./src/lib/apreq/apache_multipart_buffer.c
--- ../apache-1.3/src/lib/apreq/apache_multipart_buffer.c Wed Dec 31
19:00:00 1969
+++ ./src/lib/apreq/apache_multipart_buffer.c Thu Dec 19 00:22:38 2002
@@ -0,0 +1,338 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#include "apache_multipart_buffer.h"
+
+/*********************** internal functions *********************/
+
+/*
+ search for a string in a fixed-length byte string.
+ if partial is true, partial matches are allowed at the end of the buffer.
+ returns NULL if not found, or a pointer to the start of the first match.
+*/
+void* my_memstr(char* haystack, int haystacklen, const char* needle,
+ int partial)
+{
+ int needlen = strlen(needle);
+ int len = haystacklen;
+ char *ptr = haystack;
+
+ /* iterate through first character matches */
+ while( (ptr = memchr(ptr, needle[0], len)) ) {
+ /* calculate length after match */
+ len = haystacklen - (ptr - (char *)haystack);
+
+ /* done if matches up to capacity of buffer */
+ if(memcmp(needle, ptr, needlen < len ? needlen : len) == 0 &&
+ (partial || len >= needlen))
+ break;
+
+ /* next character */
+ ptr++; len--;
+ }
+
+ return ptr;
+}
+
+/*
+ fill up the buffer with client data.
+ returns number of bytes added to buffer.
+*/
+int fill_buffer(multipart_buffer *self)
+{
+ int bytes_to_read, actual_read = 0;
+
+ /* shift the existing data if necessary */
+ if(self->bytes_in_buffer > 0 && self->buf_begin != self->buffer)
+ memmove(self->buffer, self->buf_begin, self->bytes_in_buffer);
+ self->buf_begin = self->buffer;
+
+ /* calculate the free space in the buffer */
+ bytes_to_read = self->bufsize - self->bytes_in_buffer;
+
+ if (bytes_to_read >= self->r->remaining) {
+ bytes_to_read = self->r->remaining - strlen(self->boundary);
+#ifdef DEBUG
+ ap_log_rerror(MPB_ERROR, "mozilla 0.97 hack: '%ld'",
self->r->remaining);
+#endif
+ }
+
+ /* read the required number of bytes */
+ if(bytes_to_read > 0) {
+ char *buf = self->buffer + self->bytes_in_buffer;
+ ap_hard_timeout("[libapreq] multipart_buffer.c:fill_buffer", self->r);
+ actual_read = ap_get_client_block(self->r, buf, bytes_to_read);
+ ap_kill_timeout(self->r);
+
+ /* update the buffer length */
+ if(actual_read > 0)
+ self->bytes_in_buffer += actual_read;
+ }
+
+ return actual_read;
+}
+
+/*
+ gets the next CRLF terminated line from the input buffer.
+ if it doesn't find a CRLF, and the buffer isn't completely full, returns
+ NULL; otherwise, returns the beginning of the null-terminated line,
+ minus the CRLF.
+
+ note that we really just look for LF terminated lines. this works
+ around a bug in internet explorer for the macintosh which sends mime
+ boundaries that are only LF terminated when you use an image submit
+ button in a multipart/form-data form.
+ */
+char* next_line(multipart_buffer *self)
+{
+ /* look for LF in the data */
+ char* line = self->buf_begin;
+ char* ptr = memchr(self->buf_begin, '\n', self->bytes_in_buffer);
+
+ /* LF found */
+ if(ptr) {
+ /* terminate the string, remove CRLF */
+ if((ptr - line) > 0 && *(ptr-1) == '\r') *(ptr-1) = 0;
+ else *ptr = 0;
+
+ /* bump the pointer */
+ self->buf_begin = ptr + 1;
+ self->bytes_in_buffer -= (self->buf_begin - line);
+ }
+
+ /* no LF found */
+ else {
+ /* buffer isn't completely full, fail */
+ if(self->bytes_in_buffer < self->bufsize)
+ return NULL;
+
+ /* return entire buffer as a partial line */
+ line[self->bufsize] = 0;
+ self->buf_begin = ptr;
+ self->bytes_in_buffer = 0;
+ }
+
+ return line;
+}
+
+/* returns the next CRLF terminated line from the client */
+char* get_line(multipart_buffer *self)
+{
+ char* ptr = next_line(self);
+
+ if(!ptr) {
+ fill_buffer(self);
+ ptr = next_line(self);
+ }
+
+#ifdef DEBUG
+ ap_log_rerror(MPB_ERROR, "get_line: '%s'", ptr);
+#endif
+
+ return ptr;
+}
+
+/* finds a boundary */
+int find_boundary(multipart_buffer *self, char *boundary)
+{
+ char *line;
+
+ /* loop thru lines */
+ while( (line = get_line(self)) ) {
+#ifdef DEBUG
+ ap_log_rerror(MPB_ERROR, "find_boundary: '%s' ?= '%s'",
+ line, boundary);
+#endif
+
+ /* finished if we found the boundary */
+ if(strEQ(line, boundary))
+ return 1;
+ }
+
+ /* didn't find the boundary */
+ return 0;
+}
+
+/*********************** external functions *********************/
+
+/* create new multipart_buffer structure */
+multipart_buffer *multipart_buffer_new(char *boundary, long length,
request_rec *r)
+{
+ multipart_buffer *self = (multipart_buffer *)
+ ap_pcalloc(r->pool, sizeof(multipart_buffer));
+
+ int minsize = strlen(boundary)+6;
+ if(minsize < FILLUNIT) minsize = FILLUNIT;
+
+ self->r = r;
+ self->buffer = (char *) ap_pcalloc(r->pool, minsize+1);
+ self->bufsize = minsize;
+ self->request_length = length;
+ self->boundary = ap_pstrcat(r->pool, "--", boundary, NULL);
+ self->boundary_next = ap_pstrcat(r->pool, "\n", self->boundary, NULL);
+ self->buf_begin = self->buffer;
+ self->bytes_in_buffer = 0;
+
+ return self;
+}
+
+/* parse headers and return them in an apache table */
+table *multipart_buffer_headers(multipart_buffer *self)
+{
+ table *tab;
+ char *line;
+
+ /* didn't find boundary, abort */
+ if(!find_boundary(self, self->boundary)) return NULL;
+
+ /* get lines of text, or CRLF_CRLF */
+ tab = ap_make_table(self->r->pool, 10);
+ while( (line = get_line(self)) && strlen(line) > 0 ) {
+ /* add header to table */
+ char *key = line;
+ char *value = strchr(line, ':');
+
+ if(value) {
+ *value = 0;
+ do { value++; } while(ap_isspace(*value));
+
+#ifdef DEBUG
+ ap_log_rerror(MPB_ERROR,
+ "multipart_buffer_headers: '%s' = '%s'",
+ key, value);
+#endif
+
+ ap_table_add(tab, key, value);
+ }
+ else {
+#ifdef DEBUG
+ ap_log_rerror(MPB_ERROR,
+ "multipart_buffer_headers: '%s' = ''", key);
+#endif
+
+ ap_table_add(tab, key, "");
+ }
+ }
+
+ return tab;
+}
+
+/* read until a boundary condition */
+int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes)
+{
+ int len, max;
+ char *bound;
+
+ /* fill buffer if needed */
+ if(bytes > self->bytes_in_buffer) fill_buffer(self);
+
+ /* look for a potential boundary match, only read data up to that point
*/
+ if( (bound = my_memstr(self->buf_begin, self->bytes_in_buffer,
+ self->boundary_next, 1)) )
+ max = bound - self->buf_begin;
+ else
+ max = self->bytes_in_buffer;
+
+ /* maximum number of bytes we are reading */
+ len = max < bytes-1 ? max : bytes-1;
+
+ /* if we read any data... */
+ if(len > 0) {
+ /* copy the data */
+ memcpy(buf, self->buf_begin, len);
+ buf[len] = 0;
+ if(bound && len > 0 && buf[len-1] == '\r') buf[--len] = 0;
+
+ /* update the buffer */
+ self->bytes_in_buffer -= len;
+ self->buf_begin += len;
+ }
+
+#ifdef DEBUG
+ ap_log_rerror(MPB_ERROR, "multipart_buffer_read: %d bytes", len);
+#endif
+
+ return len;
+}
+
+/*
+ XXX: this is horrible memory-usage-wise, but we only expect
+ to do this on small pieces of form data.
+*/
+char *multipart_buffer_read_body(multipart_buffer *self)
+{
+ char buf[FILLUNIT], *out = "";
+
+ while(multipart_buffer_read(self, buf, sizeof(buf)))
+ out = ap_pstrcat(self->r->pool, out, buf, NULL);
+
+#ifdef DEBUG
+ ap_log_rerror(MPB_ERROR, "multipart_buffer_read_body: '%s'", out);
+#endif
+
+ return out;
+}
+
+/* eof if we are out of bytes, or if we hit the final boundary */
+int multipart_buffer_eof(multipart_buffer *self)
+{
+ if( (self->bytes_in_buffer == 0 && fill_buffer(self) < 1) )
+ return 1;
+ else
+ return 0;
+}
diff -urN ../apache-1.3/src/lib/apreq/apache_multipart_buffer.h
./src/lib/apreq/apache_multipart_buffer.h
--- ../apache-1.3/src/lib/apreq/apache_multipart_buffer.h Wed Dec 31
19:00:00 1969
+++ ./src/lib/apreq/apache_multipart_buffer.h Thu Dec 19 00:22:38 2002
@@ -0,0 +1,42 @@
+#ifndef _APACHE_MULTIPART_BUFFER_H
+#define _APACHE_MULTIPART_BUFFER_H
+
+#include "apache_request.h"
+
+/*#define DEBUG 1*/
+#define FILLUNIT (1024 * 5)
+#define MPB_ERROR APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, self->r
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef struct {
+ /* request info */
+ request_rec *r;
+ long request_length;
+
+ /* read buffer */
+ char *buffer;
+ char *buf_begin;
+ int bufsize;
+ int bytes_in_buffer;
+
+ /* boundary info */
+ char *boundary;
+ char *boundary_next;
+ char *boundary_end;
+} multipart_buffer;
+
+multipart_buffer *
+ multipart_buffer_new(char *boundary, long length, request_rec *r);
+table *multipart_buffer_headers(multipart_buffer *self);
+int multipart_buffer_read(multipart_buffer *self, char *buf, int bytes);
+char *multipart_buffer_read_body(multipart_buffer *self);
+int multipart_buffer_eof(multipart_buffer *self);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
diff -urN ../apache-1.3/src/lib/apreq/apache_request.c
./src/lib/apreq/apache_request.c
--- ../apache-1.3/src/lib/apreq/apache_request.c Wed Dec 31 19:00:00 1969
+++ ./src/lib/apreq/apache_request.c Thu Dec 19 00:22:38 2002
@@ -0,0 +1,584 @@
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2000 The Apache Software Foundation. All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact [EMAIL PROTECTED]
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * nor may "Apache" appear in their name, without prior written
+ * permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ * Portions of this software are based upon public domain software
+ * originally written at the National Center for Supercomputing Applications,
+ * University of Illinois, Urbana-Champaign.
+ */
+
+#include "apache_request.h"
+#include "apache_multipart_buffer.h"
+int fill_buffer(multipart_buffer *self); /* needed for mozilla hack */
+
+static void req_plustospace(char *str)
+{
+ register int x;
+ for(x=0;str[x];x++) if(str[x] == '+') str[x] = ' ';
+}
+
+static int util_read(ApacheRequest *req, const char **rbuf)
+{
+ request_rec *r = req->r;
+ int rc = OK;
+
+ if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
+ return rc;
+ }
+
+ if (ap_should_client_block(r)) {
+ char buff[HUGE_STRING_LEN];
+ int rsize, len_read, rpos=0;
+ long length = r->remaining;
+
+ if (length > req->post_max && req->post_max > 0) {
+ ap_log_rerror(REQ_ERROR, "[libapreq] entity too large (%d, max=%d)",
+ (int)length, req->post_max);
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+
+ *rbuf = ap_pcalloc(r->pool, length + 1);
+
+ ap_hard_timeout("[libapreq] util_read", r);
+
+ while ((len_read =
+ ap_get_client_block(r, buff, sizeof(buff))) > 0) {
+ if ((rpos + len_read) > length) {
+ rsize = length - rpos;
+ }
+ else {
+ rsize = len_read;
+ }
+ memcpy((char*)*rbuf + rpos, buff, rsize);
+ rpos += rsize;
+ }
+
+ ap_kill_timeout(r);
+ }
+
+ return rc;
+}
+
+char *ApacheRequest_script_name(ApacheRequest *req)
+{
+ request_rec *r = req->r;
+ char *tmp;
+
+ if (r->path_info && *r->path_info) {
+ int path_info_start = ap_find_path_info(r->uri, r->path_info);
+ tmp = ap_pstrndup(r->pool, r->uri, path_info_start);
+ }
+ else {
+ tmp = r->uri;
+ }
+
+ return tmp;
+}
+
+char *ApacheRequest_script_path(ApacheRequest *req)
+{
+ return ap_make_dirstr_parent(req->r->pool,
ApacheRequest_script_name(req));
+}
+
+const char *ApacheRequest_param(ApacheRequest *req, const char *key)
+{
+ ApacheRequest_parse(req);
+ return ap_table_get(req->parms, key);
+}
+
+static int make_params(void *data, const char *key, const char *val)
+{
+ array_header *arr = (array_header *)data;
+ *(char **)ap_push_array(arr) = (char *)val;
+ return 1;
+}
+
+array_header *ApacheRequest_params(ApacheRequest *req, const char *key)
+{
+ array_header *values = ap_make_array(req->r->pool, 4, sizeof(char *));
+ ApacheRequest_parse(req);
+ ap_table_do(make_params, (void*)values, req->parms, key, NULL);
+ return values;
+}
+
+char *ApacheRequest_params_as_string(ApacheRequest *req, const char *key)
+{
+ char *retval = NULL;
+ array_header *values = ApacheRequest_params(req, key);
+ int i;
+
+ for (i=0; i<values->nelts; i++) {
+ retval = ap_pstrcat(req->r->pool,
+ retval ? retval : "",
+ ((char **)values->elts)[i],
+ (i == (values->nelts - 1)) ? NULL : ", ",
+ NULL);
+ }
+
+ return retval;
+}
+
+ApacheUpload *ApacheUpload_new(ApacheRequest *req)
+{
+ ApacheUpload *upload = (ApacheUpload *)
+ ap_pcalloc(req->r->pool, sizeof(ApacheUpload));
+
+ upload->next = NULL;
+ upload->name = NULL;
+ upload->info = NULL;
+ upload->fp = NULL;
+ upload->size = 0;
+ upload->req = req;
+
+ return upload;
+}
+
+ApacheUpload *ApacheUpload_find(ApacheUpload *upload, char *name)
+{
+ ApacheUpload *uptr;
+
+ for (uptr = upload; uptr; uptr = uptr->next) {
+ if (strEQ(uptr->name, name)) {
+ return uptr;
+ }
+ }
+
+ return NULL;
+}
+
+ApacheRequest *ApacheRequest_new(request_rec *r)
+{
+ ApacheRequest *req = (ApacheRequest *)
+ ap_pcalloc(r->pool, sizeof(ApacheRequest));
+
+ req->status = OK;
+ req->parms = ap_make_table(r->pool, DEFAULT_TABLE_NELTS);
+ req->upload = NULL;
+ req->post_max = -1;
+ req->disable_uploads = 0;
+ req->upload_hook = NULL;
+ req->hook_data = NULL;
+ req->temp_dir = NULL;
+ req->parsed = 0;
+ req->r = r;
+
+ return req;
+}
+
+static int urlword_dlm[] = {'&', ';', 0};
+
+static char *my_urlword(pool *p, const char **line)
+{
+ char *res = NULL;
+ const char *pos = *line;
+ char ch;
+
+ while ( (ch = *pos) != '\0' && ch != ';' && ch != '&') {
+ ++pos;
+ }
+
+ res = ap_pstrndup(p, *line, pos - *line);
+
+ while (ch == ';' || ch == '&') {
+ ++pos;
+ ch = *pos;
+ }
+
+ *line = pos;
+
+ return res;
+}
+
+
+static void split_to_parms(ApacheRequest *req, const char *data)
+{
+ request_rec *r = req->r;
+ const char *val;
+
+ while (*data && (val = my_urlword(r->pool, &data))) {
+ const char *key = ap_getword(r->pool, &val, '=');
+
+ req_plustospace((char*)key);
+ ap_unescape_url((char*)key);
+ req_plustospace((char*)val);
+ ap_unescape_url((char*)val);
+
+ ap_table_add(req->parms, key, val);
+ }
+
+}
+
+int ApacheRequest___parse(ApacheRequest *req)
+{
+ request_rec *r = req->r;
+ int result;
+
+ if (r->args) {
+ split_to_parms(req, r->args);
+ }
+
+ if (r->method_number == M_POST) {
+ const char *ct = ap_table_get(r->headers_in, "Content-type");
+ if (ct && strncaseEQ(ct, DEFAULT_ENCTYPE, DEFAULT_ENCTYPE_LENGTH)) {
+ result = ApacheRequest_parse_urlencoded(req);
+ }
+ else if (ct && strncaseEQ(ct, MULTIPART_ENCTYPE,
MULTIPART_ENCTYPE_LENGTH)) {
+ result = ApacheRequest_parse_multipart(req);
+ }
+ else {
+ ap_log_rerror(REQ_ERROR,
+ "[libapreq] unknown content-type: `%s'", ct);
+ result = HTTP_INTERNAL_SERVER_ERROR;
+ }
+ }
+ else {
+ result = ApacheRequest_parse_urlencoded(req);
+ }
+
+ req->parsed = 1;
+ return result;
+
+}
+
+int ApacheRequest_parse_urlencoded(ApacheRequest *req)
+{
+ request_rec *r = req->r;
+ int rc = OK;
+
+ if (r->method_number == M_POST) {
+ const char *data = NULL, *type;
+
+ type = ap_table_get(r->headers_in, "Content-Type");
+
+ if (!strncaseEQ(type, DEFAULT_ENCTYPE, DEFAULT_ENCTYPE_LENGTH)) {
+ return DECLINED;
+ }
+ if ((rc = util_read(req, &data)) != OK) {
+ return rc;
+ }
+ if (data) {
+ split_to_parms(req, data);
+ }
+ }
+
+ return OK;
+}
+
+static void remove_tmpfile(void *data) {
+ ApacheUpload *upload = (ApacheUpload *) data;
+ ApacheRequest *req = upload->req;
+
+ if( ap_pfclose(req->r->pool, upload->fp) )
+ ap_log_rerror(REQ_ERROR,
+ "[libapreq] close error on '%s'", upload->tempname);
+#ifndef DEBUG
+ if( remove(upload->tempname) )
+ ap_log_rerror(REQ_ERROR,
+ "[libapreq] remove error on '%s'", upload->tempname);
+#endif
+
+ free(upload->tempname);
+}
+
+FILE *ApacheRequest_tmpfile(ApacheRequest *req, ApacheUpload *upload)
+{
+ request_rec *r = req->r;
+ FILE *fp;
+ char prefix[] = "apreq";
+ char *name = NULL;
+ int fd = 0;
+ int tries = 100;
+
+ while (--tries > 0) {
+ if ( (name = tempnam(req->temp_dir, prefix)) == NULL )
+ continue;
+ fd = ap_popenf(r->pool, name, O_CREAT|O_EXCL|O_RDWR|O_BINARY, 0600);
+ if ( fd >= 0 )
+ break; /* success */
+ else
+ free(name);
+ }
+
+ if ( tries == 0 || (fp = ap_pfdopen(r->pool, fd, "w+" "b") ) == NULL ) {
+ ap_log_rerror(REQ_ERROR, "[libapreq] could not create/open temp file");
+ if ( fd >= 0 ) { remove(name); free(name); }
+ return NULL;
+ }
+
+ upload->fp = fp;
+ upload->tempname = name;
+ ap_register_cleanup(r->pool, (void *)upload,
+ remove_tmpfile, ap_null_cleanup);
+ return fp;
+
+}
+
+int ApacheRequest_parse_multipart(ApacheRequest *req)
+{
+ request_rec *r = req->r;
+ int rc = OK;
+ const char *ct = ap_table_get(r->headers_in, "Content-Type");
+ long length;
+ char *boundary;
+ multipart_buffer *mbuff;
+ ApacheUpload *upload = NULL;
+
+ if (!ct) {
+ ap_log_rerror(REQ_ERROR, "[libapreq] no Content-type header!");
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR))) {
+ return rc;
+ }
+
+ if (!ap_should_client_block(r)) {
+ return rc;
+ }
+
+ if ((length = r->remaining) > req->post_max && req->post_max > 0) {
+ ap_log_rerror(REQ_ERROR, "[libapreq] entity too large (%d, max=%d)",
+ (int)length, req->post_max);
+ return HTTP_REQUEST_ENTITY_TOO_LARGE;
+ }
+
+ (void)ap_getword(r->pool, &ct, '=');
+ boundary = ap_getword_conf(r->pool, &ct);
+
+ if (!(mbuff = multipart_buffer_new(boundary, length, r))) {
+ return DECLINED;
+ }
+
+ while (!multipart_buffer_eof(mbuff)) {
+ table *header = multipart_buffer_headers(mbuff);
+ const char *cd, *param=NULL, *filename=NULL;
+ char buff[FILLUNIT];
+ int blen, wlen;
+
+ if (!header) {
+#ifdef DEBUG
+ ap_log_rerror(REQ_ERROR,
+ "[libapreq] silently drop remaining '%ld' bytes",
r->remaining);
+#endif
+ ap_hard_timeout("[libapreq] parse_multipart", r);
+ while ( ap_get_client_block(r, buff, sizeof(buff)) > 0 )
+ /* wait for more input to ignore */ ;
+ ap_kill_timeout(r);
+ return OK;
+ }
+
+ if ((cd = ap_table_get(header, "Content-Disposition"))) {
+ const char *pair;
+
+ while (*cd && (pair = ap_getword(r->pool, &cd, ';'))) {
+ const char *key;
+
+ while (ap_isspace(*cd)) {
+ ++cd;
+ }
+ if (ap_ind(pair, '=')) {
+ key = ap_getword(r->pool, &pair, '=');
+ if(strEQ(key, "name")) {
+ param = ap_getword_conf(r->pool, &pair);
+ }
+ else if(strEQ(key, "filename")) {
+ filename = ap_getword_conf(r->pool, &pair);
+ }
+ }
+ }
+ if (!filename) {
+ char *value = multipart_buffer_read_body(mbuff);
+ ap_table_add(req->parms, param, value);
+ continue;
+ }
+ if (!param) continue; /* shouldn't happen, but just in case. */
+
+ if (req->disable_uploads) {
+ ap_log_rerror(REQ_ERROR, "[libapreq] file upload forbidden");
+ return HTTP_FORBIDDEN;
+ }
+
+ ap_table_add(req->parms, param, filename);
+
+ if (upload) {
+ upload->next = ApacheUpload_new(req);
+ upload = upload->next;
+ }
+ else {
+ upload = ApacheUpload_new(req);
+ req->upload = upload;
+ }
+
+ if (! req->upload_hook && ! ApacheRequest_tmpfile(req, upload) ) {
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ upload->info = header;
+ upload->filename = ap_pstrdup(req->r->pool, filename);
+ upload->name = ap_pstrdup(req->r->pool, param);
+
+ /* mozilla empty-file (missing CRLF) hack */
+ fill_buffer(mbuff);
+ if( strEQN(mbuff->buf_begin, mbuff->boundary,
+ strlen(mbuff->boundary)) ) {
+ r->remaining -= 2;
+ continue;
+ }
+
+ while ((blen = multipart_buffer_read(mbuff, buff, sizeof(buff)))) {
+ if (req->upload_hook != NULL) {
+ wlen = req->upload_hook(req->hook_data, buff, blen, upload);
+ } else {
+ wlen = fwrite(buff, 1, blen, upload->fp);
+ }
+ if (wlen != blen) {
+ return HTTP_INTERNAL_SERVER_ERROR;
+ }
+ upload->size += wlen;
+ }
+
+ if (upload->size > 0 && (upload->fp != NULL)) {
+ fseek(upload->fp, 0, 0);
+ }
+ }
+ }
+
+ return OK;
+}
+
+#define Mult_s 1
+#define Mult_m 60
+#define Mult_h (60*60)
+#define Mult_d (60*60*24)
+#define Mult_M (60*60*24*30)
+#define Mult_y (60*60*24*365)
+
+static int expire_mult(char s)
+{
+ switch (s) {
+ case 's':
+ return Mult_s;
+ case 'm':
+ return Mult_m;
+ case 'h':
+ return Mult_h;
+ case 'd':
+ return Mult_d;
+ case 'M':
+ return Mult_M;
+ case 'y':
+ return Mult_y;
+ default:
+ return 1;
+ };
+}
+
+static time_t expire_calc(char *time_str)
+{
+ int is_neg = 0, offset = 0;
+ char buf[256];
+ int ix = 0;
+
+ if (*time_str == '-') {
+ is_neg = 1;
+ ++time_str;
+ }
+ else if (*time_str == '+') {
+ ++time_str;
+ }
+ else if (strcaseEQ(time_str, "now")) {
+ /*ok*/
+ }
+ else {
+ return 0;
+ }
+
+ /* wtf, ap_isdigit() returns false for '1' !? */
+ while (*time_str && (ap_isdigit(*time_str) || (*time_str == '1'))) {
+ buf[ix++] = *time_str++;
+ }
+ buf[ix] = '\0';
+ offset = atoi(buf);
+
+ return time(NULL) +
+ (expire_mult(*time_str) * (is_neg ? (0 - offset) : offset));
+}
+
+char *ApacheUtil_expires(pool *p, char *time_str, int type)
+{
+ time_t when;
+ struct tm *tms;
+ int sep = (type == EXPIRES_HTTP) ? ' ' : '-';
+
+ if (!time_str) {
+ return NULL;
+ }
+
+ when = expire_calc(time_str);
+
+ if (!when) {
+ return ap_pstrdup(p, time_str);
+ }
+
+ tms = gmtime(&when);
+ return ap_psprintf(p,
+ "%s, %.2d%c%s%c%.2d %.2d:%.2d:%.2d GMT",
+ ap_day_snames[tms->tm_wday],
+ tms->tm_mday, sep, ap_month_snames[tms->tm_mon], sep,
+ tms->tm_year + 1900,
+ tms->tm_hour, tms->tm_min, tms->tm_sec);
+}
+
+char *ApacheRequest_expires(ApacheRequest *req, char *time_str)
+{
+ return ApacheUtil_expires(req->r->pool, time_str, EXPIRES_HTTP);
+}
diff -urN ../apache-1.3/src/lib/apreq/apache_request.h
./src/lib/apreq/apache_request.h
--- ../apache-1.3/src/lib/apreq/apache_request.h Wed Dec 31 19:00:00 1969
+++ ./src/lib/apreq/apache_request.h Thu Dec 19 00:22:38 2002
@@ -0,0 +1,138 @@
+#ifndef _APACHE_REQUEST_H
+
+#define _APACHE_REQUEST_H
+
+#include "httpd.h"
+#include "http_config.h"
+#include "http_core.h"
+#include "http_log.h"
+#include "http_main.h"
+#include "http_protocol.h"
+#include "util_script.h"
+
+#ifdef SFIO
+#include "sfio.h"
+
+/* sfio 2000 changed _stdopen to _stdfdopen */
+#if SFIO_VERSION >= 20000101L
+#define _stdopen _stdfdopen
+#endif
+
+extern Sfio_t* _stdopen _ARG_((int, const char*)); /*1999*/
+
+#undef FILE
+#define FILE Sfio_t
+#undef fwrite
+#define fwrite(p,s,n,f) sfwrite((f),(p),(s)*(n))
+#undef fseek
+#define fseek(f,a,b) sfseek((f),(a),(b))
+#undef ap_pfdopen
+#define ap_pfdopen(p,q,r) _stdopen((q),(r))
+#undef ap_pfclose
+#define ap_pfclose(p,q) sfclose(q)
+#endif /*SFIO*/
+
+typedef struct ApacheUpload ApacheUpload;
+
+typedef struct {
+ table *parms;
+ ApacheUpload *upload;
+ int status;
+ int parsed;
+ int post_max;
+ int disable_uploads;
+ int (*upload_hook)(void *ptr, char *buf, int len, ApacheUpload *upload);
+ void *hook_data;
+ char* temp_dir;
+ request_rec *r;
+} ApacheRequest;
+
+struct ApacheUpload {
+ ApacheUpload *next;
+ char *filename;
+ char *name;
+ char *tempname;
+ table *info;
+ FILE *fp;
+ long size;
+ ApacheRequest *req;
+};
+
+#ifndef strEQ
+#define strEQ(s1,s2) (!strcmp(s1,s2))
+#endif
+
+#ifndef strEQN
+#define strEQN(s1,s2,n) (!strncmp(s1,s2,n))
+#endif
+
+#ifndef strcaseEQ
+#define strcaseEQ(s1,s2) (!strcasecmp(s1,s2))
+#endif
+
+#ifndef strncaseEQ
+#define strncaseEQ(s1,s2,n) (!strncasecmp(s1,s2,n))
+#endif
+
+#define DEFAULT_TABLE_NELTS 10
+
+#define DEFAULT_ENCTYPE "application/x-www-form-urlencoded"
+#define DEFAULT_ENCTYPE_LENGTH 33
+
+#define MULTIPART_ENCTYPE "multipart/form-data"
+#define MULTIPART_ENCTYPE_LENGTH 19
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+ApacheRequest *ApacheRequest_new(request_rec *r);
+int ApacheRequest_parse_multipart(ApacheRequest *req);
+int ApacheRequest_parse_urlencoded(ApacheRequest *req);
+char *ApacheRequest_script_name(ApacheRequest *req);
+char *ApacheRequest_script_path(ApacheRequest *req);
+const char *ApacheRequest_param(ApacheRequest *req, const char *key);
+array_header *ApacheRequest_params(ApacheRequest *req, const char *key);
+char *ApacheRequest_params_as_string(ApacheRequest *req, const char *key);
+int ApacheRequest___parse(ApacheRequest *req);
+#define ApacheRequest_parse(req) \
+ (req->status = req->parsed ? req->status : ApacheRequest___parse(req))
+
+FILE *ApacheRequest_tmpfile(ApacheRequest *req, ApacheUpload *upload);
+ApacheUpload *ApacheUpload_new(ApacheRequest *req);
+ApacheUpload *ApacheUpload_find(ApacheUpload *upload, char *name);
+
+#define ApacheRequest_upload(req) \
+ ((req->parsed || (ApacheRequest_parse(req) == OK)) ? req->upload : NULL)
+
+#define ApacheUpload_FILE(upload) (upload->fp)
+
+#define ApacheUpload_size(upload) (upload->size)
+
+#define ApacheUpload_info(upload, key) \
+ap_table_get(upload->info, key)
+
+#define ApacheUpload_type(upload) \
+ApacheUpload_info(upload, "Content-Type")
+
+#define ApacheRequest_set_post_max(req, max) (req->post_max = max)
+#define ApacheRequest_set_temp_dir(req, dir) (req->temp_dir = dir)
+
+char *ApacheUtil_expires(pool *p, char *time_str, int type);
+#define EXPIRES_HTTP 1
+#define EXPIRES_COOKIE 2
+char *ApacheRequest_expires(ApacheRequest *req, char *time_str);
+
+#ifdef __cplusplus
+ }
+#endif
+
+#define REQ_ERROR APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, req->r
+
+#ifdef REQDEBUG
+#define REQ_DEBUG(a) a
+#else
+#define REQ_DEBUG(a)
+#endif
+
+#endif /* _APACHE_REQUEST_H */
diff -urN ../apache-1.3/src/main/http_main.c ./src/main/http_main.c
--- ../apache-1.3/src/main/http_main.c Fri Oct 25 17:12:23 2002
+++ ./src/main/http_main.c Thu Dec 19 00:19:21 2002
@@ -7907,3 +7907,15 @@
}
#endif /* USE_EXPAT */
+
+/* force apreq to be linked into the server executable */
+#if defined(USE_APREQ) && !defined(SHARED_CORE_BOOTSTRAP)
+#include "apache_request.h"
+#include "apache_cookie.h"
+ApacheRequest *suck_in_apreq(request_rec *r);
+ApacheRequest *suck_in_apreq(request_rec *r)
+{
+ return ApacheCookie_new(r), ApacheRequest_new(r);
+}
+#endif /* USE_APREQ */
+