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 */
  +
  
  
  

Reply via email to