You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ch...@locus.apache.org on 2000/06/12 23:42:01 UTC

cvs commit: apache-2.0/src/modules/file_cache Makefile.in cache_util.c config.m4 file_cache.c file_garbage.c mod_cache.c mod_cache.h modules.mk

chuck       00/06/12 14:41:59

  Modified:    src/modules/proxy mod_proxy.c mod_proxy.h proxy_connect.c
                        proxy_ftp.c proxy_http.c proxy_util.c
  Added:       src/modules/proxy Makefile.in config.m4
               src/modules/file_cache Makefile.in cache_util.c config.m4
                        file_cache.c file_garbage.c mod_cache.c mod_cache.h
                        modules.mk
  Removed:     src/modules/proxy proxy_cache.c
  Log:
  New mod_proxy/mod_cache (file cache) for 2.0. This uses a caching API so
  that shared mem, LDAP servers, DBs, etc. can also be used for proxy
  caching. The caching API is very young, and subject to change as APR changes.
  
  proxy_cache.c from the proxy subdir is no longer used.
  
  Build with --enable-modules=proxy,cache
  
  Lightly tested on Linux, no warranties expressed or implied yet.
  
  Still to do:
  
  strerror(), waitpid(), stat() cleanups
  address issues marked by @@@FIXME
  add HTTP/1.1
  
  This should be considered a *reference* proxy implementation for 2.0. What
  actually ends up shipping with 2.0 is likely going to be rather different as
  the redesign evolves. This may end up being the 2.0 backwards compatibility
  workalike.
  
  Modified to work with today's conf/build/layout scheme
  
  Submitted by:	Sam Magnuson
  Reviewed by:	Chuck Murcko
  
  Revision  Changes    Path
  1.9       +295 -391  apache-2.0/src/modules/proxy/mod_proxy.c
  
  Index: mod_proxy.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/proxy/mod_proxy.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- mod_proxy.c	2000/05/27 22:40:33	1.8
  +++ mod_proxy.c	2000/06/12 21:41:57	1.9
  @@ -63,6 +63,7 @@
   #include "http_log.h"
   #include "http_vhost.h"
   #include "http_request.h"
  +#include "util_date.h"
   
   /* Some WWW schemes and their default ports; this is basically /etc/services */
   /* This will become global when the protocol abstraction comes */
  @@ -76,7 +77,7 @@
       {"wais", DEFAULT_WAIS_PORT},
       {"snews", DEFAULT_SNEWS_PORT},
       {"prospero", DEFAULT_PROSPERO_PORT},
  -    {NULL, -1}			/* unknown port */
  +    {NULL, -1}  /* unknown port */
   };
   
   /*
  @@ -98,29 +99,29 @@
       const char *aliasp = alias_fakename, *urip = uri;
   
       while (aliasp < end_fakename) {
  -	if (*aliasp == '/') {
  -	    /* any number of '/' in the alias matches any number in
  -	     * the supplied URI, but there must be at least one...
  -	     */
  -	    if (*urip != '/')
  -		return 0;
  -
  -	    while (*aliasp == '/')
  -		++aliasp;
  -	    while (*urip == '/')
  -		++urip;
  -	}
  -	else {
  -	    /* Other characters are compared literally */
  -	    if (*urip++ != *aliasp++)
  -		return 0;
  -	}
  +        if (*aliasp == '/') {
  +        /* any number of '/' in the alias matches any number in
  +         * the supplied URI, but there must be at least one...
  +         */
  +        if (*urip != '/')
  +        return 0;
  +
  +        while (*aliasp == '/')
  +        ++aliasp;
  +        while (*urip == '/')
  +        ++urip;
  +        }
  +        else {
  +        /* Other characters are compared literally */
  +            if (*urip++ != *aliasp++)
  +            return 0;
  +        }
       }
   
       /* Check last alias path component matched all the way */
   
       if (aliasp[-1] != '/' && *urip != '\0' && *urip != '/')
  -	return 0;
  +    return 0;
   
       /* Return number of characters from URI which matched (may be
        * greater than length of alias, since we may have matched
  @@ -149,25 +150,25 @@
       conf = (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
   
       if (conf->req && r->parsed_uri.scheme) {
  -	/* but it might be something vhosted */
  +    /* but it might be something vhosted */
          if (!(r->parsed_uri.hostname
  -	    && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
  -	    && ap_matches_request_vhost(r, r->parsed_uri.hostname,
  -               r->parsed_uri.port_str ? r->parsed_uri.port : ap_default_port(r)))) {
  -	    r->proxyreq = 1;
  -	    r->uri = r->unparsed_uri;
  -	    r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
  -	    r->handler = "proxy-server";
  +        && !strcasecmp(r->parsed_uri.scheme, ap_http_method(r))
  +        && ap_matches_request_vhost(r, r->parsed_uri.hostname,
  +          r->parsed_uri.port_str ? r->parsed_uri.port : ap_default_port(r)))) {
  +        r->proxyreq = 1;
  +        r->uri = r->unparsed_uri;
  +        r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
  +        r->handler = "proxy-server";
           }
       }
       /* We need special treatment for CONNECT proxying: it has no scheme part */
       else if (conf->req && r->method_number == M_CONNECT
  -	     && r->parsed_uri.hostname
  -	     && r->parsed_uri.port_str) {
  -	    r->proxyreq = 1;
  -	    r->uri = r->unparsed_uri;
  -	    r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
  -	    r->handler = "proxy-server";
  +         && r->parsed_uri.hostname
  +         && r->parsed_uri.port_str) {
  +        r->proxyreq = 1;
  +        r->uri = r->unparsed_uri;
  +        r->filename = ap_pstrcat(r->pool, "proxy:", r->uri, NULL);
  +        r->handler = "proxy-server";
       }
       return DECLINED;
   }
  @@ -181,10 +182,10 @@
       struct proxy_alias *ent = (struct proxy_alias *) conf->aliases->elts;
   
       if (r->proxyreq) {
  -	/* someone has already set up the proxy, it was possibly ourselves
  -	 * in proxy_detect
  -	 */
  -	return OK;
  +        /* someone has already set up the proxy, it was possibly ourselves
  +         * in proxy_detect
  +         */
  +        return OK;
       }
   
       /* XXX: since r->uri has been manipulated already we're not really
  @@ -194,14 +195,14 @@
   
       for (i = 0; i < conf->aliases->nelts; i++) {
           len = alias_match(r->uri, ent[i].fake);
  -	    
  -       if (len > 0) {
  +        
  +        if (len > 0) {
              r->filename = ap_pstrcat(r->pool, "proxy:", ent[i].real,
                                    r->uri + len, NULL);
              r->handler = "proxy-server";
              r->proxyreq = 1;
              return OK;
  -	}
  +        }
       }
       return DECLINED;
   }
  @@ -217,36 +218,30 @@
       char *url, *p;
   
       if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
  -	return DECLINED;
  +    return DECLINED;
   
       url = &r->filename[6];
   
   /* canonicalise each specific scheme */
       if (strncasecmp(url, "http:", 5) == 0)
  -	return ap_proxy_http_canon(r, url + 5, "http", DEFAULT_HTTP_PORT);
  +    return ap_proxy_http_canon(r, url + 5, "http", DEFAULT_HTTP_PORT);
       else if (strncasecmp(url, "ftp:", 4) == 0)
  -	return ap_proxy_ftp_canon(r, url + 4);
  +    return ap_proxy_ftp_canon(r, url + 4);
   
       p = strchr(url, ':');
       if (p == NULL || p == url)
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
   
  -    return OK;		/* otherwise; we've done the best we can */
  +    return OK;        /* otherwise; we've done the best we can */
   }
   
  -static void proxy_init(server_rec *r, ap_pool_t *p)
  -{
  -    ap_proxy_garbage_init(r, p);
  -}
  -
  -
  -
  -/* Send a redirection if the request contains a hostname which is not */
  -/* fully qualified, i.e. doesn't have a domain name appended. Some proxy */
  -/* servers like Netscape's allow this and access hosts from the local */
  -/* domain in this case. I think it is better to redirect to a FQDN, since */
  -/* these will later be found in the bookmarks files. */
  -/* The "ProxyDomain" directive determines what domain will be appended */
  +/* Send a redirection if the request contains a hostname which is not
  + * fully qualified, i.e. doesn't have a domain name appended. Some proxy
  + * servers like Netscape's allow this and access hosts from the local
  + * domain in this case. I think it is better to redirect to a FQDN, since
  + * these will later be found in the bookmarks files.
  + * The "ProxyDomain" directive determines what domain will be appended
  + */
   static int proxy_needsdomain(request_rec *r, const char *url, const char *domain)
   {
       char *nuri;
  @@ -254,29 +249,29 @@
   
       /* We only want to worry about GETs */
       if (!r->proxyreq || r->method_number != M_GET || !r->parsed_uri.hostname)
  -	return DECLINED;
  +    return DECLINED;
   
       /* If host does contain a dot already, or it is "localhost", decline */
       if (strchr(r->parsed_uri.hostname, '.') != NULL
        || strcasecmp(r->parsed_uri.hostname, "localhost") == 0)
  -	return DECLINED;	/* host name has a dot already */
  +    return DECLINED;    /* host name has a dot already */
   
       ref = ap_table_get(r->headers_in, "Referer");
   
       /* Reassemble the request, but insert the domain after the host name */
       /* Note that the domain name always starts with a dot */
       r->parsed_uri.hostname = ap_pstrcat(r->pool, r->parsed_uri.hostname,
  -				     domain, NULL);
  +                     domain, NULL);
       nuri = ap_unparse_uri_components(r->pool,
  -				  &r->parsed_uri,
  -				  UNP_REVEALPASSWORD);
  +                  &r->parsed_uri,
  +                  UNP_REVEALPASSWORD);
   
       ap_table_set(r->headers_out, "Location", nuri);
  -    ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r,
  -		"Domain missing: %s sent to %s%s%s", r->uri,
  -		ap_unparse_uri_components(r->pool, &r->parsed_uri,
  -		      UNP_OMITUSERINFO),
  -		ref ? " from " : "", ref ? ref : "");
  +    ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r,
  +        "Domain missing: %s sent to %s%s%s", r->uri,
  +        ap_unparse_uri_components(r->pool, &r->parsed_uri,
  +              UNP_OMITUSERINFO),
  +        ref ? " from " : "", ref ? ref : "");
   
       return HTTP_MOVED_PERMANENTLY;
   }
  @@ -288,51 +283,99 @@
   {
       char *url, *scheme, *p;
       void *sconf = r->server->module_config;
  -    proxy_server_conf *conf =
  -    (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
  +    proxy_server_conf *conf = (proxy_server_conf *)
  +        ap_get_module_config(sconf, &proxy_module);
       ap_array_header_t *proxies = conf->proxies;
       struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
       int i, rc;
  -    cache_req *cr;
  +    ap_cache_el *cr=NULL;
       int direct_connect = 0;
       const char *maxfwd_str;
  -
  +    const char *pragma, *auth, *imstr;
  +    
       if (!r->proxyreq || strncmp(r->filename, "proxy:", 6) != 0)
  -	return DECLINED;
  +        return DECLINED;
   
  -    if (r->method_number == M_TRACE &&
  -	(maxfwd_str = ap_table_get(r->headers_in, "Max-Forwards")) != NULL) {
  -	int maxfwd = strtol(maxfwd_str, NULL, 10);
  -	if (maxfwd < 1) {
  -	    int access_status;
  -	    r->proxyreq = 0;
  -	    if ((access_status = ap_send_http_trace(r)))
  -		ap_die(access_status, r);
  -	    else
  -		ap_finalize_request_protocol(r);
  -	    return OK;
  -	}
  -	ap_table_setn(r->headers_in, "Max-Forwards", 
  -		      ap_psprintf(r->pool, "%d", (maxfwd > 0) ? maxfwd-1 : 0));
  +    if (r->method_number == M_TRACE && (maxfwd_str =
  +      ap_table_get(r->headers_in, "Max-Forwards")) != NULL) {
  +        int maxfwd = strtol(maxfwd_str, NULL, 10);
  +        if (maxfwd < 1) {
  +            int access_status;
  +            r->proxyreq = 0;
  +            if ((access_status = ap_send_http_trace(r)))
  +                ap_die(access_status, r);
  +            else
  +                ap_finalize_request_protocol(r);
  +            return OK;
  +        }
  +        ap_table_setn(r->headers_in, "Max-Forwards", 
  +                      ap_psprintf(r->pool, "%d", (maxfwd > 0) ? maxfwd-1 : 0));
       }
   
       if ((rc = ap_setup_client_block(r, REQUEST_CHUNKED_ERROR)))
  -	return rc;
  +        return rc;
   
       url = r->filename + 6;
       p = strchr(url, ':');
       if (p == NULL)
  -	return HTTP_BAD_REQUEST;
  -
  -    rc = ap_proxy_cache_check(r, url, &conf->cache, &cr);
  -    if (rc != DECLINED)
  -	return rc;
  +        return HTTP_BAD_REQUEST;
   
  +    pragma = ap_table_get(r->headers_in, "Pragma");
  +    auth = ap_table_get(r->headers_in, "Authorization");
  +    imstr = ap_table_get(r->headers_in, "If-Modified-Since");
  +    
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "Request for %s, pragma=%s, auth=%s, imstr=%s", url,
  +                 pragma, auth, imstr);
  +
  +    /* can this request be cached at all? */
  +    if (r->method_number == M_GET && strlen(url) < 1024 &&
  +      !ap_proxy_liststr(pragma, "no-cache") && auth == NULL)
  +    {
  +        if(ap_cache_seek(conf->cache, url, &cr) == APR_SUCCESS)
  +        {
  +            int has_m = 0;
  +            /* now we need to check if the last modified date is write if */
  +        
  +            if(imstr)
  +            {
  +                time_t ims = (time_t)ap_parseHTTPdate(ap_proxy_date_canon(r->pool, imstr));
  +                if(ims == BAD_DATE)
  +                    ap_table_unset(r->headers_in, "If-Modified-Since");
  +                else
  +                {
  +                    /* ok we were asked to check, so let's do that */
  +                    if(ap_cache_el_header(cr, "Last-Modified",
  +                      (char **)&imstr) == APR_SUCCESS)
  +                    {
  +                        time_t lm =
  +                          ap_parseHTTPdate(ap_proxy_date_canon(r->pool, imstr));
  +                        if(lm != BAD_DATE)
  +                        {
  +                            if(ims < lm)
  +                                ap_table_set(r->headers_in,
  +                                  "If-Modified-Since", imstr);
  +                            else
  +                            {
  +                            
  +                                has_m = 1;
  +                            }
  +                        }
  +                    }
  +                }
  +            }
  +            return has_m ? HTTP_NOT_MODIFIED : ap_proxy_cache_send(r, cr);
  +        }
  +        /* if there wasn't an entry in the cache we get here,
  +           we need to create one */
  +        ap_cache_create(conf->cache, url, &cr);
  +    }
  +    
       /* If the host doesn't have a domain name, add one and redirect. */
       if (conf->domain != NULL) {
  -	rc = proxy_needsdomain(r, url, conf->domain);
  -	if (ap_is_HTTP_REDIRECT(rc))
  -	    return HTTP_MOVED_PERMANENTLY;
  +        rc = proxy_needsdomain(r, url, conf->domain);
  +        if (ap_is_HTTP_REDIRECT(rc))
  +            return HTTP_MOVED_PERMANENTLY;
       }
   
       *p = '\0';
  @@ -344,47 +387,47 @@
       /* we only know how to handle communication to a proxy via http */
       /*if (strcasecmp(scheme, "http") == 0) */
       {
  -	int ii;
  -	struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
  +        int ii;
  +        struct dirconn_entry *list = (struct dirconn_entry *) conf->dirconn->elts;
   
  -	for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {
  -	    direct_connect = list[ii].matcher(&list[ii], r);
  -	}
  +        for (direct_connect = ii = 0; ii < conf->dirconn->nelts && !direct_connect; ii++) {
  +            direct_connect = list[ii].matcher(&list[ii], r);
  +        }
   #if DEBUGGING
  -	ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, r,
  -		     (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
  -		     r->uri);
  +        ap_log_rerror(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r,
  +                      (direct_connect) ? "NoProxy for %s" : "UseProxy for %s",
  +                      r->uri);
   #endif
       }
   
   /* firstly, try a proxy, unless a NoProxy directive is active */
   
       if (!direct_connect)
  -	for (i = 0; i < proxies->nelts; i++) {
  -	    p = strchr(ents[i].scheme, ':');	/* is it a partial URL? */
  -	    if (strcmp(ents[i].scheme, "*") == 0 ||
  -		(p == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
  -		(p != NULL &&
  -	       strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {
  -		/* CONNECT is a special method that bypasses the normal
  -		 * proxy code.
  -		 */
  -		if (r->method_number == M_CONNECT)
  -		    rc = ap_proxy_connect_handler(r, cr, url, ents[i].hostname,
  -					       ents[i].port);
  +        for (i = 0; i < proxies->nelts; i++) {
  +            p = strchr(ents[i].scheme, ':');    /* is it a partial URL? */
  +            if (strcmp(ents[i].scheme, "*") == 0 ||
  +                (p == NULL && strcasecmp(scheme, ents[i].scheme) == 0) ||
  +                (p != NULL &&
  +                 strncasecmp(url, ents[i].scheme, strlen(ents[i].scheme)) == 0)) {
  +                /* CONNECT is a special method that bypasses the normal
  +                 * proxy code.
  +                 */
  +                if (r->method_number == M_CONNECT)
  +                    rc = ap_proxy_connect_handler(r, cr, url, ents[i].hostname,
  +                                                  ents[i].port);
   /* we only know how to handle communication to a proxy via http */
  -		else if (strcasecmp(ents[i].protocol, "http") == 0)
  -		    rc = ap_proxy_http_handler(r, cr, url, ents[i].hostname,
  -					    ents[i].port);
  -		else
  -		    rc = DECLINED;
  -
  -		/* an error or success */
  -		if (rc != DECLINED && rc != HTTP_BAD_GATEWAY)
  -		    return rc;
  -		/* we failed to talk to the upstream proxy */
  -	    }
  -	}
  +                else if (strcasecmp(ents[i].protocol, "http") == 0)
  +                    rc = ap_proxy_http_handler(r, cr, url, ents[i].hostname,
  +                                               ents[i].port);
  +                else
  +                    rc = DECLINED;
  +
  +                /* an error or success */
  +                if (rc != DECLINED && rc != HTTP_BAD_GATEWAY)
  +                    return rc;
  +                /* we failed to talk to the upstream proxy */
  +            }
  +        }
   
   /* otherwise, try it direct */
   /* N.B. what if we're behind a firewall, where we must use a proxy or
  @@ -392,20 +435,19 @@
    */
       /* handle the scheme */
       if (r->method_number == M_CONNECT)
  -	return ap_proxy_connect_handler(r, cr, url, NULL, 0);
  +        return ap_proxy_connect_handler(r, cr, url, NULL, 0);
       if (strcasecmp(scheme, "http") == 0)
  -	return ap_proxy_http_handler(r, cr, url, NULL, 0);
  +        return ap_proxy_http_handler(r, cr, url, NULL, 0);
       if (strcasecmp(scheme, "ftp") == 0)
  -	return ap_proxy_ftp_handler(r, cr, url);
  +        return ap_proxy_ftp_handler(r, cr, url);
       else
  -	return HTTP_FORBIDDEN;
  +        return HTTP_FORBIDDEN;
   }
   
   /* -------------------------------------------------------------- */
   /* Setup configurable data */
   
  -static void *
  -     create_proxy_config(ap_pool_t *p, server_rec *s)
  +static void *create_proxy_config(ap_pool_t *p, server_rec *s)
   {
       proxy_server_conf *ps = ap_pcalloc(p, sizeof(proxy_server_conf));
   
  @@ -416,21 +458,12 @@
       ps->dirconn = ap_make_array(p, 10, sizeof(struct dirconn_entry));
       ps->nocaches = ap_make_array(p, 10, sizeof(struct nocache_entry));
       ps->allowed_connect_ports = ap_make_array(p, 10, sizeof(int));
  +    ps->cache_completion = DEFAULT_CACHE_COMPLETION;
       ps->domain = NULL;
       ps->viaopt = via_off; /* initially backward compatible with 1.3.1 */
       ps->req = 0;
   
  -    ps->cache.root = NULL;
  -    ps->cache.space = DEFAULT_CACHE_SPACE;
  -    ps->cache.maxexpire = DEFAULT_CACHE_MAXEXPIRE;
  -    ps->cache.defaultexpire = DEFAULT_CACHE_EXPIRE;
  -    ps->cache.lmfactor = DEFAULT_CACHE_LMFACTOR;
  -    ps->cache.gcinterval = -1;
  -    /* at these levels, the cache can have 2^18 directories (256,000)  */
  -    ps->cache.dirlevels = 3;
  -    ps->cache.dirlength = 1;
  -    ps->cache.cache_completion = DEFAULT_CACHE_COMPLETION;
  -
  +    ap_cache_init(&ps->cache, "mod_proxy cache", s);
       return ps;
   }
   
  @@ -446,26 +479,26 @@
   
       p = strchr(r, ':');
       if (p == NULL || p[1] != '/' || p[2] != '/' || p[3] == '\0')
  -	return "ProxyRemote: Bad syntax for a remote proxy server";
  +    return "ProxyRemote: Bad syntax for a remote proxy server";
       q = strchr(p + 3, ':');
       if (q != NULL) {
  -	if (sscanf(q + 1, "%u", &port) != 1 || port > 65535)
  -	    return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)";
  -	*q = '\0';
  +    if (sscanf(q + 1, "%u", &port) != 1 || port > 65535)
  +        return "ProxyRemote: Bad syntax for a remote proxy server (bad port number)";
  +    *q = '\0';
       }
       else
  -	port = -1;
  +    port = -1;
       *p = '\0';
       if (strchr(f, ':') == NULL)
  -	ap_str_tolower(f);		/* lowercase scheme */
  -    ap_str_tolower(p + 3);		/* lowercase hostname */
  +    ap_str_tolower(f);            /* lowercase scheme */
  +    ap_str_tolower(p + 3);        /* lowercase hostname */
   
       if (port == -1) {
  -	int i;
  -	for (i = 0; defports[i].scheme != NULL; i++)
  -	    if (strcasecmp(defports[i].scheme, r) == 0)
  -		break;
  -	port = defports[i].port;
  +    int i;
  +    for (i = 0; defports[i].scheme != NULL; i++)
  +        if (strcasecmp(defports[i].scheme, r) == 0)
  +        break;
  +    port = defports[i].port;
       }
   
       new = ap_push_array(conf->proxies);
  @@ -477,6 +510,36 @@
   }
   
   static const char *
  +     set_cache_exclude(cmd_parms *cmd, void *dummy, char *arg)
  +{
  +    server_rec *s = cmd->server;
  +    proxy_server_conf *psf = (proxy_server_conf *) ap_get_module_config(s->module_config, &proxy_module);
  +    struct nocache_entry *new;
  +    struct nocache_entry *list = (struct nocache_entry *) psf->nocaches->elts;
  +    struct hostent hp;
  +    int found = 0;
  +    int i;
  +
  +    /* Don't duplicate entries */
  +    for (i = 0; i < psf->nocaches->nelts; i++) {
  +    if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
  +        found = 1;
  +    }
  +
  +    if (!found) {
  +        new = ap_push_array(psf->nocaches);
  +        new->name = arg;
  +        /* Don't do name lookups on things that aren't dotted */
  +        if (strchr(arg, '.') != NULL && ap_proxy_host2addr(new->name, &hp) == NULL)
  +            /*@@@FIXME: This copies only the first of (possibly many) IP addrs */
  +            memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
  +        else
  +            new->addr.s_addr = 0;
  +    }
  +    return NULL;
  +}
  +
  +static const char *
        add_pass(cmd_parms *cmd, void *dummy, char *f, char *r)
   {
       server_rec *s = cmd->server;
  @@ -505,8 +568,7 @@
       return NULL;
   }
   
  -static const char *
  -     set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
  +static const char *set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
   {
       server_rec *s = parms->server;
       proxy_server_conf *conf =
  @@ -519,19 +581,19 @@
   
       /* Don't duplicate entries */
       for (i = 0; i < conf->noproxies->nelts; i++) {
  -	if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
  -	    found = 1;
  +    if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
  +        found = 1;
       }
   
       if (!found) {
  -	new = ap_push_array(conf->noproxies);
  -	new->name = arg;
  -	/* Don't do name lookups on things that aren't dotted */
  -	if (strchr(arg, '.') != NULL && ap_proxy_host2addr(new->name, &hp) == NULL)
  -	    /*@@@FIXME: This copies only the first of (possibly many) IP addrs */
  -	    memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
  -	else
  -	    new->addr.s_addr = 0;
  +    new = ap_push_array(conf->noproxies);
  +    new->name = arg;
  +    /* Don't do name lookups on things that aren't dotted */
  +    if (strchr(arg, '.') != NULL && ap_proxy_host2addr(new->name, &hp) == NULL)
  +        /*@@@FIXME: This copies only the first of (possibly many) IP addrs */
  +        memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
  +    else
  +        new->addr.s_addr = 0;
       }
       return NULL;
   }
  @@ -548,7 +610,7 @@
       int *New;
   
       if (!ap_isdigit(arg[0]))
  -	return "AllowCONNECT: port number must be numeric";
  +    return "AllowCONNECT: port number must be numeric";
   
       New = ap_push_array(conf->allowed_connect_ports);
       *New = atoi(arg);
  @@ -571,45 +633,45 @@
   
       /* Don't duplicate entries */
       for (i = 0; i < conf->dirconn->nelts; i++) {
  -	if (strcasecmp(arg, list[i].name) == 0)
  -	    found = 1;
  +    if (strcasecmp(arg, list[i].name) == 0)
  +        found = 1;
       }
   
       if (!found) {
  -	New = ap_push_array(conf->dirconn);
  -	New->name = arg;
  -	New->hostentry = NULL;
  +    New = ap_push_array(conf->dirconn);
  +    New->name = arg;
  +    New->hostentry = NULL;
   
  -	if (ap_proxy_is_ipaddr(New, parms->pool)) {
  +    if (ap_proxy_is_ipaddr(New, parms->pool)) {
   #if DEBUGGING
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL, 
                            "Parsed addr %s", inet_ntoa(New->addr));
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL, 
                            "Parsed mask %s", inet_ntoa(New->mask));
   #endif
  -	}
  -	else if (ap_proxy_is_domainname(New, parms->pool)) {
  -	    ap_str_tolower(New->name);
  +    }
  +    else if (ap_proxy_is_domainname(New, parms->pool)) {
  +        ap_str_tolower(New->name);
   #if DEBUGGING
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL, 
                            "Parsed domain %s", New->name);
   #endif
  -	}
  -	else if (ap_proxy_is_hostname(New, parms->pool)) {
  -	    ap_str_tolower(New->name);
  +    }
  +    else if (ap_proxy_is_hostname(New, parms->pool)) {
  +        ap_str_tolower(New->name);
   #if DEBUGGING
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL, 
                            "Parsed host %s", New->name);
   #endif
  -	}
  -	else {
  -	    ap_proxy_is_word(New, parms->pool);
  +    }
  +    else {
  +        ap_proxy_is_word(New, parms->pool);
   #if DEBUGGING
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 0, NULL, 
                            "Parsed word %s", New->name);
   #endif
  -	}
       }
  +    }
       return NULL;
   }
   
  @@ -620,7 +682,7 @@
       ap_get_module_config(parms->server->module_config, &proxy_module);
   
       if (arg[0] != '.')
  -	return "ProxyDomain: domain name must start with a dot.";
  +    return "ProxyDomain: domain name must start with a dot.";
   
       psf->domain = arg;
       return NULL;
  @@ -638,153 +700,13 @@
   
   
   static const char *
  -     set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    int val;
  -
  -    if (sscanf(arg, "%d", &val) != 1)
  -	return "CacheSize value must be an integer (kBytes)";
  -    psf->cache.space = val;
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_root(cmd_parms *parms, void *dummy, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -
  -    psf->cache.root = arg;
  -
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_factor(cmd_parms *parms, void *dummy, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    double val;
  -
  -    if (sscanf(arg, "%lg", &val) != 1)
  -	return "CacheLastModifiedFactor value must be a float";
  -    psf->cache.lmfactor = val;
  -
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_maxex(cmd_parms *parms, void *dummy, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    double val;
  -
  -    if (sscanf(arg, "%lg", &val) != 1)
  -	return "CacheMaxExpire value must be a float";
  -    psf->cache.maxexpire = (int) (val * (double) SEC_ONE_HR);
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_defex(cmd_parms *parms, void *dummy, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    double val;
  -
  -    if (sscanf(arg, "%lg", &val) != 1)
  -	return "CacheDefaultExpire value must be a float";
  -    psf->cache.defaultexpire = (int) (val * (double) SEC_ONE_HR);
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_gcint(cmd_parms *parms, void *dummy, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    double val;
  -
  -    if (sscanf(arg, "%lg", &val) != 1)
  -	return "CacheGcInterval value must be a float";
  -    psf->cache.gcinterval = (int) (val * (double) SEC_ONE_HR);
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_dirlevels(cmd_parms *parms, char *struct_ptr, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    int val;
  -
  -    val = atoi(arg);
  -    if (val < 1)
  -	return "CacheDirLevels value must be an integer greater than 0";
  -    if (val * psf->cache.dirlength > CACHEFILE_LEN)
  -	return "CacheDirLevels*CacheDirLength value must not be higher than 20";
  -    psf->cache.dirlevels = val;
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_dirlength(cmd_parms *parms, char *struct_ptr, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    int val;
  -
  -    val = atoi(arg);
  -    if (val < 1)
  -	return "CacheDirLength value must be an integer greater than 0";
  -    if (val * psf->cache.dirlevels > CACHEFILE_LEN)
  -	return "CacheDirLevels*CacheDirLength value must not be higher than 20";
  -    psf->cache.dirlength = val;
  -    return NULL;
  -}
  -
  -static const char *
  -     set_cache_exclude(cmd_parms *parms, void *dummy, char *arg)
  -{
  -    server_rec *s = parms->server;
  -    proxy_server_conf *conf =
  -    ap_get_module_config(s->module_config, &proxy_module);
  -    struct nocache_entry *new;
  -    struct nocache_entry *list = (struct nocache_entry *) conf->nocaches->elts;
  -    struct hostent hp;
  -    int found = 0;
  -    int i;
  -
  -    /* Don't duplicate entries */
  -    for (i = 0; i < conf->nocaches->nelts; i++) {
  -	if (strcasecmp(arg, list[i].name) == 0) /* ignore case for host names */
  -	    found = 1;
  -    }
  -
  -    if (!found) {
  -	new = ap_push_array(conf->nocaches);
  -	new->name = arg;
  -	/* Don't do name lookups on things that aren't dotted */
  -	if (strchr(arg, '.') != NULL && ap_proxy_host2addr(new->name, &hp) == NULL)
  -	    /*@@@FIXME: This copies only the first of (possibly many) IP addrs */
  -	    memcpy(&new->addr, hp.h_addr, sizeof(struct in_addr));
  -	else
  -	    new->addr.s_addr = 0;
  -    }
  -    return NULL;
  -}
  -
  -static const char *
        set_recv_buffer_size(cmd_parms *parms, void *dummy, char *arg)
   {
       proxy_server_conf *psf =
       ap_get_module_config(parms->server->module_config, &proxy_module);
       int s = atoi(arg);
       if (s < 512 && s != 0) {
  -	return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
  +    return "ProxyReceiveBufferSize must be >= 512 bytes, or 0 for system default.";
       }
   
       psf->recv_buffer_size = s;
  @@ -792,26 +714,9 @@
   }
   
   static const char*
  -    set_cache_completion(cmd_parms *parms, void *dummy, char *arg)
  -{
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  -    int s = atoi(arg);
  -    if (s > 100 || s < 0) {
  -	return "CacheForceCompletion must be <= 100 percent, "
  -               "or 0 for system default.";
  -    }
  -
  -    if (s > 0)
  -      psf->cache.cache_completion = ((float)s / 100);
  -    return NULL;    
  -}
  -
  -static const char*
       set_via_opt(cmd_parms *parms, void *dummy, char *arg)
   {
  -    proxy_server_conf *psf =
  -    ap_get_module_config(parms->server->module_config, &proxy_module);
  +    proxy_server_conf *psf = ap_get_module_config(parms->server->module_config, &proxy_module);
   
       if (strcasecmp(arg, "Off") == 0)
           psf->viaopt = via_off;
  @@ -822,13 +727,28 @@
       else if (strcasecmp(arg, "Full") == 0)
           psf->viaopt = via_full;
       else {
  -	return "ProxyVia must be one of: "
  +    return "ProxyVia must be one of: "
                  "off | on | full | block";
       }
   
       return NULL;    
   }
   
  +static const char*
  +    set_cache_completion(cmd_parms *parms, void *dummy, char *arg)
  +{
  +    proxy_server_conf *psf = ap_get_module_config(parms->server->module_config, &proxy_module);
  +    int s = atoi(arg);
  +    if (s > 100 || s < 0) {
  +        return "CacheForceCompletion must be <= 100 percent, "
  +               "or 0 for system default.";
  +    }
  +
  +    if (s > 0)
  +      psf->cache_completion = ((float)s / 100);
  +    return NULL;    
  +}
  +
   static const handler_rec proxy_handlers[] =
   {
       {"proxy-server", proxy_handler},
  @@ -855,50 +775,34 @@
        "The default intranet domain name (in absence of a domain in the URL)"},
       {"AllowCONNECT", set_allowed_ports, NULL, RSRC_CONF, ITERATE,
        "A list of ports which CONNECT may connect to"},
  -    {"CacheRoot", set_cache_root, NULL, RSRC_CONF, TAKE1,
  -     "The directory to store cache files"},
  -    {"CacheSize", set_cache_size, NULL, RSRC_CONF, TAKE1,
  -     "The maximum disk space used by the cache in Kb"},
  -    {"CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF, TAKE1,
  -     "The maximum time in hours to cache a document"},
  -    {"CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF, TAKE1,
  -     "The default time in hours to cache a document"},
  -    {"CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF, TAKE1,
  -     "The factor used to estimate Expires date from LastModified date"},
  -    {"CacheGcInterval", set_cache_gcint, NULL, RSRC_CONF, TAKE1,
  -     "The interval between garbage collections, in hours"},
  -    {"CacheDirLevels", set_cache_dirlevels, NULL, RSRC_CONF, TAKE1,
  -     "The number of levels of subdirectories in the cache"},
  -    {"CacheDirLength", set_cache_dirlength, NULL, RSRC_CONF, TAKE1,
  -     "The number of characters in subdirectory names"},
  -    {"NoCache", set_cache_exclude, NULL, RSRC_CONF, ITERATE,
  -     "A list of names, hosts or domains for which caching is *not* provided"},
  -    {"CacheForceCompletion", set_cache_completion, NULL, RSRC_CONF, TAKE1,
  -     "Force a http cache completion after this percentage is loaded"},
       {"ProxyVia", set_via_opt, NULL, RSRC_CONF, TAKE1,
        "Configure Via: proxy header header to one of: on | off | block | full"},
  +    {"ProxyNoCache", set_cache_exclude, NULL, RSRC_CONF, ITERATE,
  +     "A list of names, hosts or domains for which caching is *not* provided"},
  +    {"ProxyForceCacheCompletion", set_cache_completion, NULL, RSRC_CONF, TAKE1,
  +     "Force a http cache completion after this percentage is loaded"},
  +
       {NULL}
   };
   
  +static void register_hooks(void)
  +{
  +    /* [2] filename-to-URI translation */
  +    ap_hook_translate_name(proxy_trans, NULL, NULL, AP_HOOK_FIRST);
  +    /* [8] fixups */
  +    ap_hook_fixups(proxy_fixup, NULL, NULL, AP_HOOK_FIRST);   
  +    /* [1] post read_request handling */
  +    ap_hook_post_read_request(proxy_detect, NULL, NULL, AP_HOOK_FIRST);
  +}
  +
   module MODULE_VAR_EXPORT proxy_module =
   {
  -    STANDARD_MODULE_STUFF,
  -    proxy_init,			/* initializer */
  -    NULL,			/* create per-directory config structure */
  -    NULL,			/* merge per-directory config structures */
  -    create_proxy_config,	/* create per-server config structure */
  -    NULL,			/* merge per-server config structures */
  -    proxy_cmds,			/* command ap_table_t */
  -    proxy_handlers,		/* handlers */
  -    proxy_trans,		/* translate_handler */
  -    NULL,			/* check_user_id */
  -    NULL,			/* check auth */
  -    NULL,			/* check access */
  -    NULL,			/* type_checker */
  -    proxy_fixup,		/* pre-run fixups */
  -    NULL,			/* logger */
  -    NULL,			/* header parser */
  -    NULL,			/* child_init */
  -    NULL,			/* child_exit */
  -    proxy_detect		/* post read-request */
  +    STANDARD20_MODULE_STUFF,
  +    NULL,                  /* create per-directory config structure */
  +    NULL,                  /* merge per-directory config structures */
  +    create_proxy_config,   /* create per-server config structure */
  +    NULL,                  /* merge per-server config structures */
  +    proxy_cmds,            /* command ap_table_t */
  +    proxy_handlers,        /* handlers */
  +    register_hooks
   };
  
  
  
  1.9       +49 -105   apache-2.0/src/modules/proxy/mod_proxy.h
  
  Index: mod_proxy.h
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/proxy/mod_proxy.h,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- mod_proxy.h	2000/05/27 22:40:33	1.8
  +++ mod_proxy.h	2000/06/12 21:41:58	1.9
  @@ -75,13 +75,13 @@
   
      Things to do:
   
  -   1. Make it garbage collect in the background, not while someone is waiting for
  -   a response!
  +   1. Make it garbage collect in the background, not while someone is
  +      waiting for a response!
   
      2. Check the logic thoroughly.
   
  -   3. Empty directories are only removed the next time round (but this does avoid
  -   two passes). Consider doing them the first time round.
  +   3. Empty directories are only removed the next time round (but this does
  +      avoid two passes). Consider doing them the first time round.
   
      Ben Laurie <be...@algroup.co.uk> 30 Mar 96
   
  @@ -103,12 +103,13 @@
   
    */
   
  -#define TESTING	0
  +#define TESTING    0
   #undef EXPLAIN
   
   #include "httpd.h"
   #include "http_config.h"
   #include "http_protocol.h"
  +#include "ap_cache.h"
   
   #include "explain.h"
   
  @@ -120,27 +121,25 @@
       enc_path, enc_search, enc_user, enc_fpath, enc_parm
   };
   
  -#define HDR_APP (0)		/* append header, for proxy_add_header() */
  -#define HDR_REP (1)		/* replace header, for proxy_add_header() */
  +#define HDR_APP (0)        /* append header, for proxy_add_header() */
  +#define HDR_REP (1)        /* replace header, for proxy_add_header() */
   
  -/* number of characters in the hash */
  -#define HASH_LEN (22*2)
  +#ifdef CHARSET_EBCDIC
  +#define CRLF   "\r\n"
  +#else /*CHARSET_EBCDIC*/
  +#define CRLF   "\015\012"
  +#endif /*CHARSET_EBCDIC*/
  +
  +#define    DEFAULT_FTP_DATA_PORT    20
  +#define    DEFAULT_FTP_PORT         21
  +#define    DEFAULT_GOPHER_PORT      70
  +#define    DEFAULT_NNTP_PORT       119
  +#define    DEFAULT_WAIS_PORT       210
  +#define    DEFAULT_HTTPS_PORT      443
  +#define    DEFAULT_SNEWS_PORT      563
  +#define    DEFAULT_PROSPERO_PORT  1525    /* WARNING: conflict w/Oracle */
   
  -/* maximum  'CacheDirLevels*CacheDirLength' value */
  -#define CACHEFILE_LEN 20	/* must be less than HASH_LEN/2 */
  -
  -#define	SEC_ONE_DAY		86400	/* one day, in seconds */
  -#define	SEC_ONE_HR		3600	/* one hour, in seconds */
  -
  -#define	DEFAULT_FTP_DATA_PORT	20
  -#define	DEFAULT_FTP_PORT	21
  -#define	DEFAULT_GOPHER_PORT	70
  -#define	DEFAULT_NNTP_PORT	119
  -#define	DEFAULT_WAIS_PORT	210
  -#define	DEFAULT_HTTPS_PORT	443
  -#define	DEFAULT_SNEWS_PORT	563
  -#define	DEFAULT_PROSPERO_PORT	1525	/* WARNING: conflict w/Oracle */
  -
  +#define DEFAULT_CACHE_COMPLETION (0.9)
   /* Some WWW schemes and their default ports; this is basically /etc/services */
   struct proxy_services {
       const char *scheme;
  @@ -149,10 +148,10 @@
   
   /* static information about a remote proxy */
   struct proxy_remote {
  -    const char *scheme;		/* the schemes handled by this proxy, or '*' */
  -    const char *protocol;	/* the scheme used to talk to this proxy */
  -    const char *hostname;	/* the hostname of this proxy */
  -    int port;			/* the port for this proxy */
  +    const char *scheme;        /* the schemes handled by this proxy, or '*' */
  +    const char *protocol;      /* the scheme used to talk to this proxy */
  +    const char *hostname;      /* the hostname of this proxy */
  +    int port;                  /* the port for this proxy */
   };
   
   struct proxy_alias {
  @@ -177,27 +176,7 @@
       struct in_addr addr;
   };
   
  -#define DEFAULT_CACHE_SPACE 5
  -#define DEFAULT_CACHE_MAXEXPIRE SEC_ONE_DAY
  -#define DEFAULT_CACHE_EXPIRE    SEC_ONE_HR
  -#define DEFAULT_CACHE_LMFACTOR (0.1)
  -#define DEFAULT_CACHE_COMPLETION (0.9)
  -
  -/* static information about the local cache */
  -struct cache_conf {
  -    const char *root;		/* the location of the cache directory */
  -    off_t space;			/* Maximum cache size (in 1024 bytes) */
  -    time_t maxexpire;		/* Maximum time to keep cached files in secs */
  -    time_t defaultexpire;	/* default time to keep cached file in secs */
  -    double lmfactor;		/* factor for estimating expires date */
  -    time_t gcinterval;		/* garbage collection interval, in seconds */
  -    int dirlevels;		/* Number of levels of subdirectories */
  -    int dirlength;		/* Length of subdirectory names */
  -    float cache_completion;	/* Force cache completion after this point */
  -};
  -
   typedef struct {
  -    struct cache_conf cache;	/* cache configuration */
       ap_array_header_t *proxies;
       ap_array_header_t *aliases;
       ap_array_header_t *raliases;
  @@ -205,8 +184,10 @@
       ap_array_header_t *dirconn;
       ap_array_header_t *nocaches;
       ap_array_header_t *allowed_connect_ports;
  -    char *domain;		/* domain name to use in absence of a domain name in the request */
  -    int req;			/* true if proxy requests are enabled */
  +    char *domain;       /* domain name to use in absence of
  +                           a domain name in the request */
  +    int req;            /* true if proxy requests are enabled */
  +    float cache_completion;     /* Force cache completion after this point */
       enum {
         via_off,
         via_on,
  @@ -214,97 +195,60 @@
         via_full
       } viaopt;                   /* how to deal with proxy Via: headers */
       size_t recv_buffer_size;
  +    ap_cache_handle_t *cache;
   } proxy_server_conf;
   
  -struct hdr_entry {
  -    const char *field;
  -    const char *value;
  -};
  -
  -/* caching information about a request */
   typedef struct {
  -    request_rec *req;		/* the request */
  -    char *url;			/* the URL requested */
  -    char *filename;		/* name of the cache file, or NULL if no cache */
  -    char *tempfile;		/* name of the temporary file, of NULL if not caching */
  -    time_t ims;			/* if-modified-since date of request; -1 if no header */
  -    BUFF *fp;			/* the cache file descriptor if the file is cached
  -				   and may be returned, or NULL if the file is
  -				   not cached (or must be reloaded) */
  -    time_t expire;		/* calculated expire date of cached entity */
  -    time_t lmod;		/* last-modified date of cached entity */
  -    time_t date;		/* the date the cached file was last touched */
  -    int version;		/* update count of the file */
  -    off_t len;			/* content length */
  -    char *protocol;		/* Protocol, and major/minor number, e.g. HTTP/1.1 */
  -    int status;			/* the status of the cached file */
  -    unsigned int written;	/* total *content* bytes written to cache */
  -    float cache_completion;	/* specific to this request */
  -    char *resp_line;		/* the whole status like (protocol, code + message) */
  -    ap_table_t *hdrs;		/* the HTTP headers of the file */
  -} cache_req;
  -
  -/* Additional information passed to the function called by ap_table_do() */
  -struct tbl_do_args {
  -    request_rec *req;
  -    cache_req *cache;
  -};
  +    float cache_completion; /* completion percentage */
  +    int content_length; /* length of the content */
  +} proxy_completion;
   
   /* Function prototypes */
   
  -/* proxy_cache.c */
  -
  -void ap_proxy_cache_tidy(cache_req *c);
  -int ap_proxy_cache_check(request_rec *r, char *url, struct cache_conf *conf,
  -		      cache_req **cr);
  -int ap_proxy_cache_update(cache_req *c, ap_table_t *resp_hdrs,
  -		       const int is_HTTP1, int nocache);
  -void ap_proxy_garbage_coll(request_rec *r);
  -
   /* proxy_connect.c */
   
  -int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
  -			  const char *proxyhost, int proxyport);
  +int ap_proxy_connect_handler(request_rec *r, ap_cache_el *c, char *url,
  +              const char *proxyhost, int proxyport);
   
   /* proxy_ftp.c */
   
   int ap_proxy_ftp_canon(request_rec *r, char *url);
  -int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url);
  +int ap_proxy_ftp_handler(request_rec *r, ap_cache_el *c, char *url);
   
   /* proxy_http.c */
   
   int ap_proxy_http_canon(request_rec *r, char *url, const char *scheme,
  -		     int def_port);
  -int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
  -		       const char *proxyhost, int proxyport);
  +             int def_port);
  +int ap_proxy_http_handler(request_rec *r, ap_cache_el  *c, char *url,
  +               const char *proxyhost, int proxyport);
   
   /* proxy_util.c */
   
   int ap_proxy_hex2c(const char *x);
   void ap_proxy_c2hex(int ch, char *x);
   char *ap_proxy_canonenc(ap_pool_t *p, const char *x, int len, enum enctype t,
  -		     int isenc);
  +             int isenc);
   char *ap_proxy_canon_netloc(ap_pool_t *p, char **const urlp, char **userp,
  -			 char **passwordp, char **hostp, int *port);
  +             char **passwordp, char **hostp, int *port);
   const char *ap_proxy_date_canon(ap_pool_t *p, const char *x);
  -table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
  -long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c);
  +ap_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f);
  +long int ap_proxy_send_fb(proxy_completion *, BUFF *f, request_rec *r, ap_cache_el  *c);
   void ap_proxy_send_headers(request_rec *r, const char *respline, ap_table_t *hdrs);
   int ap_proxy_liststr(const char *list, const char *val);
   void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength);
   int ap_proxy_hex2sec(const char *x);
   void ap_proxy_sec2hex(int t, char *y);
  -cache_req *ap_proxy_cache_error(cache_req *r);
  -int ap_proxyerror(request_rec *r, int statuscode, const char *message);
   const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp);
  +void ap_proxy_cache_error(ap_cache_el  **r);
  +int ap_proxyerror(request_rec *r, int statuscode, const char *message);
   int ap_proxy_is_ipaddr(struct dirconn_entry *This, ap_pool_t *p);
   int ap_proxy_is_domainname(struct dirconn_entry *This, ap_pool_t *p);
   int ap_proxy_is_hostname(struct dirconn_entry *This, ap_pool_t *p);
   int ap_proxy_is_word(struct dirconn_entry *This, ap_pool_t *p);
  -int ap_proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r);
  +int ap_proxy_doconnect(ap_socket_t *sock, char *host, ap_uint32_t port, request_rec *r);
   int ap_proxy_garbage_init(server_rec *, ap_pool_t *);
   /* This function is called by ap_table_do() for all header lines */
   int ap_proxy_send_hdr_line(void *p, const char *key, const char *value);
  -unsigned ap_proxy_bputs2(const char *data, BUFF *client, cache_req *cache);
  +unsigned ap_proxy_bputs2(const char *data, BUFF *client, ap_cache_el  *cache);
   
   #endif /*MOD_PROXY_H*/
  
  
  
  1.5       +142 -135  apache-2.0/src/modules/proxy/proxy_connect.c
  
  Index: proxy_connect.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/proxy/proxy_connect.c,v
  retrieving revision 1.4
  retrieving revision 1.5
  diff -u -r1.4 -r1.5
  --- proxy_connect.c	2000/06/09 18:57:13	1.4
  +++ proxy_connect.c	2000/06/12 21:41:58	1.5
  @@ -61,13 +61,12 @@
   #include "mod_proxy.h"
   #include "http_log.h"
   #include "http_main.h"
  +#include "iol_socket.h"
   
   #ifdef HAVE_BSTRING_H
  -#include <bstring.h>		/* for IRIX, FD_SET calls bzero() */
  +#include <bstring.h>        /* for IRIX, FD_SET calls bzero() */
   #endif
   
  -DEF_Explain
  -
   /*  
    * This handles Netscape CONNECT method secure proxy requests.
    * A connection is opened to the specified host and data is
  @@ -105,187 +104,195 @@
       int *list = (int *) conf->allowed_connect_ports->elts;
   
       for(i = 0; i < conf->allowed_connect_ports->nelts; i++) {
  -	if(port == list[i])
  -	    return 1;
  +    if(port == list[i])
  +        return 1;
       }
       return 0;
   }
   
   
  -int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
  -			  const char *proxyhost, int proxyport)
  +int ap_proxy_connect_handler(request_rec *r, ap_cache_el  *c, char *url,
  +              const char *proxyhost, int proxyport)
   {
  -    struct sockaddr_in server;
       struct in_addr destaddr;
  -    struct hostent server_hp;
       const char *host, *err;
       char *p;
  -    int port, sock;
  +    int port;
  +    ap_socket_t *sock;
       char buffer[HUGE_STRING_LEN];
       int nbytes, i, j;
  -    fd_set fds;
   
  +    BUFF *sock_buff;
  +    ap_socket_t *client_sock;
  +    ap_pollfd_t *pollfd;
  +    ap_int32_t pollcnt;
  +    ap_int16_t pollevent;
  +    
       void *sconf = r->server->module_config;
       proxy_server_conf *conf =
       (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
       struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
   
  -    memset(&server, '\0', sizeof(server));
  -    server.sin_family = AF_INET;
  -
       /* Break the URL into host:port pairs */
  -
       host = url;
       p = strchr(url, ':');
       if (p == NULL)
  -	port = DEFAULT_HTTPS_PORT;
  +    port = DEFAULT_HTTPS_PORT;
       else {
  -	port = atoi(p + 1);
  -	*p = '\0';
  +    port = atoi(p + 1);
  +    *p = '\0';
       }
   
   /* check if ProxyBlock directive on this host */
       destaddr.s_addr = ap_inet_addr(host);
       for (i = 0; i < conf->noproxies->nelts; i++) {
  -	if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
  -	    || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
  -	    return ap_proxyerror(r, HTTP_FORBIDDEN,
  -				 "Connect to remote machine blocked");
  +    if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
  +        || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
  +        return ap_proxyerror(r, HTTP_FORBIDDEN,
  +                 "Connect to remote machine blocked");
       }
   
       /* Check if it is an allowed port */
       if (conf->allowed_connect_ports->nelts == 0) {
  -	/* Default setting if not overridden by AllowCONNECT */
  -	switch (port) {
  -	    case DEFAULT_HTTPS_PORT:
  -	    case DEFAULT_SNEWS_PORT:
  -		break;
  -	    default:
  -		return HTTP_FORBIDDEN;
  -	}
  +    /* Default setting if not overridden by AllowCONNECT */
  +    switch (port) {
  +        case DEFAULT_HTTPS_PORT:
  +        case DEFAULT_SNEWS_PORT:
  +        break;
  +        default:
  +        return HTTP_FORBIDDEN;
  +    }
       } else if(!allowed_port(conf, port))
  -	return HTTP_FORBIDDEN;
  +    return HTTP_FORBIDDEN;
   
       if (proxyhost) {
  -	Explain2("CONNECT to remote proxy %s on port %d", proxyhost, proxyport);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "CONNECT to remote proxy %s on port %d", proxyhost, proxyport);
       }
       else {
  -	Explain2("CONNECT to %s on port %d", host, port);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "CONNECT to %s on port %d", host, port);
       }
  -
  -    server.sin_port = (proxyport ? htons(proxyport) : htons(port));
  -    err = ap_proxy_host2addr(proxyhost ? proxyhost : host, &server_hp);
   
  -    if (err != NULL)
  -	return ap_proxyerror(r,
  -			     proxyhost ? HTTP_BAD_GATEWAY : HTTP_INTERNAL_SERVER_ERROR,
  -			     err);
  -
  -    sock = ap_psocket(r->pool, PF_INET, SOCK_STREAM, IPPROTO_TCP);
  -    if (sock == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -		    "proxy: error creating socket");
  -	return HTTP_INTERNAL_SERVER_ERROR;
  -    }
  -
  -#ifdef CHECK_FD_SETSIZE
  -    if (sock >= FD_SETSIZE) {
  -	ap_log_error(APLOG_MARK, APLOG_NOERRNO|APLOG_WARNING, NULL,
  -	    "proxy_connect_handler: filedescriptor (%u) "
  -	    "larger than FD_SETSIZE (%u) "
  -	    "found, you probably need to rebuild Apache with a "
  -	    "larger FD_SETSIZE", sock, FD_SETSIZE);
  -	ap_pclosesocket(r->pool, sock);
  -	return HTTP_INTERNAL_SERVER_ERROR;
  +    if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error creating socket");
  +        return HTTP_INTERNAL_SERVER_ERROR;
       }
  -#endif
   
  -    j = 0;
  -    while (server_hp.h_addr_list[j] != NULL) {
  -	memcpy(&server.sin_addr, server_hp.h_addr_list[j],
  -	       sizeof(struct in_addr));
  -	i = ap_proxy_doconnect(sock, &server, r);
  -	if (i == 0)
  -	    break;
  -	j++;
  -    }
  -    if (i == -1) {
  -        char buf[120];
  -	ap_pclosesocket(r->pool, sock);
  -	return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, ap_pstrcat(r->pool,
  -					"Could not connect to remote machine:<br>",
  -					ap_strerror(errno, buf, sizeof(buf)), 
  -                                        NULL));
  +    if (ap_proxy_doconnect(sock, (char *)(proxyhost ? proxyhost : host), proxyport ? proxyport : port, r) == -1) {
  +        ap_close_socket(sock);
  +        return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR,
  +                             ap_pstrcat(r->pool, "Could not connect to remote machine:<br>",
  +                                        strerror(errno), NULL));
       }
   
       /* If we are connecting through a remote proxy, we need to pass
        * the CONNECT request on to it.
        */
       if (proxyport) {
  -	/* FIXME: We should not be calling write() directly, but we currently
  -	 * have no alternative.  Error checking ignored.  Also, we force
  -	 * a HTTP/1.0 request to keep things simple.
  -	 */
  -	Explain0("Sending the CONNECT request to the remote proxy");
  -	ap_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF,
  -		    r->uri);
  -	write(sock, buffer, strlen(buffer));
  -	ap_snprintf(buffer, sizeof(buffer),
  -		    "Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
  -	write(sock, buffer, strlen(buffer));
  +        /* FIXME: We should not be calling write() directly, but we currently
  +         * have no alternative.  Error checking ignored.  Also, we force
  +         * a HTTP/1.0 request to keep things simple.
  +         */
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "Sending the CONNECT request to the remote proxy");
  +        nbytes = ap_snprintf(buffer, sizeof(buffer), "CONNECT %s HTTP/1.0" CRLF, r->uri);
  +        ap_send(sock, buffer, &nbytes);
  +        nbytes = ap_snprintf(buffer, sizeof(buffer),"Proxy-agent: %s" CRLF CRLF, ap_get_server_version());
  +        ap_send(sock, buffer, &nbytes);
       }
       else {
  -	Explain0("Returning 200 OK Status");
  -	ap_rvputs(r, "HTTP/1.0 200 Connection established" CRLF, NULL);
  -	ap_rvputs(r, "Proxy-agent: ", ap_get_server_version(), CRLF CRLF, NULL);
  -	ap_bflush(r->connection->client);
  -    }
  -
  -    while (1) {			/* Infinite loop until error (one side closes the connection) */
  -	FD_ZERO(&fds);
  -	FD_SET(sock, &fds);
  -	FD_SET(r->connection->client->fd, &fds);
  -
  -	Explain0("Going to sleep (select)");
  -	i = ap_select((r->connection->client->fd > sock ?
  -		       r->connection->client->fd + 1 :
  -		       sock + 1), &fds, NULL, NULL, NULL);
  -	Explain1("Woke from select(), i=%d", i);
  -
  -	if (i) {
  -	    if (FD_ISSET(sock, &fds)) {
  -		Explain0("sock was set");
  -		if ((nbytes = read(sock, buffer, HUGE_STRING_LEN)) != 0) {
  -		    if (nbytes == -1)
  -			break;
  -		    if (write(r->connection->client->fd, buffer, nbytes) == EOF)
  -			break;
  -		    Explain1("Wrote %d bytes to client", nbytes);
  -		}
  -		else
  -		    break;
  -	    }
  -	    else if (FD_ISSET(r->connection->client->fd, &fds)) {
  -		Explain0("client->fd was set");
  -		if ((nbytes = read(r->connection->client->fd, buffer,
  -				   HUGE_STRING_LEN)) != 0) {
  -		    if (nbytes == -1)
  -			break;
  -		    if (write(sock, buffer, nbytes) == EOF)
  -			break;
  -		    Explain1("Wrote %d bytes to server", nbytes);
  -		}
  -		else
  -		    break;
  -	    }
  -	    else
  -		break;		/* Must be done waiting */
  -	}
  -	else
  -	    break;
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "Returning 200 OK Status");
  +    ap_rvputs(r, "HTTP/1.0 200 Connection established" CRLF, NULL);
  +    ap_rvputs(r, "Proxy-agent: ", ap_get_server_version(), CRLF CRLF, NULL);
  +    ap_bflush(r->connection->client);
  +    }
  +
  +    sock_buff = ap_bcreate(r->pool, B_RDWR);
  +    ap_bpush_iol(sock_buff, unix_attach_socket(sock));
  +
  +    if(ap_setup_poll(&pollfd, 2, r->pool) != APR_SUCCESS)
  +    {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error ap_setup_poll()");
  +        return HTTP_INTERNAL_SERVER_ERROR;
  +    }
  +
  +    /* Add client side to the poll */
  +#if 0
  +/* FIXME !!!! SDM !!! If someone can figure out how to turn a conn_rec into a ap_sock_t or something
  +   this code might work. However if we must we can change r->connection->client to non-blocking and
  +   just see if a recv gives us anything and do the same to sock (server) side, I'll leave this as TBD so
  +   one can decide the best path to take
  +*/
  +    if(ap_put_os_sock(&client_sock, (ap_os_sock_t *)get_socket(r->connection->client),
  +                      r->pool) != APR_SUCCESS)
  +    {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error creating client ap_socket_t");
  +        return HTTP_INTERNAL_SERVER_ERROR;
       }
  -
  -    ap_pclosesocket(r->pool, sock);
  +    ap_add_poll_socket(pollfd, client_sock, APR_POLLIN);
  +#endif
  +    
  +    
  +    /* Add the server side to the poll */
  +    ap_add_poll_socket(pollfd, sock, APR_POLLIN);
  +    
  +    while (1) {            /* Infinite loop until error (one side closes the connection) */
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL, "Going to sleep (poll)");
  +        if(ap_poll(pollfd, &pollcnt, -1) != APR_SUCCESS)
  +        {
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error ap_poll()");
  +            return HTTP_INTERNAL_SERVER_ERROR;
  +        }
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "Woke from select(), i=%d", pollcnt);
  +
  +        if (pollcnt) {
  +            ap_get_revents(&pollevent, sock, pollfd);
  +            if (pollevent & APR_POLLIN) {
  +                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                             "sock was set");
  +                if(ap_bread(sock_buff, buffer, HUGE_STRING_LEN, &nbytes) == APR_SUCCESS) {
  +                    int o = 0;
  +                    while(nbytes)
  +                    {
  +                        ap_bwrite(r->connection->client, buffer + o, nbytes, &i);
  +                        o += i;
  +                        nbytes -= i;
  +                    }
  +                    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                                 "Wrote %d bytes to client", nbytes);
  +                }
  +                else
  +                    break;
  +            }
  +
  +            ap_get_revents(&pollevent, client_sock, pollfd);
  +            if (pollevent & APR_POLLIN) {
  +                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                             "client was set");
  +                if(ap_bread(r->connection->client, buffer, HUGE_STRING_LEN, &nbytes) == APR_SUCCESS) {
  +                    int o = 0;
  +                    while(nbytes)
  +                    {
  +                        ap_bwrite(sock_buff, buffer + o, nbytes, &i);
  +                        o += i;
  +                        nbytes -= i;
  +                    }
  +                    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                                 "Wrote %d bytes to server", nbytes);
  +                }
  +                else
  +                    break;
  +            }
  +        }
  +        else
  +            break;
  +    }
  +    
  +    ap_close_socket(sock);
   
       return OK;
   }
  
  
  
  1.9       +678 -617  apache-2.0/src/modules/proxy/proxy_ftp.c
  
  Index: proxy_ftp.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/proxy/proxy_ftp.c,v
  retrieving revision 1.8
  retrieving revision 1.9
  diff -u -r1.8 -r1.9
  --- proxy_ftp.c	2000/06/09 18:57:14	1.8
  +++ proxy_ftp.c	2000/06/12 21:41:58	1.9
  @@ -62,10 +62,18 @@
   #include "http_main.h"
   #include "http_log.h"
   #include "http_core.h"
  +#include "iol_socket.h"
   
   #define AUTODETECT_PWD
   
  -DEF_Explain
  +static void skiplf(BUFF *foo)
  +{
  +    char c;
  +    do
  +    {
  +        c = ap_bgetc(foo);
  +    } while(c != '\n');
  +}
   
   /*
    * Decodes a '%' escaped string, and returns the number of characters
  @@ -75,15 +83,15 @@
       int i, j, ch;
   
       if (x[0] == '\0')
  -	return 0;		/* special case for no characters */
  +    return 0;        /* special case for no characters */
       for (i = 0, j = 0; x[i] != '\0'; i++, j++) {
   /* decode it if not already done */
  -	ch = x[i];
  -	if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
  -	    ch = ap_proxy_hex2c(&x[i + 1]);
  -	    i += 2;
  -	}
  -	x[j] = ch;
  +    ch = x[i];
  +    if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
  +        ch = ap_proxy_hex2c(&x[i + 1]);
  +        i += 2;
  +    }
  +    x[j] = ch;
       }
       x[j] = '\0';
       return j;
  @@ -98,17 +106,17 @@
       int i, ch;
   
       for (i = 0; x[i] != '\0'; i++) {
  -	ch = x[i];
  -	if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
  -	    ch = ap_proxy_hex2c(&x[i + 1]);
  -	    i += 2;
  -	}
  +    ch = x[i];
  +    if (ch == '%' && ap_isxdigit(x[i + 1]) && ap_isxdigit(x[i + 2])) {
  +        ch = ap_proxy_hex2c(&x[i + 1]);
  +        i += 2;
  +    }
   #ifndef CHARSET_EBCDIC
  -	if (ch == '\015' || ch == '\012' || (ch & 0x80))
  +    if (ch == '\015' || ch == '\012' || (ch & 0x80))
   #else /*CHARSET_EBCDIC*/
  -	if (ch == '\r' || ch == '\n' || (os_toascii[ch] & 0x80))
  +    if (ch == '\r' || ch == '\n' || (os_toascii[ch] & 0x80))
   #endif /*CHARSET_EBCDIC*/
  -	    return 0;
  +        return 0;
       }
       return 1;
   }
  @@ -126,11 +134,11 @@
       port = DEFAULT_FTP_PORT;
       err = ap_proxy_canon_netloc(p, &url, &user, &password, &host, &port);
       if (err)
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
       if (user != NULL && !ftp_check_string(user))
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
       if (password != NULL && !ftp_check_string(password))
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
   
   /* now parse path/parameters args, according to rfc1738 */
   /* N.B. if this isn't a true proxy request, then the URL path
  @@ -140,48 +148,48 @@
    */
       strp = strchr(url, ';');
       if (strp != NULL) {
  -	*(strp++) = '\0';
  -	parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm, r->proxyreq);
  -	if (parms == NULL)
  -	    return HTTP_BAD_REQUEST;
  +    *(strp++) = '\0';
  +    parms = ap_proxy_canonenc(p, strp, strlen(strp), enc_parm, r->proxyreq);
  +    if (parms == NULL)
  +        return HTTP_BAD_REQUEST;
       }
       else
  -	parms = "";
  +    parms = "";
   
       path = ap_proxy_canonenc(p, url, strlen(url), enc_path, r->proxyreq);
       if (path == NULL)
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
       if (!ftp_check_string(path))
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
   
       if (!r->proxyreq && r->args != NULL) {
  -	if (strp != NULL) {
  -	    strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
  -	    if (strp == NULL)
  -		return HTTP_BAD_REQUEST;
  -	    parms = ap_pstrcat(p, parms, "?", strp, NULL);
  -	}
  -	else {
  -	    strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
  -	    if (strp == NULL)
  -		return HTTP_BAD_REQUEST;
  -	    path = ap_pstrcat(p, path, "?", strp, NULL);
  -	}
  -	r->args = NULL;
  +    if (strp != NULL) {
  +        strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_parm, 1);
  +        if (strp == NULL)
  +        return HTTP_BAD_REQUEST;
  +        parms = ap_pstrcat(p, parms, "?", strp, NULL);
       }
  +    else {
  +        strp = ap_proxy_canonenc(p, r->args, strlen(r->args), enc_fpath, 1);
  +        if (strp == NULL)
  +        return HTTP_BAD_REQUEST;
  +        path = ap_pstrcat(p, path, "?", strp, NULL);
  +    }
  +    r->args = NULL;
  +    }
   
   /* now, rebuild URL */
   
       if (port != DEFAULT_FTP_PORT)
  -	ap_snprintf(sport, sizeof(sport), ":%d", port);
  +    ap_snprintf(sport, sizeof(sport), ":%d", port);
       else
  -	sport[0] = '\0';
  +    sport[0] = '\0';
   
       r->filename = ap_pstrcat(p, "proxy:ftp://", (user != NULL) ? user : "",
  -			       (password != NULL) ? ":" : "",
  -			       (password != NULL) ? password : "",
  -		          (user != NULL) ? "@" : "", host, sport, "/", path,
  -			       (parms[0] != '\0') ? ";" : "", parms, NULL);
  +                   (password != NULL) ? ":" : "",
  +                   (password != NULL) ? password : "",
  +                  (user != NULL) ? "@" : "", host, sport, "/", path,
  +                   (parms[0] != '\0') ? ";" : "", parms, NULL);
   
       return OK;
   }
  @@ -197,30 +205,30 @@
   
       len = ap_bgets(linebuff, sizeof linebuff, f);
       if (len == -1)
  -	return -1;
  +    return -1;
   /* check format */
       if (len < 5 || !ap_isdigit(linebuff[0]) || !ap_isdigit(linebuff[1]) ||
  -	!ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
  -	status = 0;
  +    !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
  +    status = 0;
       else
  -	status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
  +    status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
   
       if (linebuff[len - 1] != '\n') {
  -	(void)ap_bskiplf(f);
  +        skiplf(f);
       }
   
   /* skip continuation lines */
       if (linebuff[3] == '-') {
  -	memcpy(buff, linebuff, 3);
  -	buff[3] = ' ';
  -	do {
  -	    len = ap_bgets(linebuff, sizeof linebuff, f);
  -	    if (len == -1)
  -		return -1;
  -	    if (linebuff[len - 1] != '\n') {
  -		(void)ap_bskiplf(f);
  -	    }
  -	} while (memcmp(linebuff, buff, 4) != 0);
  +    memcpy(buff, linebuff, 3);
  +    buff[3] = ' ';
  +    do {
  +        len = ap_bgets(linebuff, sizeof linebuff, f);
  +        if (len == -1)
  +        return -1;
  +        if (linebuff[len - 1] != '\n') {
  +            skiplf(f);
  +        }
  +    } while (memcmp(linebuff, buff, 4) != 0);
       }
   
       return status;
  @@ -235,39 +243,39 @@
       int len, status;
       char linebuff[100], buff[5];
       char *mb = msgbuf,
  -	 *me = &msgbuf[msglen];
  +     *me = &msgbuf[msglen];
   
       len = ap_bgets(linebuff, sizeof linebuff, f);
       if (len == -1)
  -	return -1;
  +    return -1;
       if (len < 5 || !ap_isdigit(linebuff[0]) || !ap_isdigit(linebuff[1]) ||
  -	!ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
  -	status = 0;
  +    !ap_isdigit(linebuff[2]) || (linebuff[3] != ' ' && linebuff[3] != '-'))
  +    status = 0;
       else
  -	status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
  +    status = 100 * linebuff[0] + 10 * linebuff[1] + linebuff[2] - 111 * '0';
   
       mb = ap_cpystrn(mb, linebuff+4, me - mb);
   
       if (linebuff[len - 1] != '\n')
  -	(void)ap_bskiplf(f);
  +        skiplf(f);
   
       if (linebuff[3] == '-') {
  -	memcpy(buff, linebuff, 3);
  -	buff[3] = ' ';
  -	do {
  -	    len = ap_bgets(linebuff, sizeof linebuff, f);
  -	    if (len == -1)
  -		return -1;
  -	    if (linebuff[len - 1] != '\n') {
  -		(void)ap_bskiplf(f);
  -	    }
  -	    mb = ap_cpystrn(mb, linebuff+4, me - mb);
  -	} while (memcmp(linebuff, buff, 4) != 0);
  +    memcpy(buff, linebuff, 3);
  +    buff[3] = ' ';
  +    do {
  +        len = ap_bgets(linebuff, sizeof linebuff, f);
  +        if (len == -1)
  +        return -1;
  +        if (linebuff[len - 1] != '\n') {
  +            skiplf(f);
  +        }
  +        mb = ap_cpystrn(mb, linebuff+4, me - mb);
  +    } while (memcmp(linebuff, buff, 4) != 0);
       }
       return status;
   }
   
  -static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *cwd)
  +static long int send_dir(BUFF *f, request_rec *r, ap_cache_el  *c, char *cwd)
   {
       char buf[IOBUFSIZE];
       char buf2[IOBUFSIZE];
  @@ -275,11 +283,15 @@
       int searchidx = 0;
       char *searchptr = NULL;
       int firstfile = 1;
  +    ap_ssize_t cntr;
       unsigned long total_bytes_sent = 0;
       register int n, o, w;
       conn_rec *con = r->connection;
       char *dir, *path, *reldir, *site;
  +    BUFF *cachefp = NULL;
   
  +    if(c) ap_cache_el_data(c, &cachefp);
  +    
       /* Save "scheme://site" prefix without password */
       site = ap_unparse_uri_components(r->pool, &r->parsed_uri, UNP_OMITPASSWORD|UNP_OMITPATHINFO);
       /* ... and path without query args */
  @@ -289,118 +301,119 @@
       /* Copy path, strip (all except the last) trailing slashes */
       path = dir = ap_pstrcat(r->pool, path, "/", NULL);
       while ((n = strlen(path)) > 1 && path[n-1] == '/' && path[n-2] == '/')
  -	path[n-1] = '\0';
  +    path[n-1] = '\0';
   
       /* print "ftp://host/" */
       n = ap_snprintf(buf, sizeof(buf), DOCTYPE_HTML_3_2
  -		"<HTML><HEAD><TITLE>%s%s</TITLE>\n"
  -		"<BASE HREF=\"%s%s\"></HEAD>\n"
  -		"<BODY><H2>Directory of "
  -		"<A HREF=\"/\">%s</A>/",
  -		site, path, site, path, site);
  +        "<HTML><HEAD><TITLE>%s%s</TITLE>\n"
  +        "<BASE HREF=\"%s%s\"></HEAD>\n"
  +        "<BODY><H2>Directory of "
  +        "<A HREF=\"/\">%s</A>/",
  +        site, path, site, path, site);
       total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
   
       while ((dir = strchr(dir+1, '/')) != NULL)
       {
  -	*dir = '\0';
  -	if ((reldir = strrchr(path+1, '/'))==NULL)
  -	    reldir = path+1;
  -	else
  -	    ++reldir;
  -	/* print "path/" component */
  -	ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
  -	total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
  -	*dir = '/';
  +    *dir = '\0';
  +    if ((reldir = strrchr(path+1, '/'))==NULL)
  +        reldir = path+1;
  +    else
  +        ++reldir;
  +    /* print "path/" component */
  +    ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
  +    total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
  +    *dir = '/';
       }
       /* If the caller has determined the current directory, and it differs */
       /* from what the client requested, then show the real name */
       if (cwd == NULL || strncmp (cwd, path, strlen(cwd)) == 0) {
  -	ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
  +    ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
       } else {
  -	ap_snprintf(buf, sizeof(buf), "</H2>\n(%s)\n<HR><PRE>", cwd);
  +    ap_snprintf(buf, sizeof(buf), "</H2>\n(%s)\n<HR><PRE>", cwd);
       }
       total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
   
       while (!con->aborted) {
  -	n = ap_bgets(buf, sizeof buf, f);
  -	if (n == -1) {		/* input error */
  -	    if (c != NULL) {
  -		ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -		    "proxy: error reading from %s", c->url);
  -		c = ap_proxy_cache_error(c);
  -	    }
  -	    break;
  -	}
  -	if (n == 0)
  -	    break;		/* EOF */
  -	if (buf[0] == 'l' && (filename=strstr(buf, " -> ")) != NULL) {
  -	    char *link_ptr = filename;
  -
  -	    do {
  -		filename--;
  -	    } while (filename[0] != ' ');
  -	    *(filename++) = '\0';
  -	    *(link_ptr++) = '\0';
  -	    if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n')
  -	      link_ptr[n - 1] = '\0';
  -	    ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s %s</A>\n", buf, filename, filename, link_ptr);
  -	    ap_cpystrn(buf, buf2, sizeof(buf));
  -	    n = strlen(buf);
  -	}
  -	else if (buf[0] == 'd' || buf[0] == '-' || buf[0] == 'l' || ap_isdigit(buf[0])) {
  -	    if (ap_isdigit(buf[0])) {	/* handle DOS dir */
  -		searchptr = strchr(buf, '<');
  -		if (searchptr != NULL)
  -		    *searchptr = '[';
  -		searchptr = strchr(buf, '>');
  -		if (searchptr != NULL)
  -		    *searchptr = ']';
  -	    }
  -
  -	    filename = strrchr(buf, ' ');
  -	    *(filename++) = 0;
  -	    filename[strlen(filename) - 1] = 0;
  -
  -	    /* handle filenames with spaces in 'em */
  -	    if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
  -		firstfile = 0;
  -		searchidx = filename - buf;
  -	    }
  -	    else if (searchidx != 0 && buf[searchidx] != 0) {
  -		*(--filename) = ' ';
  -		buf[searchidx - 1] = 0;
  -		filename = &buf[searchidx];
  -	    }
  -
  -	    /* Special handling for '.' and '..' */
  -	    if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
  -		ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s/\">%s</A>\n",
  -		    buf, filename, filename);
  -	    }
  -	    else {
  -		ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\n", buf, filename, filename);
  -	    }
  -	    ap_cpystrn(buf, buf2, sizeof(buf));
  -	    n = strlen(buf);
  -	}
  -
  -	o = 0;
  -	total_bytes_sent += n;
  -
  -	if (c != NULL && c->fp && ap_bwrite(c->fp, buf, n) != n) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -		"proxy: error writing to %s", c->tempfile);
  -	    c = ap_proxy_cache_error(c);
  -	}
  -
  -	while (n && !r->connection->aborted) {
  -	    w = ap_bwrite(con->client, &buf[o], n);
  -	    if (w <= 0)
  -		break;
  -	    n -= w;
  -	    o += w;
  -	}
  +    n = ap_bgets(buf, sizeof buf, f);
  +    if (n == -1) {        /* input error */
  +        if (c != NULL) {
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                          "proxy: error reading from cache");
  +            ap_proxy_cache_error(&c);
  +        }
  +        break;
  +    }
  +    if (n == 0)
  +        break;        /* EOF */
  +    if (buf[0] == 'l' && (filename=strstr(buf, " -> ")) != NULL) {
  +        char *link_ptr = filename;
  +
  +        do {
  +        filename--;
  +        } while (filename[0] != ' ');
  +        *(filename++) = '\0';
  +        *(link_ptr++) = '\0';
  +        if ((n = strlen(link_ptr)) > 1 && link_ptr[n - 1] == '\n')
  +          link_ptr[n - 1] = '\0';
  +        ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s %s</A>\n", buf, filename, filename, link_ptr);
  +        ap_cpystrn(buf, buf2, sizeof(buf));
  +        n = strlen(buf);
  +    }
  +    else if (buf[0] == 'd' || buf[0] == '-' || buf[0] == 'l' || ap_isdigit(buf[0])) {
  +        if (ap_isdigit(buf[0])) {    /* handle DOS dir */
  +        searchptr = strchr(buf, '<');
  +        if (searchptr != NULL)
  +            *searchptr = '[';
  +        searchptr = strchr(buf, '>');
  +        if (searchptr != NULL)
  +            *searchptr = ']';
  +        }
  +
  +        filename = strrchr(buf, ' ');
  +        *(filename++) = 0;
  +        filename[strlen(filename) - 1] = 0;
  +
  +        /* handle filenames with spaces in 'em */
  +        if (!strcmp(filename, ".") || !strcmp(filename, "..") || firstfile) {
  +        firstfile = 0;
  +        searchidx = filename - buf;
  +        }
  +        else if (searchidx != 0 && buf[searchidx] != 0) {
  +        *(--filename) = ' ';
  +        buf[searchidx - 1] = 0;
  +        filename = &buf[searchidx];
  +        }
  +
  +        /* Special handling for '.' and '..' */
  +        if (!strcmp(filename, ".") || !strcmp(filename, "..") || buf[0] == 'd') {
  +        ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s/\">%s</A>\n",
  +            buf, filename, filename);
  +        }
  +        else {
  +        ap_snprintf(buf2, sizeof(buf2), "%s <A HREF=\"%s\">%s</A>\n", buf, filename, filename);
  +        }
  +        ap_cpystrn(buf, buf2, sizeof(buf));
  +        n = strlen(buf);
  +    }
  +
  +    o = 0;
  +    total_bytes_sent += n;
  +
  +    if (cachefp && ap_bwrite(cachefp, buf, n, &cntr) != n) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error writing to cache");
  +        ap_proxy_cache_error(&c);
  +        cachefp = NULL;
  +    }
  +
  +    while (n && !r->connection->aborted) {
  +        w = ap_bwrite(con->client, &buf[o], n, &cntr);
  +        if (w <= 0)
  +        break;
  +        n -= w;
  +        o += w;
       }
  +    }
   
       total_bytes_sent += ap_proxy_bputs2("</PRE><HR>\n", con->client, c);
       total_bytes_sent += ap_proxy_bputs2(ap_psignature("", r), con->client, c);
  @@ -425,16 +438,16 @@
        * (log username/password guessing attempts)
        */
       if (log_it)
  -	ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, r,
  -		      "proxy: missing or failed auth to %s",
  -		      ap_unparse_uri_components(r->pool,
  -		      &r->parsed_uri, UNP_OMITPATHINFO));
  +    ap_log_rerror(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r,
  +              "proxy: missing or failed auth to %s",
  +              ap_unparse_uri_components(r->pool,
  +              &r->parsed_uri, UNP_OMITPATHINFO));
   
       ap_table_setn(r->err_headers_out, "WWW-Authenticate",
                     ap_pstrcat(r->pool, "Basic realm=\"",
  -		  ap_unparse_uri_components(r->pool, &r->parsed_uri,
  -					    UNP_OMITPASSWORD|UNP_OMITPATHINFO),
  -		  "\"", NULL));
  +          ap_unparse_uri_components(r->pool, &r->parsed_uri,
  +                        UNP_OMITPASSWORD|UNP_OMITPATHINFO),
  +          "\"", NULL));
   
       return HTTP_UNAUTHORIZED;
   }
  @@ -445,28 +458,25 @@
    * Troy Morrison <sp...@zoom.com>
    * PASV added by Chuck
    */
  -int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
  +int ap_proxy_ftp_handler(request_rec *r, ap_cache_el  *c, char *url)
   {
  -    char *host, *path, *strp, *parms;
  +    char *host, *path, *strp, *parms, *server_addr;
       char *cwd = NULL;
       char *user = NULL;
   /*    char *account = NULL; how to supply an account in a URL? */
       const char *password = NULL;
       const char *err;
  -    int port, i, j, len, sock, dsock, rc, nocache = 0;
  -    int csd = 0;
  -    struct sockaddr_in server;
  -    struct hostent server_hp;
  +    ap_socket_t *sock, *dsock, *inc;
  +    int port, i, j, len, rc, nocache = 0;
  +    ap_socket_t *csd;
       struct in_addr destaddr;
  -    ap_table_t *resp_hdrs;
  -    BUFF *f;
  +    BUFF *f, *cachefp = NULL;
       BUFF *data = NULL;
       ap_pool_t *p = r->pool;
       int one = 1;
       const long int zero = 0L;
  -    NET_SIZE_T clen;
  -    struct tbl_do_args tdo;
  -
  +    ap_table_t *resp_hdrs;
  +    
       void *sconf = r->server->module_config;
       proxy_server_conf *conf =
       (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
  @@ -480,8 +490,11 @@
       struct sockaddr_in data_addr;
       int pasvmode = 0;
       char pasv[64];
  -    char *pstr;
  +    char *pstr, dates[AP_RFC822_DATE_LEN];
   
  +    char *npaddr;
  +    ap_uint32_t npport;
  +    
   /* stuff for responses */
       char resp[MAX_STRING_LEN];
       char *size = NULL;
  @@ -489,14 +502,14 @@
   /* we only support GET and HEAD */
   
       if (r->method_number != M_GET)
  -	return HTTP_NOT_IMPLEMENTED;
  +    return HTTP_NOT_IMPLEMENTED;
   
   /* We break the URL into host, port, path-search */
   
       host = r->parsed_uri.hostname;
       port = (r->parsed_uri.port != 0)
  -	    ? r->parsed_uri.port
  -	    : ap_default_port_for_request(r);
  +        ? r->parsed_uri.port
  +        : ap_default_port_for_request(r);
       path = ap_pstrdup(p, r->parsed_uri.path);
       path = (path != NULL && path[0] != '\0') ? &path[1] : "";
   
  @@ -509,111 +522,77 @@
        * But chances are still smaller that the URL is logged regularly.
        */
       if ((password = ap_table_get(r->headers_in, "Authorization")) != NULL
  -	&& strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0
  -	&& (password = ap_pbase64decode(r->pool, password))[0] != ':') {
  -	/* Note that this allocation has to be made from r->connection->pool
  -	 * because it has the lifetime of the connection.  The other allocations
  -	 * are temporary and can be tossed away any time.
  -	 */
  -	user = ap_getword_nulls (r->pool, &password, ':');
  -	r->ap_auth_type = "Basic";
  -	r->user = r->parsed_uri.user = user;
  -	nocache = 1;	/* This resource only accessible with username/password */
  +    && strcasecmp(ap_getword(r->pool, &password, ' '), "Basic") == 0
  +        && (password = ap_pbase64decode(r->pool, password))[0] != ':') {
  +        /* Note that this allocation has to be made from r->connection->pool
  +         * because it has the lifetime of the connection.  The other allocations
  +         * are temporary and can be tossed away any time.
  +         */
  +        user = ap_getword_nulls (r->pool, &password, ':');
  +        r->ap_auth_type = "Basic";
  +        r->user = r->parsed_uri.user = user;
  +        nocache = 1;    /* This resource only accessible with username/password */
       }
       else if ((user = r->parsed_uri.user) != NULL) {
  -	user = ap_pstrdup(p, user);
  -	decodeenc(user);
  -	if ((password = r->parsed_uri.password) != NULL) {
  -	    char *tmp = ap_pstrdup(p, password);
  -	    decodeenc(tmp);
  -	    password = tmp;
  -	}
  -	nocache = 1;	/* This resource only accessible with username/password */
  +    user = ap_pstrdup(p, user);
  +    decodeenc(user);
  +    if ((password = r->parsed_uri.password) != NULL) {
  +        char *tmp = ap_pstrdup(p, password);
  +        decodeenc(tmp);
  +        password = tmp;
  +    }
  +    nocache = 1;    /* This resource only accessible with username/password */
       }
       else {
  -	user = "anonymous";
  -	password = "apache_proxy@";
  +        user = "anonymous";
  +        password = "apache_proxy@";
       }
   
   /* check if ProxyBlock directive on this host */
       destaddr.s_addr = ap_inet_addr(host);
       for (i = 0; i < conf->noproxies->nelts; i++) {
  -	if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
  -	    || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
  -	    return ap_proxyerror(r, HTTP_FORBIDDEN,
  -				 "Connect to remote machine blocked");
  +    if ((npent[i].name != NULL && strstr(host, npent[i].name) != NULL)
  +        || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
  +        return ap_proxyerror(r, HTTP_FORBIDDEN,
  +                 "Connect to remote machine blocked");
       }
   
  -    Explain2("FTP: connect to %s:%d", host, port);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: connect to %s:%d", host, port);
   
       parms = strchr(path, ';');
       if (parms != NULL)
  -	*(parms++) = '\0';
  +    *(parms++) = '\0';
   
  -    memset(&server, 0, sizeof(struct sockaddr_in));
  -    server.sin_family = AF_INET;
  -    server.sin_port = htons(port);
  -    err = ap_proxy_host2addr(host, &server_hp);
  -    if (err != NULL)
  -	return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, err);
  -
  -    sock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
  -    if (sock == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -		     "proxy: error creating socket");
  -	return HTTP_INTERNAL_SERVER_ERROR;
  -    }
  -
  -    if (conf->recv_buffer_size > 0
  -	&& setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
  -		       (const char *) &conf->recv_buffer_size, sizeof(int))
  -	    == -1) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -			 "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
  +    if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error creating socket");
  +        return HTTP_INTERNAL_SERVER_ERROR;
       }
   
  -    if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
  -		   sizeof(one)) == -1) {
  +    if (conf->recv_buffer_size > 0 && ap_setsocketopt(sock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
  +    }
  +    
  +    if (ap_setsocketopt(sock, APR_SO_REUSEADDR, one)) {
   #ifndef _OSD_POSIX /* BS2000 has this option "always on" */
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -		     "proxy: error setting reuseaddr option: setsockopt(SO_REUSEADDR)");
  -	ap_pclosesocket(p, sock);
  -	return HTTP_INTERNAL_SERVER_ERROR;
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error setting reuseaddr option: setsockopt(SO_REUSEADDR)");
  +        ap_close_socket(sock);
  +        return HTTP_INTERNAL_SERVER_ERROR;
   #endif /*_OSD_POSIX*/
       }
  -
  -#ifdef SINIX_D_RESOLVER_BUG
  -    {
  -	struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list;
   
  -	for (; ip_addr->s_addr != 0; ++ip_addr) {
  -	    memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr));
  -	    i = ap_proxy_doconnect(sock, &server, r);
  -	    if (i == 0)
  -		break;
  -	}
  -    }
  -#else
  -    j = 0;
  -    while (server_hp.h_addr_list[j] != NULL) {
  -	memcpy(&server.sin_addr, server_hp.h_addr_list[j],
  -	       sizeof(struct in_addr));
  -	i = ap_proxy_doconnect(sock, &server, r);
  -	if (i == 0)
  -	    break;
  -	j++;
  +    if (ap_proxy_doconnect(sock, host, port, r) == -1) {
  +        ap_close_socket(sock);
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +                             ap_pstrcat(r->pool, "Could not connect to remote machine: ",
  +                                        strerror(errno), NULL));
       }
  -#endif
  -    if (i == -1) {
  -        char buf[120];
  -	ap_pclosesocket(p, sock);
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
  -				"Could not connect to remote machine: ",
  -				ap_strerror(errno, buf, sizeof(buf)), NULL));
  -    }
   
  -    f = ap_bcreate(p, B_RDWR | B_SOCKET);
  -    ap_bpushfd(f, sock);
  +    f = ap_bcreate(p, B_RDWR);
  +    ap_bpush_iol(f, unix_attach_socket(sock));
   /* shouldn't we implement telnet control options here? */
   
   #ifdef CHARSET_EBCDIC
  @@ -625,36 +604,39 @@
       /* 220 Service ready for new user. */
       /* 421 Service not available, closing control connection. */
       i = ftp_getrc_msg(f, resp, sizeof resp);
  -    Explain1("FTP: returned status %d", i);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: returned status %d", i);
       if (i == -1) {
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                "Error reading from remote server");
       }
   #if 0
       if (i == 120) {
  -	/* RFC2068 states:
  -	 * 14.38 Retry-After
  -	 * 
  -	 *  The Retry-After response-header field can be used with a 503 (Service
  -	 *  Unavailable) response to indicate how long the service is expected to
  -	 *  be unavailable to the requesting client. The value of this field can
  -	 *  be either an HTTP-date or an integer number of seconds (in decimal)
  -	 *  after the time of the response.
  -	 *     Retry-After  = "Retry-After" ":" ( HTTP-date | delta-seconds )
  -	 */
  -	ap_set_header("Retry-After", ap_psprintf(p, "%u", 60*wait_mins);
  -	return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, resp);
  +    /* RFC2068 states:
  +     * 14.38 Retry-After
  +     * 
  +     *  The Retry-After response-header field can be used with a 503 (Service
  +     *  Unavailable) response to indicate how long the service is expected to
  +     *  be unavailable to the requesting client. The value of this field can
  +     *  be either an HTTP-date or an integer number of seconds (in decimal)
  +     *  after the time of the response.
  +     *     Retry-After  = "Retry-After" ":" ( HTTP-date | delta-seconds )
  +     */
  +    ap_set_header("Retry-After", ap_psprintf(p, "%u", 60*wait_mins);
  +    return ap_proxyerror(r, HTTP_SERVICE_UNAVAILABLE, resp);
       }
   #endif
       if (i != 220) {
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY, resp);
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY, resp);
       }
   
  -    Explain0("FTP: connected.");
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: connected.");
   
       ap_bvputs(f, "USER ", user, CRLF, NULL);
  -    ap_bflush(f);			/* capture any errors */
  -    Explain1("FTP: USER %s", user);
  +    ap_bflush(f);            /* capture any errors */
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: USER %s", user);
   
   /* possible results; 230, 331, 332, 421, 500, 501, 530 */
   /* states: 1 - error, 2 - success; 3 - send password, 4,5 fail */
  @@ -667,48 +649,51 @@
       /* 501 Syntax error in parameters or arguments. */
       /* 530 Not logged in. */
       i = ftp_getrc(f);
  -    Explain1("FTP: returned status %d", i);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: returned status %d", i);
       if (i == -1) {
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                "Error reading from remote server");
       }
       if (i == 530) {
  -	return ftp_unauthorized (r, 1);	/* log it: user name guessing attempt? */
  +        return ftp_unauthorized (r, 1);    /* log it: user name guessing attempt? */
       }
       if (i != 230 && i != 331) {
  -	return HTTP_BAD_GATEWAY;
  +        return HTTP_BAD_GATEWAY;
       }
   
  -    if (i == 331) {		/* send password */
  -	if (password == NULL) {
  -	    return ftp_unauthorized (r, 0);
  -	}
  -	ap_bvputs(f, "PASS ", password, CRLF, NULL);
  -	ap_bflush(f);
  -	Explain1("FTP: PASS %s", password);
  +    if (i == 331) {        /* send password */
  +        if (password == NULL) {
  +            return ftp_unauthorized (r, 0);
  +        }
  +        ap_bvputs(f, "PASS ", password, CRLF, NULL);
  +        ap_bflush(f);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: PASS %s", password);
   /* possible results 202, 230, 332, 421, 500, 501, 503, 530 */
  -    /* 230 User logged in, proceed. */
  -    /* 332 Need account for login. */
  -    /* 421 Service not available, closing control connection. */
  -    /* 500 Syntax error, command unrecognized. */
  -    /* 501 Syntax error in parameters or arguments. */
  -    /* 503 Bad sequence of commands. */
  -    /* 530 Not logged in. */
  -	i = ftp_getrc(f);
  -	Explain1("FTP: returned status %d", i);
  -	if (i == -1) {
  -	    return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
  -	}
  -	if (i == 332) {
  -	    return ap_proxyerror(r, HTTP_UNAUTHORIZED, "Need account for login");
  -	}
  -	/* @@@ questionable -- we might as well return a 403 Forbidden here */
  -	if (i == 530) {
  -	    return ftp_unauthorized (r, 1); /* log it: passwd guessing attempt? */
  -	}
  -	if (i != 230 && i != 202) {
  -	    return HTTP_BAD_GATEWAY;
  -	}
  +        /* 230 User logged in, proceed. */
  +        /* 332 Need account for login. */
  +        /* 421 Service not available, closing control connection. */
  +        /* 500 Syntax error, command unrecognized. */
  +        /* 501 Syntax error in parameters or arguments. */
  +        /* 503 Bad sequence of commands. */
  +        /* 530 Not logged in. */
  +        i = ftp_getrc(f);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: returned status %d", i);
  +        if (i == -1) {
  +            return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server");
  +        }
  +        if (i == 332) {
  +            return ap_proxyerror(r, HTTP_UNAUTHORIZED, "Need account for login");
  +        }
  +        /* @@@ questionable -- we might as well return a 403 Forbidden here */
  +        if (i == 530) {
  +            return ftp_unauthorized (r, 1); /* log it: passwd guessing attempt? */
  +        }
  +        if (i != 230 && i != 202) {
  +            return HTTP_BAD_GATEWAY;
  +        }
       }
   
   /* set the directory (walk directory component by component):
  @@ -716,58 +701,61 @@
    * machine
    */
       for (;;) {
  -	strp = strchr(path, '/');
  -	if (strp == NULL)
  -	    break;
  -	*strp = '\0';
  -
  -	len = decodeenc(path);
  -	ap_bvputs(f, "CWD ", path, CRLF, NULL);
  -	ap_bflush(f);
  -	Explain1("FTP: CWD %s", path);
  -	*strp = '/';
  +        strp = strchr(path, '/');
  +        if (strp == NULL)
  +            break;
  +        *strp = '\0';
  +
  +        len = decodeenc(path);
  +        ap_bvputs(f, "CWD ", path, CRLF, NULL);
  +        ap_bflush(f);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: CWD %s", path);
  +        *strp = '/';
   /* responses: 250, 421, 500, 501, 502, 530, 550 */
  -    /* 250 Requested file action okay, completed. */
  -    /* 421 Service not available, closing control connection. */
  -    /* 500 Syntax error, command unrecognized. */
  -    /* 501 Syntax error in parameters or arguments. */
  -    /* 502 Command not implemented. */
  -    /* 530 Not logged in. */
  -    /* 550 Requested action not taken. */
  -	i = ftp_getrc(f);
  -	Explain1("FTP: returned status %d", i);
  -	if (i == -1) {
  -	    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +        /* 250 Requested file action okay, completed. */
  +        /* 421 Service not available, closing control connection. */
  +        /* 500 Syntax error, command unrecognized. */
  +        /* 501 Syntax error in parameters or arguments. */
  +        /* 502 Command not implemented. */
  +        /* 530 Not logged in. */
  +        /* 550 Requested action not taken. */
  +        i = ftp_getrc(f);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: returned status %d", i);
  +        if (i == -1) {
  +            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                    "Error reading from remote server");
  -	}
  -	if (i == 550) {
  -	    return HTTP_NOT_FOUND;
  -	}
  -	if (i != 250) {
  -	    return HTTP_BAD_GATEWAY;
  -	}
  +        }
  +        if (i == 550) {
  +            return HTTP_NOT_FOUND;
  +        }
  +        if (i != 250) {
  +            return HTTP_BAD_GATEWAY;
  +        }
   
  -	path = strp + 1;
  +        path = strp + 1;
       }
   
       if (parms != NULL && strncmp(parms, "type=", 5) == 0) {
  -	parms += 5;
  -	if ((parms[0] != 'd' && parms[0] != 'a' && parms[0] != 'i') ||
  -	    parms[1] != '\0')
  -	    parms = "";
  +    parms += 5;
  +    if ((parms[0] != 'd' && parms[0] != 'a' && parms[0] != 'i') ||
  +        parms[1] != '\0')
  +        parms = "";
       }
       else
  -	parms = "";
  +    parms = "";
   
       /* changed to make binary transfers the default */
   
       if (parms[0] != 'a') {
  -	/* set type to image */
  -	/* TM - Added \015\012 to the end of TYPE I, otherwise it hangs the
  -	   connection */
  -	ap_bputs("TYPE I" CRLF, f);
  -	ap_bflush(f);
  -	Explain0("FTP: TYPE I");
  +    /* set type to image */
  +    /* TM - Added \015\012 to the end of TYPE I, otherwise it hangs the
  +       connection */
  +    ap_bputs("TYPE I" CRLF, f);
  +    ap_bflush(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: TYPE I");
   /* responses: 200, 421, 500, 501, 504, 530 */
       /* 200 Command okay. */
       /* 421 Service not available, closing control connection. */
  @@ -775,40 +763,38 @@
       /* 501 Syntax error in parameters or arguments. */
       /* 504 Command not implemented for that parameter. */
       /* 530 Not logged in. */
  -	i = ftp_getrc(f);
  -	Explain1("FTP: returned status %d", i);
  -	if (i == -1) {
  -	    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +    i = ftp_getrc(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: returned status %d", i);
  +    if (i == -1) {
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                    "Error reading from remote server");
  -	}
  -	if (i != 200 && i != 504) {
  -	    return HTTP_BAD_GATEWAY;
  -	}
  +    }
  +    if (i != 200 && i != 504) {
  +        return HTTP_BAD_GATEWAY;
  +    }
   /* Allow not implemented */
  -	if (i == 504)
  -	    parms[0] = '\0';
  +    if (i == 504)
  +        parms[0] = '\0';
       }
   
   /* try to set up PASV data connection first */
  -    dsock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
  -    if (dsock == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -		     "proxy: error creating PASV socket");
  -	ap_bclose(f);
  -	return HTTP_INTERNAL_SERVER_ERROR;
  +    if ((ap_create_tcp_socket(&dsock, r->pool)) != APR_SUCCESS) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error creating PASV socket");
  +        ap_bclose(f);
  +        return HTTP_INTERNAL_SERVER_ERROR;
       }
   
  -    if (conf->recv_buffer_size) {
  -	if (setsockopt(dsock, SOL_SOCKET, SO_RCVBUF,
  -	       (const char *) &conf->recv_buffer_size, sizeof(int)) == -1) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -			 "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
  -	}
  +    if (conf->recv_buffer_size > 0 && ap_setsocketopt(dsock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +             "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
       }
   
       ap_bputs("PASV" CRLF, f);
       ap_bflush(f);
  -    Explain0("FTP: PASV command issued");
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: PASV command issued");
   /* possible results: 227, 421, 500, 501, 502, 530 */
       /* 227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
       /* 421 Service not available, closing control connection. */
  @@ -818,13 +804,45 @@
       /* 530 Not logged in. */
       i = ap_bgets(pasv, sizeof(pasv), f);
       if (i == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
  -		     "PASV: control connection is toast");
  -	ap_pclosesocket(p, dsock);
  -	ap_bclose(f);
  -	return HTTP_INTERNAL_SERVER_ERROR;
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
  +                      "PASV: control connection is toast");
  +        ap_close_socket(dsock);
  +        ap_bclose(f);
  +        return HTTP_INTERNAL_SERVER_ERROR;
       }
       else {
  +<<<<<<< proxy_ftp.c
  +        pasv[i - 1] = '\0';
  +        pstr = strtok(pasv, " ");    /* separate result code */
  +        if (pstr != NULL) {
  +            presult = atoi(pstr);
  +            if (*(pstr + strlen(pstr) + 1) == '=')
  +                pstr += strlen(pstr) + 2;
  +            else
  +            {
  +                pstr = strtok(NULL, "(");  /* separate address & port params */
  +                if (pstr != NULL)
  +                    pstr = strtok(NULL, ")");
  +            }
  +        }
  +        else
  +            presult = atoi(pasv);
  +
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: returned status %d", presult);
  +
  +        if (presult == 227 && pstr != NULL && (sscanf(pstr,
  +                                                      "%d,%d,%d,%d,%d,%d", &h3, &h2, &h1, &h0, &p1, &p0) == 6)) {
  +            /* pardon the parens, but it makes gcc happy */
  +            destaddr.s_addr = htonl((((((h3 << 8) + h2) << 8) + h1) << 8) + h0);
  +            pport = (p1 << 8) + p0;
  +            ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                         "FTP: contacting host %d.%d.%d.%d:%d",
  +                         h3, h2, h1, h0, pport);
  +
  +            if (ap_proxy_doconnect(dsock, inet_ntoa(destaddr), pport, r) == -1) {
  +                return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +=======
   	pasv[i - 1] = '\0';
   	pstr = strtok(pasv, " ");	/* separate result code */
   	if (pstr != NULL) {
  @@ -858,8 +876,35 @@
   	    if (i == -1) {
                   char buf[120];
   		return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +>>>>>>> 1.8
                                        ap_pstrcat(r->pool,
                                                   "Could not connect to remote machine: ",
  +<<<<<<< proxy_ftp.c
  +                                                strerror(errno), NULL));
  +            }
  +            else {
  +                pasvmode = 1;
  +            }
  +        }
  +        else
  +            ap_close_socket(dsock);    /* and try the regular way */
  +    }
  +
  +    if (!pasvmode) {        /* set up data connection */
  +        
  +        if ((ap_create_tcp_socket(&dsock, r->pool)) != APR_SUCCESS) {
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                          "proxy: error creating socket");
  +            ap_bclose(f);
  +            return HTTP_INTERNAL_SERVER_ERROR;
  +        }
  +        ap_get_local_port(&npport, sock);
  +        ap_get_local_ipaddr(&npaddr, sock);
  +        ap_set_local_port(dsock, npport);
  +        ap_set_local_ipaddr(dsock, npaddr);
  +        
  +        if (ap_setsocketopt(dsock, APR_SO_REUSEADDR, one) != APR_SUCCESS) {
  +=======
                                                   ap_strerror(errno, buf, 
                                                             sizeof(buf)), NULL));
   	    }
  @@ -890,27 +935,27 @@
   
   	if (setsockopt(dsock, SOL_SOCKET, SO_REUSEADDR, (void *) &one,
   		       sizeof(one)) == -1) {
  +>>>>>>> 1.8
   #ifndef _OSD_POSIX /* BS2000 has this option "always on" */
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -			 "proxy: error setting reuseaddr option");
  -	    ap_pclosesocket(p, dsock);
  -	    ap_bclose(f);
  -	    return HTTP_INTERNAL_SERVER_ERROR;
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                          "proxy: error setting reuseaddr option");
  +            ap_close_socket(dsock);
  +            ap_bclose(f);
  +            return HTTP_INTERNAL_SERVER_ERROR;
   #endif /*_OSD_POSIX*/
  -	}
  +        }
   
  -	if (bind(dsock, (struct sockaddr *) &server,
  -		 sizeof(struct sockaddr_in)) == -1) {
  -	    char buff[22];
  +        if (ap_bind(dsock) != APR_SUCCESS) {
  +            char buff[22];
   
  -	    ap_snprintf(buff, sizeof(buff), "%s:%d", inet_ntoa(server.sin_addr), server.sin_port);
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -			 "proxy: error binding to ftp data socket %s", buff);
  -	    ap_bclose(f);
  -	    ap_pclosesocket(p, dsock);
  -	    return HTTP_INTERNAL_SERVER_ERROR;
  -	}
  -	listen(dsock, 2);	/* only need a short queue */
  +            ap_snprintf(buff, sizeof(buff), "%s:%d", npaddr, npport);
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                          "proxy: error binding to ftp data socket %s", buff);
  +            ap_bclose(f);
  +            ap_close_socket(dsock);
  +            return HTTP_INTERNAL_SERVER_ERROR;
  +        }
  +        ap_listen(dsock, 2);    /* only need a short queue */
       }
   
   /* set request; "path" holds last path component */
  @@ -919,58 +964,64 @@
       /* TM - if len == 0 then it must be a directory (you can't RETR nothing) */
   
       if (len == 0) {
  -	parms = "d";
  +        parms = "d";
       }
       else {
  -	ap_bvputs(f, "SIZE ", path, CRLF, NULL);
  -	ap_bflush(f);
  -	Explain1("FTP: SIZE %s", path);
  -	i = ftp_getrc_msg(f, resp, sizeof resp);
  -	Explain2("FTP: returned status %d with response %s", i, resp);
  -	if (i != 500) {		/* Size command not recognized */
  -	    if (i == 550) {	/* Not a regular file */
  -		Explain0("FTP: SIZE shows this is a directory");
  -		parms = "d";
  -		ap_bvputs(f, "CWD ", path, CRLF, NULL);
  -		ap_bflush(f);
  -		Explain1("FTP: CWD %s", path);
  -		i = ftp_getrc(f);
  -		/* possible results: 250, 421, 500, 501, 502, 530, 550 */
  -		/* 250 Requested file action okay, completed. */
  -		/* 421 Service not available, closing control connection. */
  -		/* 500 Syntax error, command unrecognized. */
  -		/* 501 Syntax error in parameters or arguments. */
  -		/* 502 Command not implemented. */
  -		/* 530 Not logged in. */
  -		/* 550 Requested action not taken. */
  -		Explain1("FTP: returned status %d", i);
  -		if (i == -1) {
  -		    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +        ap_bvputs(f, "SIZE ", path, CRLF, NULL);
  +        ap_bflush(f);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: SIZE %s", path);
  +        i = ftp_getrc_msg(f, resp, sizeof resp);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: returned status %d with response %s", i, resp);
  +        if (i != 500) {        /* Size command not recognized */
  +            if (i == 550) {    /* Not a regular file */
  +                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                             "FTP: SIZE shows this is a directory");
  +                parms = "d";
  +                ap_bvputs(f, "CWD ", path, CRLF, NULL);
  +                ap_bflush(f);
  +                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                             "FTP: CWD %s", path);
  +                i = ftp_getrc(f);
  +                /* possible results: 250, 421, 500, 501, 502, 530, 550 */
  +                /* 250 Requested file action okay, completed. */
  +                /* 421 Service not available, closing control connection. */
  +                /* 500 Syntax error, command unrecognized. */
  +                /* 501 Syntax error in parameters or arguments. */
  +                /* 502 Command not implemented. */
  +                /* 530 Not logged in. */
  +                /* 550 Requested action not taken. */
  +                ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                             "FTP: returned status %d", i);
  +                if (i == -1) {
  +                    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                            "Error reading from remote server");
  -		}
  -		if (i == 550) {
  -		    return HTTP_NOT_FOUND;
  -		}
  -		if (i != 250) {
  -		    return HTTP_BAD_GATEWAY;
  -		}
  -		path = "";
  -		len = 0;
  -	    }
  -	    else if (i == 213) { /* Size command ok */
  -		for (j = 0; j < sizeof resp && ap_isdigit(resp[j]); j++)
  -			;
  -		resp[j] = '\0';
  -		if (resp[0] != '\0')
  -		    size = ap_pstrdup(p, resp);
  -	    }
  -	}
  +                }
  +                if (i == 550) {
  +                    return HTTP_NOT_FOUND;
  +                }
  +                if (i != 250) {
  +                    return HTTP_BAD_GATEWAY;
  +                }
  +                path = "";
  +                len = 0;
  +            }
  +            else if (i == 213) { /* Size command ok */
  +                for (j = 0; j < sizeof resp && ap_isdigit(resp[j]); j++)
  +                    ;
  +                resp[j] = '\0';
  +                if (resp[0] != '\0')
  +                    size = ap_pstrdup(p, resp);
  +            }
  +        }
       }
   
   #ifdef AUTODETECT_PWD
       ap_bvputs(f, "PWD", CRLF, NULL);
       ap_bflush(f);
  -    Explain0("FTP: PWD");
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: PWD");
   /* responses: 257, 500, 501, 502, 421, 550 */
       /* 257 "<directory-name>" <commentary> */
       /* 421 Service not available, closing control connection. */
  @@ -979,30 +1030,33 @@
       /* 502 Command not implemented. */
       /* 550 Requested action not taken. */
       i = ftp_getrc_msg(f, resp, sizeof resp);
  -    Explain1("FTP: PWD returned status %d", i);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: PWD returned status %d", i);
       if (i == -1 || i == 421) {
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                "Error reading from remote server");
       }
       if (i == 550) {
  -	return HTTP_NOT_FOUND;
  +    return HTTP_NOT_FOUND;
       }
       if (i == 257) {
  -	const char *dirp = resp;
  -	cwd = ap_getword_conf(r->pool, &dirp);
  +    const char *dirp = resp;
  +    cwd = ap_getword_conf(r->pool, &dirp);
       }
   #endif /*AUTODETECT_PWD*/
   
       if (parms[0] == 'd') {
  -	if (len != 0)
  -	    ap_bvputs(f, "LIST ", path, CRLF, NULL);
  -	else
  -	    ap_bputs("LIST -lag" CRLF, f);
  -	Explain1("FTP: LIST %s", (len == 0 ? "" : path));
  +        if (len != 0)
  +            ap_bvputs(f, "LIST ", path, CRLF, NULL);
  +        else
  +            ap_bputs("LIST -lag" CRLF, f);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: LIST %s", (len == 0 ? "" : path));
       }
       else {
  -	ap_bvputs(f, "RETR ", path, CRLF, NULL);
  -	Explain1("FTP: RETR %s", path);
  +        ap_bvputs(f, "RETR ", path, CRLF, NULL);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: RETR %s", path);
       }
       ap_bflush(f);
   /* RETR: 110, 125, 150, 226, 250, 421, 425, 426, 450, 451, 500, 501, 530, 550
  @@ -1022,195 +1076,203 @@
       /* 530 Not logged in. */
       /* 550 Requested action not taken. */
       rc = ftp_getrc(f);
  -    Explain1("FTP: returned status %d", rc);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: returned status %d", rc);
       if (rc == -1) {
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                "Error reading from remote server");
       }
       if (rc == 550) {
  -	Explain0("FTP: RETR failed, trying LIST instead");
  -	parms = "d";
  -	ap_bvputs(f, "CWD ", path, CRLF, NULL);
  -	ap_bflush(f);
  -	Explain1("FTP: CWD %s", path);
  -	/* possible results: 250, 421, 500, 501, 502, 530, 550 */
  -	/* 250 Requested file action okay, completed. */
  -	/* 421 Service not available, closing control connection. */
  -	/* 500 Syntax error, command unrecognized. */
  -	/* 501 Syntax error in parameters or arguments. */
  -	/* 502 Command not implemented. */
  -	/* 530 Not logged in. */
  -	/* 550 Requested action not taken. */
  -	rc = ftp_getrc(f);
  -	Explain1("FTP: returned status %d", rc);
  -	if (rc == -1) {
  -	    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: RETR failed, trying LIST instead");
  +    parms = "d";
  +    ap_bvputs(f, "CWD ", path, CRLF, NULL);
  +    ap_bflush(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: CWD %s", path);
  +    /* possible results: 250, 421, 500, 501, 502, 530, 550 */
  +    /* 250 Requested file action okay, completed. */
  +    /* 421 Service not available, closing control connection. */
  +    /* 500 Syntax error, command unrecognized. */
  +    /* 501 Syntax error in parameters or arguments. */
  +    /* 502 Command not implemented. */
  +    /* 530 Not logged in. */
  +    /* 550 Requested action not taken. */
  +    rc = ftp_getrc(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: returned status %d", rc);
  +    if (rc == -1) {
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                    "Error reading from remote server");
  -	}
  -	if (rc == 550) {
  -	    return HTTP_NOT_FOUND;
  -	}
  -	if (rc != 250) {
  -	    return HTTP_BAD_GATEWAY;
  -	}
  +    }
  +    if (rc == 550) {
  +        return HTTP_NOT_FOUND;
  +    }
  +    if (rc != 250) {
  +        return HTTP_BAD_GATEWAY;
  +    }
   
   #ifdef AUTODETECT_PWD
  -	ap_bvputs(f, "PWD", CRLF, NULL);
  -	ap_bflush(f);
  -	Explain0("FTP: PWD");
  +    ap_bvputs(f, "PWD", CRLF, NULL);
  +    ap_bflush(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: PWD");
   /* responses: 257, 500, 501, 502, 421, 550 */
  -	/* 257 "<directory-name>" <commentary> */
  -	/* 421 Service not available, closing control connection. */
  -	/* 500 Syntax error, command unrecognized. */
  -	/* 501 Syntax error in parameters or arguments. */
  -	/* 502 Command not implemented. */
  -	/* 550 Requested action not taken. */
  -	i = ftp_getrc_msg(f, resp, sizeof resp);
  -	Explain1("FTP: PWD returned status %d", i);
  -	if (i == -1 || i == 421) {
  -	    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +    /* 257 "<directory-name>" <commentary> */
  +    /* 421 Service not available, closing control connection. */
  +    /* 500 Syntax error, command unrecognized. */
  +    /* 501 Syntax error in parameters or arguments. */
  +    /* 502 Command not implemented. */
  +    /* 550 Requested action not taken. */
  +    i = ftp_getrc_msg(f, resp, sizeof resp);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: PWD returned status %d", i);
  +    if (i == -1 || i == 421) {
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
                                    "Error reading from remote server");
  -	}
  -	if (i == 550) {
  -	    return HTTP_NOT_FOUND;
  -	}
  -	if (i == 257) {
  -	    const char *dirp = resp;
  -	    cwd = ap_getword_conf(r->pool, &dirp);
  -	}
  +    }
  +    if (i == 550) {
  +        return HTTP_NOT_FOUND;
  +    }
  +    if (i == 257) {
  +        const char *dirp = resp;
  +        cwd = ap_getword_conf(r->pool, &dirp);
  +    }
   #endif /*AUTODETECT_PWD*/
   
  -	ap_bputs("LIST -lag" CRLF, f);
  -	ap_bflush(f);
  -	Explain0("FTP: LIST -lag");
  -	rc = ftp_getrc(f);
  -	Explain1("FTP: returned status %d", rc);
  -	if (rc == -1)
  -	    return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  -				 "Error reading from remote server");
  +    ap_bputs("LIST -lag" CRLF, f);
  +    ap_bflush(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: LIST -lag");
  +    rc = ftp_getrc(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: returned status %d", rc);
  +    if (rc == -1)
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +                 "Error reading from remote server");
       }
       if (rc != 125 && rc != 150 && rc != 226 && rc != 250)
  -	return HTTP_BAD_GATEWAY;
  +    return HTTP_BAD_GATEWAY;
   
       r->status = HTTP_OK;
       r->status_line = "200 OK";
  -
       resp_hdrs = ap_make_table(p, 2);
  -    c->hdrs = resp_hdrs;
  -
  -    ap_table_setn(resp_hdrs, "Date", ap_gm_timestr_822(r->pool, r->request_time));
  +    
  +    ap_rfc822_date(dates, r->request_time);
  +    ap_table_setn(resp_hdrs, "Date", dates);
       ap_table_setn(resp_hdrs, "Server", ap_get_server_version());
   
       if (parms[0] == 'd')
  -	ap_table_setn(resp_hdrs, "Content-Type", "text/html");
  +        ap_table_setn(resp_hdrs, "Content-Type", "text/html");
       else {
  -	if (r->content_type != NULL) {
  -	    ap_table_setn(resp_hdrs, "Content-Type", r->content_type);
  -	    Explain1("FTP: Content-Type set to %s", r->content_type);
  -	}
  -	else {
  -	    ap_table_setn(resp_hdrs, "Content-Type", ap_default_type(r));
  -	}
  -	if (parms[0] != 'a' && size != NULL) {
  -	    /* We "trust" the ftp server to really serve (size) bytes... */
  -	    ap_table_set(resp_hdrs, "Content-Length", size);
  -	    Explain1("FTP: Content-Length set to %s", size);
  -	}
  +    if (r->content_type != NULL) {
  +        ap_table_setn(resp_hdrs, "Content-Type", r->content_type);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: Content-Type set to %s", r->content_type);
  +    }
  +    else {
  +        ap_table_setn(resp_hdrs, "Content-Type", ap_default_type(r));
  +    }
  +    if (parms[0] != 'a' && size != NULL) {
  +        /* We "trust" the ftp server to really serve (size) bytes... */
  +        ap_table_setn(resp_hdrs, "Content-Length", size);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: Content-Length set to %s", size);
  +    }
       }
       if (r->content_encoding != NULL && r->content_encoding[0] != '\0') {
  -	Explain1("FTP: Content-Encoding set to %s", r->content_encoding);
  -	ap_table_setn(resp_hdrs, "Content-Encoding", r->content_encoding);
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "FTP: Content-Encoding set to %s", r->content_encoding);
  +        ap_table_setn(resp_hdrs, "Content-Encoding", r->content_encoding);
       }
  -
  +    ap_cache_el_header_merge(c, resp_hdrs);
  +    
   /* check if NoCache directive on this host */
       for (i = 0; i < conf->nocaches->nelts; i++) {
  -	if ((ncent[i].name != NULL && strstr(host, ncent[i].name) != NULL)
  -	    || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
  -	    nocache = 1;
  +    if ((ncent[i].name != NULL && strstr(host, ncent[i].name) != NULL)
  +        || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
  +        nocache = 1;
       }
   
  -    i = ap_proxy_cache_update(c, resp_hdrs, 0, nocache);
  +    if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, 0))
  +        ap_proxy_cache_error(&c);
  +    else
  +        ap_cache_el_data(c, &cachefp);
   
  -    if (i != DECLINED) {
  -	ap_pclosesocket(p, dsock);
  -	ap_bclose(f);
  -	return i;
  +    if (!pasvmode) {        /* wait for connection */
  +        for(;;)
  +        {
  +            switch(ap_accept(&inc, dsock, r->pool))
  +            {
  +            case APR_EINTR:
  +                continue;
  +            case APR_SUCCESS:
  +                break;
  +            default:
  +                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                              "proxy: failed to accept data connection");
  +                ap_close_socket(dsock);
  +                ap_bclose(f);
  +                if (c != NULL) ap_proxy_cache_error(&c);
  +                return HTTP_BAD_GATEWAY;
  +            }
  +        }
  +        data = ap_bcreate(p, B_RDWR);
  +        ap_bpush_iol(f, unix_attach_socket(csd));
       }
  -
  -    if (!pasvmode) {		/* wait for connection */
  -	clen = sizeof(struct sockaddr_in);
  -	do
  -	    csd = accept(dsock, (struct sockaddr *) &server, &clen);
  -	while (csd == -1 && errno == EINTR);
  -	if (csd == -1) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -			 "proxy: failed to accept data connection");
  -	    ap_pclosesocket(p, dsock);
  -	    ap_bclose(f);
  -	    if (c != NULL)
  -		c = ap_proxy_cache_error(c);
  -	    return HTTP_BAD_GATEWAY;
  -	}
  -	ap_note_cleanups_for_socket(p, csd);
  -	data = ap_bcreate(p, B_RDWR | B_SOCKET);
  -	ap_bpushfd(data, csd);
  -    }
       else {
  -	data = ap_bcreate(p, B_RDWR | B_SOCKET);
  -	ap_bpushfd(data, dsock);
  +        data = ap_bcreate(p, B_RDWR);
  +        ap_bpush_iol(data, unix_attach_socket(dsock));
       }
   
   /* send response */
   /* write status line */
       if (!r->assbackwards)
  -	ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
  -    if (c != NULL && c->fp != NULL
  -	&& ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -		"proxy: error writing CRLF to %s", c->tempfile);
  -	    c = ap_proxy_cache_error(c);
  +    ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
  +    if (cachefp    && ap_bvputs(cachefp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error writing CRLF to cache");
  +        ap_proxy_cache_error(&c);
  +        cachefp = NULL;
       }
   
   /* send headers */
  -    tdo.req = r;
  -    tdo.cache = c;
  -    ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
  -
  +    ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
       if (!r->assbackwards)
  -	ap_rputs(CRLF, r);
  -    if (c != NULL && c->fp != NULL && ap_bputs(CRLF, c->fp) == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -	    "proxy: error writing CRLF to %s", c->tempfile);
  -	c = ap_proxy_cache_error(c);
  +        ap_rputs(CRLF, r);
  +    if (cachefp && ap_bputs(CRLF, cachefp) == -1) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error writing CRLF to cache");
  +        ap_proxy_cache_error(&c);
  +        cachefp = NULL;
       }
   
       ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
       r->sent_bodyct = 1;
   /* send body */
       if (!r->header_only) {
  -	if (parms[0] != 'd') {
  -/* we need to set this for ap_proxy_send_fb()... */
  -	    if (c != NULL)
  -		c->cache_completion = 0;
  -	    ap_proxy_send_fb(data, r, c);
  -	} else
  -	    send_dir(data, r, c, cwd);
  +        if (parms[0] != 'd') {
  +            /* we don't need no steekin' cache completion*/
  +            ap_proxy_send_fb(NULL, data, r, c);
  +        } else
  +        send_dir(data, r, c, cwd);
   
  -	if (rc == 125 || rc == 150)
  -	    rc = ftp_getrc(f);
  +    if (rc == 125 || rc == 150)
  +        rc = ftp_getrc(f);
   
  -	/* XXX: we checked for 125||150||226||250 above. This is redundant. */
  -	if (rc != 226 && rc != 250)
  +    /* XXX: we checked for 125||150||226||250 above. This is redundant. */
  +    if (rc != 226 && rc != 250)
               /* XXX: we no longer log an "error writing to c->tempfile" - should we? */
  -	    c = ap_proxy_cache_error(c);
  +        ap_proxy_cache_error(&c);
       }
       else {
   /* abort the transfer */
  -	ap_bputs("ABOR" CRLF, f);
  -	ap_bflush(f);
  -	if (!pasvmode)
  -	    ap_bclose(data);
  -	Explain0("FTP: ABOR");
  +    ap_bputs("ABOR" CRLF, f);
  +    ap_bflush(f);
  +    if (!pasvmode)
  +        ap_bclose(data);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: ABOR");
   /* responses: 225, 226, 421, 500, 501, 502 */
       /* 225 Data connection open; no transfer in progress. */
       /* 226 Closing data connection. */
  @@ -1218,29 +1280,28 @@
       /* 500 Syntax error, command unrecognized. */
       /* 501 Syntax error in parameters or arguments. */
       /* 502 Command not implemented. */
  -	i = ftp_getrc(f);
  -	Explain1("FTP: returned status %d", i);
  +    i = ftp_getrc(f);
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: returned status %d", i);
       }
   
  -    ap_proxy_cache_tidy(c);
  -
   /* finish */
       ap_bputs("QUIT" CRLF, f);
       ap_bflush(f);
  -    Explain0("FTP: QUIT");
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: QUIT");
   /* responses: 221, 500 */
       /* 221 Service closing control connection. */
       /* 500 Syntax error, command unrecognized. */
       i = ftp_getrc(f);
  -    Explain1("FTP: QUIT: status %d", i);
  -
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "FTP: QUIT: status %d", i);
       if (pasvmode)
  -	ap_bclose(data);
  +    ap_bclose(data);
       ap_bclose(f);
  -
  -    ap_rflush(r);	/* flush before garbage collection */
   
  -    ap_proxy_garbage_coll(r);
  +    ap_rflush(r);    /* flush before garbage collection */
   
  +    if(c) ap_proxy_cache_update(c);
       return OK;
   }
  
  
  
  1.8       +205 -254  apache-2.0/src/modules/proxy/proxy_http.c
  
  Index: proxy_http.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/proxy/proxy_http.c,v
  retrieving revision 1.7
  retrieving revision 1.8
  diff -u -r1.7 -r1.8
  --- proxy_http.c	2000/06/09 18:57:14	1.7
  +++ proxy_http.c	2000/06/12 21:41:58	1.8
  @@ -63,6 +63,7 @@
   #include "http_main.h"
   #include "http_core.h"
   #include "util_date.h"
  +#include "iol_socket.h"
   
   /*
    * Canonicalise http-like URLs.
  @@ -82,7 +83,7 @@
       port = def_port;
       err = ap_proxy_canon_netloc(r->pool, &url, NULL, NULL, &host, &port);
       if (err)
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
   
   /* now parse path/search args, according to rfc1738 */
   /* N.B. if this isn't a true proxy request, then the URL _path_
  @@ -90,25 +91,25 @@
    * == r->unparsed_uri, and no others have that property.
    */
       if (r->uri == r->unparsed_uri) {
  -	search = strchr(url, '?');
  -	if (search != NULL)
  -	    *(search++) = '\0';
  +    search = strchr(url, '?');
  +    if (search != NULL)
  +        *(search++) = '\0';
       }
       else
  -	search = r->args;
  +    search = r->args;
   
   /* process path */
       path = ap_proxy_canonenc(r->pool, url, strlen(url), enc_path, r->proxyreq);
       if (path == NULL)
  -	return HTTP_BAD_REQUEST;
  +    return HTTP_BAD_REQUEST;
   
       if (port != def_port)
  -	ap_snprintf(sport, sizeof(sport), ":%d", port);
  +    ap_snprintf(sport, sizeof(sport), ":%d", port);
       else
  -	sport[0] = '\0';
  +    sport[0] = '\0';
   
       r->filename = ap_pstrcat(r->pool, "proxy:", scheme, "://", host, sport, "/",
  -		   path, (search) ? "?" : "", (search) ? search : "", NULL);
  +           path, (search) ? "?" : "", (search) ? search : "", NULL);
       return OK;
   }
    
  @@ -142,17 +143,17 @@
   
       ap_table_unset(headers, "Proxy-Connection");
       if (!next)
  -	return;
  +        return;
   
       while (*next) {
  -	name = next;
  -	while (*next && !ap_isspace(*next) && (*next != ','))
  -	    ++next;
  -	while (*next && (ap_isspace(*next) || (*next == ','))) {
  -	    *next = '\0';
  -	    ++next;
  -	}
  -	ap_table_unset(headers, name);
  +        name = next;
  +        while (*next && !ap_isspace(*next) && (*next != ','))
  +            ++next;
  +        while (*next && (ap_isspace(*next) || (*next == ','))) {
  +            *next = '\0';
  +            ++next;
  +        }
  +        ap_table_unset(headers, name);
       }
       ap_table_unset(headers, "Connection");
   }
  @@ -166,33 +167,34 @@
    * we return DECLINED so that we can try another proxy. (Or the direct
    * route.)
    */
  -int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
  -		       const char *proxyhost, int proxyport)
  +int ap_proxy_http_handler(request_rec *r, ap_cache_el  *c, char *url,
  +               const char *proxyhost, int proxyport)
   {
       const char *strp;
       char *strp2;
       const char *err, *desthost;
  -    int i, j, sock, len, backasswards;
  +    ap_socket_t *sock;
  +    int i, j, len, backasswards, content_length=-1;
       ap_array_header_t *reqhdrs_arr;
       ap_table_t *resp_hdrs;
  -    table_entry *reqhdrs;
  +    ap_table_entry_t *reqhdrs;
       struct sockaddr_in server;
       struct in_addr destaddr;
       struct hostent server_hp;
  -    BUFF *f;
  +    BUFF *f, *cachefp=NULL;
       char buffer[HUGE_STRING_LEN];
       char portstr[32];
       ap_pool_t *p = r->pool;
       const long int zero = 0L;
       int destport = 0;
  +    ap_ssize_t cntr;
       char *destportstr = NULL;
       const char *urlptr = NULL;
  -    const char *datestr;
  -    struct tbl_do_args tdo;
  +    char *datestr, *clen;
   
       void *sconf = r->server->module_config;
       proxy_server_conf *conf =
  -    (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
  +        (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
       struct noproxy_entry *npent = (struct noproxy_entry *) conf->noproxies->elts;
       struct nocache_entry *ncent = (struct nocache_entry *) conf->nocaches->elts;
       int nocache = 0;
  @@ -204,308 +206,259 @@
   
       urlptr = strstr(url, "://");
       if (urlptr == NULL)
  -	return HTTP_BAD_REQUEST;
  +        return HTTP_BAD_REQUEST;
       urlptr += 3;
       destport = DEFAULT_HTTP_PORT;
       strp = strchr(urlptr, '/');
       if (strp == NULL) {
  -	desthost = ap_pstrdup(p, urlptr);
  -	urlptr = "/";
  +        desthost = ap_pstrdup(p, urlptr);
  +        urlptr = "/";
       }
       else {
  -	char *q = ap_palloc(p, strp - urlptr + 1);
  -	memcpy(q, urlptr, strp - urlptr);
  -	q[strp - urlptr] = '\0';
  -	urlptr = strp;
  -	desthost = q;
  +        char *q = ap_palloc(p, strp - urlptr + 1);
  +        memcpy(q, urlptr, strp - urlptr);
  +        q[strp - urlptr] = '\0';
  +        urlptr = strp;
  +        desthost = q;
       }
   
       strp2 = strchr(desthost, ':');
       if (strp2 != NULL) {
  -	*(strp2++) = '\0';
  -	if (ap_isdigit(*strp2)) {
  -	    destport = atoi(strp2);
  -	    destportstr = strp2;
  -	}
  +        *(strp2++) = '\0';
  +        if (ap_isdigit(*strp2)) {
  +            destport = atoi(strp2);
  +            destportstr = strp2;
  +        }
       }
   
   /* check if ProxyBlock directive on this host */
       destaddr.s_addr = ap_inet_addr(desthost);
       for (i = 0; i < conf->noproxies->nelts; i++) {
  -	if ((npent[i].name != NULL && strstr(desthost, npent[i].name) != NULL)
  -	    || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
  -	    return ap_proxyerror(r, HTTP_FORBIDDEN,
  -				 "Connect to remote machine blocked");
  +        if ((npent[i].name != NULL && strstr(desthost, npent[i].name) != NULL)
  +            || destaddr.s_addr == npent[i].addr.s_addr || npent[i].name[0] == '*')
  +            return ap_proxyerror(r, HTTP_FORBIDDEN,
  +                                 "Connect to remote machine blocked");
  +    }
  +
  +    if ((ap_create_tcp_socket(&sock, r->pool)) != APR_SUCCESS) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error creating socket");
  +        return HTTP_INTERNAL_SERVER_ERROR;
       }
   
  +    if (conf->recv_buffer_size > 0 && ap_setsocketopt(sock, APR_SO_RCVBUF,conf->recv_buffer_size)) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
  +    }
  +    
       if (proxyhost != NULL) {
  -	server.sin_port = htons(proxyport);
  -	err = ap_proxy_host2addr(proxyhost, &server_hp);
  -	if (err != NULL)
  -	    return DECLINED;	/* try another */
  +        i = ap_proxy_doconnect(sock, (char *)proxyhost, proxyport, r);
       }
       else {
  -	server.sin_port = htons(destport);
  -	err = ap_proxy_host2addr(desthost, &server_hp);
  -	if (err != NULL)
  -	    return ap_proxyerror(r, HTTP_INTERNAL_SERVER_ERROR, err);
  -    }
  -
  -    sock = ap_psocket(p, PF_INET, SOCK_STREAM, IPPROTO_TCP);
  -    if (sock == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -		    "proxy: error creating socket");
  -	return HTTP_INTERNAL_SERVER_ERROR;
  -    }
  -
  -    if (conf->recv_buffer_size) {
  -	if (setsockopt(sock, SOL_SOCKET, SO_RCVBUF,
  -		       (const char *) &conf->recv_buffer_size, sizeof(int))
  -	    == -1) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -			 "setsockopt(SO_RCVBUF): Failed to set ProxyReceiveBufferSize, using default");
  -	}
  -    }
  -
  -#ifdef SINIX_D_RESOLVER_BUG
  -    {
  -	struct in_addr *ip_addr = (struct in_addr *) *server_hp.h_addr_list;
  -
  -	for (; ip_addr->s_addr != 0; ++ip_addr) {
  -	    memcpy(&server.sin_addr, ip_addr, sizeof(struct in_addr));
  -	    i = ap_proxy_doconnect(sock, &server, r);
  -	    if (i == 0)
  -		break;
  -	}
  -    }
  -#else
  -    j = 0;
  -    while (server_hp.h_addr_list[j] != NULL) {
  -	memcpy(&server.sin_addr, server_hp.h_addr_list[j],
  -	       sizeof(struct in_addr));
  -	i = ap_proxy_doconnect(sock, &server, r);
  -	if (i == 0)
  -	    break;
  -	j++;
  +        i = ap_proxy_doconnect(sock, (char *)desthost, destport, r);
       }
  -#endif
  +
       if (i == -1) {
  -	if (proxyhost != NULL)
  -	    return DECLINED;	/* try again another way */
  -	else
  -            char buf[120];
  -	    return ap_proxyerror(r, HTTP_BAD_GATEWAY, ap_pstrcat(r->pool,
  -				"Could not connect to remote machine: ",
  -				ap_strerror(errno, buf, sizeof(buf)), NULL));
  +        if (proxyhost != NULL)
  +            return DECLINED;    /* try again another way */
  +        else
  +            return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +                ap_pstrcat(r->pool, "Could not connect to remote machine: ",
  +                    strerror(errno), NULL));
       }
   
  -    clear_connection(r->pool, r->headers_in);	/* Strip connection-based headers */
  +    clear_connection(r->pool, r->headers_in);    /* Strip connection-based headers */
   
  -    f = ap_bcreate(p, B_RDWR | B_SOCKET);
  -    ap_bpushfd(f, sock);
  +    f = ap_bcreate(p, B_RDWR);
  +    ap_bpush_iol(f, unix_attach_socket(sock));
   
       ap_bvputs(f, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.0" CRLF,
  -	   NULL);
  +              NULL);
       if (destportstr != NULL && destport != DEFAULT_HTTP_PORT)
  -	ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
  +        ap_bvputs(f, "Host: ", desthost, ":", destportstr, CRLF, NULL);
       else
  -	ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
  +        ap_bvputs(f, "Host: ", desthost, CRLF, NULL);
   
       if (conf->viaopt == via_block) {
  -	/* Block all outgoing Via: headers */
  -	ap_table_unset(r->headers_in, "Via");
  +        /* Block all outgoing Via: headers */
  +        ap_table_unset(r->headers_in, "Via");
       } else if (conf->viaopt != via_off) {
  -	/* Create a "Via:" request header entry and merge it */
  -	i = ap_get_server_port(r);
  -	if (ap_is_default_port(i,r)) {
  -	    strcpy(portstr,"");
  -	} else {
  -	    ap_snprintf(portstr, sizeof portstr, ":%d", i);
  -	}
  -	/* Generate outgoing Via: header with/without server comment: */
  -	ap_table_mergen(r->headers_in, "Via",
  -		    (conf->viaopt == via_full)
  -			? ap_psprintf(p, "%d.%d %s%s (%s)",
  -				HTTP_VERSION_MAJOR(r->proto_num),
  -				HTTP_VERSION_MINOR(r->proto_num),
  -				ap_get_server_name(r), portstr,
  -				SERVER_BASEVERSION)
  -			: ap_psprintf(p, "%d.%d %s%s",
  -				HTTP_VERSION_MAJOR(r->proto_num),
  -				HTTP_VERSION_MINOR(r->proto_num),
  -				ap_get_server_name(r), portstr)
  -			);
  +        /* Create a "Via:" request header entry and merge it */
  +        i = ap_get_server_port(r);
  +        if (ap_is_default_port(i,r)) {
  +            strcpy(portstr,"");
  +        } else {
  +            ap_snprintf(portstr, sizeof portstr, ":%d", i);
  +        }
  +        /* Generate outgoing Via: header with/without server comment: */
  +        ap_table_mergen(r->headers_in, "Via",
  +                        (conf->viaopt == via_full)
  +                        ? ap_psprintf(p, "%d.%d %s%s (%s)",
  +                                      HTTP_VERSION_MAJOR(r->proto_num),
  +                                      HTTP_VERSION_MINOR(r->proto_num),
  +                                      ap_get_server_name(r), portstr,
  +                                      AP_SERVER_BASEVERSION)
  +                        : ap_psprintf(p, "%d.%d %s%s",
  +                                      HTTP_VERSION_MAJOR(r->proto_num),
  +                                      HTTP_VERSION_MINOR(r->proto_num),
  +                                      ap_get_server_name(r), portstr)
  +            );
       }
   
       reqhdrs_arr = ap_table_elts(r->headers_in);
  -    reqhdrs = (table_entry *) reqhdrs_arr->elts;
  +    reqhdrs = (ap_table_entry_t *) reqhdrs_arr->elts;
       for (i = 0; i < reqhdrs_arr->nelts; i++) {
  -	if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL
  -	/* Clear out headers not to send */
  -	    || !strcasecmp(reqhdrs[i].key, "Host")	/* Already sent */
  -	    /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be 
  -	     * suppressed if THIS server requested the authentication,
  -	     * not when a frontend proxy requested it!
  -	     */
  -	    || !strcasecmp(reqhdrs[i].key, "Proxy-Authorization"))
  -	    continue;
  -	ap_bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL);
  +        if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL
  +            /* Clear out headers not to send */
  +            || !strcasecmp(reqhdrs[i].key, "Host")    /* Already sent */
  +            /* XXX: @@@ FIXME: "Proxy-Authorization" should *only* be 
  +             * suppressed if THIS server requested the authentication,
  +             * not when a frontend proxy requested it!
  +             */
  +            || !strcasecmp(reqhdrs[i].key, "Proxy-Authorization"))
  +            continue;
  +        ap_bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL);
       }
   
       ap_bputs(CRLF, f);
   /* send the request data, if any. */
   
       if (ap_should_client_block(r)) {
  -	while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0)
  -	    ap_bwrite(f, buffer, i);
  +        while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0)
  +            ap_bwrite(f, buffer, i, &cntr);
       }
       ap_bflush(f);
   
       len = ap_bgets(buffer, sizeof buffer - 1, f);
       if (len == -1) {
  -	ap_bclose(f);
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -		     "ap_bgets() - proxy receive - Error reading from remote server %s (length %d)",
  -		     proxyhost ? proxyhost : desthost, len);
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  -			     "Error reading from remote server");
  +        ap_bclose(f);
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "ap_bgets() - proxy receive - Error reading from remote server %s (length %d)",
  +                      proxyhost ? proxyhost : desthost, len);
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +                             "Error reading from remote server");
       } else if (len == 0) {
  -	ap_bclose(f);
  -	return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  -			     "Document contains no data");
  +        ap_bclose(f);
  +        return ap_proxyerror(r, HTTP_BAD_GATEWAY,
  +                             "Document contains no data");
       }
   
   /* Is it an HTTP/1 response?  This is buggy if we ever see an HTTP/1.10 */
       if (ap_checkmask(buffer, "HTTP/#.# ###*")) {
  -	int major, minor;
  -	if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
  -	    major = 1;
  -	    minor = 0;
  -	}
  +        int major, minor;
  +        if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) {
  +            major = 1;
  +            minor = 0;
  +        }
   
   /* If not an HTTP/1 message or if the status line was > 8192 bytes */
  -	if (buffer[5] != '1' || buffer[len - 1] != '\n') {
  -	    ap_bclose(f);
  -	    return HTTP_BAD_GATEWAY;
  -	}
  -	backasswards = 0;
  -	buffer[--len] = '\0';
  -
  -	buffer[12] = '\0';
  -	r->status = atoi(&buffer[9]);
  -	buffer[12] = ' ';
  -	r->status_line = ap_pstrdup(p, &buffer[9]);
  +        if (buffer[5] != '1' || buffer[len - 1] != '\n') {
  +            ap_bclose(f);
  +            return HTTP_BAD_GATEWAY;
  +        }
  +        backasswards = 0;
  +        buffer[--len] = '\0';
  +
  +        buffer[12] = '\0';
  +        r->status = atoi(&buffer[9]);
  +        buffer[12] = ' ';
  +        r->status_line = ap_pstrdup(p, &buffer[9]);
   
   /* read the headers. */
   /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */
   /* Also, take care with headers with multiple occurences. */
  -
  -	resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f);
  -	if (resp_hdrs == NULL) {
  -	    ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r->server,
  -		 "proxy: Bad HTTP/%d.%d header returned by %s (%s)",
  -		 major, minor, r->uri, r->method);
  -	    resp_hdrs = ap_make_table(p, 20);
  -	    nocache = 1;    /* do not cache this broken file */
  -	}
  -
  -	if (conf->viaopt != via_off && conf->viaopt != via_block) {
  -	    /* Create a "Via:" response header entry and merge it */
  -	    i = ap_get_server_port(r);
  -	    if (ap_is_default_port(i,r)) {
  -		strcpy(portstr,"");
  -	    } else {
  -		ap_snprintf(portstr, sizeof portstr, ":%d", i);
  -	    }
  -	    ap_table_mergen((table *)resp_hdrs, "Via",
  -			    (conf->viaopt == via_full)
  -			    ? ap_psprintf(p, "%d.%d %s%s (%s)",
  -				major, minor,
  -				ap_get_server_name(r), portstr,
  -				SERVER_BASEVERSION)
  -			    : ap_psprintf(p, "%d.%d %s%s",
  -				major, minor,
  -				ap_get_server_name(r), portstr)
  -			    );
  -	}
  -
  -	clear_connection(p, resp_hdrs);	/* Strip Connection hdrs */
  +        resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f);
  +        if (resp_hdrs == NULL) {
  +            ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
  +                         "proxy: Bad HTTP/%d.%d header returned by %s (%s)",
  +                         major, minor, r->uri, r->method);
  +            nocache = 1;    /* do not cache this broken file */
  +        }
  +        else
  +        {
  +            clear_connection(p, resp_hdrs);    /* Strip Connection hdrs */
  +            ap_cache_el_header_merge(c, resp_hdrs);
  +        }
  +            
  +        if (conf->viaopt != via_off && conf->viaopt != via_block) {
  +            /* Create a "Via:" response header entry and merge it */
  +            i = ap_get_server_port(r);
  +            if (ap_is_default_port(i,r)) {
  +                strcpy(portstr,"");
  +            } else {
  +                ap_snprintf(portstr, sizeof portstr, ":%d", i);
  +            }
  +            ap_cache_el_header_add(c, "Via", (conf->viaopt == via_full)
  +                         ? ap_psprintf(p, "%d.%d %s%s (%s)", major, minor,
  +                                       ap_get_server_name(r), portstr, AP_SERVER_BASEVERSION)
  +                         : ap_psprintf(p, "%d.%d %s%s", major, minor, ap_get_server_name(r), portstr)
  +                );
  +        }
       }
       else {
   /* an http/0.9 response */
  -	backasswards = 1;
  -	r->status = 200;
  -	r->status_line = "200 OK";
  -
  -/* no headers */
  -	resp_hdrs = ap_make_table(p, 20);
  +        backasswards = 1;
  +        r->status = 200;
  +        r->status_line = "200 OK";
       }
   
  -    c->hdrs = resp_hdrs;
  -
  -
   /*
    * HTTP/1.0 requires us to accept 3 types of dates, but only generate
    * one type
    */
  -    if ((datestr = ap_table_get(resp_hdrs, "Date")) != NULL)
  -	ap_table_set(resp_hdrs, "Date", ap_proxy_date_canon(p, datestr));
  -    if ((datestr = ap_table_get(resp_hdrs, "Last-Modified")) != NULL)
  -	ap_table_set(resp_hdrs, "Last-Modified", ap_proxy_date_canon(p, datestr));
  -    if ((datestr = ap_table_get(resp_hdrs, "Expires")) != NULL)
  -	ap_table_set(resp_hdrs, "Expires", ap_proxy_date_canon(p, datestr));
  -
  -    if ((datestr = ap_table_get(resp_hdrs, "Location")) != NULL)
  -	ap_table_set(resp_hdrs, "Location", proxy_location_reverse_map(r, datestr));
  -    if ((datestr = ap_table_get(resp_hdrs, "URI")) != NULL)
  -	ap_table_set(resp_hdrs, "URI", proxy_location_reverse_map(r, datestr));
  +    if (ap_cache_el_header(c, "Date", &datestr) == APR_SUCCESS)
  +        ap_cache_el_header_set(c, "Date", ap_proxy_date_canon(p, datestr));
  +    if (ap_cache_el_header(c, "Last-Modified", &datestr) == APR_SUCCESS)
  +        ap_cache_el_header_set(c, "Last-Modified", ap_proxy_date_canon(p, datestr));
  +    if (ap_cache_el_header(c, "Expires", &datestr) == APR_SUCCESS)
  +        ap_cache_el_header_set(c, "Expires", ap_proxy_date_canon(p, datestr));
  +
  +    if (ap_cache_el_header(c, "Location", &datestr) == APR_SUCCESS)
  +        ap_cache_el_header_set(c, "Location", proxy_location_reverse_map(r, datestr));
  +    if (ap_cache_el_header(c, "URI", &datestr) == APR_SUCCESS)
  +        ap_cache_el_header_set(c, "URI", proxy_location_reverse_map(r, datestr));
   
   /* check if NoCache directive on this host */
  -    for (i = 0; i < conf->nocaches->nelts; i++) {
  -	if ((ncent[i].name != NULL && strstr(desthost, ncent[i].name) != NULL)
  -	    || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
  -	    nocache = 1;
  -    }
  +    if (ap_cache_el_header(c, "Content-Length", &clen) == APR_SUCCESS)
  +        content_length = atoi(clen ? clen : "-1");
   
  -    i = ap_proxy_cache_update(c, resp_hdrs, !backasswards, nocache);
  -    if (i != DECLINED) {
  -	ap_bclose(f);
  -	return i;
  +    for (i = 0; i < conf->nocaches->nelts; i++) {
  +        if ((ncent[i].name != NULL && strstr(desthost, ncent[i].name) != NULL)
  +            || destaddr.s_addr == ncent[i].addr.s_addr || ncent[i].name[0] == '*')
  +            nocache = 1;
       }
   
  +    if(nocache || !ap_proxy_cache_should_cache(r, resp_hdrs, !backasswards))
  +        ap_proxy_cache_error(&c);
  +    else
  +        ap_cache_el_data(c, &cachefp);
  +    
   /* write status line */
       if (!r->assbackwards)
  -	ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
  -    if (c != NULL && c->fp != NULL &&
  -	ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -		"proxy: error writing status line to %s", c->tempfile);
  -	    c = ap_proxy_cache_error(c);
  +        ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
  +    if (cachefp &&    ap_bvputs(cachefp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1) {
  +        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                      "proxy: error writing status line to cache");
  +        ap_proxy_cache_error(&c);
  +        cachefp = NULL;
       }
   
   /* send headers */
  -    tdo.req = r;
  -    tdo.cache = c;
  -    ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
  +    ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
   
       if (!r->assbackwards)
  -	ap_rputs(CRLF, r);
  -    if (c != NULL && c->fp != NULL && ap_bputs(CRLF, c->fp) == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -	    "proxy: error writing CRLF to %s", c->tempfile);
  -	c = ap_proxy_cache_error(c);
  -    }
  +        ap_rputs(CRLF, r);
   
       ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
       r->sent_bodyct = 1;
   /* Is it an HTTP/0.9 respose? If so, send the extra data */
       if (backasswards) {
  -	ap_bwrite(r->connection->client, buffer, len);
  -	if (c != NULL && c->fp != NULL && ap_bwrite(c->fp, buffer, len) != len) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -		"proxy: error writing extra data to %s", c->tempfile);
  -	    c = ap_proxy_cache_error(c);
  -	}
  +        ap_bwrite(r->connection->client, buffer, len, &cntr);
  +        if (cachefp && ap_bwrite(cachefp, buffer, len, &cntr) != len) {
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                          "proxy: error writing extra data to cache", cachefp);
  +            ap_proxy_cache_error(&c);
  +        }
       }
   
   #ifdef CHARSET_EBCDIC
  @@ -516,19 +469,17 @@
       ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
   #endif
   
  -/* send body */
  -/* if header only, then cache will be NULL */
  -/* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
  +    /* send body */
  +    /* if header only, then cache will be NULL */
  +    /* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */
       if (!r->header_only) {
  -/* we need to set this for ap_proxy_send_fb()... */
  -	c->cache_completion = conf->cache.cache_completion;
  -	ap_proxy_send_fb(f, r, c);
  +        proxy_completion pc;
  +        pc.content_length = content_length;
  +        pc.cache_completion = conf->cache_completion;
  +        ap_proxy_send_fb(&pc, f, r, c);
       }
   
  -    ap_proxy_cache_tidy(c);
  -
       ap_bclose(f);
  -
  -    ap_proxy_garbage_coll(r);
  +    if(c) ap_proxy_cache_update(c);
       return OK;
   }
  
  
  
  1.14      +477 -518  apache-2.0/src/modules/proxy/proxy_util.c
  
  Index: proxy_util.c
  ===================================================================
  RCS file: /home/cvs/apache-2.0/src/modules/proxy/proxy_util.c,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- proxy_util.c	2000/04/28 18:27:52	1.13
  +++ proxy_util.c	2000/06/12 21:41:58	1.14
  @@ -62,7 +62,7 @@
   #include "apr_md5.h"
   #include "http_log.h"
   #include "util_uri.h"
  -#include "util_date.h"	/* get ap_checkmask() decl. */
  +#include "util_date.h"    /* get ap_checkmask() decl. */
   
   #include <pthread.h>
   
  @@ -79,20 +79,20 @@
   #ifndef CHARSET_EBCDIC
       ch = x[0];
       if (ap_isdigit(ch))
  -	i = ch - '0';
  +    i = ch - '0';
       else if (ap_isupper(ch))
  -	i = ch - ('A' - 10);
  +    i = ch - ('A' - 10);
       else
  -	i = ch - ('a' - 10);
  +    i = ch - ('a' - 10);
       i <<= 4;
   
       ch = x[1];
       if (ap_isdigit(ch))
  -	i += ch - '0';
  +    i += ch - '0';
       else if (ap_isupper(ch))
  -	i += ch - ('A' - 10);
  +    i += ch - ('A' - 10);
       else
  -	i += ch - ('a' - 10);
  +    i += ch - ('a' - 10);
       return i;
   #else /*CHARSET_EBCDIC*/
       return (1 == sscanf(x, "%2x", &i)) ? os_toebcdic[i&0xFF] : 0;
  @@ -107,15 +107,15 @@
       x[0] = '%';
       i = (ch & 0xF0) >> 4;
       if (i >= 10)
  -	x[1] = ('A' - 10) + i;
  +    x[1] = ('A' - 10) + i;
       else
  -	x[1] = '0' + i;
  +    x[1] = '0' + i;
   
       i = ch & 0x0F;
       if (i >= 10)
  -	x[2] = ('A' - 10) + i;
  +    x[2] = ('A' - 10) + i;
       else
  -	x[2] = '0' + i;
  +    x[2] = '0' + i;
   #else /*CHARSET_EBCDIC*/
       static const char ntoa[] = { "0123456789ABCDEF" };
       ch &= 0xFF;
  @@ -141,8 +141,8 @@
   {
       int i, j, ch;
       char *y;
  -    const char *allowed;	/* characters which should not be encoded */
  -    const char *reserved;	/* characters which much not be en/de-coded */
  +    const char *allowed;    /* characters which should not be encoded */
  +    const char *reserved;    /* characters which much not be en/de-coded */
   
   /* N.B. in addition to :@&=, this allows ';' in an http path
    * and '?' in an ftp path -- this may be revised
  @@ -152,52 +152,52 @@
    * it only permits ; / ? : @ = & as reserved chars.)
    */
       if (t == enc_path)
  -	allowed = "$-_.+!*'(),;:@&=";
  +    allowed = "$-_.+!*'(),;:@&=";
       else if (t == enc_search)
  -	allowed = "$-_.!*'(),;:@&=";
  +    allowed = "$-_.!*'(),;:@&=";
       else if (t == enc_user)
  -	allowed = "$-_.+!*'(),;@&=";
  +    allowed = "$-_.+!*'(),;@&=";
       else if (t == enc_fpath)
  -	allowed = "$-_.+!*'(),?:@&=";
  -    else			/* if (t == enc_parm) */
  -	allowed = "$-_.+!*'(),?/:@&=";
  +    allowed = "$-_.+!*'(),?:@&=";
  +    else            /* if (t == enc_parm) */
  +    allowed = "$-_.+!*'(),?/:@&=";
   
       if (t == enc_path)
  -	reserved = "/";
  +    reserved = "/";
       else if (t == enc_search)
  -	reserved = "+";
  +    reserved = "+";
       else
  -	reserved = "";
  +    reserved = "";
   
       y = ap_palloc(p, 3 * len + 1);
   
       for (i = 0, j = 0; i < len; i++, j++) {
   /* always handle '/' first */
  -	ch = x[i];
  -	if (strchr(reserved, ch)) {
  -	    y[j] = ch;
  -	    continue;
  -	}
  +    ch = x[i];
  +    if (strchr(reserved, ch)) {
  +        y[j] = ch;
  +        continue;
  +    }
   /* decode it if not already done */
  -	if (isenc && ch == '%') {
  -	    if (!ap_isxdigit(x[i + 1]) || !ap_isxdigit(x[i + 2]))
  -		return NULL;
  -	    ch = ap_proxy_hex2c(&x[i + 1]);
  -	    i += 2;
  -	    if (ch != 0 && strchr(reserved, ch)) {	/* keep it encoded */
  -		ap_proxy_c2hex(ch, &y[j]);
  -		j += 2;
  -		continue;
  -	    }
  -	}
  +    if (isenc && ch == '%') {
  +        if (!ap_isxdigit(x[i + 1]) || !ap_isxdigit(x[i + 2]))
  +        return NULL;
  +        ch = ap_proxy_hex2c(&x[i + 1]);
  +        i += 2;
  +        if (ch != 0 && strchr(reserved, ch)) {    /* keep it encoded */
  +        ap_proxy_c2hex(ch, &y[j]);
  +        j += 2;
  +        continue;
  +        }
  +    }
   /* recode it, if necessary */
  -	if (!ap_isalnum(ch) && !strchr(allowed, ch)) {
  -	    ap_proxy_c2hex(ch, &y[j]);
  -	    j += 2;
  -	}
  -	else
  -	    y[j] = ch;
  +    if (!ap_isalnum(ch) && !strchr(allowed, ch)) {
  +        ap_proxy_c2hex(ch, &y[j]);
  +        j += 2;
       }
  +    else
  +        y[j] = ch;
  +    }
       y[j] = '\0';
       return y;
   }
  @@ -214,73 +214,73 @@
    */
   char *
        ap_proxy_canon_netloc(ap_pool_t *p, char **const urlp, char **userp,
  -			char **passwordp, char **hostp, int *port)
  +            char **passwordp, char **hostp, int *port)
   {
       int i;
       char *strp, *host, *url = *urlp;
       char *user = NULL, *password = NULL;
   
       if (url[0] != '/' || url[1] != '/')
  -	return "Malformed URL";
  +    return "Malformed URL";
       host = url + 2;
       url = strchr(host, '/');
       if (url == NULL)
  -	url = "";
  +    url = "";
       else
  -	*(url++) = '\0';	/* skip seperating '/' */
  +    *(url++) = '\0';    /* skip seperating '/' */
   
       /* find _last_ '@' since it might occur in user/password part */
       strp = strrchr(host, '@');
   
       if (strp != NULL) {
  -	*strp = '\0';
  -	user = host;
  -	host = strp + 1;
  +    *strp = '\0';
  +    user = host;
  +    host = strp + 1;
   
   /* find password */
  -	strp = strchr(user, ':');
  -	if (strp != NULL) {
  -	    *strp = '\0';
  -	    password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
  -	    if (password == NULL)
  -		return "Bad %-escape in URL (password)";
  -	}
  -
  -	user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
  -	if (user == NULL)
  -	    return "Bad %-escape in URL (username)";
  +    strp = strchr(user, ':');
  +    if (strp != NULL) {
  +        *strp = '\0';
  +        password = ap_proxy_canonenc(p, strp + 1, strlen(strp + 1), enc_user, 1);
  +        if (password == NULL)
  +        return "Bad %-escape in URL (password)";
       }
  +
  +    user = ap_proxy_canonenc(p, user, strlen(user), enc_user, 1);
  +    if (user == NULL)
  +        return "Bad %-escape in URL (username)";
  +    }
       if (userp != NULL) {
  -	*userp = user;
  +    *userp = user;
       }
       if (passwordp != NULL) {
  -	*passwordp = password;
  +    *passwordp = password;
       }
   
       strp = strrchr(host, ':');
       if (strp != NULL) {
  -	*(strp++) = '\0';
  +    *(strp++) = '\0';
   
  -	for (i = 0; strp[i] != '\0'; i++)
  -	    if (!ap_isdigit(strp[i]))
  -		break;
  -
  -	/* if (i == 0) the no port was given; keep default */
  -	if (strp[i] != '\0') {
  -	    return "Bad port number in URL";
  -	} else if (i > 0) {
  -	    *port = atoi(strp);
  -	    if (*port > 65535)
  -		return "Port number in URL > 65535";
  -	}
  +    for (i = 0; strp[i] != '\0'; i++)
  +        if (!ap_isdigit(strp[i]))
  +        break;
  +
  +    /* if (i == 0) the no port was given; keep default */
  +    if (strp[i] != '\0') {
  +        return "Bad port number in URL";
  +    } else if (i > 0) {
  +        *port = atoi(strp);
  +        if (*port > 65535)
  +        return "Port number in URL > 65535";
  +    }
       }
  -    ap_str_tolower(host);		/* DNS names are case insensitive */
  +    ap_str_tolower(host);        /* DNS names are case insensitive */
       if (*host == '\0')
  -	return "Missing host in URL";
  +    return "Missing host in URL";
   /* check hostname syntax */
       for (i = 0; host[i] != '\0'; i++)
  -	if (!ap_isdigit(host[i]) && host[i] != '.')
  -	    break;
  +    if (!ap_isdigit(host[i]) && host[i] != '.')
  +        break;
       /* must be an IP address */
   #ifdef WIN32
       if (host[i] == '\0' && (inet_addr(host) == -1))
  @@ -288,7 +288,7 @@
       if (host[i] == '\0' && (ap_inet_addr(host) == -1 || inet_network(host) == -1))
   #endif
       {
  -	return "Bad IP address in URL";
  +    return "Bad IP address in URL";
       }
   
   /*    if (strchr(host,'.') == NULL && domain != NULL)
  @@ -319,49 +319,49 @@
       q = strchr(x, ',');
       /* check for RFC 850 date */
       if (q != NULL && q - x > 3 && q[1] == ' ') {
  -	*q = '\0';
  -	for (wk = 0; wk < 7; wk++)
  -	    if (strcmp(x, lwday[wk]) == 0)
  -		break;
  -	*q = ',';
  -	if (wk == 7)
  -	    return x;		/* not a valid date */
  -	if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
  -	    q[17] != ':' || strcmp(&q[20], " GMT") != 0)
  -	    return x;
  -	if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
  -		   &hour, &min, &sec, zone) != 7)
  -	    return x;
  -	if (year < 70)
  -	    year += 2000;
  -	else
  -	    year += 1900;
  +    *q = '\0';
  +    for (wk = 0; wk < 7; wk++)
  +        if (strcmp(x, lwday[wk]) == 0)
  +        break;
  +    *q = ',';
  +    if (wk == 7)
  +        return x;        /* not a valid date */
  +    if (q[4] != '-' || q[8] != '-' || q[11] != ' ' || q[14] != ':' ||
  +        q[17] != ':' || strcmp(&q[20], " GMT") != 0)
  +        return x;
  +    if (sscanf(q + 2, "%u-%3s-%u %u:%u:%u %3s", &mday, month, &year,
  +           &hour, &min, &sec, zone) != 7)
  +        return x;
  +    if (year < 70)
  +        year += 2000;
  +    else
  +        year += 1900;
       }
       else {
   /* check for acstime() date */
  -	if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
  -	    x[16] != ':' || x[19] != ' ' || x[24] != '\0')
  -	    return x;
  -	if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
  -		   &min, &sec, &year) != 7)
  -	    return x;
  -	for (wk = 0; wk < 7; wk++)
  -	    if (strcmp(week, ap_day_snames[wk]) == 0)
  -		break;
  -	if (wk == 7)
  -	    return x;
  +    if (x[3] != ' ' || x[7] != ' ' || x[10] != ' ' || x[13] != ':' ||
  +        x[16] != ':' || x[19] != ' ' || x[24] != '\0')
  +        return x;
  +    if (sscanf(x, "%3s %3s %u %u:%u:%u %u", week, month, &mday, &hour,
  +           &min, &sec, &year) != 7)
  +        return x;
  +    for (wk = 0; wk < 7; wk++)
  +        if (strcmp(week, ap_day_snames[wk]) == 0)
  +        break;
  +    if (wk == 7)
  +        return x;
       }
   
   /* check date */
       for (mon = 0; mon < 12; mon++)
  -	if (strcmp(month, ap_month_snames[mon]) == 0)
  -	    break;
  +    if (strcmp(month, ap_month_snames[mon]) == 0)
  +        break;
       if (mon == 12)
  -	return x;
  +    return x;
   
       q = ap_palloc(p, 30);
       ap_snprintf(q, 30, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", ap_day_snames[wk], mday,
  -		ap_month_snames[mon], year, hour, min, sec);
  +        ap_month_snames[mon], year, hour, min, sec);
       return q;
   }
   
  @@ -416,7 +416,7 @@
            * the next line begins with a continuation character.
            */
       } while (fold && (retval != 1) && (n > 1)
  -                  && (ap_blookc(&next, in) == 1)
  +                  && (next = ap_blookc(in))
                     && ((next == ' ') || (next == '\t')));
   
       return total;
  @@ -430,7 +430,7 @@
    * @@@: XXX: FIXME: currently the headers are passed thru un-merged. 
    * Is that okay, or should they be collapsed where possible?
    */
  -table *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f)
  +ap_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f)
   {
       ap_table_t *resp_hdrs;
       int len;
  @@ -444,71 +444,74 @@
        * the connection closes (EOF), or we timeout.
        */
       while ((len = proxy_getline(buffer, size, f, 1)) > 0) {
  -	
  -	if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */
  +    
  +    if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */
  +
  +        /* Buggy MS IIS servers sometimes return invalid headers
  +         * (an extra "HTTP/1.0 200, OK" line sprinkled in between
  +         * the usual MIME headers). Try to deal with it in a sensible
  +         * way, but log the fact.
  +         * XXX: The mask check is buggy if we ever see an HTTP/1.10 */
  +
  +        if (!ap_checkmask(buffer, "HTTP/#.# ###*")) {
  +        /* Nope, it wasn't even an extra HTTP header. Give up. */
  +        return NULL;
  +        }
   
  -	    /* Buggy MS IIS servers sometimes return invalid headers
  -	     * (an extra "HTTP/1.0 200, OK" line sprinkled in between
  -	     * the usual MIME headers). Try to deal with it in a sensible
  -	     * way, but log the fact.
  -	     * XXX: The mask check is buggy if we ever see an HTTP/1.10 */
  -
  -	    if (!ap_checkmask(buffer, "HTTP/#.# ###*")) {
  -		/* Nope, it wasn't even an extra HTTP header. Give up. */
  -		return NULL;
  -	    }
  -
  -	    ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, r->server,
  -			 "proxy: Ignoring duplicate HTTP header "
  -			 "returned by %s (%s)", r->uri, r->method);
  -	    continue;
  -	}
  +        ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
  +             "proxy: Ignoring duplicate HTTP header "
  +             "returned by %s (%s)", r->uri, r->method);
  +        continue;
  +    }
   
           *value = '\0';
           ++value;
  -	/* XXX: RFC2068 defines only SP and HT as whitespace, this test is
  -	 * wrong... and so are many others probably.
  -	 */
  +    /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
  +     * wrong... and so are many others probably.
  +     */
           while (ap_isspace(*value))
               ++value;            /* Skip to start of value   */
   
  -	/* should strip trailing whitespace as well */
  -	for (end = &value[strlen(value)-1]; end > value && ap_isspace(*end); --end)
  -	    *end = '\0';
  +    /* should strip trailing whitespace as well */
  +    for (end = &value[strlen(value)-1]; end > value && ap_isspace(*end); --end)
  +        *end = '\0';
   
           ap_table_add(resp_hdrs, buffer, value);
   
  -	/* the header was too long; at the least we should skip extra data */
  -	if (len >= size - 1) { 
  -	    while ((len = proxy_getline(field, MAX_STRING_LEN, f, 1))
  -		    >= MAX_STRING_LEN - 1) {
  -		/* soak up the extra data */
  -	    }
  -	    if (len == 0) /* time to exit the larger loop as well */
  -		break;
  -	}
  +    /* the header was too long; at the least we should skip extra data */
  +    if (len >= size - 1) { 
  +        while ((len = proxy_getline(field, MAX_STRING_LEN, f, 1))
  +            >= MAX_STRING_LEN - 1) {
  +        /* soak up the extra data */
  +        }
  +        if (len == 0) /* time to exit the larger loop as well */
  +        break;
  +    }
       }
       return resp_hdrs;
   }
   
  -long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c)
  +long int ap_proxy_send_fb(proxy_completion *completion, BUFF *f, request_rec *r, ap_cache_el  *c)
   {
       int  ok;
       char buf[IOBUFSIZE];
  -    long total_bytes_rcvd;
  +    long total_bytes_rcvd, in_buffer;
  +    proxy_server_conf *conf = (proxy_server_conf *) ap_get_module_config(r->server->module_config, &proxy_module);
  +    ap_ssize_t cntr;
       register int n, o, w;
       conn_rec *con = r->connection;
  -    int alternate_timeouts = 1;	/* 1 if we alternate between soft & hard timeouts */
  -
  +    int alternate_timeouts = 1;    /* 1 if we alternate between soft & hard timeouts */
  +    BUFF *cachefp = NULL;
  +    int written = 0, wrote_to_cache;
  +    
       total_bytes_rcvd = 0;
  -    if (c != NULL)
  -        c->written = 0;
  +    if (c) ap_cache_el_data(c, &cachefp);
   
   #ifdef CHARSET_EBCDIC
       /* The cache copy is ASCII, not EBCDIC, even for text/html) */
       ap_bsetflag(f, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
       if (c != NULL && c->fp != NULL)
  -	ap_bsetflag(c->fp, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
  +        ap_bsetflag(c->fp, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
       ap_bsetflag(con->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
   #endif
   
  @@ -527,7 +530,7 @@
        * BUT, if we *can't* continue anyway, just use hard_timeout.
        */
   
  -    if (c == NULL || c->len <= 0 || c->cache_completion == 1.0) {
  +    if (!completion || completion->content_length > 0 || completion->cache_completion == 1.0) {
           alternate_timeouts = 0;
       }
   #endif
  @@ -536,66 +539,60 @@
        * or (after the client aborted) while we can successfully
        * read and finish the configured cache_completion.
        */
  -     for (ok = 1; ok; ) {
  -	/* Read block from server */
  -	n = ap_bread(f, buf, IOBUFSIZE);
  -
  -	if (n == -1) {		/* input error */
  -	    if (c != NULL) {
  -		ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -		    "proxy: error reading from %s", c->url);
  -		c = ap_proxy_cache_error(c);
  -	    }
  -	    break;
  -	}
  -	if (n == 0)
  -	    break;		/* EOF */
  -	o = 0;
  -	total_bytes_rcvd += n;
  -
  -	/* Write to cache first. */
  -	/*@@@ XXX FIXME: Assuming that writing the cache file won't time out?!!? */
  -        if (c != NULL && c->fp != NULL) {
  -            if (ap_bwrite(c->fp, &buf[0], n) != n) {
  -                ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
  -		    "proxy: error writing to %s", c->tempfile);
  -		c = ap_proxy_cache_error(c);
  -            } else {
  -                c->written += n;
  +    for (ok = 1; ok; cntr=0) {
  +        /* Read block from server */
  +        if(ap_bread(f, buf, IOBUFSIZE, &cntr) != APR_SUCCESS && !cntr)
  +        {
  +            if (c != NULL) {
  +                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                              "proxy: error reading from %s", c->name);
  +                ap_proxy_cache_error(&c);
               }
  +            break;
           }
  -
  -	/* Write the block to the client, detect aborted transfers */
  -        while (!con->aborted && n > 0) {
  -            w = ap_bwrite(con->client, &buf[o], n);
  +        else if(cntr == 0) break;
  +       
  +    
  +        /* Write to cache first. */
  +        /*@@@ XXX FIXME: Assuming that writing the cache file won't time out?!!? */
  +        if (cachefp && ap_bwrite(cachefp, &buf[0], cntr, &wrote_to_cache) != APR_SUCCESS) {
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
  +                          "proxy: error writing to cache");
  +            ap_proxy_cache_error(&c);
  +            cachefp = NULL;
  +        } else {
  +            written += n;
  +        }
   
  -            if (w <= 0) {
  -                if (c != NULL && c->fp != NULL) {
  +        o = 0;
  +        total_bytes_rcvd += cntr;
  +        in_buffer = cntr;
  +
  +        /* Write the block to the client, detect aborted transfers */
  +        while (!con->aborted && in_buffer > 0) {
  +            if (ap_bwrite(con->client, &buf[o], in_buffer, &cntr) != APR_SUCCESS) {
  +                if (completion) {
                       /* when a send failure occurs, we need to decide
                        * whether to continue loading and caching the
                        * document, or to abort the whole thing
                        */
  -                    ok = (c->len > 0) &&
  -                         (c->cache_completion > 0) &&
  -                         (c->len * c->cache_completion < total_bytes_rcvd);
  -
  -                    if (! ok) {
  -                        ap_pclosef(c->req->pool, c->fp->fd);
  -                        c->fp = NULL;
  -                        unlink(c->tempfile);
  -			c = NULL;
  -                    }
  +                    ok = (completion->content_length > 0) &&
  +                        (completion->cache_completion > 0) &&
  +                        (completion->content_length * completion->cache_completion < total_bytes_rcvd);
  +
  +                    if (!ok)
  +                        ap_proxy_cache_error(&c);
                   }
                   con->aborted = 1;
                   break;
               }
  -            n -= w;
  -            o += w;
  +            in_buffer -= cntr;
  +            o += cntr;
           } /* while client alive and more data to send */
       } /* loop and ap_bread while "ok" */
   
       if (!con->aborted)
  -	ap_bflush(con->client);
  +        ap_bflush(con->client);
   
       return total_bytes_rcvd;
   }
  @@ -611,15 +608,15 @@
   {
       int i;
       BUFF *fp = r->connection->client;
  -    table_entry *elts = (table_entry *) ap_table_elts(t)->elts;
  +    ap_table_entry_t *elts = (ap_table_entry_t *) ap_table_elts(t)->elts;
   
       ap_bvputs(fp, respline, CRLF, NULL);
   
       for (i = 0; i < ap_table_elts(t)->nelts; ++i) {
  -	if (elts[i].key != NULL) {
  -	    ap_bvputs(fp, elts[i].key, ": ", elts[i].val, CRLF, NULL);
  -	    ap_table_addn(r->headers_out, elts[i].key, elts[i].val);
  -	}
  +        if (elts[i].key != NULL) {
  +            ap_bvputs(fp, elts[i].key, ": ", elts[i].val, CRLF, NULL);
  +            ap_table_addn(r->headers_out, elts[i].key, elts[i].val);
  +        }
       }
   
       ap_bputs(CRLF, fp);
  @@ -640,127 +637,25 @@
       len = strlen(val);
   
       while (list != NULL) {
  -	p = strchr(list, ',');
  -	if (p != NULL) {
  -	    i = p - list;
  -	    do
  -		p++;
  -	    while (ap_isspace(*p));
  -	}
  -	else
  -	    i = strlen(list);
  -
  -	while (i > 0 && ap_isspace(list[i - 1]))
  -	    i--;
  -	if (i == len && strncasecmp(list, val, len) == 0)
  -	    return 1;
  -	list = p;
  -    }
  -    return 0;
  -}
  -
  -#ifdef CASE_BLIND_FILESYSTEM
  -
  -/*
  - * On some platforms, the file system is NOT case sensitive. So, a == A
  - * need to map to smaller set of characters
  - */
  -void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength)
  -{
  -    ap_md5_ctx_t context;
  -    unsigned char digest[MD5_DIGESTSIZE];
  -    char tmp[26];
  -    int i, k, d;
  -    unsigned int x;
  -    static const char enc_table[32] = "abcdefghijklmnopqrstuvwxyz012345";
  -
  -    ap_MD5Init(&context);
  -    ap_MD5Update(&context, (const unsigned char *) it, strlen(it));
  -    ap_MD5Final(digest, &context);
  -
  -/* encode 128 bits as 26 characters, using a modified uuencoding */
  -/* the encoding is 5 bytes -> 8 characters
  - * i.e. 128 bits is 3 x 5 bytes + 1 byte -> 3 * 8 characters + 2 characters
  - */
  -    for (i = 0, k = 0; i < 15; i += 5) {
  -	x = (digest[i] << 24) | (digest[i + 1] << 16) | (digest[i + 2] << 8) | digest[i + 3];
  -	tmp[k++] = enc_table[x >> 27];
  -	tmp[k++] = enc_table[(x >> 22) & 0x1f];
  -	tmp[k++] = enc_table[(x >> 17) & 0x1f];
  -	tmp[k++] = enc_table[(x >> 12) & 0x1f];
  -	tmp[k++] = enc_table[(x >> 7) & 0x1f];
  -	tmp[k++] = enc_table[(x >> 2) & 0x1f];
  -	x = ((x & 0x3) << 8) | digest[i + 4];
  -	tmp[k++] = enc_table[x >> 5];
  -	tmp[k++] = enc_table[x & 0x1f];
  -    }
  -/* one byte left */
  -    x = digest[15];
  -    tmp[k++] = enc_table[x >> 3];	/* use up 5 bits */
  -    tmp[k++] = enc_table[x & 0x7];
  -    /* now split into directory levels */
  -
  -    for (i = k = d = 0; d < ndepth; ++d) {
  -	memcpy(&val[i], &tmp[k], nlength);
  -	k += nlength;
  -	val[i + nlength] = '/';
  -	i += nlength + 1;
  +    p = strchr(list, ',');
  +    if (p != NULL) {
  +        i = p - list;
  +        do
  +        p++;
  +        while (ap_isspace(*p));
       }
  -    memcpy(&val[i], &tmp[k], 26 - k);
  -    val[i + 26 - k] = '\0';
  -}
  -
  -#else
  -
  -void ap_proxy_hash(const char *it, char *val, int ndepth, int nlength)
  -{
  -    ap_md5_ctx_t context;
  -    unsigned char digest[MD5_DIGESTSIZE];
  -    char tmp[22];
  -    int i, k, d;
  -    unsigned int x;
  -#if defined(AIX) && defined(__ps2__)
  -    /* Believe it or not, AIX 1.x does not allow you to name a file '@',
  -     * so hack around it in the encoding. */
  -    static const char enc_table[64] =
  -	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_%";
  -#else
  -    static const char enc_table[64] =
  -	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
  -#endif
  +    else
  +        i = strlen(list);
   
  -    ap_MD5Init(&context);
  -    ap_MD5Update(&context, (const unsigned char *) it, strlen(it));
  -    ap_MD5Final(digest, &context);
  -
  -/* encode 128 bits as 22 characters, using a modified uuencoding */
  -/* the encoding is 3 bytes -> 4 characters
  - * i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
  - */
  -    for (i = 0, k = 0; i < 15; i += 3) {
  -	x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
  -	tmp[k++] = enc_table[x >> 18];
  -	tmp[k++] = enc_table[(x >> 12) & 0x3f];
  -	tmp[k++] = enc_table[(x >> 6) & 0x3f];
  -	tmp[k++] = enc_table[x & 0x3f];
  -    }
  -/* one byte left */
  -    x = digest[15];
  -    tmp[k++] = enc_table[x >> 2];	/* use up 6 bits */
  -    tmp[k++] = enc_table[(x << 4) & 0x3f];
  -    /* now split into directory levels */
  -
  -    for (i = k = d = 0; d < ndepth; ++d) {
  -	memcpy(&val[i], &tmp[k], nlength);
  -	k += nlength;
  -	val[i + nlength] = '/';
  -	i += nlength + 1;
  +    while (i > 0 && ap_isspace(list[i - 1]))
  +        i--;
  +    if (i == len && strncasecmp(list, val, len) == 0)
  +        return 1;
  +    list = p;
       }
  -    memcpy(&val[i], &tmp[k], 22 - k);
  -    val[i + 22 - k] = '\0';
  +    return 0;
   }
   
  -#endif /* CASE_BLIND_FILESYSTEM */
   
   /*
    * Converts 8 hex digits to a time integer
  @@ -771,19 +666,19 @@
       unsigned int j;
   
       for (i = 0, j = 0; i < 8; i++) {
  -	ch = x[i];
  -	j <<= 4;
  -	if (ap_isdigit(ch))
  -	    j |= ch - '0';
  -	else if (ap_isupper(ch))
  -	    j |= ch - ('A' - 10);
  -	else
  -	    j |= ch - ('a' - 10);
  +    ch = x[i];
  +    j <<= 4;
  +    if (ap_isdigit(ch))
  +        j |= ch - '0';
  +    else if (ap_isupper(ch))
  +        j |= ch - ('A' - 10);
  +    else
  +        j |= ch - ('a' - 10);
       }
       if (j == 0xffffffff)
  -	return -1;		/* so that it works with 8-byte ints */
  +    return -1;        /* so that it works with 8-byte ints */
       else
  -	return j;
  +    return j;
   }
   
   /*
  @@ -795,41 +690,39 @@
       unsigned int j = t;
   
       for (i = 7; i >= 0; i--) {
  -	ch = j & 0xF;
  -	j >>= 4;
  -	if (ch >= 10)
  -	    y[i] = ch + ('A' - 10);
  -	else
  -	    y[i] = ch + '0';
  +    ch = j & 0xF;
  +    j >>= 4;
  +    if (ch >= 10)
  +        y[i] = ch + ('A' - 10);
  +    else
  +        y[i] = ch + '0';
       }
       y[8] = '\0';
   }
   
   
  -cache_req *ap_proxy_cache_error(cache_req *c)
  +void ap_proxy_cache_error(ap_cache_el  **c)
   {
  -    if (c != NULL) {
  -	if (c->fp != NULL) {
  -	    ap_pclosef(c->req->pool, c->fp->fd);
  -	    c->fp = NULL;
  -	}
  -	if (c->tempfile) unlink(c->tempfile);
  +    if (c && *c) {
  +        const char *name = (*c)->name;
  +        ap_cache_el_finalize((*c));
  +        ap_cache_remove((*c)->cache, name);
  +        *c = NULL;
       }
  -    return NULL;
   }
   
   int ap_proxyerror(request_rec *r, int statuscode, const char *message)
   {
       ap_table_setn(r->notes, "error-notes",
  -		  ap_pstrcat(r->pool, 
  -			     "The proxy server could not handle the request "
  -			     "<EM><A HREF=\"", ap_escape_uri(r->pool, r->uri),
  -			     "\">", ap_escape_html(r->pool, r->method),
  -			     "&nbsp;", 
  -			     ap_escape_html(r->pool, r->uri), "</A></EM>.<P>\n"
  -			     "Reason: <STRONG>",
  -			     ap_escape_html(r->pool, message), 
  -			     "</STRONG>", NULL));
  +          ap_pstrcat(r->pool, 
  +                 "The proxy server could not handle the request "
  +                 "<EM><A HREF=\"", ap_escape_uri(r->pool, r->uri),
  +                 "\">", ap_escape_html(r->pool, r->method),
  +                 "&nbsp;", 
  +                 ap_escape_html(r->pool, r->uri), "</A></EM>.<P>\n"
  +                 "Reason: <STRONG>",
  +                 ap_escape_html(r->pool, message), 
  +                 "</STRONG>", NULL));
   
       /* Allow "error-notes" string to be printed by ap_send_error_response() */
       ap_table_setn(r->notes, "verbose-error-to", ap_pstrdup(r->pool, "*"));
  @@ -841,8 +734,7 @@
   /*
    * This routine returns its own error message
    */
  -const char *
  -     ap_proxy_host2addr(const char *host, struct hostent *reqhp)
  +const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp)
   {
       int i;
       struct hostent *hp;
  @@ -853,27 +745,27 @@
       static APACHE_TLS char *charpbuf[2];
   
       for (i = 0; host[i] != '\0'; i++)
  -	if (!ap_isdigit(host[i]) && host[i] != '.')
  -	    break;
  +        if (!ap_isdigit(host[i]) && host[i] != '.')
  +            break;
   
       if (host[i] != '\0') {
  -	hp = gethostbyname(host);
  -	if (hp == NULL)
  -	    return "Host not found";
  +        hp = gethostbyname(host);
  +        if (hp == NULL)
  +            return "Host not found";
       }
       else {
  -	ipaddr = ap_inet_addr(host);
  -	hp = gethostbyaddr((char *) &ipaddr, sizeof(u_long), AF_INET);
  -	if (hp == NULL) {
  -	    memset(&hpbuf, 0, sizeof(hpbuf));
  -	    hpbuf.h_name = 0;
  -	    hpbuf.h_addrtype = AF_INET;
  -	    hpbuf.h_length = sizeof(u_long);
  -	    hpbuf.h_addr_list = charpbuf;
  -	    hpbuf.h_addr_list[0] = (char *) &ipaddr;
  -	    hpbuf.h_addr_list[1] = 0;
  -	    hp = &hpbuf;
  -	}
  +        ipaddr = ap_inet_addr(host);
  +        hp = gethostbyaddr((char *) &ipaddr, sizeof(u_long), AF_INET);
  +        if (hp == NULL) {
  +            memset(&hpbuf, 0, sizeof(hpbuf));
  +            hpbuf.h_name = 0;
  +            hpbuf.h_addrtype = AF_INET;
  +            hpbuf.h_length = sizeof(u_long);
  +            hpbuf.h_addr_list = charpbuf;
  +            hpbuf.h_addr_list[0] = (char *) &ipaddr;
  +            hpbuf.h_addr_list[1] = 0;
  +            hp = &hpbuf;
  +        }
       }
       *reqhp = *hp;
       return NULL;
  @@ -886,24 +778,24 @@
       int port = -1;
   
       if (r->hostname != NULL)
  -	return r->hostname;
  +    return r->hostname;
   
       /* Set url to the first char after "scheme://" */
       if ((url = strchr(r->uri, ':')) == NULL
  -	|| url[1] != '/' || url[2] != '/')
  -	return NULL;
  +    || url[1] != '/' || url[2] != '/')
  +    return NULL;
   
  -    url = ap_pstrdup(r->pool, &url[1]);	/* make it point to "//", which is what proxy_canon_netloc expects */
  +    url = ap_pstrdup(r->pool, &url[1]);    /* make it point to "//", which is what proxy_canon_netloc expects */
   
       err = ap_proxy_canon_netloc(r->pool, &url, &user, &password, &host, &port);
   
       if (err != NULL)
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r,
  -		     "%s", err);
  +    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, r,
  +             "%s", err);
   
       r->hostname = host;
   
  -    return host;		/* ought to return the port, too */
  +    return host;        /* ought to return the port, too */
   }
   
   /* Return TRUE if addr represents an IP address (or an IP network address) */
  @@ -928,86 +820,86 @@
   
       /* Iterate over up to 4 (dotted) quads. */
       for (quads = 0; quads < 4 && *addr != '\0'; ++quads) {
  -	char *tmp;
  +    char *tmp;
   
  -	if (*addr == '/' && quads > 0)	/* netmask starts here. */
  -	    break;
  +    if (*addr == '/' && quads > 0)    /* netmask starts here. */
  +        break;
   
  -	if (!ap_isdigit(*addr))
  -	    return 0;		/* no digit at start of quad */
  +    if (!ap_isdigit(*addr))
  +        return 0;        /* no digit at start of quad */
   
  -	ip_addr[quads] = strtol(addr, &tmp, 0);
  +    ip_addr[quads] = strtol(addr, &tmp, 0);
   
  -	if (tmp == addr)	/* expected a digit, found something else */
  -	    return 0;
  +    if (tmp == addr)    /* expected a digit, found something else */
  +        return 0;
   
  -	if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
  -	    /* invalid octet */
  -	    return 0;
  -	}
  +    if (ip_addr[quads] < 0 || ip_addr[quads] > 255) {
  +        /* invalid octet */
  +        return 0;
  +    }
   
  -	addr = tmp;
  +    addr = tmp;
   
  -	if (*addr == '.' && quads != 3)
  -	    ++addr;		/* after the 4th quad, a dot would be illegal */
  +    if (*addr == '.' && quads != 3)
  +        ++addr;        /* after the 4th quad, a dot would be illegal */
       }
   
       for (This->addr.s_addr = 0, i = 0; i < quads; ++i)
  -	This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
  +    This->addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
   
  -    if (addr[0] == '/' && ap_isdigit(addr[1])) {	/* net mask follows: */
  -	char *tmp;
  +    if (addr[0] == '/' && ap_isdigit(addr[1])) {    /* net mask follows: */
  +    char *tmp;
   
  -	++addr;
  +    ++addr;
   
  -	bits = strtol(addr, &tmp, 0);
  +    bits = strtol(addr, &tmp, 0);
   
  -	if (tmp == addr)	/* expected a digit, found something else */
  -	    return 0;
  +    if (tmp == addr)    /* expected a digit, found something else */
  +        return 0;
   
  -	addr = tmp;
  +    addr = tmp;
   
  -	if (bits < 0 || bits > 32)	/* netmask must be between 0 and 32 */
  -	    return 0;
  +    if (bits < 0 || bits > 32)    /* netmask must be between 0 and 32 */
  +        return 0;
   
       }
       else {
  -	/* Determine (i.e., "guess") netmask by counting the */
  -	/* number of trailing .0's; reduce #quads appropriately */
  -	/* (so that 192.168.0.0 is equivalent to 192.168.)        */
  -	while (quads > 0 && ip_addr[quads - 1] == 0)
  -	    --quads;
  -
  -	/* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
  -	if (quads < 1)
  -	    return 0;
  +    /* Determine (i.e., "guess") netmask by counting the */
  +    /* number of trailing .0's; reduce #quads appropriately */
  +    /* (so that 192.168.0.0 is equivalent to 192.168.)        */
  +    while (quads > 0 && ip_addr[quads - 1] == 0)
  +        --quads;
  +
  +    /* "IP Address should be given in dotted-quad form, optionally followed by a netmask (e.g., 192.168.111.0/24)"; */
  +    if (quads < 1)
  +        return 0;
   
  -	/* every zero-byte counts as 8 zero-bits */
  -	bits = 8 * quads;
  +    /* every zero-byte counts as 8 zero-bits */
  +    bits = 8 * quads;
   
  -	if (bits != 32)		/* no warning for fully qualified IP address */
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +    if (bits != 32)        /* no warning for fully qualified IP address */
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "Warning: NetMask not supplied with IP-Addr; guessing: %s/%ld",
  -		    inet_ntoa(This->addr), bits);
  +            inet_ntoa(This->addr), bits);
       }
   
       This->mask.s_addr = htonl(INADDR_NONE << (32 - bits));
   
       if (*addr == '\0' && (This->addr.s_addr & ~This->mask.s_addr) != 0) {
  -	ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
  -		inet_ntoa(This->addr), bits);
  -	This->addr.s_addr &= This->mask.s_addr;
  -	ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "Warning: NetMask and IP-Addr disagree in %s/%ld\n",
  +        inet_ntoa(This->addr), bits);
  +    This->addr.s_addr &= This->mask.s_addr;
  +    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                        "         Set to %s/%ld",
  -		inet_ntoa(This->addr), bits);
  +        inet_ntoa(This->addr), bits);
       }
   
       if (*addr == '\0') {
  -	This->matcher = proxy_match_ipaddr;
  -	return 1;
  +    This->matcher = proxy_match_ipaddr;
  +    return 1;
       }
       else
  -	return (*addr == '\0');	/* okay iff we've parsed the whole string */
  +    return (*addr == '\0');    /* okay iff we've parsed the whole string */
   }
   
   /* Return TRUE if addr represents an IP address (or an IP network address) */
  @@ -1028,75 +920,75 @@
       memset(ip_addr, '\0', sizeof ip_addr);
   
       if (4 == sscanf(host, "%d.%d.%d.%d", &ip_addr[0], &ip_addr[1], &ip_addr[2], &ip_addr[3])) {
  -	for (addr.s_addr = 0, i = 0; i < 4; ++i)
  -	    addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
  +    for (addr.s_addr = 0, i = 0; i < 4; ++i)
  +        addr.s_addr |= htonl(ip_addr[i] << (24 - 8 * i));
   
  -	if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
  +    if (This->addr.s_addr == (addr.s_addr & This->mask.s_addr)) {
   #if DEBUGGING
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "1)IP-Match: %s[%s] <-> ", host, inet_ntoa(addr));
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "%s/", inet_ntoa(This->addr));
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "%s", inet_ntoa(This->mask));
   #endif
  -	    return 1;
  -	}
  +        return 1;
  +    }
   #if DEBUGGING
  -	else {
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +    else {
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "1)IP-NoMatch: %s[%s] <-> ", host, inet_ntoa(addr));
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "%s/", inet_ntoa(This->addr));
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "%s", inet_ntoa(This->mask));
  -	}
  +    }
   #endif
       }
       else {
  -	struct hostent the_host;
  +    struct hostent the_host;
   
  -	memset(&the_host, '\0', sizeof the_host);
  -	found = ap_proxy_host2addr(host, &the_host);
  +    memset(&the_host, '\0', sizeof the_host);
  +    found = ap_proxy_host2addr(host, &the_host);
   
  -	if (found != NULL) {
  +    if (found != NULL) {
   #if DEBUGGING
  -	    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                            "2)IP-NoMatch: hostname=%s msg=%s", host, found);
   #endif
  -	    return 0;
  -	}
  +        return 0;
  +    }
  +
  +    if (the_host.h_name != NULL)
  +        found = the_host.h_name;
  +    else
  +        found = host;
   
  -	if (the_host.h_name != NULL)
  -	    found = the_host.h_name;
  -	else
  -	    found = host;
  -
  -	/* Try to deal with multiple IP addr's for a host */
  -	for (ip_listptr = the_host.h_addr_list; *ip_listptr; ++ip_listptr) {
  -	    ip_list = (struct in_addr *) *ip_listptr;
  -	    if (This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr)) {
  +    /* Try to deal with multiple IP addr's for a host */
  +    for (ip_listptr = the_host.h_addr_list; *ip_listptr; ++ip_listptr) {
  +        ip_list = (struct in_addr *) *ip_listptr;
  +        if (This->addr.s_addr == (ip_list->s_addr & This->mask.s_addr)) {
   #if DEBUGGING
  -		ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
                          "3)IP-Match: %s[%s] <-> ", found, inet_ntoa(*ip_list));
  -		ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
                          "%s/", inet_ntoa(This->addr));
  -		ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
                          "%s", inet_ntoa(This->mask));
   #endif
  -		return 1;
  -	    }
  +        return 1;
  +        }
   #if DEBUGGING
  -	    else {
  -		ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
  +        else {
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
                          "3)IP-NoMatch: %s[%s] <-> ", found, inet_ntoa(*ip_list));
  -		ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
                          "%s/", inet_ntoa(This->addr));
  -		ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
  +        ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
                          "%s", inet_ntoa(This->mask));
  -	    }
  +        }
   #endif
  -	}
  +    }
       }
   
       return 0;
  @@ -1110,26 +1002,26 @@
   
       /* Domain name must start with a '.' */
       if (addr[0] != '.')
  -	return 0;
  +    return 0;
   
       /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
       for (i = 0; ap_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i)
  -	continue;
  +    continue;
   
   #if 0
       if (addr[i] == ':') {
  -	ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                        "@@@@ handle optional port in proxy_is_domainname()");
  -	/* @@@@ handle optional port */
  +    /* @@@@ handle optional port */
       }
   #endif
   
       if (addr[i] != '\0')
  -	return 0;
  +    return 0;
   
       /* Strip trailing dots */
       for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
  -	addr[i] = '\0';
  +    addr[i] = '\0';
   
       This->matcher = proxy_match_domainname;
       return 1;
  @@ -1141,19 +1033,19 @@
       const char *host = proxy_get_host_of_request(r);
       int d_len = strlen(This->name), h_len;
   
  -    if (host == NULL)		/* some error was logged already */
  -	return 0;
  +    if (host == NULL)        /* some error was logged already */
  +    return 0;
   
       h_len = strlen(host);
   
       /* @@@ do this within the setup? */
       /* Ignore trailing dots in domain comparison: */
       while (d_len > 0 && This->name[d_len - 1] == '.')
  -	--d_len;
  +    --d_len;
       while (h_len > 0 && host[h_len - 1] == '.')
  -	--h_len;
  +    --h_len;
       return h_len > d_len
  -	&& strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
  +    && strncasecmp(&host[h_len - d_len], This->name, d_len) == 0;
   }
   
   /* Return TRUE if addr represents a host name */
  @@ -1165,27 +1057,27 @@
   
       /* Host names must not start with a '.' */
       if (addr[0] == '.')
  -	return 0;
  +    return 0;
   
       /* rfc1035 says DNS names must consist of "[-a-zA-Z0-9]" and '.' */
       for (i = 0; ap_isalnum(addr[i]) || addr[i] == '-' || addr[i] == '.'; ++i);
   
   #if 0
       if (addr[i] == ':') {
  -	ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
  +    ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                        "@@@@ handle optional port in proxy_is_hostname()");
  -	/* @@@@ handle optional port */
  +    /* @@@@ handle optional port */
       }
   #endif
   
       if (addr[i] != '\0' || ap_proxy_host2addr(addr, &host) != NULL)
  -	return 0;
  +    return 0;
   
       This->hostentry = ap_pduphostent (p, &host);
   
       /* Strip trailing dots */
       for (i = strlen(addr) - 1; i > 0 && addr[i] == '.'; --i)
  -	addr[i] = '\0';
  +    addr[i] = '\0';
   
       This->matcher = proxy_match_hostname;
       return 1;
  @@ -1210,17 +1102,17 @@
   
       /* Try to deal with multiple IP addr's for a host */
       for (ip_list = *This->hostentry->h_addr_list; *ip_list != 0UL; ++ip_list)
  -	if (*ip_list == ? ? ? ? ? ? ? ? ? ? ? ? ?)
  -	    return 1;
  +    if (*ip_list == ? ? ? ? ? ? ? ? ? ? ? ? ?)
  +        return 1;
   #endif
   
       /* Ignore trailing dots in host2 comparison: */
       while (h2_len > 0 && host2[h2_len - 1] == '.')
  -	--h2_len;
  +    --h2_len;
       while (h1_len > 0 && host[h1_len - 1] == '.')
  -	--h1_len;
  +    --h1_len;
       return h1_len == h2_len
  -	&& strncasecmp(host, host2, h1_len) == 0;
  +    && strncasecmp(host, host2, h1_len) == 0;
   }
   
   /* Return TRUE if addr is to be matched as a word */
  @@ -1237,24 +1129,32 @@
       return host != NULL && strstr(host, This->name) != NULL;
   }
   
  -int ap_proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r)
  +int ap_proxy_doconnect(ap_socket_t *sock, char *host, ap_uint32_t port, request_rec *r)
   {
       int i;
  +    for (i = 0; host[i] != '\0'; i++)
  +        if (!ap_isdigit(host[i]) && host[i] != '.')
  +            break;
   
  -    do {
  -	i = connect(sock, (struct sockaddr *) addr, sizeof(struct sockaddr_in));
  -#ifdef WIN32
  -	if (i == SOCKET_ERROR)
  -	    errno = WSAGetLastError();
  -#endif /* WIN32 */
  -    } while (i == -1 && errno == EINTR);
  -    if (i == -1) {
  -	ap_log_rerror(APLOG_MARK, APLOG_ERR, r,
  -		     "proxy connect to %s port %d failed",
  -		     inet_ntoa(addr->sin_addr), ntohs(addr->sin_port));
  +    ap_set_remote_port(sock, port);
  +    if (host[i] == '\0') {
  +        ap_set_remote_ipaddr(sock, host);
  +        host = NULL;
       }
  -
  -    return i;
  +    for(;;)
  +    {
  +        switch(ap_connect(sock, host))
  +        {
  +        case APR_EINTR:
  +            continue;
  +        case APR_SUCCESS:
  +            return 0;
  +        default:
  +            ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy connect to %s port %d failed", host, port);
  +            return -1;
  +        }
  +    }
  +    return -1;
   }
   
   /* This function is called by ap_table_do() for all header lines */
  @@ -1262,27 +1162,86 @@
   /* It is passed a table_do_args struct pointer and a MIME field and value pair */
   int ap_proxy_send_hdr_line(void *p, const char *key, const char *value)
   {
  -    struct tbl_do_args *parm = (struct tbl_do_args *)p;
  -
  +    struct request_rec *r = (struct request_rec *)p;
       if (key == NULL || value == NULL || value[0] == '\0')
  -	return 1;
  -    if (!parm->req->assbackwards)
  -	ap_rvputs(parm->req, key, ": ", value, CRLF, NULL);
  -    if (parm->cache != NULL && parm->cache->fp != NULL &&
  -	ap_bvputs(parm->cache->fp, key, ": ", value, CRLF, NULL) == -1) {
  -	    ap_log_rerror(APLOG_MARK, APLOG_ERR, parm->cache->req,
  -		    "proxy: error writing header to %s", parm->cache->tempfile);
  -	    parm->cache = ap_proxy_cache_error(parm->cache);
  -    }
  +        return 1;
  +    if (!r->assbackwards)
  +        ap_rvputs(r, key, ": ", value, CRLF, NULL);
       return 1; /* tell ap_table_do() to continue calling us for more headers */
   }
   
   /* send a text line to one or two BUFF's; return line length */
  -unsigned ap_proxy_bputs2(const char *data, BUFF *client, cache_req *cache)
  +unsigned ap_proxy_bputs2(const char *data, BUFF *client, ap_cache_el  *cache)
   {
       unsigned len = ap_bputs(data, client);
  -    if (cache != NULL && cache->fp != NULL)
  -	ap_bputs(data, cache->fp);
  +    BUFF *cachefp = NULL;
  +    
  +    if (ap_cache_el_data(cache, &cachefp) == APR_SUCCESS)
  +        ap_bputs(data, cachefp);
       return len;
   }
   
  +int ap_proxy_cache_send(request_rec *r, ap_cache_el *c)
  +{
  +    BUFF *cachefp = NULL, *fp = r->connection->client;
  +    char buffer[500];
  +    
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "Sending cache file for %s", c->name);
  +    if(ap_cache_el_data(c, &cachefp) != APR_SUCCESS)
  +        return HTTP_INTERNAL_SERVER_ERROR;
  +    /* send the response */
  +    if(ap_bgets(buffer, sizeof(buffer), cachefp))
  +        ap_bvputs(fp, buffer, NULL);
  +    /* send headers */
  +    ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL);
  +    ap_bputs(CRLF, fp);
  +    /* send data */
  +    if(!r->header_only && !ap_proxy_send_fb(0, cachefp, r, NULL))
  +        return HTTP_INTERNAL_SERVER_ERROR;
  +    return OK;
  +}
  +
  +int ap_proxy_cache_should_cache(request_rec *r, ap_table_t *resp_hdrs, const int is_HTTP1)
  +{
  +    const char *expire = ap_table_get(resp_hdrs, "Expires");
  +    time_t expc;
  +    if (expire != NULL)
  +        expc = ap_parseHTTPdate(expire);
  +    else
  +        expc = BAD_DATE;
  +    if((r->status != HTTP_OK && r->status != HTTP_MOVED_PERMANENTLY && r->status != HTTP_NOT_MODIFIED) ||
  +       (r->status == HTTP_NOT_MODIFIED) ||
  +       r->header_only ||
  +       ap_table_get(r->headers_in, "Authorization") != NULL ||
  +       (expire != NULL && expc == BAD_DATE) ||
  +       (r->status == HTTP_OK && !ap_table_get(resp_hdrs, "Last-Modified") && is_HTTP1))
  +    {
  +        ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                     "proxy: Response is not cacheable: %s", r->unparsed_uri);
  +        return 0;
  +    }
  +    return 1;
  +}
  +    
  +/*
  + * what responses should we not cache?
  + * Unknown status responses and those known to be uncacheable
  + * 304 HTTP_NOT_MODIFIED response when we have no valid cache file, or
  + * 200 HTTP_OK response from HTTP/1.0 and up without a Last-Modified header, or
  + * HEAD requests, or
  + * requests with an Authorization header, or
  + * protocol requests nocache (e.g. ftp with user/password)
  + */
  +/* @@@ XXX FIXME: is the test "r->status != HTTP_MOVED_PERMANENTLY" correct?
  + * or shouldn't it be "ap_is_HTTP_REDIRECT(r->status)" ? -MnKr */
  +int ap_proxy_cache_update(ap_cache_el *c)
  +{
  +    ap_cache_handle_t *h = c ? c->cache : NULL;
  +    if(!h) return DECLINED;
  +    ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
  +                 "proxy: Cache finalized: %s", c->name);
  +    ap_cache_el_finalize(c);
  +    ap_cache_garbage_collect(h);
  +    return DECLINED;
  +}
  
  
  
  1.1                  apache-2.0/src/modules/proxy/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  
  LTLIBRARY_NAME    = libapachemod_proxy.la
  LTLIBRARY_SOURCES = mod_proxy.lo proxy_connect.lo proxy_ftp.lo proxy_http.lo proxy_util.lo
  
  include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.1                  apache-2.0/src/modules/proxy/config.m4
  
  Index: config.m4
  ===================================================================
  dnl modules enabled in this directory by default
  
  dnl AC_DEFUN(modulename, modulestructname, defaultonoroff, configmacros)
  dnl XXX - Need to add help text to --enable-module flags
  dnl XXX - Need to allow --enable-module to fail if optional config fails
  
  AC_DEFUN(APACHE_CHECK_PROXY_MODULE, [
    APACHE_MODULE($1,,,$2,$3,$4)
  ])
  
  APACHE_MODPATH_INIT(proxy)
  
  APACHE_CHECK_PROXY_MODULE(proxy, , yes)
  
  dnl APACHE_CHECK_STANDARD_MODULE(auth_db, , no, [
  dnl   AC_CHECK_HEADERS(db.h)
  dnl   AC_CHECK_LIB(db,main)
  dnl ]) 
  
  dnl APACHE_CHECK_STANDARD_MODULE(usertrack, , no, [
  dnl   AC_CHECK_HEADERS(sys/times.h)
  dnl   AC_CHECK_FUNCS(times)
  dnl ])
  
  APACHE_MODPATH_FINISH
  
  if test "$sharedobjs" = "yes"; then
      LIBS="$LIBS -ldl"
      LTFLAGS="$LTFLAGS -export-dynamic"
  fi
      
  APACHE_SUBST(STANDARD_LIBS)
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/Makefile.in
  
  Index: Makefile.in
  ===================================================================
  
  LTLIBRARY_NAME    = libapachemod_cache.la
  LTLIBRARY_SOURCES = mod_cache.c file_garbage.c file_cache.c cache_util.c
  
  include $(top_srcdir)/build/ltlib.mk
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/cache_util.c
  
  Index: cache_util.c
  ===================================================================
  /* ====================================================================
   * 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 apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <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 "mod_cache.h"
  #include "http_conf_globals.h"
  #include "http_log.h"
  #include "http_main.h"
  #include "apr_md5.h"
  
  int file_cache_get_hdrs(cache_req *cq)
  {
      BUFF *fp;
      if(cq->state & FC_TEMP_FILE && !cq->hdrs)
          cq->hdrs = ap_make_table(cq->el.cache->pool, 20);
      return file_cache_read_hdrs(cq);
  }
  int file_cache_get_data(cache_req *cq)
  {
      if(!cq->fp)
      {
          const char *file = cq->datafile;
          int mode = APR_WRITE | APR_READ | APR_BINARY;
          if(cq->state & FC_TEMP_FILE)
          {
              file = cq->tempfile;
              mode |= APR_CREATE | APR_EXCL;
          }
          if(!file ||
             !(cq->fp = ap_bopenf(cq->el.cache->pool, file, mode, APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD)))
          {
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                           "cache: error opening file %s",
                           file);
              return 0;
          }
      }
      return 1;
  }
  
  /* *** THESE NEXT FUNCTIONS WERE STOLEN FROM MOD_PROXY, PROBABY OUGHT TO PUT
         THESE SOMEWHERE BOTH CAN ACCESS, AND MAINTAIN IN ONE PLACE, NAMES HAVE
         BEEN CHANGED JUST SO I DON'T DEPEND ON MOD_PROXY -
         BUT CAN BE BUILT WITH IT */
  /*
   * Converts ap_time_t hex digits to a time integer
   */
  ap_time_t ap_cache_hex2msec(const char *x)
  {
      int i, ch;
      ap_time_t j;
      for (i = 0, j = 0; i < sizeof(j) * 2; i++) {
          ch = x[i];
          j <<= 4;
          if (ap_isdigit(ch))
              j |= ch - '0';
          else if (ap_isupper(ch))
              j |= ch - ('A' - 10);
          else
              j |= ch - ('a' - 10);
      }
      return j;
  }
  
  /*
   * Converts a time integer to ap_time_t hex digits
   */
  void ap_cache_msec2hex(ap_time_t j, char *y)
  {
      int i, ch;
  
      for (i = (sizeof(j) * 2)-1; i >= 0; i--) {
          ch = j & 0xF;
          j >>= 4;
          if (ch >= 10)
              y[i] = ch + ('A' - 10);
          else
              y[i] = ch + '0';
      }
      y[sizeof(j) * 2] = '\0';
  }
  /* NOTE: This routine is taken from http_protocol::getline()
   * because the old code found in the proxy module was too
   * difficult to understand and maintain.
   */
  /* Get a line of protocol input, including any continuation lines
   * caused by MIME folding (or broken clients) if fold != 0, and place it
   * in the buffer s, of size n bytes, without the ending newline.
   *
   * Returns -1 on error, or the length of s.
   *
   * Note: Because bgets uses 1 char for newline and 1 char for NUL,
   *       the most we can get is (n - 2) actual characters if it
   *       was ended by a newline, or (n - 1) characters if the line
   *       length exceeded (n - 1).  So, if the result == (n - 1),
   *       then the actual input line exceeded the buffer length,
   *       and it would be a good idea for the caller to puke 400 or 414.
   */
  static int cache_getline(char *s, int n, BUFF *in, int fold)
  {
      char *pos, next;
      int retval;
      int total = 0;
  
      pos = s;
  
      do {
          retval = ap_bgets(pos, n, in);     /* retval == -1 if error, 0 if EOF */
  
          if (retval <= 0)
              return ((retval < 0) && (total == 0)) ? -1 : total;
  
          /* retval is the number of characters read, not including NUL      */
  
          n -= retval;            /* Keep track of how much of s is full     */
          pos += (retval - 1);    /* and where s ends                        */
          total += retval;        /* and how long s has become               */
  
          if (*pos == '\n') {     /* Did we get a full line of input?        */
              *pos = '\0';
              --total;
              ++n;
          }
          else
              return total;       /* if not, input line exceeded buffer size */
  
          /* Continue appending if line folding is desired and
           * the last line was not empty and we have room in the buffer and
           * the next line begins with a continuation character.
           */
      } while (fold && (retval != 1) && (n > 1)
                    && (next = ap_blookc(in))
                    && ((next == ' ') || (next == '\t')));
  
      return total;
  }
  
  /* These two functions get and put state information into the data file for an ap_cache_el, this state
     informatino will be read and written transparent to clients of this module */
  static int file_cache_read_mydata(BUFF *fp, cache_req *cq)
  {
       char urlbuff[1034], *strp;
      int len, offset=0;
  
      if(cq->state & FC_READ_MY_DATA || !cq->hdrsfile)
          return 1;
  
      /* read the data from the cache file */
      /* format
       * date SP expire SP count CRLF
       * dates are stored as hex seconds since 1970
       */
      len = ap_bgets(urlbuff, sizeof urlbuff, fp);
      if (len == -1)
          return -1;
      if (len == 0 || urlbuff[len - 1] != '\n')
          return 0;
      urlbuff[len - 1] = '\0';
  
      if (!ap_checkmask(urlbuff, "&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&"))
          return 0;
  
      cq->date = ap_cache_hex2msec(urlbuff + offset);
      offset += (sizeof(cq->date)*2) + 1;
      cq->expire = ap_cache_hex2msec(urlbuff + offset);
      offset += (sizeof(cq->expire)*2) + 1;
      cq->version = ap_cache_hex2msec(urlbuff + offset);
      
      /* check that we have the same URL */
      len = ap_bgets(urlbuff, sizeof urlbuff, fp);
      if (len == -1)
          return 0;
      if (len == 0 || strncmp(urlbuff, "X-NAME: ", 7) != 0 || urlbuff[len - 1] != '\n')
          return 0;
      urlbuff[len - 1] = '\0';
      if (strcmp(urlbuff + 8, cq->el.name) != 0)
          return 0;
      
      cq->state |= FC_READ_MY_DATA;
      return 1;
  }
  
  /*
   * Reads headers from a buffer and returns an array of headers.
   * Returns NULL on file error
   * This routine tries to deal with too long lines and continuation lines.
   * @@@: XXX: FIXME: currently the headers are passed thru un-merged. 
   * Is that okay, or should they be collapsed where possible?
   */
  int file_cache_read_hdrs(cache_req *cq)
  {
      int len;
      char *value, *end;
      char field[MAX_STRING_LEN];
      char buffer[1034];
      BUFF *f;
      if(cq->state & FC_READ_HEADERS)
          return 1;
      
      if(!cq->hdrs) cq->hdrs = ap_make_table(cq->el.cache->pool, 20);
  
      if(!cq->fp && cq->state & FC_TEMP_FILE) {
          cq->state |= FC_READ_HEADERS | FC_READ_MY_DATA; /* done, because there is nothing to be done :) */
          return 1; 
      }
      
      if(!cq->hdrsfile || !(f = ap_bopenf(cq->el.cache->pool, cq->hdrsfile, APR_READ | APR_BINARY, 0)))
          return 0;
      if(!file_cache_read_mydata(f, cq))
      {
          ap_bclose(f);
          return 0;
      }
      
      /*
       * Read header lines until we get the empty separator line, a read error,
       * the connection closes (EOF), or we timeout.
       */
      while ((len = cache_getline(buffer, sizeof(buffer), f, 1)) > 0) {
          if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */
              continue;
          }
  
          *value = '\0';
          ++value;
          /* XXX: RFC2068 defines only SP and HT as whitespace, this test is
           * wrong... and so are many others probably.
           */
          while (ap_isspace(*value))
              ++value;            /* Skip to start of value   */
  
          /* should strip trailing whitespace as well */
          for (end = &value[strlen(value)-1]; end > value && ap_isspace(*end); --end)
              *end = '\0';
  
          ap_table_add(cq->hdrs, buffer, value);
          /* the header was too long; at the least we should skip extra data */
          if (len >= sizeof(buffer) - 1) { 
              while ((len = cache_getline(field, MAX_STRING_LEN, f, 1))
                     >= MAX_STRING_LEN - 1) {
                  /* soak up the extra data */
              }
              if (len == 0) /* time to exit the larger loop as well */
                  break;
          }
      }
      ap_bclose(f);
      cq->state |= FC_READ_HEADERS;
      return 1;
  }
  
  static int file_cache_write_mydata(BUFF *fp, cache_req *cq)
  {
      char buff[sizeof(ap_time_t) * 2];
      cache_server_conf *conf = (cache_server_conf *)
          ap_get_module_config(cq->el.cache->server->module_config, &cache_module);
      ap_time_t now, lmod;
      const char *expire, *lmods;
      char *dates;
  
      if(!cq->hdrs && !file_cache_get_hdrs(cq))
      {
          ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                       "cache: error getting headers for mydata");
          return 0;
      }
  
      now = ap_now();
      /* 1) date generation */
      dates = (char *)ap_table_get(cq->hdrs, "Date");
      if (dates != NULL)
          cq->date = ap_parseHTTPdate(dates);
      if (!dates || cq->date == BAD_DATE) {    /* No, or bad date */
          /* no date header! */
          /* add one; N.B. use the time _now_ rather than when we were checking the cache */
          cq->date = now;
          ap_rfc822_date(dates = ap_palloc(cq->el.cache->pool, AP_RFC822_DATE_LEN), now);
          ap_table_set(cq->hdrs, "Date", dates);
          ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
                       "Added date header");
      }
      /* 2) last mod generation */
      lmods = ap_table_get(cq->hdrs, "Last-Modified");
      if (lmods != NULL) {
          lmod = ap_parseHTTPdate(lmods);
          if (lmod == BAD_DATE) 
              lmods = NULL; /* kill last modified date */
      }
      if(!lmods || (lmod != BAD_DATE && lmod > cq->date))
      {
          lmod = cq->date;
          ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
                       "Last modified is in the future, replacing with now");
      }
      /* 3) expiration generation */
      expire = ap_table_get(cq->hdrs, "Expires");
      if (expire != NULL)
          cq->expire = ap_parseHTTPdate(expire);
      if(!expire || cq->expire == BAD_DATE)
      {
          char buff[20];
          /* so we now have the expiry date */
          /* if no expiry date then
           *   if lastmod
           *      expiry date = now + min((date - lastmod) * factor, maxexpire)
           *   else
           *      expire date = now + defaultexpire
           */
          if (lmod != BAD_DATE) {
              ap_time_t x = ((ap_time_t) conf->lmfactor) * (cq->date - lmod);
              if (x > conf->maxexpire)
                  x = conf->maxexpire;
              cq->expire = now + x;
          }
          else
              cq->expire = now + conf->defaultexpire;
          ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
                           "Expiry date calculated %ld", cq->expire);
      }
  
      ap_cache_msec2hex(cq->date, buff);
      ap_bvputs(fp, buff, " ", NULL);
      ap_cache_msec2hex(cq->expire, buff);
      ap_bvputs(fp, buff, " ", NULL);
      ap_cache_msec2hex(cq->version++, buff);
      ap_bvputs(fp, buff, "\n", NULL);
  
      if (ap_bvputs(fp, "X-NAME: ", cq->el.name, "\n", NULL) == -1) {
          ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                       "cache: error writing (my_data) in cache");
          return 0;
      }
      return 1;
  }
  int file_cache_write_hdrs(cache_req *cq)
  {
      BUFF *fp;
      cache_server_conf *conf = (cache_server_conf *)
          ap_get_module_config(cq->el.cache->server->module_config, &cache_module);
  
      if(cq->state & FC_READ_HEADERS || cq->state & FC_READ_MY_DATA)
      {
          if(!cq->hdrsfile) cq->hdrsfile = header_file(cq->el.cache, cq->el.name);
          if(unlink(cq->hdrsfile)) /* if we can remove it, we clearly don't have to build the dirs */
              mkdir_structure(cq->hdrsfile, conf->root);
          if(!(fp = ap_bopenf(cq->el.cache->pool, cq->hdrsfile, APR_WRITE | APR_CREATE | APR_BINARY | APR_EXCL,
                              APR_UREAD | APR_UWRITE | APR_GREAD | APR_WREAD))) {
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                           "cache: error creating cache header file %s",
                           cq->hdrsfile);
              return errno;
          }
          if(cq->state & FC_READ_MY_DATA)
              file_cache_write_mydata(fp, cq);
          if(cq->hdrs)
          {
              int i;
              ap_table_entry_t *elts = (ap_table_entry_t *) ap_table_elts(cq->hdrs)->elts;
              for (i = 0; i < ap_table_elts(cq->hdrs)->nelts; ++i) {
                  if (elts[i].key != NULL) {
                      ap_bvputs(fp, elts[i].key, ": ", elts[i].val, CRLF, NULL);
                  }
              }
          }
          ap_bclose(fp); /* flush and close */
      }
      return 1;
  }
  
  int mkdir_structure(char *file, const char *root)
  {
      int rootlen = root ? strlen(root) : 0;
      char *p;
      for (p = file + rootlen + 1;;) {
          p = strchr(p, '/');
          if (!p)
              break;
          *p = '\0';
  #ifdef WIN32
          if (mkdir(file) < 0 && errno != EEXIST)
  #elif defined(__TANDEM)
              if (mkdir(file, S_IRWXU | S_IRWXG | S_IRWXO) < 0 && errno != EEXIST)
  #else
                  if (mkdir(file, S_IREAD | S_IWRITE | S_IEXEC) < 0 && errno != EEXIST)
  #endif /* WIN32 */
                      ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
                                   "cache: error creating cache directory %s",
                                   file);
          *p = '/';
          ++p;
      }
      return 1;
  }
  
  /* ********* FIGURES OUT FILENAMES FOR CACHE_ELEMENT */
  #ifdef CASE_BLIND_FILESYSTEM
  /*
   * On some platforms, the file system is NOT case sensitive. So, a == A
   * need to map to smaller set of characters
   */
  static void ap_cache_hash(const char *it, char *val, int ndepth, int nlength)
  {
      ap_md5_ctx_t context;
      unsigned char digest[16];
      char tmp[26];
      int i, k, d;
      unsigned int x;
      static const char enc_table[32] = "abcdefghijklmnopqrstuvwxyz012345";
  
      ap_MD5Init(&context);
      ap_MD5Update(&context, (const unsigned char *) it, strlen(it));
      ap_MD5Final(digest, &context);
  
  /* encode 128 bits as 26 characters, using a modified uuencoding */
  /* the encoding is 5 bytes -> 8 characters
   * i.e. 128 bits is 3 x 5 bytes + 1 byte -> 3 * 8 characters + 2 characters
   */
      for (i = 0, k = 0; i < 15; i += 5) {
      x = (digest[i] << 24) | (digest[i + 1] << 16) | (digest[i + 2] << 8) | digest[i + 3];
      tmp[k++] = enc_table[x >> 27];
      tmp[k++] = enc_table[(x >> 22) & 0x1f];
      tmp[k++] = enc_table[(x >> 17) & 0x1f];
      tmp[k++] = enc_table[(x >> 12) & 0x1f];
      tmp[k++] = enc_table[(x >> 7) & 0x1f];
      tmp[k++] = enc_table[(x >> 2) & 0x1f];
      x = ((x & 0x3) << 8) | digest[i + 4];
      tmp[k++] = enc_table[x >> 5];
      tmp[k++] = enc_table[x & 0x1f];
      }
  /* one byte left */
      x = digest[15];
      tmp[k++] = enc_table[x >> 3];    /* use up 5 bits */
      tmp[k++] = enc_table[x & 0x7];
      /* now split into directory levels */
  
      for (i = k = d = 0; d < ndepth; ++d) {
      memcpy(&val[i], &tmp[k], nlength);
      k += nlength;
      val[i + nlength] = '/';
      i += nlength + 1;
      }
      memcpy(&val[i], &tmp[k], 26 - k);
      val[i + 26 - k] = '\0';
  }
  
  #else
  static void ap_cache_hash(const char *it, char *val, int ndepth, int nlength)
  {
      ap_md5_ctx_t context;
      unsigned char digest[16];
      char tmp[22];
      int i, k, d;
      unsigned int x;
  #if defined(AIX) && defined(__ps2__)
      /* Believe it or not, AIX 1.x does not allow you to name a file '@',
       * so hack around it in the encoding. */
      static const char enc_table[64] =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_%";
  #else
      static const char enc_table[64] =
      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_@";
  #endif
  
      ap_MD5Init(&context);
      ap_MD5Update(&context, (const unsigned char *) it, strlen(it));
      ap_MD5Final(digest, &context);
  
  /* encode 128 bits as 22 characters, using a modified uuencoding */
  /* the encoding is 3 bytes -> 4 characters
   * i.e. 128 bits is 5 x 3 bytes + 1 byte -> 5 * 4 characters + 2 characters
   */
      for (i = 0, k = 0; i < 15; i += 3) {
      x = (digest[i] << 16) | (digest[i + 1] << 8) | digest[i + 2];
      tmp[k++] = enc_table[x >> 18];
      tmp[k++] = enc_table[(x >> 12) & 0x3f];
      tmp[k++] = enc_table[(x >> 6) & 0x3f];
      tmp[k++] = enc_table[x & 0x3f];
      }
  /* one byte left */
      x = digest[15];
      tmp[k++] = enc_table[x >> 2];    /* use up 6 bits */
      tmp[k++] = enc_table[(x << 4) & 0x3f];
      /* now split into directory levels */
  
      for (i = k = d = 0; d < ndepth; ++d) {
      memcpy(&val[i], &tmp[k], nlength);
      k += nlength;
      val[i + nlength] = '/';
      i += nlength + 1;
      }
      memcpy(&val[i], &tmp[k], 22 - k);
      val[i + 22 - k] = '\0';
  }
  
  #endif /* CASE_BLIND_FILESYSTEM */
  static char *generate_name(ap_cache_handle_t *h, const char *name)
  {
      char hashfile[66], *filebase;
      cache_server_conf *conf = (cache_server_conf *)    ap_get_module_config(h->server->module_config, &cache_module);
      ap_cache_hash(name, hashfile, conf->dirlevels, conf->dirlength);
      filebase = ap_pstrcat(h->pool, conf->root, "/", hashfile, "%s", NULL);
      return filebase;
  }
  char *header_file(ap_cache_handle_t *h, const char *name)
  {
      return ap_psprintf(h->pool, generate_name(h, name), CACHE_HEADER_SUFFIX);
  }
  char *data_file(ap_cache_handle_t *h, const char *name)
  {
      return ap_psprintf(h->pool, generate_name(h, name), CACHE_DATA_SUFFIX);
  }
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/config.m4
  
  Index: config.m4
  ===================================================================
  dnl modules enabled in this directory by default
  
  dnl AC_DEFUN(modulename, modulestructname, defaultonoroff, configmacros)
  dnl XXX - Need to add help text to --enable-module flags
  dnl XXX - Need to allow --enable-module to fail if optional config fails
  
  AC_DEFUN(APACHE_CHECK_CACHE_MODULE, [
    APACHE_MODULE($1,,,$2,$3,$4)
  ])
  
  APACHE_MODPATH_INIT(file_cache)
  
  APACHE_CHECK_CACHE_MODULE(cache, , yes)
  
  dnl APACHE_CHECK_STANDARD_MODULE(auth_db, , no, [
  dnl   AC_CHECK_HEADERS(db.h)
  dnl   AC_CHECK_LIB(db,main)
  dnl ]) 
  
  dnl APACHE_CHECK_STANDARD_MODULE(usertrack, , no, [
  dnl   AC_CHECK_HEADERS(sys/times.h)
  dnl   AC_CHECK_FUNCS(times)
  dnl ])
  
  APACHE_MODPATH_FINISH
  
  if test "$sharedobjs" = "yes"; then
      LIBS="$LIBS -ldl"
      LTFLAGS="$LTFLAGS -export-dynamic"
  fi
      
  APACHE_SUBST(STANDARD_LIBS)
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/file_cache.c
  
  Index: file_cache.c
  ===================================================================
  /* ====================================================================
   * 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 apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <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 "mod_cache.h"
  #include "http_conf_globals.h"
  #include "http_log.h"
  #include "http_main.h"
  
  #if defined(ULTRIX_BRAIN_DEATH) || defined(SINIX_D_RESOLVER_BUG)
  extern char *mktemp(char *template);
  #endif 
  
  static cache_req *create_cache_el(ap_cache_handle_t *h, const char *name)
  {
      cache_req *cq = ap_pcalloc(h->pool, sizeof(cache_req));
      memset(cq, '\0', sizeof(cache_req));
      cq->el.cache = h;
      cq->el.name = name;
      cq->state = FC_READ_NONE;
      return cq;
  }
  
  ap_status_t file_cache_element(ap_cache_handle_t *h, const char *name, ap_cache_el **el_in,
                                 ap_cache_query flag)
  {
      cache_server_conf *conf = (cache_server_conf *) ap_get_module_config(h->server->module_config, &cache_module);
  
      switch(flag)
      {
      case AP_CACHE_CREATE:
      {
          cache_req *cq = create_cache_el(h, name);
  
          *el_in = NULL;
          cq->state |= FC_TEMP_FILE;
          /* open temporary file */
  #define TMPFILESTR    "/tmpXXXXXX"
          if (conf->root == NULL)
              return errno;
          cq->tempfile = ap_pstrcat(h->pool, conf->root, TMPFILESTR, NULL);
  #undef TMPFILESTR
          if(!mktemp(cq->tempfile))
              return errno;
          (*el_in) = (ap_cache_el*)cq;
          return APR_SUCCESS;
      }
      case AP_CACHE_SEEK:
      {
          BUFF *fp;
          ap_status_t ret = APR_ENOENT;
          char *data = data_file(h, name);
          *el_in = NULL;
          if(fp = ap_bopenf(h->pool, data, APR_WRITE | APR_READ | APR_BINARY, 0))
          {
              cache_req *cq = create_cache_el(h, name);
              cq->fp = fp;
              cq->datafile = data;
              cq->hdrsfile = header_file(h, name);
              if(file_cache_read_hdrs(cq))
              {
                  ap_time_t now = ap_now();
                  if(cq->expire > now)
                  {
                      (*el_in) = (ap_cache_el *)cq;
                      ret = APR_SUCCESS;
                  }
                  else
                  {
                      ap_log_error(APLOG_MARK, APLOG_ERR, 0, h->server,
                                   "cache: cache entry has expired, seek failed");
                  }
              }
          }
          else if(errno == APR_EACCES)
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, h->server,
                           "cache: cache entry couldn't be opened, perhaps permission error");
          return ret;
      }
      case AP_CACHE_REMOVE:
      {
          ap_status_t ret = APR_SUCCESS;
          char *data = data_file(h, name);
          char *hdrs = header_file(h, name);
          
          if(unlink(data) == -1)
          {
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, h->server,
                           "cache: error deleting data file %s", data);
              ret = errno;
          }
          if(unlink(hdrs) == -1)
          {
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, h->server,
                           "cache: error deleting header file %s", hdrs);
              ret = errno;
          }
          return ret;
      }
      default:
          break;
      }
      
      return APR_ENOTIMPL;
  }
  
  ap_status_t file_cache_el_final(ap_cache_el *el)
  {
      cache_req *cq = (cache_req *)el;
      cache_server_conf *conf = (cache_server_conf *)
          ap_get_module_config(cq->el.cache->server->module_config, &cache_module);
      
      /* write headers */
      file_cache_write_hdrs(cq);
      
      /* move the data over */
      if(cq->state & FC_TEMP_FILE && cq->fp)
      {
          if(!cq->datafile) cq->datafile = data_file(cq->el.cache, cq->el.name);
          if(unlink(cq->datafile)) /* if we can remove it, we clearly don't have to build the dirs */
              mkdir_structure(cq->datafile, conf->root);
  
  #if defined(OS2) || defined(WIN32)         /* Under OS/2 use rename. */
          if (rename(cq->tempfile, cq->datafile) == -1)
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, el->cache->server,
                           "proxy: error renaming cache file %s to %s",
                           c->tempfile, cq->datafile);
  #else
          if (link(cq->tempfile, cq->datafile) == -1)
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, el->cache->server,
                           "proxy: error linking cache file %s to %s",
                           cq->tempfile, cq->datafile);
          if (unlink(cq->tempfile) == -1)
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, el->cache->server,
                           "proxy: error deleting temp file %s", cq->tempfile);
  #endif
      }
      if(cq->fp)
          ap_bclose(cq->fp); /* if you finalize, you are done writing, so close it */
  
      memset(el, '\0', sizeof(ap_cache_el)); /* clear it out, for the sake of clarity */
      return APR_SUCCESS;
  }
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/file_garbage.c
  
  Index: file_garbage.c
  ===================================================================
  /* ====================================================================
   * 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 apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <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.
   */
  
  /* everything garbagearific */
  
  #include "mod_cache.h"
  #ifdef WIN32
  #include <sys/utime.h>
  #else
  #include <utime.h>
  #endif /* WIN32 */
  #include <pthread.h>
  #include "http_log.h"
  #include "http_main.h"
  
  #ifndef O_BINARY
  #define O_BINARY 0
  #endif
  
  /* I use this instead of HUGE_STRING_LEN because I can probably come up with a better calculated
     number, and I'd rather mark with this so I can come back and FIXME. */
  #define LARGE_FILE_NAME HUGE_STRING_LEN
  
  /* Poor man's 61 bit arithmetic */
  typedef struct {
      long lower;    /* lower 30 bits of result */
      long upper; /* upper 31 bits of result */
  } long61_t;
  
  struct gc_ent {
      unsigned long int len;
      ap_time_t expire;
      char base[LARGE_FILE_NAME];
  };
  
  /* FIXME: The block size can be different on a `per file system' base.
   * This would make automatic detection highly OS specific.
   * In the GNU fileutils code for du(1), you can see how complicated it can
   * become to detect the block size. And, with BSD-4.x fragments, it
   * it even more difficult to get precise results.
   * As a compromise (and to improve on the incorrect counting of cache
   * size on byte level, omitting directory sizes entirely, which was
   * used up to apache-1.3b7) we're rounding to multiples of 512 here.
   * Your file system may be using larger blocks (I certainly hope so!)
   * but it will hardly use smaller blocks.
   * (So this approximation is still closer to reality than the old behavior).
   * The best solution would be automatic detection, the next best solution
   * IMHO is a sensible default and the possibility to override it.
   */
  
  #define ROUNDUP2BLOCKS(_bytes) (((_bytes)+block_size-1) & ~(block_size-1))
  static long block_size = 512;    /* this must be a power of 2 */
  static long61_t curbytes, cachesize;
  static ap_time_t garbage_now, garbage_expire;
  static pthread_mutex_t garbage_mutex = PTHREAD_MUTEX_INITIALIZER;
  
  
  static int sub_garbage_coll(ap_cache_handle_t *r, ap_array_header_t *files,
                  const char *cachedir, const char *cachesubdir);
  static void help_cache_garbage_coll(struct ap_cache_handle_t *r);
  static int should_cache_garbage_coll(struct ap_cache_handle_t *r);
  #if !defined(WIN32) && !defined(MPE) && !defined(OS2)
  static void detached_cache_garbage_coll(ap_cache_handle_t *r);
  #endif
  
  ap_status_t file_cache_gc(ap_cache_handle_t *r)
  {
      static int inside = 0;
  
      (void) pthread_mutex_lock(&garbage_mutex);
      if (inside == 1) {
      (void) pthread_mutex_unlock(&garbage_mutex);
      return;
      }
      else
      inside = 1;
      (void) pthread_mutex_unlock(&garbage_mutex);
  
      if (should_cache_garbage_coll(r))
  #if !defined(WIN32) && !defined(MPE) && !defined(OS2) 
          detached_cache_garbage_coll(r);
  #else
          help_cache_garbage_coll(r);
  #endif
  
      (void) pthread_mutex_lock(&garbage_mutex);
      inside = 0;
      (void) pthread_mutex_unlock(&garbage_mutex);
      return APR_SUCCESS;
  }
  
  
  static void
  add_long61 (long61_t *accu, long val)
  {
      /* Add in lower 30 bits */
      accu->lower += (val & 0x3FFFFFFFL);
      /* add in upper bits, and carry */
      accu->upper += (val >> 30) + ((accu->lower & ~0x3FFFFFFFL) != 0L);
      /* Clear carry */
      accu->lower &= 0x3FFFFFFFL;
  }
  
  static void
  sub_long61 (long61_t *accu, long val)
  {
      int carry = (val & 0x3FFFFFFFL) > accu->lower;
      /* Subtract lower 30 bits */
      accu->lower = accu->lower - (val & 0x3FFFFFFFL) + ((carry) ? 0x40000000 : 0);
      /* add in upper bits, and carry */
      accu->upper -= (val >> 30) + carry;
  }
  
  /* Compare two long61's:
   * return <0 when left < right
   * return  0 when left == right
   * return >0 when left > right
   */
  static long
  cmp_long61 (long61_t *left, long61_t *right)
  {
      return (left->upper == right->upper) ? (left->lower - right->lower)
                       : (left->upper - right->upper);
  }
  
  /* Compare two gc_ent's, sort them by expiration date */
  static int gcdiff(const void *ap, const void *bp)
  {
      const struct gc_ent *a = (const struct gc_ent * const) ap;
      const struct gc_ent *b = (const struct gc_ent * const) bp;
  
      if (a->expire > b->expire)
          return 1;
      else if (a->expire < b->expire)
          return -1;
      else
          return 0;
  }
  
  #if !defined(WIN32) && !defined(MPE) && !defined(OS2)
  static void detached_cache_garbage_coll(ap_cache_handle_t *r)
  {
      pid_t pid;
      int status;
      pid_t pgrp;
  
  #if 0
      ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
               "cache: Guess what; we fork() again...");
  #endif
      switch (pid = fork()) {
      case -1:
          ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
               "cache: fork() for cache cleanup failed");
          return;
  
      case 0:    /* Child */
  
          /* close all sorts of things, including the socket fd */
          ap_cleanup_for_exec();
  
          /* Fork twice to disassociate from the child */
          switch (pid = fork()) {
          case -1:
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
               "cache: fork(2nd) for cache cleanup failed");
              exit(1);
  
          case 0:    /* Child */
              /* The setpgrp() stuff was snarfed from http_main.c */
  #ifndef NO_SETSID
              if ((pgrp = setsid()) == -1) {
              perror("setsid");
              ap_log_error(APLOG_MARK, 0, APLOG_STARTUP | APLOG_NOERRNO,  0, NULL, "%s: setsid failed",
                       ap_server_argv0);
              exit(1);
              }
  #elif defined(NEXT) || defined(NEWSOS)
              if (setpgrp(0, getpid()) == -1 || (pgrp = getpgrp(0)) == -1) {
              perror("setpgrp");
              ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, "%S: setpgrp or getpgrp failed",
                       ap_server_argv0);
              exit(1);
              }
  #else
              if ((pgrp = setpgrp(getpid(), 0)) == -1) {
              perror("setpgrp");
              ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 
                                       NULL, "%s: setpgrp failed",
                       ap_server_argv0);
              exit(1);
              }
  #endif
              help_cache_garbage_coll(r);
              exit(0);
  
          default:    /* Father */
              /* After grandson has been forked off, */
              /* there's nothing else to do. */
              exit(0);            
          }
      default:
          /* Wait until grandson has been forked off */
          /* (without wait we'd leave a zombie) */
          waitpid(pid, &status, 0);
          return;
      }
  }
  #endif /* ndef WIN32 */
  
  #define DOT_TIME "/.time"    /* marker */
  
  static int should_cache_garbage_coll(ap_cache_handle_t *r)
  {
      cache_server_conf *conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module);
      const char *cachedir = conf->root;
      char *filename;
      struct stat buf;
      int timefd;
      ap_time_t every = conf->gcinterval;
      static ap_time_t lastcheck = BAD_DATE;         /* static (per-process) data!!! */
  
      if (cachedir == NULL || every == -1)
          return 0;
  
      filename = ap_palloc(r->pool, strlen(cachedir) + strlen( DOT_TIME ) +1);
  
      garbage_now = ap_now();
      /* Usually, the modification time of <cachedir>/.time can only increase.
       * Thus, even with several child processes having their own copy of
       * lastcheck, if time(NULL) still < lastcheck then it's not time
       * for GC yet.
       */
      if (garbage_now != -1 && lastcheck != BAD_DATE && garbage_now < lastcheck + every)
          return 0;
  
  
      strcpy(filename, cachedir);
      strcat(filename, DOT_TIME);
  
      /* At this point we have a bit of an engineering compromise. We could either
       * create and/or mark the .time file  (prior to the fork which might
       * fail on a resource issue) or wait until we are safely forked. The
       * advantage of doing it now in this process is that we get some
       * usefull live out of the global last check variable. (XXX which
       * should go scoreboard IMHO.) Note that the actual counting is 
       * at a later moment.
       */
      if (stat(filename, &buf) == -1) {        /* does not exist */
          if (errno != ENOENT) {
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                           "cache: stat(%s)", filename);
              return 0;
          }
          if ((timefd = creat(filename, 0666)) == -1) {
              if (errno != EEXIST)
                  ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                               "cache: creat(%s)", filename);
              else
                  lastcheck = garbage_now;        /* someone else got in there */
              return 0;
          }
          close(timefd);
      }
      else {
          lastcheck = buf.st_mtime * AP_USEC_PER_SEC;        /* save the time */
          if (garbage_now < lastcheck + every) {
              return 0;
          }
          if (utime(filename, NULL) == -1)
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                           "cache: utimes(%s)", filename);
      }
  
      return 1;
  }
  
  static void help_cache_garbage_coll(ap_cache_handle_t *r)
  {
      const char *cachedir;
      cache_server_conf *conf = (cache_server_conf *) ap_get_module_config(r->server->module_config, &cache_module);
      ap_array_header_t *files;
      struct gc_ent *fent;
      char filename[LARGE_FILE_NAME];
      int i;
  
      cachedir = conf->root;
      /* configured size is given in kB. Make it bytes, convert to long61_t: */
      cachesize.lower = cachesize.upper = 0;
      add_long61(&cachesize, conf->space << 10);
  
      files = ap_make_array(r->pool, 100, sizeof(struct gc_ent));
      curbytes.upper = curbytes.lower = 0L;
  
      sub_garbage_coll(r, files, cachedir, "/");
  
      if (cmp_long61(&curbytes, &cachesize) < 0L) {
          ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                       "cache GC: Cache is %ld%% full (nothing deleted)",
                       (long)(((curbytes.upper<<20)|(curbytes.lower>>10))*100/conf->space));
          return;
      }
  
      /* sort the files we found by expiration date */
      qsort(files->elts, files->nelts, sizeof(struct gc_ent), gcdiff);
  
      for (i = 0; i < files->nelts; i++) {
          fent = &((struct gc_ent *) files->elts)[i];
          sprintf(filename, "%s%s%s", cachedir, fent->base, CACHE_HEADER_SUFFIX);
          ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                       "GC Unlinking %s (expiry %ld, garbage_now %ld)", filename, fent->expire, garbage_now);
  #if TESTING
          ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                       "Would unlink %s", filename);
  #else
          if (unlink(filename) == -1) {
              if (errno != ENOENT)
                  ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                               "cache gc: unlink(%s)", filename);
          }
  #endif
  
          sprintf(filename, "%s%s%s", cachedir, fent->base, CACHE_DATA_SUFFIX);
  #if TESTING
          ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL, 
                       "Would unlink %s", filename);
  #else
          if (unlink(filename) == -1) {
              if (errno != ENOENT)
                  ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                               "cache gc: unlink(%s)", filename);
          }
  #endif
  
          sub_long61(&curbytes, ROUNDUP2BLOCKS(fent->len));
          if (cmp_long61(&curbytes, &cachesize) < 0)
              break;
      }
      ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, r->server,
                   "cache GC: Cache is %ld%% full (%d deleted)",
                   (long)(((curbytes.upper<<20)|(curbytes.lower>>10))*100/conf->space), i);
  }
  
  static int sub_garbage_coll(ap_cache_handle_t *r, ap_array_header_t *files,
                const char *cachebasedir, const char *cachesubdir)
  {
      char line[27];
      char cachedir[HUGE_STRING_LEN];
      struct stat buf;
      int fd, i, hdrfile;
      DIR *dir;
  #if defined(NEXT) || defined(WIN32)
      struct DIR_TYPE *ent;
  #else
      struct dirent *ent;
  #endif
      struct gc_ent *fent;
      int nfiles = 0;
      const int basedirlen = strlen(cachebasedir);
      char *filename, basename[LARGE_FILE_NAME], *s;
  
      ap_snprintf(cachedir, sizeof(cachedir), "%s%s", cachebasedir, cachesubdir);
      filename = ap_palloc(r->pool, strlen(cachedir) + HASH_LEN + 2);
      ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
                   "GC Examining directory %s", cachedir);
      dir = opendir(cachedir);
      if (dir == NULL) {
          ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                       "cache gc: opendir(%s)", cachedir);
          return 0;
      }
  
      while ((ent = readdir(dir)) != NULL) {
          if (ent->d_name[0] == '.')
              continue;
          sprintf(filename, "%s%s", cachedir, ent->d_name);
          ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
                       "GC Examining file %s", filename);
  /* is it a temporary file? */
          if (strncmp(ent->d_name, "tmp", 3) == 0) {
  /* then stat it to see how old it is; delete temporary files > 1 day old */
              if (stat(filename, &buf) == -1) {
                  if (errno != ENOENT)
                      ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                                   "cache gc: stat(%s)", filename);
              }
              else if (garbage_now != -1 &&
                       (buf.st_atime*AP_USEC_PER_SEC) < garbage_now - MSEC_ONE_DAY &&
                       (buf.st_mtime*AP_USEC_PER_SEC) < garbage_now - MSEC_ONE_DAY) {
                  ap_log_error(APLOG_MARK, APLOG_DEBUG|APLOG_NOERRNO, 0, NULL,
                               "GC unlink %s", filename);
                  ap_log_error(APLOG_MARK, APLOG_INFO|APLOG_NOERRNO, 0, r->server,
                               "cache gc: deleting orphaned cache file %s", filename);
  #if TESTING
                  ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 
                               NULL, "Would unlink %s", filename);
  #else
                  unlink(filename);
  #endif
              }
              continue;
          }
          ++nfiles;
  /* under OS/2 use dirent's d_attr to identify a diretory */
  #ifdef OS2
  /* is it a directory? */
          if (ent->d_attr & A_DIR) {
              char newcachedir[HUGE_STRING_LEN];
              ap_snprintf(newcachedir, sizeof(newcachedir),
                          "%s%s/", cachesubdir, ent->d_name);
              if (!sub_garbage_coll(r, files, cachebasedir, newcachedir)) {
                  ap_snprintf(newcachedir, sizeof(newcachedir),
                              "%s%s", cachedir, ent->d_name);
  #if TESTING
                  ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 
                               NULL, "Would remove directory %s", newcachedir);
  #else
                  rmdir(newcachedir);
  #endif
                  --nfiles;
              }
              continue;
          }
  #endif
  
  /* read the file */
          fd = open(filename, O_RDONLY | O_BINARY);
          if (fd == -1) {
              if (errno != ENOENT)
                  ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                               "cache gc: open(%s)", filename);
              continue;
          }
          if (fstat(fd, &buf) == -1) {
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                           "cache gc: fstat(%s)", filename);
              close(fd);
              continue;
          }
  
  /* In OS/2 this has already been done above */
  #ifndef OS2
          if (S_ISDIR(buf.st_mode)) {
              char newcachedir[HUGE_STRING_LEN];
              close(fd);
              ap_snprintf(newcachedir, sizeof(newcachedir),
                          "%s%s/", cachesubdir, ent->d_name);
              if (!sub_garbage_coll(r, files, cachebasedir, newcachedir)) {
                  ap_snprintf(newcachedir, sizeof(newcachedir),
                              "%s%s", cachedir, ent->d_name);
  #if TESTING
                  ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 
                               NULL, "Would remove directory %s", newcachedir);
  #else
                  rmdir(newcachedir);
  #endif
                  --nfiles;
              } else {
                  /* Directory is not empty. Account for its size: */
                  add_long61(&curbytes, ROUNDUP2BLOCKS(buf.st_size));
              }
              continue;
          }
  #endif
          /* this is ugly, however I must correspond a header file with a cache file,
             the separate files make writing easier, however GC is nastier */
          if((hdrfile = ((s = strstr(filename, CACHE_HEADER_SUFFIX)) != NULL)) ||
             (s = strstr(filename, CACHE_DATA_SUFFIX)))
          {
              int got_both = 0, baselen = (s - filename);
              ap_cpystrn(basename, filename + basedirlen, (baselen-basedirlen)+1);
          
              for(i = 0; i < files->nelts; i++)
                  if(!strcmp(((struct gc_ent *)files->elts + i)->base, basename))
                  {
                      got_both = -1; /* this is to flag file I already knew about */
                      break;
                  }
              if(got_both == -1) continue;
              
              if(hdrfile)
              {
                   struct stat data_buf;
                  char data_file[LARGE_FILE_NAME];
                  ap_snprintf(data_file, sizeof(data_file), "%s%s%s", cachebasedir, basename, CACHE_DATA_SUFFIX);
                  if(((got_both = stat(data_file, &data_buf) != -1)))
                      buf.st_size += data_buf.st_size;
              }
              else
              {
                  struct stat hdr_buf;
                  char hdr_file[LARGE_FILE_NAME];
                  close(fd);
                  ap_snprintf(hdr_file, sizeof(hdr_file), "%s%s%s", cachebasedir, basename, CACHE_HEADER_SUFFIX);
                  if((got_both = ((fd = open(hdr_file, O_RDONLY | O_BINARY)) != -1) && fstat(fd, &hdr_buf) != -1))
                      buf.st_size += hdr_buf.st_size;
              }
              if(!got_both)
              {
                  ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
                               "cache: deleting rogue cache file: %s", filename);
  #if TESTING
                  ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, NULL,
                               "Would unlink rogue file %s", filename);
  #else
                  unlink(filename);
  #endif
                  continue;
              }
          }
          else
          {
              ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
                           "cache: unknown cache file: %s", filename);
  #if TESTING
              ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 
                           NULL, "Would unlink unknown file %s", filename);
  #else
              unlink(filename);
  #endif
              continue;
          }
  
          /* now read the info */
          i = read(fd, line, 26);
          close(fd);
          if (i == -1)
              ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server,
                           "cache gc: read(%s)", filename);
          if (!ap_checkmask(line, "&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&"))
              if((garbage_expire = ap_cache_hex2msec(line + (sizeof(garbage_expire)*2)))== BAD_DATE)
                  continue;
              /* bad file */
              if (garbage_now != -1 &&
                  (buf.st_atime*AP_USEC_PER_SEC) > garbage_now + MSEC_ONE_DAY &&
                  (buf.st_mtime*AP_USEC_PER_SEC) > garbage_now + MSEC_ONE_DAY) {
                  ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server,
                               "cache: deleting bad cache file with future date: %s", filename);
  #if TESTING
                  ap_log_error(APLOG_MARK, APLOG_STARTUP | APLOG_NOERRNO, 0, 
                               NULL, "Would unlink bad file %s", filename);
  #else
                  unlink(filename);
  #endif
                  continue;
              }
          /*
           * we need to calculate an 'old' factor, and remove the 'oldest' files
           * so that the space requirement is met; sort by the expires date of the
           * file.
           *
           */
          fent = (struct gc_ent *) ap_push_array(files);
          fent->len = buf.st_size;
          fent->expire = garbage_expire;
          strcpy(fent->base, basename);
  
      /* accumulate in blocks, to cope with directories > 4Gb */
          add_long61(&curbytes, ROUNDUP2BLOCKS(fent->len));
      }
      closedir(dir);
      return nfiles;
  }
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/mod_cache.c
  
  Index: mod_cache.c
  ===================================================================
  /* ====================================================================
   * 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 apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <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 "mod_cache.h"
  
  #define CORE_PRIVATE
  
  #include "http_log.h"
  
  ap_status_t file_cache_close(ap_cache_handle_t *h)
  {
      ap_destroy_pool(h->pool);
      return APR_SUCCESS;
  }
  ap_status_t file_cache_el_hdr_walk(ap_cache_el *el, 
                                     int (*comp)(void *, const char *, const char *), void *rec, va_list args)
  {
      cache_req *cq = (cache_req *)el;
      if(!cq->hdrs && !file_cache_get_hdrs(cq))
          return errno;
      ap_table_vdo(comp, rec, cq->hdrs, args);
      return APR_SUCCESS;
  }
  ap_status_t file_cache_el_hdr(ap_cache_el *el, const char *name, const char *val, ap_cache_query flag)
  {
      cache_req *cq = (cache_req *)el;
  
      if(!cq->hdrs && !file_cache_get_hdrs(cq))
          return errno;
      switch(flag)
      {
      case AP_CACHE_CREATE:
          ap_table_add(cq->hdrs, name, val);
          break;
      case AP_CACHE_CHANGE:
          ap_table_set(cq->hdrs, name, val);
          break;
      case AP_CACHE_REMOVE:
          ap_table_unset(cq->hdrs, name);
          break;
      default:
          return APR_BADARG;
      }
      return APR_SUCCESS;
  }
  ap_status_t file_cache_el_data(ap_cache_el *el, BUFF **b)
  {
      cache_req *cq = (cache_req *)el;
      *b = NULL;
      if(!cq->fp && !file_cache_get_data(cq))
          return errno;
      *b = cq->fp;
      return APR_SUCCESS;
  }
  ap_status_t file_cache_reset(ap_cache_el *el, ap_cache_part f)
  {
      cache_req *cq = (cache_req *)el;
      if(f == AP_CACHE_DATA && cq->fp)
      {
          cq->state &= ~FC_READ_MY_DATA; /* re-read my data later */
          ap_bclose(cq->fp);
          cq->fp = NULL;
      }
      else if(f == AP_CACHE_HEADER && cq->hdrs)
      {
          cq->state &= ~FC_READ_HEADERS; /* re-read headers later */
          cq->hdrs = NULL; 
      }
      return APR_SUCCESS;
  }
          
  /* module hook and callback setup */
  static ap_status_t cache_init(ap_cache_handle_t **h, const char *desc, server_rec *server)
  {
      ap_pool_t *my_pool;
      ap_cache_handle_t *han;
  
      if(!h) return APR_BADARG;
  
      ap_create_pool(&my_pool, server->process->pool);
      han = (*h) = ap_pcalloc(my_pool, sizeof(ap_cache_handle_t));
      
      memset(han, '\0', sizeof(ap_cache_handle_t));
      han->pool = my_pool;
      han->server = server;
      han->meth.cache_garbage_coll = file_cache_gc; /* file_garbage.c */
      han->meth.cache_element = file_cache_element; /* file_cache.c */
      han->meth.cache_el_final = file_cache_el_final; /* file_cache.c */
      han->meth.cache_close = file_cache_close; /* here */
      han->meth.cache_el_header_walk = file_cache_el_hdr_walk; /* here */
      han->meth.cache_el_hdr = file_cache_el_hdr; /* here */
      han->meth.cache_el_data = file_cache_el_data; /* here */
      han->meth.cache_el_reset = file_cache_reset; /* here */
  
      return APR_SUCCESS;
  }
  
  
  /* -------------------------------------------------------------- */
  /* Setup configurable data */
  
  static void *create_cache_config(ap_pool_t *p, server_rec *s)
  {
      cache_server_conf *ps = ap_pcalloc(p, sizeof(cache_server_conf));
      ps->root = NULL;
      ps->space = DEFAULT_CACHE_SPACE;
      ps->maxexpire = DEFAULT_CACHE_MAXEXPIRE;
      ps->defaultexpire = DEFAULT_CACHE_EXPIRE;
      ps->lmfactor = DEFAULT_CACHE_LMFACTOR;
      ps->gcinterval = -1;
      /* at these levels, the cache can have 2^18 directories (256,000)  */
      ps->dirlevels = 3;
      ps->dirlength = 1;
      return ps;
  }
  
  
  static const char
  *set_cache_size(cmd_parms *parms, char *struct_ptr, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
      int val;
  
      if (sscanf(arg, "%d", &val) != 1)
      return "CacheSize value must be an integer (kBytes)";
      psf->space = val;
      return NULL;
  }
  
  static const char
  *set_cache_root(cmd_parms *parms, void *dummy, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
  
      psf->root = ap_server_root_relative(parms->pool, arg);
  
      return NULL;
  }
  
  static const char
  *set_cache_factor(cmd_parms *parms, void *dummy, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
      double val;
  
      if (sscanf(arg, "%lg", &val) != 1)
          return "CacheLastModifiedFactor value must be a float";
      psf->lmfactor = val;
  
      return NULL;
  }
  
  static const char
  *set_cache_maxex(cmd_parms *parms, void *dummy, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
      double val;
  
      if (sscanf(arg, "%lg", &val) != 1)
          return "CacheMaxExpire value must be a float";
      psf->maxexpire = (ap_time_t) (val * MSEC_ONE_HR);
      return NULL;
  }
  
  static const char
  *set_cache_defex(cmd_parms *parms, void *dummy, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
      double val;
  
      if (sscanf(arg, "%lg", &val) != 1)
          return "CacheDefaultExpire value must be a float";
      psf->defaultexpire = (ap_time_t) (val * MSEC_ONE_HR);
      return NULL;
  }
  
  static const char
  *set_cache_gcint(cmd_parms *parms, void *dummy, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
      double val;
  
      if (sscanf(arg, "%lg", &val) != 1)
          return "CacheGcInterval value must be a float";
      psf->gcinterval = (ap_time_t) (val * (double) MSEC_ONE_HR);
      return NULL;
  }
  
  static const char
  *set_cache_dirlevels(cmd_parms *parms, char *struct_ptr, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
      int val;
  
      val = atoi(arg);
      if (val < 1)
          return "CacheDirLevels value must be an integer greater than 0";
      if (val * psf->dirlength > CACHEFILE_LEN)
      return "CacheDirLevels*CacheDirLength value must not be higher than 20";
      psf->dirlevels = val;
      return NULL;
  }
  
  static const char
  *set_cache_dirlength(cmd_parms *parms, char *struct_ptr, char *arg)
  {
      cache_server_conf *psf = ap_get_module_config(parms->server->module_config, &cache_module);
      int val;
  
      val = atoi(arg);
      if (val < 1)
          return "CacheDirLength value must be an integer greater than 0";
      if (val * psf->dirlevels > CACHEFILE_LEN)
          return "CacheDirLevels*CacheDirLength value must not be higher than 20";
      psf->dirlength = val;
      return NULL;
  }
  
  static const command_rec cache_cmds[] =
  {
      {"CacheRoot", set_cache_root, NULL, RSRC_CONF, TAKE1,
       "The directory to store cache files"},
      {"CacheSize", set_cache_size, NULL, RSRC_CONF, TAKE1,
       "The maximum disk space used by the cache in Kb"},
      {"CacheMaxExpire", set_cache_maxex, NULL, RSRC_CONF, TAKE1,
       "The maximum time in hours to cache a document"},
      {"CacheDefaultExpire", set_cache_defex, NULL, RSRC_CONF, TAKE1,
       "The default time in hours to cache a document"},
      {"CacheLastModifiedFactor", set_cache_factor, NULL, RSRC_CONF, TAKE1,
       "The factor used to estimate Expires date from LastModified date"},
      {"CacheGcInterval", set_cache_gcint, NULL, RSRC_CONF, TAKE1,
       "The interval between garbage collections, in hours"},
      {"CacheDirLevels", set_cache_dirlevels, NULL, RSRC_CONF, TAKE1,
       "The number of levels of subdirectories in the cache"},
      {"CacheDirLength", set_cache_dirlength, NULL, RSRC_CONF, TAKE1,
       "The number of characters in subdirectory names"},
      {NULL}
  };
  
  static void
  register_hooks(void)
  {
      /* cache initializer */
      ap_hook_cache_init(cache_init, NULL, NULL, AP_HOOK_FIRST);
  }
  
  module MODULE_VAR_EXPORT cache_module =
  {
      STANDARD20_MODULE_STUFF,
      NULL,            /* create per-directory config structure */
      NULL,            /* merge per-directory config structures */
      create_cache_config,    /* create per-server config structure */
      NULL,            /* merge per-server config structures */
      cache_cmds,            /* command ap_table_t */
      NULL,            /* handlers */
      register_hooks
  };
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/mod_cache.h
  
  Index: mod_cache.h
  ===================================================================
  /* ====================================================================
   * 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 apache@apache.org.
   *
   * 5. Products derived from this software may not be called "Apache",
   *    nor may "Apache" appear in their name, without prior written
   *    permission of the Apache Software Foundation.
   *
   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   * ====================================================================
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Apache Software Foundation.  For more
   * information on the Apache Software Foundation, please see
   * <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.
   */
  
  #ifndef MOD_CACHE_H
  #define MOD_CACHE_H 
  
  #include <sys/stat.h>
  #include "ap_cache.h"
  
  /*
   * Main include file for the Apache proxy
   */
  
  /*
  
     Note that the Explain() stuff is not yet complete.
     Also note numerous FIXMEs and CHECKMEs which should be eliminated.
  
     If TESTING is set, then garbage collection doesn't delete ... probably a good
     idea when hacking.
  
     This code is still experimental!
  
     Things to do:
  
     1. Make it garbage collect in the background, not while someone is waiting
        for a response!
  
     2. Check the logic thoroughly.
  
     3. Empty directories are only removed the next time round (but this does
        avoid two passes). Consider doing them the first time round.
  
     Ben Laurie <be...@algroup.co.uk> 30 Mar 96
  
     More things to do:
  
     0. Code cleanup (ongoing)
  
     1. add 230 response output for ftp now that it works
  
     2. Make the ftp proxy transparent, also same with (future) gopher & wais
  
     3. Use protocol handler struct a la Apache module handlers (Dirk van Gulik)
  
     4. Use a cache expiry database for more efficient GC (Jeremy Wohl)
  
     5. Bulletproof GC against SIGALRM
  
     Chuck Murcko <ch...@topsail.org> 15 April 1997
  
   */
  
  #define TESTING 0
  
  #include "httpd.h"
  #include "http_config.h"
  #include "http_protocol.h"
  #include "util_date.h"
  
  extern module MODULE_VAR_EXPORT cache_module;
  
  /* number of characters in the hash */
  #define HASH_LEN (22*2)
  
  /* maximum  'CacheDirLevels*CacheDirLength' value */
  #define CACHEFILE_LEN 20    /* must be less than HASH_LEN/2 */
  
  #ifdef CHARSET_EBCDIC
  #define CRLF   "\r\n"
  #else /*CHARSET_EBCDIC*/
  #define CRLF   "\015\012"
  #endif /*CHARSET_EBCDIC*/
  
  #define CACHE_HEADER_SUFFIX ".header"
  #define CACHE_DATA_SUFFIX ".data"
  
  #define    MSEC_ONE_DAY        ((ap_time_t)(86400*AP_USEC_PER_SEC))    /* one day, in microseconds */
  #define    MSEC_ONE_HR        ((ap_time_t)(3600*AP_USEC_PER_SEC))    /* one hour, in microseconds */
  
  #define DEFAULT_CACHE_SPACE 5
  #define DEFAULT_CACHE_MAXEXPIRE MSEC_ONE_DAY
  #define DEFAULT_CACHE_EXPIRE    MSEC_ONE_HR
  #define DEFAULT_CACHE_LMFACTOR (0.1)
  
  /* static information about the local cache */
  typedef struct {
      const char *root;           /* the location of the cache directory */
      off_t space;                /* Maximum cache size (in 1024 bytes) */
      ap_time_t maxexpire;        /* Maximum time to keep cached files in msecs */
      ap_time_t defaultexpire;    /* default time to keep cached file in msecs */
      double lmfactor;            /* factor for estimating expires date */
      ap_time_t gcinterval;       /* garbage collection interval, in msec */
      int dirlevels;              /* Number of levels of subdirectories */
      int dirlength;              /* Length of subdirectory names */
  } cache_server_conf;
  
  /* caching information about a request */
  enum read_states { FC_READ_NONE=0x00, FC_READ_MY_DATA=0x01, FC_READ_HEADERS=0x02, FC_TEMP_FILE=0x04 };
  typedef struct {
      ap_cache_el el;
      char *tempfile;          /* name of the temporary file, used for cache
                                  element creation */
  
      /* states and gc states */
      char state;
      ap_time_t expire;        /* calculated expire date of cached entity */
      ap_time_t date;          /* the date the cached file was last touched */
      int version;             /* update count of the file */
  
      /* names of files */
      char *datafile;          /* where the data will go */
      char *hdrsfile;          /* where the hdrs will go */
  
      /* stuff the API uses */
      ap_table_t *hdrs;        /* the HTTP headers of the file */
      BUFF *fp;                /* the cache file descriptors */
  } cache_req;
  
  /* in file_garbage.c */
  ap_status_t file_cache_gc(ap_cache_handle_t *r);
  
  /* in file_cache.c */
  ap_status_t file_cache_element(ap_cache_handle_t *h, const char *name, ap_cache_el **el_in, ap_cache_query flag);
  ap_status_t file_cache_el_final(ap_cache_el *el);
  
  /* in cache_util.c */
  char *header_file(ap_cache_handle_t *h, const char *name); /* generate hdrsfile */
  int file_cache_write_hdrs(cache_req *el); /* write headers to file */
  int file_cache_read_hdrs(cache_req *el); /* read headers from file */
  int file_cache_get_hdrs(cache_req *el); /* prepare el's hdrs */
  char *data_file(ap_cache_handle_t *h, const char *name); /* generate datafile */
  int file_cache_get_data(cache_req *el); /* prepare el's fp */
  int mkdir_structure(char *file, const char *root);
  
  #endif
  
  
  
  1.1                  apache-2.0/src/modules/file_cache/modules.mk
  
  Index: modules.mk
  ===================================================================
  libapachemod_cache.la: mod_cache.lo
  	$(LINK) mod_cache.lo
  static =  libapachemod_cache.la
  shared =