You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by ma...@hyperreal.org on 1998/08/16 22:21:30 UTC

cvs commit: apache-1.3/src/modules/proxy mod_proxy.c mod_proxy.h proxy_cache.c proxy_connect.c proxy_ftp.c proxy_http.c proxy_util.c

martin      98/08/16 13:21:30

  Modified:    src      CHANGES
               src/include ap_mmn.h
               src/modules/proxy mod_proxy.c mod_proxy.h proxy_cache.c
                        proxy_connect.c proxy_ftp.c proxy_http.c
                        proxy_util.c
  Log:
  Modify the proxy to use tables instead of array_headers for header lines.
  That simplifies some code, but changes many of the proxy-internal interfaces.
  It should also prevent the proxy from merging multiple "Set-Cookie:" headers
  into one.
  
  Revision  Changes    Path
  1.1027    +3 -0      apache-1.3/src/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/CHANGES,v
  retrieving revision 1.1026
  retrieving revision 1.1027
  diff -u -u -r1.1026 -r1.1027
  --- CHANGES	1998/08/15 15:02:44	1.1026
  +++ CHANGES	1998/08/16 20:21:24	1.1027
  @@ -1,5 +1,8 @@
   Changes with Apache 1.3.2
   
  +  *) Change the proxy to use tables instead of array_headers for
  +     the header lines. [Martin Kraemer]
  +
     *) Make sure the config.status file is not overridden when just
        ``configure --help'' is used. [Ralf S. Engelschall] PR#2844
   
  
  
  
  1.4       +9 -2      apache-1.3/src/include/ap_mmn.h
  
  Index: ap_mmn.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/include/ap_mmn.h,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -u -r1.3 -r1.4
  --- ap_mmn.h	1998/08/14 02:49:09	1.3
  +++ ap_mmn.h	1998/08/16 20:21:25	1.4
  @@ -66,6 +66,7 @@
    *
    * MODULE_MAGIC_NUMBER_MINOR
    * Minor API changes that do not cause binary compatibility problems.
  + * Should be reset to 0 when upgrading MODULE_MAGIC_NUMBER_MAJOR.
    *
    * See the MODULE_MAGIC_AT_LEAST macro below for an example.
    */
  @@ -164,12 +165,18 @@
    *			  ap_get_limit_req_body() to get its value.
    * 19980812 (1.3.2-dev)	- split off MODULE_MAGIC_NUMBER
    * 19980812.2           - add ap_overlap_tables()
  + * 19980816 (1.3.2-dev)	- change proxy to use tables for headers, change
  + *                        struct cache_req to typedef cache_req.
  + *                        Delete ap_proxy_get_header(), ap_proxy_add_header(),
  + *                        ap_proxy_del_header(). Change interface of 
  + *                        ap_proxy_send_fb() and ap_proxy_cache_error(). 
  + *                        Add ap_proxy_send_hdr_line() and ap_proxy_bputs2().
    */
   
   #ifndef MODULE_MAGIC_NUMBER_MAJOR
  -#define MODULE_MAGIC_NUMBER_MAJOR 19980812
  +#define MODULE_MAGIC_NUMBER_MAJOR 19980816
   #endif
  -#define MODULE_MAGIC_NUMBER_MINOR 2
  +#define MODULE_MAGIC_NUMBER_MINOR 0                     /* 0...n */
   #define MODULE_MAGIC_NUMBER MODULE_MAGIC_NUMBER_MAJOR	/* backward compat */
   
   /* Useful for testing for features. */
  
  
  
  1.59      +1 -1      apache-1.3/src/modules/proxy/mod_proxy.c
  
  Index: mod_proxy.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/proxy/mod_proxy.c,v
  retrieving revision 1.58
  retrieving revision 1.59
  diff -u -u -r1.58 -r1.59
  --- mod_proxy.c	1998/08/06 17:30:40	1.58
  +++ mod_proxy.c	1998/08/16 20:21:26	1.59
  @@ -292,7 +292,7 @@
       array_header *proxies = conf->proxies;
       struct proxy_remote *ents = (struct proxy_remote *) proxies->elts;
       int i, rc;
  -    struct cache_req *cr;
  +    cache_req *cr;
       int direct_connect = 0;
       const char *maxfwd_str;
   
  
  
  
  1.38      +26 -17    apache-1.3/src/modules/proxy/mod_proxy.h
  
  Index: mod_proxy.h
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/proxy/mod_proxy.h,v
  retrieving revision 1.37
  retrieving revision 1.38
  diff -u -u -r1.37 -r1.38
  --- mod_proxy.h	1998/07/09 19:45:56	1.37
  +++ mod_proxy.h	1998/08/16 20:21:27	1.38
  @@ -55,6 +55,9 @@
    *
    */
   
  +#ifndef MOD_PROXY_H
  +#define MOD_PROXY_H 
  +
   /*
    * Main include file for the Apache proxy
    */
  @@ -218,7 +221,7 @@
   };
   
   /* caching information about a request */
  -struct cache_req {
  +typedef struct {
       request_rec *req;		/* the request */
       char *url;			/* the URL requested */
       char *filename;		/* name of the cache file, or NULL if no cache */
  @@ -237,35 +240,41 @@
       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) */
  -    array_header *hdrs;		/* the HTTP headers of the file */
  +    table *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;
   };
   
   /* Function prototypes */
   
   /* proxy_cache.c */
   
  -void ap_proxy_cache_tidy(struct cache_req *c);
  +void ap_proxy_cache_tidy(cache_req *c);
   int ap_proxy_cache_check(request_rec *r, char *url, struct cache_conf *conf,
  -		      struct cache_req **cr);
  -int ap_proxy_cache_update(struct cache_req *c, array_header *resp_hdrs,
  +		      cache_req **cr);
  +int ap_proxy_cache_update(cache_req *c, table *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, struct cache_req *c, char *url,
  +int ap_proxy_connect_handler(request_rec *r, cache_req *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, struct cache_req *c, char *url);
  +int ap_proxy_ftp_handler(request_rec *r, cache_req *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, struct cache_req *c, char *url,
  +int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
   		       const char *proxyhost, int proxyport);
   
   /* proxy_util.c */
  @@ -277,19 +286,14 @@
   char *ap_proxy_canon_netloc(pool *p, char **const urlp, char **userp,
   			 char **passwordp, char **hostp, int *port);
   const char *ap_proxy_date_canon(pool *p, const char *x);
  -array_header *ap_proxy_read_headers(pool *p, char *buffer, int size, BUFF *f);
  -long int ap_proxy_send_fb(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c);
  -struct hdr_entry *ap_proxy_get_header(array_header *hdrs_arr, const char *name);
  -struct hdr_entry *ap_proxy_add_header(array_header *hdrs_arr, const char *field,
  -				      const char *value, int rep);
  -void ap_proxy_del_header(array_header *hdrs_arr, const char *field);
  -void ap_proxy_send_headers(request_rec *r, const char *respline,
  -			array_header *hdrs_arr);
  +table *ap_proxy_read_headers(pool *p, char *buffer, int size, BUFF *f);
  +long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c);
  +void ap_proxy_send_headers(request_rec *r, const char *respline, table *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);
  -BUFF *ap_proxy_cache_error(struct cache_req *r);
  +cache_req *ap_proxy_cache_error(cache_req *r);
   int ap_proxyerror(request_rec *r, const char *message);
   const char *ap_proxy_host2addr(const char *host, struct hostent *reqhp);
   int ap_proxy_is_ipaddr(struct dirconn_entry *This, pool *p);
  @@ -298,3 +302,8 @@
   int ap_proxy_is_word(struct dirconn_entry *This, pool *p);
   int ap_proxy_doconnect(int sock, struct sockaddr_in *addr, request_rec *r);
   int ap_proxy_garbage_init(server_rec *, pool *);
  +/* 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);
  +
  +#endif /*MOD_PROXY_H*/
  
  
  
  1.50      +50 -56    apache-1.3/src/modules/proxy/proxy_cache.c
  
  Index: proxy_cache.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/proxy/proxy_cache.c,v
  retrieving revision 1.49
  retrieving revision 1.50
  diff -u -u -r1.49 -r1.50
  --- proxy_cache.c	1998/08/06 17:30:41	1.49
  +++ proxy_cache.c	1998/08/16 20:21:27	1.50
  @@ -535,7 +535,7 @@
    *         0 on failure (bad file or wrong URL)
    *        -1 on UNIX error
    */
  -static int rdcache(pool *p, BUFF *cachefp, struct cache_req *c)
  +static int rdcache(pool *p, BUFF *cachefp, cache_req *c)
   {
       char urlbuff[1034], *strp;
       int len;
  @@ -544,7 +544,7 @@
    * date SP lastmod SP expire SP count SP content-length CRLF
    * dates are stored as hex seconds since 1970
    */
  -    len = ap_bgets(urlbuff, 1034, cachefp);
  +    len = ap_bgets(urlbuff, sizeof urlbuff, cachefp);
       if (len == -1)
   	return -1;
       if (len == 0 || urlbuff[len - 1] != '\n')
  @@ -562,7 +562,7 @@
       c->len = ap_proxy_hex2sec(urlbuff + 36);
   
   /* check that we have the same URL */
  -    len = ap_bgets(urlbuff, 1034, cachefp);
  +    len = ap_bgets(urlbuff, sizeof urlbuff, cachefp);
       if (len == -1)
   	return -1;
       if (len == 0 || strncmp(urlbuff, "X-URL: ", 7) != 0 ||
  @@ -573,7 +573,7 @@
   	return 0;
   
   /* What follows is the message */
  -    len = ap_bgets(urlbuff, 1034, cachefp);
  +    len = ap_bgets(urlbuff, sizeof urlbuff, cachefp);
       if (len == -1)
   	return -1;
       if (len == 0 || urlbuff[len - 1] != '\n')
  @@ -586,16 +586,13 @@
   	return 0;
   
       c->status = atoi(strp);
  -    c->hdrs = ap_proxy_read_headers(p, urlbuff, 1034, cachefp);
  +    c->hdrs = ap_proxy_read_headers(p, urlbuff, sizeof urlbuff, cachefp);
       if (c->hdrs == NULL)
   	return -1;
       if (c->len != -1) {		/* add a content-length header */
  -	struct hdr_entry *q;
  -	q = ap_proxy_get_header(c->hdrs, "Content-Length");
  -	if (q == NULL) {
  -	    strp = ap_palloc(p, 15);
  -	    ap_snprintf(strp, 15, "%lu", (unsigned long)c->len);
  -	    ap_proxy_add_header(c->hdrs, "Content-Length", strp, HDR_REP);
  +	if (ap_table_get(c->hdrs, "Content-Length") == NULL) {
  +	    ap_table_set(c->hdrs, "Content-Length",
  +			 ap_psprintf(p, "%lu", (unsigned long)c->len));
   	}
       }
       return 1;
  @@ -617,11 +614,11 @@
    *            last modified date to request
    */
   int ap_proxy_cache_check(request_rec *r, char *url, struct cache_conf *conf,
  -		      struct cache_req **cr)
  +		      cache_req **cr)
   {
       char hashfile[66];
       const char *imstr, *pragma, *auth;
  -    struct cache_req *c;
  +    cache_req *c;
       time_t now;
       BUFF *cachefp;
       int cfd, i;
  @@ -630,7 +627,7 @@
       proxy_server_conf *pconf =
       (proxy_server_conf *) ap_get_module_config(sconf, &proxy_module);
   
  -    c = ap_pcalloc(r->pool, sizeof(struct cache_req));
  +    c = ap_pcalloc(r->pool, sizeof(cache_req));
       *cr = c;
       c->req = r;
       c->url = ap_pstrdup(r->pool, url);
  @@ -696,7 +693,7 @@
   /* fixed?  in this case, we want to get the headers from the remote server
      it will be handled later if we don't do this (I hope ;-)
       if (cachefp == NULL)
  -	c->hdrs = ap_make_array(r->pool, 2, sizeof(struct hdr_entry));
  +	c->hdrs = ap_make_table(r->pool, 20);
   */
       /* FIXME: Shouldn't we check the URL somewhere? */
       now = time(NULL);
  @@ -708,16 +705,12 @@
   /* has the cached file changed since this request? */
   	    if (c->date == BAD_DATE || c->date > c->ims) {
   /* No, but these header values may have changed, so we send them with the
  - * 304 response
  + * 304 HTTP_NOT_MODIFIED response
    */
  -		/* CHECKME: surely this was wrong? (Ben)
  -		   p = table_get(r->headers_in, "Expires");
  -		 */
  -		struct hdr_entry *q;
  -
  -		q = ap_proxy_get_header(c->hdrs, "Expires");
  -		if (q != NULL && q->value != NULL)
  -		    ap_table_set(r->headers_out, "Expires", q->value);
  +		const char *q;
  +
  +		if ((q = ap_table_get(c->hdrs, "Expires")) != NULL)
  +		    ap_table_set(r->headers_out, "Expires", q);
   	    }
   	    ap_pclosef(r->pool, cachefp->fd);
   	    Explain0("Use local copy, cached file hasn't changed");
  @@ -736,7 +729,7 @@
   	ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
   	r->sent_bodyct = 1;
   	if (!r->header_only)
  -	    ap_proxy_send_fb(cachefp, r, NULL, NULL);
  +	    ap_proxy_send_fb(cachefp, r, NULL);
   	ap_pclosef(r->pool, cachefp->fd);
   	return OK;
       }
  @@ -751,13 +744,11 @@
    * from the cache
    */
   	if (c->ims == BAD_DATE || c->ims < c->lmod) {
  -	    struct hdr_entry *q;
  -
  -	    q = ap_proxy_get_header(c->hdrs, "Last-Modified");
  +	    const char *q;
   
  -	    if (q != NULL && q->value != NULL)
  +	    if ((q = ap_table_get(c->hdrs, "Last-Modified")) != NULL)
   		ap_table_set(r->headers_in, "If-Modified-Since",
  -			  (char *) q->value);
  +			  (char *) q);
   	}
       }
       c->fp = cachefp;
  @@ -779,7 +770,7 @@
    *  from the cache, maybe updating the header line
    *  otherwise, delete the old cached file and open a new temporary file
    */
  -int ap_proxy_cache_update(struct cache_req *c, array_header *resp_hdrs,
  +int ap_proxy_cache_update(cache_req *c, table *resp_hdrs,
   		       const int is_HTTP1, int nocache)
   {
   #ifdef ULTRIX_BRAIN_DEATH
  @@ -788,7 +779,7 @@
       request_rec *r = c->req;
       char *p;
       int i;
  -    struct hdr_entry *expire, *dates, *lmods, *clen;
  +    const char *expire, *lmods, *dates, *clen;
       time_t expc, date, lmod, now;
       char buff[46];
       void *sconf = r->server->module_config;
  @@ -802,21 +793,20 @@
   /* read expiry date; if a bad date, then leave it so the client can
    * read it
    */
  -    expire = ap_proxy_get_header(resp_hdrs, "Expires");
  +    expire = ap_table_get(resp_hdrs, "Expires");
       if (expire != NULL)
  -	expc = ap_parseHTTPdate(expire->value);
  +	expc = ap_parseHTTPdate(expire);
       else
   	expc = BAD_DATE;
   
   /*
    * read the last-modified date; if the date is bad, then delete it
    */
  -    lmods = ap_proxy_get_header(resp_hdrs, "Last-Modified");
  +    lmods = ap_table_get(resp_hdrs, "Last-Modified");
       if (lmods != NULL) {
  -	lmod = ap_parseHTTPdate(lmods->value);
  +	lmod = ap_parseHTTPdate(lmods);
   	if (lmod == BAD_DATE) {
   /* kill last modified date */
  -	    lmods->value = NULL;
   	    lmods = NULL;
   	}
       }
  @@ -826,16 +816,18 @@
   /*
    * what responses should we not cache?
    * Unknown status responses and those known to be uncacheable
  - * 304 response when we have no valid cache file, or
  - * 200 response from HTTP/1.0 and up without a Last-Modified header, or
  + * 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)
    */
  -    if ((r->status != 200 && r->status != 301 && r->status != 304) ||
  +/* @@@ XXX FIXME: is the test "r->status != HTTP_MOVED_PERMANENTLY" corerct?
  + * or shouldn't it be "is_HTTP_REDIRECT(r->status)" ? -MnKr */
  +    if ((r->status != HTTP_OK && r->status != HTTP_MOVED_PERMANENTLY && r->status != HTTP_NOT_MODIFIED) ||
   	(expire != NULL && expc == BAD_DATE) ||
  -	(r->status == 304 && c->fp == NULL) ||
  -	(r->status == 200 && lmods == NULL && is_HTTP1) ||
  +	(r->status == HTTP_NOT_MODIFIED && (c == NULL || c->fp == NULL)) ||
  +	(r->status == HTTP_OK && lmods == NULL && is_HTTP1) ||
   	r->header_only ||
   	ap_table_get(r->headers_in, "Authorization") != NULL ||
   	nocache) {
  @@ -855,9 +847,9 @@
   /*
    * Read the date. Generate one if one is not supplied
    */
  -    dates = ap_proxy_get_header(resp_hdrs, "Date");
  +    dates = ap_table_get(resp_hdrs, "Date");
       if (dates != NULL)
  -	date = ap_parseHTTPdate(dates->value);
  +	date = ap_parseHTTPdate(dates);
       else
   	date = BAD_DATE;
   
  @@ -868,8 +860,8 @@
   /* add one; N.B. use the time _now_ rather than when we were checking the cache
    */
   	date = now;
  -	p = ap_gm_timestr_822(r->pool, now);
  -	dates = ap_proxy_add_header(resp_hdrs, "Date", p, HDR_REP);
  +	dates = ap_gm_timestr_822(r->pool, now);
  +	ap_table_set(resp_hdrs, "Date", dates);
   	Explain0("Added date header");
       }
   
  @@ -878,7 +870,7 @@
   /* if its in the future, then replace by date */
       {
   	lmod = date;
  -	lmods->value = dates->value;
  +	lmods = dates;
   	Explain0("Last modified is in the future, replacing with now");
       }
   /* if the response did not contain the header, then use the cached version */
  @@ -889,9 +881,9 @@
   
   /* we now need to calculate the expire data for the object. */
       if (expire == NULL && c->fp != NULL) {	/* no expiry data sent in response */
  -	expire = ap_proxy_get_header(c->hdrs, "Expires");
  +	expire = ap_table_get(c->hdrs, "Expires");
   	if (expire != NULL)
  -	    expc = ap_parseHTTPdate(expire->value);
  +	    expc = ap_parseHTTPdate(expire);
       }
   /* so we now have the expiry date */
   /* if no expiry date then
  @@ -915,11 +907,11 @@
       }
   
   /* get the content-length header */
  -    clen = ap_proxy_get_header(resp_hdrs, "Content-Length");
  +    clen = ap_table_get(resp_hdrs, "Content-Length");
       if (clen == NULL)
   	c->len = -1;
       else
  -	c->len = atoi(clen->value);
  +	c->len = atoi(clen);
   
       ap_proxy_sec2hex(date, buff);
       buff[8] = ' ';
  @@ -934,7 +926,7 @@
       buff[45] = '\0';
   
   /* if file not modified */
  -    if (r->status == 304) {
  +    if (r->status == HTTP_NOT_MODIFIED) {
   	if (c->ims != BAD_DATE && lmod != BAD_DATE && lmod <= c->ims) {
   /* set any changed headers somehow */
   /* update dates and version, but not content-length */
  @@ -967,7 +959,7 @@
   	    ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
   	    r->sent_bodyct = 1;
   	    if (!r->header_only)
  -		ap_proxy_send_fb(c->fp, r, NULL, NULL);
  +		ap_proxy_send_fb(c->fp, r, NULL);
   /* set any changed headers somehow */
   /* update dates and version, but not content-length */
   	    if (lmod != c->lmod || expc != c->expire || date != c->date) {
  @@ -1030,13 +1022,15 @@
       return DECLINED;
   }
   
  -void ap_proxy_cache_tidy(struct cache_req *c)
  +void ap_proxy_cache_tidy(cache_req *c)
   {
  -    server_rec *s = c->req->server;
  +    server_rec *s;
       long int bc;
   
  -    if (c->fp == NULL)
  +    if (c == NULL || c->fp == NULL)
   	return;
  +
  +    s = c->req->server;
   
   /* don't care how much was sent, but rather how much was written to cache
       ap_bgetopt(c->req->connection->client, BO_BYTECT, &bc);
  
  
  
  1.31      +1 -1      apache-1.3/src/modules/proxy/proxy_connect.c
  
  Index: proxy_connect.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/proxy/proxy_connect.c,v
  retrieving revision 1.30
  retrieving revision 1.31
  diff -u -u -r1.30 -r1.31
  --- proxy_connect.c	1998/08/06 17:30:42	1.30
  +++ proxy_connect.c	1998/08/16 20:21:27	1.31
  @@ -97,7 +97,7 @@
    * FIXME: no check for r->assbackwards, whatever that is.
    */
   
  -int ap_proxy_connect_handler(request_rec *r, struct cache_req *c, char *url,
  +int ap_proxy_connect_handler(request_rec *r, cache_req *c, char *url,
   			  const char *proxyhost, int proxyport)
   {
       struct sockaddr_in server;
  
  
  
  1.66      +38 -75    apache-1.3/src/modules/proxy/proxy_ftp.c
  
  Index: proxy_ftp.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/proxy/proxy_ftp.c,v
  retrieving revision 1.65
  retrieving revision 1.66
  diff -u -u -r1.65 -r1.66
  --- proxy_ftp.c	1998/08/06 17:30:43	1.65
  +++ proxy_ftp.c	1998/08/16 20:21:28	1.66
  @@ -263,7 +263,7 @@
       return status;
   }
   
  -static long int send_dir(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c, char *url)
  +static long int send_dir(BUFF *f, request_rec *r, cache_req *c, char *url)
   {
       char buf[IOBUFSIZE];
       char buf2[IOBUFSIZE];
  @@ -278,7 +278,6 @@
       int hostlen;
       conn_rec *con = r->connection;
       char *dir, *path, *reldir, *site, *psite;
  -    const char *sig;
   
       tempurl = ap_pstrdup(r->pool, url);
   
  @@ -318,10 +317,7 @@
   		"<BODY><H2>Directory of "
   		"<A HREF=\"/\">%s</A>/",
   		tempurl, psite, path, site);
  -    ap_bputs(buf, con->client);
  -    if (f2 != NULL)
  -	ap_bputs(buf, f2);
  -    total_bytes_sent += strlen(buf);
  +    total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
   
       while ((dir = strchr(dir+1, '/')) != NULL)
       {
  @@ -332,17 +328,12 @@
   	    ++reldir;
   	/* print "path/" component */
   	ap_snprintf(buf, sizeof(buf), "<A HREF=\"/%s/\">%s</A>/", path+1, reldir);
  -	ap_bputs(buf, con->client);
  -    if (f2 != NULL)
  -	    ap_bputs(buf, f2);
  +	total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
   	total_bytes_sent += strlen(buf);
   	*dir = '/';
       }
       ap_snprintf(buf, sizeof(buf), "</H2>\n<HR><PRE>");
  -    ap_bputs(buf, con->client);
  -    if (f2 != NULL)
  -	    ap_bputs(buf, f2);
  -    total_bytes_sent += strlen(buf);
  +    total_bytes_sent += ap_proxy_bputs2(buf, con->client, c);
   
       for (hostlen=0; url[hostlen]!='/'; ++hostlen)
   	continue;
  @@ -355,8 +346,8 @@
       while (!con->aborted) {
   	n = ap_bgets(buf, sizeof buf, f);
   	if (n == -1) {		/* input error */
  -	    if (f2 != NULL)
  -		f2 = ap_proxy_cache_error(c);
  +	    if (c != NULL)
  +		c = ap_proxy_cache_error(c);
   	    break;
   	}
   	if (n == 0)
  @@ -416,9 +407,8 @@
   	o = 0;
   	total_bytes_sent += n;
   
  -	if (f2 != NULL)
  -	    if (ap_bwrite(f2, buf, n) != n)
  -		f2 = ap_proxy_cache_error(c);
  +	if (c != NULL && c->fp && ap_bwrite(c->fp, buf, n) != n)
  +	    c = ap_proxy_cache_error(c);
   
   	while (n && !r->connection->aborted) {
   	    w = ap_bwrite(con->client, &buf[o], n);
  @@ -429,23 +419,11 @@
   	    o += w;
   	}
       }
  -    site = "</PRE><HR>\n";
  -    ap_bputs(site, con->client);
  -    if (f2 != NULL)
  -	ap_bputs(site, f2);
  -    total_bytes_sent += strlen(site);
  -
  -    sig = ap_psignature("", r);
  -    ap_bputs(sig, con->client);
  -    if (f2 != NULL)
  -	ap_bputs(sig, f2);
  -    total_bytes_sent += strlen(sig);
  -
  -    site = "</BODY></HTML>\n";
  -    ap_bputs(site, con->client);
  -    if (f2 != NULL)
  -	ap_bputs(site, f2);
  -    total_bytes_sent += strlen(site);
  +
  +    total_bytes_sent += ap_proxy_bputs2("</PRE><HR>\n", con->client, c);
  +    total_bytes_sent += ap_proxy_bputs2(ap_psignature("", r), con->client, c);
  +    total_bytes_sent += ap_proxy_bputs2("</BODY></HTML>\n", con->client, c);
  +
       ap_bflush(con->client);
   
       return total_bytes_sent;
  @@ -457,7 +435,7 @@
    * Troy Morrison <sp...@zoom.com>
    * PASV added by Chuck
    */
  -int ap_proxy_ftp_handler(request_rec *r, struct cache_req *c, char *url)
  +int ap_proxy_ftp_handler(request_rec *r, cache_req *c, char *url)
   {
       char *host, *path, *strp, *user, *password, *parms;
       const char *err;
  @@ -466,15 +444,15 @@
       int csd = 0;
       struct sockaddr_in server;
       struct hostent server_hp;
  -    struct hdr_entry *hdr;
       struct in_addr destaddr;
  -    array_header *resp_hdrs;
  -    BUFF *f, *cache;
  +    table *resp_hdrs;
  +    BUFF *f;
       BUFF *data = NULL;
       pool *p = r->pool;
       int one = 1;
       const long int zero = 0L;
       NET_SIZE_T clen;
  +    struct tbl_do_args tdo;
   
       void *sconf = r->server->module_config;
       proxy_server_conf *conf =
  @@ -999,25 +977,24 @@
       if (rc != 125 && rc != 150 && rc != 226 && rc != 250)
   	return HTTP_BAD_GATEWAY;
   
  -    r->status = 200;
  +    r->status = HTTP_OK;
       r->status_line = "200 OK";
   
  -    resp_hdrs = ap_make_array(p, 2, sizeof(struct hdr_entry));
  +    resp_hdrs = ap_make_table(p, 2);
       c->hdrs = resp_hdrs;
   
       if (parms[0] == 'd')
  -	ap_proxy_add_header(resp_hdrs, "Content-Type", "text/html", HDR_REP);
  +	ap_table_set(resp_hdrs, "Content-Type", "text/html");
       else {
   	if (r->content_type != NULL) {
  -	    ap_proxy_add_header(resp_hdrs, "Content-Type", r->content_type,
  -			     HDR_REP);
  +	    ap_table_set(resp_hdrs, "Content-Type", r->content_type);
   	    Explain1("FTP: Content-Type set to %s", r->content_type);
   	}
   	else {
  -	    ap_proxy_add_header(resp_hdrs, "Content-Type", "text/plain", HDR_REP);
  +	    ap_table_set(resp_hdrs, "Content-Type", "text/plain");
   	}
   	if (parms[0] != 'a' && size != NULL) {
  -	    ap_proxy_add_header(resp_hdrs, "Content-Length", size, HDR_REP);
  +	    ap_table_set(resp_hdrs, "Content-Length", size);
   	    Explain1("FTP: Content-Length set to %s", size);
   	}
       }
  @@ -1037,10 +1014,6 @@
   	return i;
       }
   
  -    cache = c->fp;
  -
  -    c->hdrs = resp_hdrs;
  -
       if (!pasvmode) {		/* wait for connection */
   	ap_hard_timeout("proxy ftp data connect", r);
   	clen = sizeof(struct sockaddr_in);
  @@ -1053,7 +1026,8 @@
   	    ap_pclosesocket(p, dsock);
   	    ap_bclose(f);
   	    ap_kill_timeout(r);
  -	    ap_proxy_cache_error(c);
  +	    if (c != NULL)
  +		c = ap_proxy_cache_error(c);
   	    return HTTP_BAD_GATEWAY;
   	}
   	ap_note_cleanups_for_socket(p, csd);
  @@ -1075,31 +1049,19 @@
   /* write status line */
       if (!r->assbackwards)
   	ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
  -    if (cache != NULL)
  -	if (ap_bvputs(cache, "HTTP/1.0 ", r->status_line, CRLF,
  -		   NULL) == -1)
  -	    cache = ap_proxy_cache_error(c);
  +    if (c != NULL && c->fp != NULL &&
  +	ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1)
  +	c = ap_proxy_cache_error(c);
   
   /* send headers */
  -    len = resp_hdrs->nelts;
  -    hdr = (struct hdr_entry *) resp_hdrs->elts;
  -    for (i = 0; i < len; i++) {
  -	if (hdr[i].field == NULL || hdr[i].value == NULL ||
  -	    hdr[i].value[0] == '\0')
  -	    continue;
  -	if (!r->assbackwards)
  -	    ap_rvputs(r, hdr[i].field, ": ", hdr[i].value, CRLF, NULL);
  -	if (cache != NULL)
  -	    if (ap_bvputs(cache, hdr[i].field, ": ", hdr[i].value, CRLF,
  -		       NULL) == -1)
  -		cache = ap_proxy_cache_error(c);
  -    }
  +    tdo.req = r;
  +    tdo.cache = c;
  +    ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
   
       if (!r->assbackwards)
   	ap_rputs(CRLF, r);
  -    if (cache != NULL)
  -	if (ap_bputs(CRLF, cache) == -1)
  -	    cache = ap_proxy_cache_error(c);
  +    if (c != NULL && c->fp != NULL && ap_bputs(CRLF, c->fp) == -1)
  +	c = ap_proxy_cache_error(c);
   
       ap_bsetopt(r->connection->client, BO_BYTECT, &zero);
       r->sent_bodyct = 1;
  @@ -1107,15 +1069,16 @@
       if (!r->header_only) {
   	if (parms[0] != 'd') {
   /* we need to set this for ap_proxy_send_fb()... */
  -	    c->cache_completion = 0;
  -	    ap_proxy_send_fb(data, r, cache, c);
  +	    if (c != NULL)
  +		c->cache_completion = 0;
  +	    ap_proxy_send_fb(data, r, c);
   	} else
  -	    send_dir(data, r, cache, c, url);
  +	    send_dir(data, r, c, url);
   
   	if (rc == 125 || rc == 150)
   	    rc = ftp_getrc(f);
   	if (rc != 226 && rc != 250)
  -	    ap_proxy_cache_error(c);
  +	    c = ap_proxy_cache_error(c);
       }
       else {
   /* abort the transfer */
  
  
  
  1.57      +32 -50    apache-1.3/src/modules/proxy/proxy_http.c
  
  Index: proxy_http.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/proxy/proxy_http.c,v
  retrieving revision 1.56
  retrieving revision 1.57
  diff -u -u -r1.56 -r1.57
  --- proxy_http.c	1998/08/09 17:39:25	1.56
  +++ proxy_http.c	1998/08/16 20:21:28	1.57
  @@ -165,26 +165,28 @@
    * we return DECLINED so that we can try another proxy. (Or the direct
    * route.)
    */
  -int ap_proxy_http_handler(request_rec *r, struct cache_req *c, char *url,
  +int ap_proxy_http_handler(request_rec *r, cache_req *c, char *url,
   		       const char *proxyhost, int proxyport)
   {
       const char *strp;
       char *strp2;
       const char *err, *desthost;
       int i, j, sock, len, backasswards;
  -    array_header *reqhdrs_arr, *resp_hdrs;
  +    array_header *reqhdrs_arr;
  +    table *resp_hdrs;
       table_entry *reqhdrs;
       struct sockaddr_in server;
       struct in_addr destaddr;
       struct hostent server_hp;
  -    BUFF *f, *cache;
  -    struct hdr_entry *hdr;
  +    BUFF *f;
       char buffer[HUGE_STRING_LEN];
       pool *p = r->pool;
       const long int zero = 0L;
       int destport = 0;
       char *destportstr = NULL;
       const char *urlptr = NULL;
  +    const char *datestr;
  +    struct tbl_do_args tdo;
   
       void *sconf = r->server->module_config;
       proxy_server_conf *conf =
  @@ -313,7 +315,7 @@
   	if (reqhdrs[i].key == NULL || reqhdrs[i].val == NULL
   	/* Clear out headers not to send */
   	    || !strcasecmp(reqhdrs[i].key, "Host")	/* Already sent */
  -	    ||!strcasecmp(reqhdrs[i].key, "Proxy-Authorization"))
  +	    || !strcasecmp(reqhdrs[i].key, "Proxy-Authorization"))
   	    continue;
   	ap_bvputs(f, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL);
       }
  @@ -322,7 +324,7 @@
   /* send the request data, if any. N.B. should we trap SIGPIPE ? */
   
       if (ap_should_client_block(r)) {
  -	while ((i = ap_get_client_block(r, buffer, HUGE_STRING_LEN)) > 0)
  +	while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0)
   	    ap_bwrite(f, buffer, i);
       }
       ap_bflush(f);
  @@ -330,7 +332,7 @@
   
       ap_hard_timeout("proxy receive", r);
   
  -    len = ap_bgets(buffer, HUGE_STRING_LEN - 1, f);
  +    len = ap_bgets(buffer, sizeof buffer - 1, f);
       if (len == -1 || len == 0) {
   	ap_bclose(f);
   	ap_kill_timeout(r);
  @@ -368,7 +370,7 @@
   	r->status_line = "200 OK";
   
   /* no headers */
  -	resp_hdrs = ap_make_array(p, 2, sizeof(struct hdr_entry));
  +	resp_hdrs = ap_make_table(p, 20);
       }
   
       c->hdrs = resp_hdrs;
  @@ -379,21 +381,18 @@
    * 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));
   
  -    hdr = (struct hdr_entry *) resp_hdrs->elts;
  -    for (i = 0; i < resp_hdrs->nelts; i++) {
  -	if (hdr[i].value[0] == '\0')
  -	    continue;
  -	strp = hdr[i].field;
  -	if (strcasecmp(strp, "Date") == 0 ||
  -	    strcasecmp(strp, "Last-Modified") == 0 ||
  -	    strcasecmp(strp, "Expires") == 0)
  -	    hdr[i].value = ap_proxy_date_canon(p, hdr[i].value);
  -	if (strcasecmp(strp, "Location") == 0 ||
  -	    strcasecmp(strp, "URI") == 0)
  -	    hdr[i].value = proxy_location_reverse_map(r, hdr[i].value);
  -    }
  -
   /* 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)
  @@ -407,49 +406,32 @@
   	return i;
       }
   
  -    cache = c->fp;
  -
       ap_hard_timeout("proxy receive", r);
   
   /* write status line */
       if (!r->assbackwards)
   	ap_rvputs(r, "HTTP/1.0 ", r->status_line, CRLF, NULL);
  -    if (cache != NULL)
  -	if (ap_bvputs(cache, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1)
  -	    cache = ap_proxy_cache_error(c);
  +    if (c != NULL && c->fp != NULL &&
  +	ap_bvputs(c->fp, "HTTP/1.0 ", r->status_line, CRLF, NULL) == -1)
  +	c = ap_proxy_cache_error(c);
   
   /* send headers */
  -    for (i = 0; i < resp_hdrs->nelts; i++) {
  -	if (hdr[i].field == NULL || hdr[i].value == NULL ||
  -	    hdr[i].value[0] == '\0')
  -	    continue;
  -	if (!r->assbackwards) {
  -	    ap_rvputs(r, hdr[i].field, ": ", hdr[i].value, CRLF, NULL);
  -	    /* XXX: can't this be ap_table_setn? -djg */
  -	    ap_table_set(r->headers_out, hdr[i].field, hdr[i].value);
  -	    /* XXX: regardless, there's an O(n^2) attack here, which
  -	     * could be fixed with ap_overlap_tables */
  -	}
  -	if (cache != NULL)
  -	    if (ap_bvputs(cache, hdr[i].field, ": ", hdr[i].value, CRLF,
  -		       NULL) == -1)
  -		cache = ap_proxy_cache_error(c);
  -    }
  +    tdo.req = r;
  +    tdo.cache = c;
  +    ap_table_do(ap_proxy_send_hdr_line, &tdo, resp_hdrs, NULL);
   
       if (!r->assbackwards)
   	ap_rputs(CRLF, r);
  -    if (cache != NULL)
  -	if (ap_bputs(CRLF, cache) == -1)
  -	    cache = ap_proxy_cache_error(c);
  +    if (c != NULL && c->fp != NULL && ap_bputs(CRLF, c->fp) == -1)
  +	c = ap_proxy_cache_error(c);
   
       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 (cache != NULL)
  -	    if (ap_bwrite(f, buffer, len) != len)
  -		cache = ap_proxy_cache_error(c);
  +	if (c != NULL && c->fp != NULL && ap_bwrite(c->fp, buffer, len) != len)
  +	    c = ap_proxy_cache_error(c);
       }
       ap_kill_timeout(r);
   
  @@ -467,7 +449,7 @@
       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, cache, c);
  +	ap_proxy_send_fb(f, r, c);
       }
   
       ap_proxy_cache_tidy(c);
  
  
  
  1.69      +152 -150  apache-1.3/src/modules/proxy/proxy_util.c
  
  Index: proxy_util.c
  ===================================================================
  RCS file: /export/home/cvs/apache-1.3/src/modules/proxy/proxy_util.c,v
  retrieving revision 1.68
  retrieving revision 1.69
  diff -u -u -r1.68 -r1.69
  --- proxy_util.c	1998/08/09 17:39:25	1.68
  +++ proxy_util.c	1998/08/16 20:21:28	1.69
  @@ -359,89 +359,118 @@
       return q;
   }
   
  +
  +/* 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 proxy_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)
  +                  && (ap_blookc(&next, in) == 1)
  +                  && ((next == ' ') || (next == '\t')));
  +
  +    return total;
  +}
  +
  +
   /*
    * Reads headers from a buffer and returns an array of headers.
    * Returns NULL on file error
  - */
  -array_header *
  -             ap_proxy_read_headers(pool *p, char *buffer, int size, BUFF *f)
  -{
  -    int gotcr, len, i, j;
  -    array_header *resp_hdrs;
  -    struct hdr_entry *hdr;
  -    char *strp;
  -    const char *strcp;
  -
  -    resp_hdrs = ap_make_array(p, 10, sizeof(struct hdr_entry));
  -    hdr = NULL;
  -
  -    gotcr = 1;
  -    for (;;) {
  -	len = ap_bgets(buffer, size, f);
  -	if (len == -1)
  + * 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?
  + */
  +table *ap_proxy_read_headers(pool *p, char *buffer, int size, BUFF *f)
  +{
  +    table *resp_hdrs;
  +    int len;
  +    char *value, *end;
  +    char field[MAX_STRING_LEN];
  +
  +    resp_hdrs = ap_make_table(p, 20);
  +
  +    /*
  +     * Read header lines until we get the empty separator line, a read error,
  +     * the connection closes (EOF), or we timeout.
  +     */
  +    while ((len = proxy_getline(buffer, size, f, 1)) > 0) {
  +	
  +	if (!(value = strchr(buffer, ':'))) {     /* Find the colon separator */
   	    return NULL;
  -	if (len == 0)
  -	    break;
  -	if (buffer[len - 1] == '\n') {
  -	    buffer[--len] = '\0';
  -	    i = 1;
   	}
  -	else
  -	    i = 0;
   
  -	if (!gotcr || buffer[0] == ' ' || buffer[0] == '\t') {
  -	    /* a continuation header */
  -	    if (hdr == NULL) {
  -		/* error!! */
  -		if (!i) {
  -		    i = ap_bskiplf(f);
  -		    if (i == -1)
  -			return NULL;
  -		}
  -		gotcr = 1;
  -		continue;
  -	    }
  -	    hdr->value = ap_pstrcat(p, hdr->value, buffer, NULL);
  -	}
  -	else if (gotcr && len == 0)
  -	    break;
  -	else {
  -	    strp = strchr(buffer, ':');
  -	    if (strp == NULL) {
  -		/* error!! */
  -		if (!gotcr) {
  -		    i = ap_bskiplf(f);
  -		    if (i == -1)
  -			return NULL;
  -		}
  -		gotcr = 1;
  -		hdr = NULL;
  -		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(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 */
   	    }
  -	    hdr = ap_push_array(resp_hdrs);
  -	    *(strp++) = '\0';
  -	    hdr->field = ap_pstrdup(p, buffer);
  -	    while (*strp == ' ' || *strp == '\t')
  -		strp++;
  -	    hdr->value = ap_pstrdup(p, strp);
  -	    gotcr = i;
  +	    if (len == 0) /* time to exit the larger loop as well */
  +		break;
   	}
       }
  -
  -    hdr = (struct hdr_entry *) resp_hdrs->elts;
  -    for (i = 0; i < resp_hdrs->nelts; i++) {
  -	strcp = hdr[i].value;
  -	j = strlen(strcp);
  -	while (j > 0 && (strcp[j - 1] == ' ' || strcp[j - 1] == '\t'))
  -	    j--;
  -	/* Note that this is OK, coz we created the header above */
  -	((char *)strcp)[j] = '\0';
  -    }
  -
       return resp_hdrs;
   }
   
  -long int ap_proxy_send_fb(BUFF *f, request_rec *r, BUFF *f2, struct cache_req *c)
  +long int ap_proxy_send_fb(BUFF *f, request_rec *r, cache_req *c)
   {
       int  ok = 1;
       char buf[IOBUFSIZE];
  @@ -457,8 +486,8 @@
   #ifdef CHARSET_EBCDIC
       /* The cache copy is ASCII, not EBCDIC, even for text/html) */
       ap_bsetflag(f, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
  -    if (f2 != NULL)
  -	ap_bsetflag(f2, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
  +    if (c != NULL && c->fp != NULL)
  +	ap_bsetflag(c->fp, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
       ap_bsetflag(con->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0);
   #endif
   
  @@ -492,10 +521,11 @@
       }
   #endif
   
  -    while (ok && f != NULL) {
  +    while (ok) {
           if (alt_to)
               ap_hard_timeout("proxy send body", r);
   
  +	/* Read block from server */
   	n = ap_bread(f, buf, IOBUFSIZE);
   
           if (alt_to)
  @@ -504,8 +534,8 @@
               ap_reset_timeout(r);
   
   	if (n == -1) {		/* input error */
  -	    if (f2 != NULL)
  -		f2 = ap_proxy_cache_error(c);
  +	    if (c != NULL)
  +		c = ap_proxy_cache_error(c);
   	    break;
   	}
   	if (n == 0)
  @@ -513,14 +543,16 @@
   	o = 0;
   	total_bytes_rcv += n;
   
  -        if (f2 != NULL) {
  -            if (ap_bwrite(f2, &buf[0], n) != n) {
  -                f2 = ap_proxy_cache_error(c);
  +	/* Write to cache first. */
  +        if (c != NULL && c->fp != NULL) {
  +            if (ap_bwrite(c->fp, &buf[0], n) != n) {
  +                c = ap_proxy_cache_error(c);
               } else {
                   c->written += n;
               }
           }
   
  +	/* Write the block to the client, detect aborted transfers */
           while (n && !con->aborted) {
               if (alt_to)
                   ap_soft_timeout("proxy send body", r);
  @@ -533,7 +565,7 @@
                   ap_reset_timeout(r);
   
               if (w <= 0) {
  -                if (f2 != NULL) {
  +                if (c != NULL) {
                       /* when a send failure occurs, we need to decide
                        * whether to continue loading and caching the
                        * document, or to abort the whole thing
  @@ -545,8 +577,8 @@
                       if (! ok) {
                           ap_pclosef(c->req->pool, c->fp->fd);
                           c->fp = NULL;
  -                        f2 = NULL;
                           unlink(c->tempfile);
  +			c = NULL;
                       }
                   }
                   con->aborted = 1;
  @@ -565,85 +597,28 @@
   }
   
   /*
  - * Read a header from the array, returning the first entry
  - */
  -struct hdr_entry *
  -          ap_proxy_get_header(array_header *hdrs_arr, const char *name)
  -{
  -    struct hdr_entry *hdrs;
  -    int i;
  -
  -    hdrs = (struct hdr_entry *) hdrs_arr->elts;
  -    for (i = 0; i < hdrs_arr->nelts; i++)
  -	if (hdrs[i].field != NULL && strcasecmp(name, hdrs[i].field) == 0)
  -	    return &hdrs[i];
  -
  -    return NULL;
  -}
  -
  -/*
  - * Add to the header reply, either concatenating, or replacing existin
  - * headers. It stores the pointers provided, so make sure the data
  - * is not subsequently overwritten
  - */
  -struct hdr_entry *
  -          ap_proxy_add_header(array_header *hdrs_arr, const char *field, const char *value,
  -			   int rep)
  -{
  -    int i;
  -    struct hdr_entry *hdrs;
  -
  -    hdrs = (struct hdr_entry *) hdrs_arr->elts;
  -    if (rep)
  -	for (i = 0; i < hdrs_arr->nelts; i++)
  -	    if (hdrs[i].field != NULL && strcasecmp(field, hdrs[i].field) == 0) {
  -		hdrs[i].value = value;
  -		return hdrs;
  -	    }
  -
  -    hdrs = ap_push_array(hdrs_arr);
  -    hdrs->field = field;
  -    hdrs->value = value;
  -
  -    return hdrs;
  -}
  -
  -void ap_proxy_del_header(array_header *hdrs_arr, const char *field)
  -{
  -    int i;
  -    struct hdr_entry *hdrs;
  -
  -    hdrs = (struct hdr_entry *) hdrs_arr->elts;
  -
  -    for (i = 0; i < hdrs_arr->nelts; i++)
  -	if (hdrs[i].field != NULL && strcasecmp(field, hdrs[i].field) == 0)
  -	    hdrs[i].value = NULL;
  -}
  -
  -/*
    * Sends response line and headers.  Uses the client fd and the 
    * headers_out array from the passed request_rec to talk to the client
    * and to properly set the headers it sends for things such as logging.
    * 
    * A timeout should be set before calling this routine.
    */
  -void ap_proxy_send_headers(request_rec *r, const char *respline, array_header *hdrs_arr)
  +void ap_proxy_send_headers(request_rec *r, const char *respline, table *t)
   {
  -    struct hdr_entry *hdrs;
       int i;
       BUFF *fp = r->connection->client;
  -
  -    hdrs = (struct hdr_entry *) hdrs_arr->elts;
  +    table_entry *elts = (table_entry *) ap_table_elts(t)->elts;
   
       ap_bputs(respline, fp);
       ap_bputs(CRLF, fp);
  -    for (i = 0; i < hdrs_arr->nelts; i++) {
  -	if (hdrs[i].field == NULL)
  -	    continue;
  -	ap_bvputs(fp, hdrs[i].field, ": ", hdrs[i].value, CRLF, NULL);
  -	/* XXX: can't this be ap_table_setn? -djg */
  -	ap_table_set(r->headers_out, hdrs[i].field, hdrs[i].value);
  -	/* XXX: another O(n^2) attack, fixed by ap_overlap_tables */
  +
  +    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);
  +	    /* FIXME: @@@ This used to be ap_table_set(), but I think
  +	     * ap_table_addn() is correct. MnKr */
  +	    ap_table_addn(r->headers_out, elts[i].key, elts[i].val);
  +	}
       }
   
       ap_bputs(CRLF, fp);
  @@ -829,8 +804,8 @@
       y[8] = '\0';
   }
   
  -BUFF *
  -     ap_proxy_cache_error(struct cache_req *c)
  +
  +cache_req *ap_proxy_cache_error(cache_req *c)
   {
       ap_log_rerror(APLOG_MARK, APLOG_ERR, c->req,
   		 "proxy: error writing to cache file %s", c->tempfile);
  @@ -1253,3 +1228,30 @@
   
       return i;
   }
  +
  +/* This function is called by ap_table_do() for all header lines */
  +/* (from proxy_http.c and proxy_ftp.c) */
  +/* 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;
  +
  +    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)
  +	    parm->cache = ap_proxy_cache_error(parm->cache);
  +    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 len = ap_bputs(data, client);
  +    if (cache != NULL && cache->fp != NULL)
  +	ap_bputs(data, cache->fp);
  +    return len;
  +}
  +