httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Dirk-Willem van Gulik\(mda00\)" <di...@mda00.jrc.it>
Subject Re: [PATCH] 7% to 25% performance improvement
Date Mon, 26 Jan 1998 17:48:47 GMT

Tried it, does not break things on FreeBSD. But 25% speedup,
nay; not really :-) But an increase of 108 to 129 req/seq
I would dare to contribute to it.

Dw.

On Sat, 24 Jan 1998, Dean Gaudet wrote:

> This patch is based on code submitted by Dmitry Khrustalev
> <dima@bog.msu.su>.  The table_(set|add|merge) routines all do pstrdup() 
> of their key and val.  But this isn't always required... in fact it's
> almost never required.  In many of the cases where these routines are
> called the key is a constant string, and the value has been constructed by
> pstrcat() or getword() or something else which has already allocated in
> the appropriate pool. 
> 
> Dmitry's patch adds three routines table_(set|add|merge)n, which do not
> pstrdup() their args at all.  He made all the necessary changes in the
> core of the code to use these routines effectively.  I went on and made
> similar changes in the modules. 
> 
> One issue with this patch is erroneously passing a pointer from the wrong
> pool to the table_*n routines.  For any string placed in table t, the
> "right" pools are t->pool, any ancestor of t->pool, or a string which is
> constant.  To detect this I wrote some code which is enabled by defining
> POOL_DEBUG.  It currently only works on the unix hosts, but someone
> knowing the right WIN32 foo could probably get it to work there too.  When
> enabled, the server will abort() when it detects the wrong pool being
> used. 
> 
> This patch shows a 7% to 25% speedup depending on the request type and the
> machine it's done on and stuff like that. 
> 
> I'm posting for votes 'cause it extends the API... but hey, for 25%
> performance improvement on a static server I'm pretty keen on getting this
> in.
> 
> Dean
> 
> Index: main/alloc.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/main/alloc.c,v
> retrieving revision 1.68
> diff -u -r1.68 alloc.c
> --- alloc.c	1998/01/24 19:00:21	1.68
> +++ alloc.c	1998/01/24 20:51:33
> @@ -88,6 +88,24 @@
>   */
>  /* #define ALLOC_USE_MALLOC */
>  
> +/* Pool debugging support.  This is intended to detect cases where the
> + * wrong pool is used when assigning data to an object in another pool.
> + * In particular, it causes the table_{set,add,merge}n routines to check
> + * that their arguments are safe for the table they're being placed in.
> + * It currently only works with the unix multiprocess model, but could
> + * be extended to others.
> + */
> +/* #define POOL_DEBUG */
> +
> +#ifdef POOL_DEBUG
> +#ifdef ALLOC_USE_MALLOC
> +# error "sorry, no support for ALLOC_USE_MALLOC and POOL_DEBUG at the same time"
> +#endif
> +#ifdef MULTITHREAD
> +# error "sorry, no support for MULTITHREAD and POOL_DEBUG at the same time"
> +#endif
> +#endif
> +
>  #ifdef ALLOC_USE_MALLOC
>  #undef BLOCK_MINFREE
>  #undef BLOCK_MINALLOC
> @@ -124,12 +142,22 @@
>  	char *endp;
>  	union block_hdr *next;
>  	char *first_avail;
> +#ifdef POOL_DEBUG
> +	union block_hdr *global_next;
> +	struct pool *owning_pool;
> +#endif
>      } h;
>  };
>  
>  union block_hdr *block_freelist = NULL;
>  mutex *alloc_mutex = NULL;
>  mutex *spawn_mutex = NULL;
> +#ifdef POOL_DEBUG
> +static char *known_stack_point;
> +static int stack_direction;
> +static union block_hdr *global_block_list;
> +#define FREE_POOL	((struct pool *)(-1))
> +#endif
>  
>  #ifdef ALLOC_DEBUG
>  #define FILL_BYTE	((char)(0xa5))
> @@ -170,16 +198,20 @@
>      blok->h.next = NULL;
>      blok->h.first_avail = (char *) (blok + 1);
>      blok->h.endp = size + blok->h.first_avail;
> +#ifdef POOL_DEBUG
> +    blok->h.global_next = global_block_list;
> +    global_block_list = blok;
> +    blok->h.owning_pool = NULL;
> +#endif
>  
>      return blok;
>  }
>  
>  
>  
> -void chk_on_blk_list(union block_hdr *blok, union block_hdr *free_blk)
> +#ifdef ALLOC_DEBUG
> +static void chk_on_blk_list(union block_hdr *blok, union block_hdr *free_blk)
>  {
> -    /* Debugging code.  Left in for the moment. */
> -
>      while (free_blk) {
>  	if (free_blk == blok) {
>  	    fprintf(stderr, "Ouch!  Freeing free block\n");
> @@ -189,6 +221,9 @@
>  	free_blk = free_blk->h.next;
>      }
>  }
> +#else
> +#define chk_on_blk_list(_x, _y)
> +#endif
>  
>  /* Free a chain of blocks --- must be called with alarms blocked. */
>  
> @@ -226,12 +261,18 @@
>  	chk_on_blk_list(blok, old_free_list);
>  	blok->h.first_avail = (char *) (blok + 1);
>  	debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
> +#ifdef POOL_DEBUG
> +	blok->h.owning_pool = FREE_POOL;
> +#endif
>  	blok = blok->h.next;
>      }
>  
>      chk_on_blk_list(blok, old_free_list);
>      blok->h.first_avail = (char *) (blok + 1);
>      debug_fill(blok->h.first_avail, blok->h.endp - blok->h.first_avail);
> +#ifdef POOL_DEBUG
> +    blok->h.owning_pool = FREE_POOL;
> +#endif
>  
>      /* Finally, reset next pointer to get the old free blocks back */
>  
> @@ -346,6 +387,9 @@
>      blok = new_block(POOL_HDR_BYTES);
>      new_pool = (pool *) blok->h.first_avail;
>      blok->h.first_avail += POOL_HDR_BYTES;
> +#ifdef POOL_DEBUG
> +    blok->h.owning_pool = new_pool;
> +#endif
>  
>      memset((char *) new_pool, '\0', sizeof(struct pool));
>      new_pool->free_first_avail = blok->h.first_avail;
> @@ -365,8 +409,28 @@
>      return new_pool;
>  }
>  
> +#ifdef POOL_DEBUG
> +static void stack_var_init(char *s)
> +{
> +    char t;
> +
> +    if (s < &t) {
> +	stack_direction = 1; /* stack grows up */
> +    }
> +    else {
> +	stack_direction = -1; /* stack grows down */
> +    }
> +}
> +#endif
> +
>  void init_alloc(void)
>  {
> +#ifdef POOL_DEBUG
> +    char s;
> +
> +    known_stack_point = &s;
> +    stack_var_init(&s);
> +#endif
>      alloc_mutex = create_mutex(NULL);
>      spawn_mutex = create_mutex(NULL);
>      permanent_pool = make_sub_pool(NULL);
> @@ -442,6 +506,87 @@
>  }
>  
>  /*****************************************************************
> + * POOL_DEBUG support
> + */
> +#ifdef POOL_DEBUG
> +
> +/* the unix linker defines this symbol as the last byte + 1 of
> + * the executable... so it includes TEXT, BSS, and DATA
> + */
> +extern char _end;
> +
> +/* is ptr in the range [lo,hi) */
> +#define is_ptr_in_range(ptr, lo, hi)	\
> +    (((unsigned long)(ptr) - (unsigned long)(lo)) \
> +	< \
> +	(unsigned long)(hi) - (unsigned long)(lo))
> +
> +/* Find the pool that ts belongs to, return NULL if it doesn't
> + * belong to any pool.
> + */
> +pool *find_pool(const void *ts)
> +{
> +    const char *s = ts;
> +    union block_hdr **pb;
> +    union block_hdr *b;
> +
> +    /* short-circuit stuff which is in TEXT, BSS, or DATA */
> +    if (is_ptr_in_range(s, 0, &_end)) {
> +	return NULL;
> +    }
> +    /* consider stuff on the stack to also be in the NULL pool...
> +     * XXX: there's cases where we don't want to assume this
> +     */
> +    if ((stack_direction == -1 && is_ptr_in_range(s, &ts, known_stack_point))
> +	|| (stack_direction == 1 && is_ptr_in_range(s, known_stack_point, &ts))) {
> +	abort();
> +	return NULL;
> +    }
> +    block_alarms();
> +    /* search the global_block_list */
> +    for (pb = &global_block_list; *pb; pb = &b->h.global_next) {
> +	b = *pb;
> +	if (is_ptr_in_range(s, b, b->h.endp)) {
> +	    if (b->h.owning_pool == FREE_POOL) {
> +		fprintf(stderr,
> +		    "Ouch!  find_pool() called on pointer in a free block\n");
> +		abort();
> +		exit(1);
> +	    }
> +	    if (b != global_block_list) {
> +		/* promote b to front of list, this is a hack to speed
> +		 * up the lookup */
> +		*pb = b->h.global_next;
> +		b->h.global_next = global_block_list;
> +		global_block_list = b;
> +	    }
> +	    unblock_alarms();
> +	    return b->h.owning_pool;
> +	}
> +    }
> +    unblock_alarms();
> +    return NULL;
> +}
> +
> +/* return TRUE iff a is an ancestor of b
> + * NULL is considered an ancestor of all pools
> + */
> +int pool_is_ancestor(pool *a, pool *b)
> +{
> +    if (a == NULL) {
> +	return 1;
> +    }
> +    while (b) {
> +	if (a == b) {
> +	    return 1;
> +	}
> +	b = b->parent;
> +    }
> +    return 0;
> +}
> +#endif
> +
> +/*****************************************************************
>   *
>   * Allocating stuff...
>   */
> @@ -501,6 +646,9 @@
>      blok = new_block(size);
>      a->last->h.next = blok;
>      a->last = blok;
> +#ifdef POOL_DEBUG
> +    blok->h.owning_pool = a;
> +#endif
>  
>      (void) release_mutex(alloc_mutex);
>  
> @@ -523,10 +671,13 @@
>  API_EXPORT(char *) pstrdup(struct pool *a, const char *s)
>  {
>      char *res;
> +    size_t len;
> +
>      if (s == NULL)
>  	return NULL;
> -    res = palloc(a, strlen(s) + 1);
> -    strcpy(res, s);
> +    len = strlen(s) + 1;
> +    res = palloc(a, len);
> +    memcpy(res, s, len);
>      return res;
>  }
>  
> @@ -781,6 +932,52 @@
>      }
>  }
>  
> +API_EXPORT(void) table_setn(table *t, char *key, char *val)
> +{
> +    register int i, j, k;
> +    table_entry *elts = (table_entry *) t->a.elts;
> +    int done = 0;
> +
> +#ifdef POOL_DEBUG
> +    {
> +	if (!pool_is_ancestor(find_pool(key), t->a.pool)) {
> +	    fprintf(stderr, "table_set: key not in ancestor pool of t\n");
> +	    abort();
> +	}
> +	if (!pool_is_ancestor(find_pool(val), t->a.pool)) {
> +	    fprintf(stderr, "table_set: key not in ancestor pool of t\n");
> +	    abort();
> +	}
> +    }
> +#endif
> +
> +    for (i = 0; i < t->a.nelts; ) {
> +	if (!strcasecmp(elts[i].key, key)) {
> +	    if (!done) {
> +		elts[i].val =  val;
> +		done = 1;
> +		++i;
> +	    }
> +	    else {		/* delete an extraneous element */
> +		for (j = i, k = i + 1; k < t->a.nelts; ++j, ++k) {
> +		    elts[j].key = elts[k].key;
> +		    elts[j].val = elts[k].val;
> +		}
> +		--t->a.nelts;
> +	    }
> +	}
> +	else {
> +	    ++i;
> +	}
> +    }
> +
> +    if (!done) {
> +	elts = (table_entry *) push_array(&t->a);
> +	elts->key = key;
> +	elts->val = val;
> +    }
> +}
> +
>  API_EXPORT(void) table_unset(table *t, const char *key)
>  {
>      register int i, j, k;
> @@ -811,18 +1008,47 @@
>      table_entry *elts = (table_entry *) t->a.elts;
>      int i;
>  
> -    for (i = 0; i < t->a.nelts; ++i) {
> +    for (i = 0; i < t->a.nelts; ++i)
>  	if (!strcasecmp(elts[i].key, key)) {
>  	    elts[i].val = pstrcat(t->a.pool, elts[i].val, ", ", val, NULL);
>  	    return;
>  	}
> -    }
>  
>      elts = (table_entry *) push_array(&t->a);
>      elts->key = pstrdup(t->a.pool, key);
>      elts->val = pstrdup(t->a.pool, val);
>  }
>  
> +API_EXPORT(void) table_mergen(table *t, char *key, char *val)
> +{
> +    table_entry *elts = (table_entry *) t->a.elts;
> +    int i;
> +
> +#ifdef POOL_DEBUG
> +    {
> +	if (!pool_is_ancestor(find_pool(key), t->a.pool)) {
> +	    fprintf(stderr, "table_set: key not in ancestor pool of t\n");
> +	    abort();
> +	}
> +	if (!pool_is_ancestor(find_pool(val), t->a.pool)) {
> +	    fprintf(stderr, "table_set: key not in ancestor pool of t\n");
> +	    abort();
> +	}
> +    }
> +#endif
> +
> +    for (i = 0; i < t->a.nelts; ++i) {
> +	if (!strcasecmp(elts[i].key, key)) {
> +	    elts[i].val = pstrcat(t->a.pool, elts[i].val, ", ", val, NULL);
> +	    return;
> +	}
> +    }
> +
> +    elts = (table_entry *) push_array(&t->a);
> +    elts->key = key;
> +    elts->val = val;
> +}
> +
>  API_EXPORT(void) table_add(table *t, const char *key, const char *val)
>  {
>      table_entry *elts = (table_entry *) t->a.elts;
> @@ -830,6 +1056,28 @@
>      elts = (table_entry *) push_array(&t->a);
>      elts->key = pstrdup(t->a.pool, key);
>      elts->val = pstrdup(t->a.pool, val);
> +}
> +
> +API_EXPORT(void) table_addn(table *t, char *key, char *val)
> +{
> +    table_entry *elts = (table_entry *) t->a.elts;
> +
> +#ifdef POOL_DEBUG
> +    {
> +	if (!pool_is_ancestor(find_pool(key), t->a.pool)) {
> +	    fprintf(stderr, "table_set: key not in ancestor pool of t\n");
> +	    abort();
> +	}
> +	if (!pool_is_ancestor(find_pool(val), t->a.pool)) {
> +	    fprintf(stderr, "table_set: key not in ancestor pool of t\n");
> +	    abort();
> +	}
> +    }
> +#endif
> +
> +    elts = (table_entry *) push_array(&t->a);
> +    elts->key = key;
> +    elts->val = val;
>  }
>  
>  API_EXPORT(table *) overlay_tables(pool *p, const table *overlay, const table *base)
> Index: main/alloc.h
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/main/alloc.h,v
> retrieving revision 1.42
> diff -u -r1.42 alloc.h
> --- alloc.h	1998/01/24 20:02:19	1.42
> +++ alloc.h	1998/01/24 20:51:36
> @@ -155,9 +155,12 @@
>  API_EXPORT(void) clear_table(table *);
>  API_EXPORT(char *) table_get(const table *, const char *);
>  API_EXPORT(void) table_set(table *, const char *name, const char *val);
> +API_EXPORT(void) table_setn(table *, char *name, char *val);
>  API_EXPORT(void) table_merge(table *, const char *name, const char *more_val);
> +API_EXPORT(void) table_mergen(table *, char *name, char *more_val);
>  API_EXPORT(void) table_unset(table *, const char *key);
>  API_EXPORT(void) table_add(table *, const char *name, const char *val);
> +API_EXPORT(void) table_addn(table *, char *name, char *val);
>  API_EXPORT(void) table_do(int (*comp) (void *, const char *, const char *), void *rec,
>  			  const table *t,...);
>  
> Index: main/http_core.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/main/http_core.c,v
> retrieving revision 1.147
> diff -u -r1.147 http_core.c
> --- http_core.c	1998/01/21 22:15:56	1.147
> +++ http_core.c	1998/01/24 20:51:40
> @@ -1895,7 +1895,7 @@
>  #endif
>  
>  	if (d->content_md5 & 1) {
> -	    table_set (r->headers_out, "Content-MD5", ap_md5digest(r->pool, f));
> +	    table_setn(r->headers_out, "Content-MD5", ap_md5digest(r->pool, f));
>  	}
>  
>  	rangestatus = set_byterange(r);
> @@ -1956,7 +1956,7 @@
>  	    
>  	    MD5Init(&context);
>  	    MD5Update(&context, (void *)mm, r->finfo.st_size);
> -	    table_set (r->headers_out, "Content-MD5",
> +	    table_setn(r->headers_out, "Content-MD5",
>  		ap_md5contextTo64(r->pool, &context));
>  	}
>  
> Index: main/http_protocol.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/main/http_protocol.c,v
> retrieving revision 1.178
> diff -u -r1.178 http_protocol.c
> --- http_protocol.c	1998/01/23 04:11:32	1.178
> +++ http_protocol.c	1998/01/24 20:51:41
> @@ -138,7 +138,7 @@
>          range = table_get(r->headers_in, "Request-Range");
>  
>      if (!range || strncmp(range, "bytes=", 6)) {
> -        table_set(r->headers_out, "Accept-Ranges", "bytes");
> +        table_setn(r->headers_out, "Accept-Ranges", "bytes");
>          return 0;
>      }
>  
> @@ -165,9 +165,9 @@
>  
>          ap_snprintf(ts, sizeof(ts), "bytes %ld-%ld/%ld",
>                      range_start, range_end, r->clength);
> -        table_set(r->headers_out, "Content-Range", ts);
> +        table_setn(r->headers_out, "Content-Range", pstrdup(r->pool, ts));
>          ap_snprintf(ts, sizeof(ts), "%ld", range_end - range_start + 1);
> -        table_set(r->headers_out, "Content-Length", ts);
> +        table_setn(r->headers_out, "Content-Length", pstrdup(r->pool, ts));
>      }
>      else {
>          /* a multiple range */
> @@ -181,7 +181,7 @@
>          r->boundary = pstrdup(r->pool, boundary);
>          while (internal_byterange(0, &tlength, r, &r_range, NULL, NULL));
>          ap_snprintf(ts, sizeof(ts), "%ld", tlength);
> -        table_set(r->headers_out, "Content-Length", ts);
> +        table_setn(r->headers_out, "Content-Length", pstrdup(r->pool, ts));
>      }
>  
>      r->status = PARTIAL_CONTENT;
> @@ -259,7 +259,7 @@
>      r->clength = clength;
>  
>      ap_snprintf(ts, sizeof(ts), "%ld", clength);
> -    table_set(r->headers_out, "Content-Length", ts);
> +    table_setn(r->headers_out, "Content-Length", pstrdup(r->pool, ts));
>  
>      return 0;
>  }
> @@ -331,8 +331,8 @@
>              else
>                  ap_snprintf(header, sizeof(header), "timeout=%d",
>                              r->server->keep_alive_timeout);
> -            table_set(r->headers_out, "Keep-Alive", header);
> -            table_merge(r->headers_out, "Connection", "Keep-Alive");
> +            table_setn(r->headers_out, "Keep-Alive", pstrdup(r->pool, header));
> +            table_mergen(r->headers_out, "Connection", "Keep-Alive");
>          }
>  
>          return 1;
> @@ -347,7 +347,7 @@
>       * to a HTTP/1.1 client. Better safe than sorry.
>       */
>      if (!wimpy)
> -      table_merge(r->headers_out, "Connection", "close");
> +	table_mergen(r->headers_out, "Connection", "close");
>  
>      r->connection->keepalive = 0;
>  
> @@ -502,7 +502,7 @@
>      }
>  
>      etag = weak_etag + ((r->request_time - r->mtime > 1) ? 2 : 0);
> -    table_set(r->headers_out, "ETag", etag);
> +    table_setn(r->headers_out, "ETag", pstrdup(r->pool, etag));
>  }
>  
>  /*
> @@ -514,7 +514,7 @@
>  {
>      time_t mod_time = rationalize_mtime(r, r->mtime);
>  
> -    table_set(r->headers_out, "Last-Modified",
> +    table_setn(r->headers_out, "Last-Modified",
>                gm_timestr_822(r->pool, mod_time));
>  }
>  
> @@ -753,8 +753,10 @@
>       * overflow (len == MAX_STRING_LEN-1)?
>       */
>      while ((len = getline(field, MAX_STRING_LEN, c->client, 1)) > 0) {
> +        char *copy = palloc(r->pool, len + 1);
> +        memcpy(copy, field, len + 1);
>  
> -        if (!(value = strchr(field, ':')))      /* Find the colon separator */
> +        if (!(value = strchr(copy, ':')))      /* Find the colon separator */
>              continue;           /* or should puke 400 here */
>  
>          *value = '\0';
> @@ -762,7 +764,7 @@
>          while (isspace(*value))
>              ++value;            /* Skip to start of value   */
>  
> -        table_merge(r->headers_in, field, value);
> +        table_mergen(r->headers_in, copy, value);
>      }
>  }
>  
> @@ -906,7 +908,7 @@
>      if (strcasecmp(auth_type(r), "Basic"))
>          note_auth_failure(r);
>      else
> -        table_set(r->err_headers_out,
> +        table_setn(r->err_headers_out,
>                    r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
>                    pstrcat(r->pool, "Basic realm=\"", auth_name(r), "\"",
>                            NULL));
> @@ -917,7 +919,7 @@
>      char nonce[256];
>  
>      ap_snprintf(nonce, sizeof(nonce), "%lu", r->request_time);
> -    table_set(r->err_headers_out,
> +    table_setn(r->err_headers_out,
>                r->proxyreq ? "Proxy-Authenticate" : "WWW-Authenticate",
>                pstrcat(r->pool, "Digest realm=\"", auth_name(r),
>                        "\", nonce=\"", nonce, "\"", NULL));
> @@ -1173,8 +1175,8 @@
>  
>      basic_http_header(r);
>  
> -    table_set(r->headers_out, "Content-Length", "0");
> -    table_set(r->headers_out, "Allow", make_allow(r));
> +    table_setn(r->headers_out, "Content-Length", "0");
> +    table_setn(r->headers_out, "Allow", make_allow(r));
>      set_keepalive(r);
>  
>      table_do((int (*) (void *, const char *, const char *)) send_header_field,
> @@ -1231,37 +1233,37 @@
>      set_keepalive(r);
>  
>      if (r->chunked) {
> -        table_merge(r->headers_out, "Transfer-Encoding", "chunked");
> +        table_mergen(r->headers_out, "Transfer-Encoding", "chunked");
>          table_unset(r->headers_out, "Content-Length");
>      }
>  
>      if (r->byterange > 1)
> -        table_set(r->headers_out, "Content-Type",
> +        table_setn(r->headers_out, "Content-Type",
>                    pstrcat(r->pool, "multipart", use_range_x(r) ? "/x-" : "/",
>                            "byteranges; boundary=", r->boundary, NULL));
>      else if (r->content_type)
> -        table_set(r->headers_out, "Content-Type", r->content_type);
> +        table_setn(r->headers_out, "Content-Type", r->content_type);
>      else
> -        table_set(r->headers_out, "Content-Type", default_type(r));
> +        table_setn(r->headers_out, "Content-Type", default_type(r));
>  
>      if (r->content_encoding)
> -        table_set(r->headers_out, "Content-Encoding", r->content_encoding);
> +        table_setn(r->headers_out, "Content-Encoding", r->content_encoding);
>  
>      if (r->content_languages && r->content_languages->nelts) {
>          for (i = 0; i < r->content_languages->nelts; ++i) {
> -            table_merge(r->headers_out, "Content-Language",
> +            table_mergen(r->headers_out, "Content-Language",
>                          ((char **) (r->content_languages->elts))[i]);
>          }
>      }
>      else if (r->content_language)
> -        table_set(r->headers_out, "Content-Language", r->content_language);
> +        table_setn(r->headers_out, "Content-Language", r->content_language);
>  
>      /*
>       * Control cachability for non-cachable responses if not already set by
>       * some other part of the server configuration.
>       */
>      if (r->no_cache && !table_get(r->headers_out, "Expires"))
> -        table_add(r->headers_out, "Expires",
> +        table_addn(r->headers_out, "Expires",
>                    gm_timestr_822(r->pool, r->request_time));
>  
>      /* Send the entire table of header fields, terminated by an empty line. */
> @@ -1486,7 +1488,8 @@
>                  get_mime_headers(r);
>                  ap_snprintf(buffer, bufsiz, "%ld", r->read_length);
>                  table_unset(r->headers_in, "Transfer-Encoding");
> -                table_set(r->headers_in, "Content-Length", buffer);
> +                table_setn(r->headers_in, "Content-Length",
> +                    pstrdup(r->pool, buffer));
>                  return 0;
>              }
>              r->remaining = -1;  /* Indicate footers in-progress */
> @@ -1992,7 +1995,7 @@
>  
>          if (location && *location
>              && (is_HTTP_REDIRECT(status) || status == HTTP_CREATED))
> -            table_set(r->headers_out, "Location", location);
> +            table_setn(r->headers_out, "Location", location);
>  
>          r->content_language = NULL;
>          r->content_languages = NULL;
> @@ -2001,7 +2004,7 @@
>          r->content_type = "text/html";
>  
>          if ((status == METHOD_NOT_ALLOWED) || (status == NOT_IMPLEMENTED))
> -            table_set(r->headers_out, "Allow", make_allow(r));
> +            table_setn(r->headers_out, "Allow", make_allow(r));
>  
>          send_http_header(r);
>  
> Index: main/http_request.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/main/http_request.c,v
> retrieving revision 1.100
> diff -u -r1.100 http_request.c
> --- http_request.c	1998/01/21 22:48:13	1.100
> +++ http_request.c	1998/01/24 20:51:42
> @@ -903,7 +903,7 @@
>               * status...
>               */
>              r->status = REDIRECT;
> -            table_set(r->headers_out, "Location", custom_response);
> +            table_setn(r->headers_out, "Location", custom_response);
>          }
>          else if (custom_response[0] == '/') {
>              r->no_local_copy = 1;       /* Do NOT send USE_LOCAL_COPY for
> @@ -912,7 +912,7 @@
>               * This redirect needs to be a GET no matter what the original
>               * method was.
>               */
> -            table_set(r->subprocess_env, "REQUEST_METHOD", r->method);
> +            table_setn(r->subprocess_env, "REQUEST_METHOD", r->method);
>              r->method = pstrdup(r->pool, "GET");
>              r->method_number = M_GET;
>              internal_redirect(custom_response, r);
> @@ -1168,7 +1168,7 @@
>      for (i = 0; i < env_arr->nelts; ++i) {
>          if (!elts[i].key)
>              continue;
> -        table_set(new, pstrcat(p, "REDIRECT_", elts[i].key, NULL),
> +        table_setn(new, pstrcat(p, "REDIRECT_", elts[i].key, NULL),
>                    elts[i].val);
>      }
>  
> @@ -1228,7 +1228,7 @@
>      new->read_length     = r->read_length;     /* We can only read it once */
>  
>      ap_snprintf(t, sizeof(t), "%d", r->status);
> -    table_set(new->subprocess_env, "REDIRECT_STATUS", t);
> +    table_setn(new->subprocess_env, "REDIRECT_STATUS", pstrdup(r->pool, t));
>  
>      /*
>       * XXX: hmm.  This is because mod_setenvif and mod_unique_id really need
> Index: main/util_script.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/main/util_script.c,v
> retrieving revision 1.92
> diff -u -r1.92 util_script.c
> --- util_script.c	1998/01/21 22:31:46	1.92
> +++ util_script.c	1998/01/24 20:51:44
> @@ -205,9 +205,9 @@
>  	 */
>  
>  	if (!strcasecmp(hdrs[i].key, "Content-type"))
> -	    table_set(e, "CONTENT_TYPE", hdrs[i].val);
> +	    table_setn(e, "CONTENT_TYPE", hdrs[i].val);
>  	else if (!strcasecmp(hdrs[i].key, "Content-length"))
> -	    table_set(e, "CONTENT_LENGTH", hdrs[i].val);
> +	    table_setn(e, "CONTENT_LENGTH", hdrs[i].val);
>  	/*
>  	 * You really don't want to disable this check, since it leaves you
>  	 * wide open to CGIs stealing passwords and people viewing them
> @@ -218,7 +218,7 @@
>  	    continue;
>  #endif
>  	else
> -	    table_set(e, http2env(r->pool, hdrs[i].key), hdrs[i].val);
> +	    table_setn(e, http2env(r->pool, hdrs[i].key), hdrs[i].val);
>      }
>  
>      ap_snprintf(port, sizeof(port), "%u", s->port);
> @@ -228,42 +228,42 @@
>  
>  #ifdef WIN32
>      if (env_temp = getenv("SystemRoot"))
> -        table_set(e, "SystemRoot", env_temp);         
> +        table_setn(e, "SystemRoot", env_temp);         
>      if (env_temp = getenv("COMSPEC"))
> -        table_set(e, "COMSPEC", env_temp);            
> +        table_setn(e, "COMSPEC", env_temp);            
>      if (env_temp = getenv("WINDIR"))
> -        table_set(e, "WINDIR", env_temp);             
> +        table_setn(e, "WINDIR", env_temp);             
>  #endif
>  
> -    table_set(e, "PATH", env_path);
> -    table_set(e, "SERVER_SOFTWARE", SERVER_VERSION);
> -    table_set(e, "SERVER_NAME", s->server_hostname);
> -    table_set(e, "SERVER_PORT", port);
> -    table_set(e, "REMOTE_HOST",
> -	      get_remote_host(c, r->per_dir_config, REMOTE_NAME));
> -    table_set(e, "REMOTE_ADDR", c->remote_ip);
> -    table_set(e, "DOCUMENT_ROOT", document_root(r));	/* Apache */
> -    table_set(e, "SERVER_ADMIN", s->server_admin);	/* Apache */
> -    table_set(e, "SCRIPT_FILENAME", r->filename);	/* Apache */
> +    table_setn(e, "PATH", env_path);
> +    table_setn(e, "SERVER_SOFTWARE", SERVER_VERSION);
> +    table_setn(e, "SERVER_NAME", s->server_hostname);
> +    table_setn(e, "SERVER_PORT", pstrdup(r->pool,port));
> +    table_setn(e, "REMOTE_HOST",
> +        pstrdup(r->pool, get_remote_host(c, r->per_dir_config, REMOTE_NAME)));
> +    table_setn(e, "REMOTE_ADDR", c->remote_ip);
> +    table_setn(e, "DOCUMENT_ROOT", document_root(r));	/* Apache */
> +    table_setn(e, "SERVER_ADMIN", s->server_admin);	/* Apache */
> +    table_setn(e, "SCRIPT_FILENAME", r->filename);	/* Apache */
>  
>      ap_snprintf(port, sizeof(port), "%d", ntohs(c->remote_addr.sin_port));
> -    table_set(e, "REMOTE_PORT", port);	/* Apache */
> +    table_setn(e, "REMOTE_PORT", pstrdup(r->pool, port)); /* Apache */
>  
>      if (c->user)
> -	table_set(e, "REMOTE_USER", c->user);
> +	table_setn(e, "REMOTE_USER", c->user);
>      if (c->auth_type)
> -	table_set(e, "AUTH_TYPE", c->auth_type);
> +	table_setn(e, "AUTH_TYPE", c->auth_type);
>      rem_logname = get_remote_logname(r);
>      if (rem_logname)
> -	table_set(e, "REMOTE_IDENT", rem_logname);
> +	table_setn(e, "REMOTE_IDENT", pstrdup(r->pool, rem_logname));
>  
>      /* Apache custom error responses. If we have redirected set two new vars */
>  
>      if (r->prev) {
>  	if (r->prev->args)
> -	    table_set(e, "REDIRECT_QUERY_STRING", r->prev->args);
> +	    table_setn(e, "REDIRECT_QUERY_STRING", r->prev->args);
>  	if (r->prev->uri)
> -	    table_set(e, "REDIRECT_URL", r->prev->uri);
> +	    table_setn(e, "REDIRECT_URL", r->prev->uri);
>      }
>  }
>  
> @@ -316,11 +316,11 @@
>  {
>      table *e = r->subprocess_env;
>  
> -    table_set(e, "GATEWAY_INTERFACE", "CGI/1.1");
> -    table_set(e, "SERVER_PROTOCOL", r->protocol);
> -    table_set(e, "REQUEST_METHOD", r->method);
> -    table_set(e, "QUERY_STRING", r->args ? r->args : "");
> -    table_set(e, "REQUEST_URI", original_uri(r));
> +    table_setn(e, "GATEWAY_INTERFACE", "CGI/1.1");
> +    table_setn(e, "SERVER_PROTOCOL", r->protocol);
> +    table_setn(e, "REQUEST_METHOD", r->method);
> +    table_setn(e, "QUERY_STRING", r->args ? r->args : "");
> +    table_setn(e, "REQUEST_URI", original_uri(r));
>  
>      /* Note that the code below special-cases scripts run from includes,
>       * because it "knows" that the sub_request has been hacked to have the
> @@ -329,20 +329,20 @@
>       */
>  
>      if (!strcmp(r->protocol, "INCLUDED")) {
> -	table_set(e, "SCRIPT_NAME", r->uri);
> +	table_setn(e, "SCRIPT_NAME", r->uri);
>  	if (r->path_info && *r->path_info)
> -	    table_set(e, "PATH_INFO", r->path_info);
> +	    table_setn(e, "PATH_INFO", r->path_info);
>      }
>      else if (!r->path_info || !*r->path_info) {
> -	table_set(e, "SCRIPT_NAME", r->uri);
> +	table_setn(e, "SCRIPT_NAME", r->uri);
>      }
>      else {
>  	int path_info_start = find_path_info(r->uri, r->path_info);
>  
> -	table_set(e, "SCRIPT_NAME", pstrndup(r->pool, r->uri,
> +	table_setn(e, "SCRIPT_NAME", pstrndup(r->pool, r->uri,
>  					     path_info_start));
>  
> -	table_set(e, "PATH_INFO", r->path_info);
> +	table_setn(e, "PATH_INFO", r->path_info);
>      }
>  
>      if (r->path_info && r->path_info[0]) {
> @@ -370,9 +370,9 @@
>  #ifdef WIN32
>  	    /* We need to make this a real Windows path name */
>  	    GetFullPathName(pt, HUGE_STRING_LEN, buffer, NULL);
> -	    table_set(e, "PATH_TRANSLATED", buffer);
> +	    table_setn(e, "PATH_TRANSLATED", pstrdup(r->pool, buffer));
>  #else
> -	    table_set(e, "PATH_TRANSLATED", pt);
> +	    table_setn(e, "PATH_TRANSLATED", pt);
>  #endif
>  	}
>      }
> @@ -471,13 +471,13 @@
>  	    r->status_line = pstrdup(r->pool, l);
>  	}
>  	else if (!strcasecmp(w, "Location")) {
> -	    table_set(r->headers_out, w, l);
> +	    table_setn(r->headers_out, pstrdup(r->pool,w), pstrdup(r->pool,l));
>  	}
>  	else if (!strcasecmp(w, "Content-Length")) {
> -	    table_set(r->headers_out, w, l);
> +	    table_setn(r->headers_out, pstrdup(r->pool,w), pstrdup(r->pool,l));
>  	}
>  	else if (!strcasecmp(w, "Transfer-Encoding")) {
> -	    table_set(r->headers_out, w, l);
> +	    table_setn(r->headers_out, pstrdup(r->pool,w), pstrdup(r->pool,l));
>  	}
>  	/*
>  	 * If the script gave us a Last-Modified header, we can't just
> @@ -494,7 +494,7 @@
>  	 * we'll use - otherwise we assume 200 OK.
>  	 */
>  	else if (!strcasecmp(w, "Status")) {
> -	    table_set(r->headers_out, w, l);
> +	    table_setn(r->headers_out, pstrdup(r->pool,w), pstrdup(r->pool,l));
>  	    cgi_status = atoi(l);
>  	}
>  
> @@ -504,10 +504,10 @@
>  	 * separately.  Lets humour those browsers.
>  	 */
>  	else if (!strcasecmp(w, "Set-Cookie")) {
> -	    table_add(r->err_headers_out, w, l);
> +	    table_addn(r->err_headers_out, pstrdup(r->pool,w), pstrdup(r->pool,l));
>  	}
>  	else {
> -	    table_merge(r->err_headers_out, w, l);
> +	    table_mergen(r->err_headers_out, pstrdup(r->pool,w), pstrdup(r->pool,l));
>  	}
>      }
>  }
> Index: modules/proxy/mod_proxy.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/proxy/mod_proxy.c,v
> retrieving revision 1.32
> diff -u -r1.32 mod_proxy.c
> --- mod_proxy.c	1998/01/24 20:30:07	1.32
> +++ mod_proxy.c	1998/01/24 20:51:44
> @@ -251,7 +251,7 @@
>  		       host, domain, strport, "/", path,
>  		       NULL);
>  
> -	table_set(r->headers_out, "Location", nuri);
> +	table_setn(r->headers_out, "Location", nuri);
>  	aplog_error(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, r->server,
>  	    "Domain missing: %s sent to %s from %s", r->uri, nuri,
>  	    ref ? ref : "-");
> Index: modules/standard/mod_alias.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_alias.c,v
> retrieving revision 1.29
> diff -u -r1.29 mod_alias.c
> --- mod_alias.c	1998/01/07 16:46:43	1.29
> +++ mod_alias.c	1998/01/24 20:51:44
> @@ -328,7 +328,7 @@
>  	if (found) {
>  	    if (p->handler) {	/* Set handler, and leave a note for mod_cgi */
>  		r->handler = pstrdup(r->pool, p->handler);
> -		table_set(r->notes, "alias-forced-type", p->handler);
> +		table_setn(r->notes, "alias-forced-type", r->handler);
>  	    }
>  
>  	    *status = p->redir_status;
> @@ -363,7 +363,7 @@
>  	    if (r->args) {
>  		ret = pstrcat(r->pool, ret, "?", r->args, NULL);
>  	    }
> -	    table_set(r->headers_out, "Location", ret);
> +	    table_setn(r->headers_out, "Location", ret);
>  	}
>  	return status;
>      }
> @@ -388,7 +388,7 @@
>  
>      if ((ret = try_alias_list(r, dirconf->redirects, 1, &status)) != NULL) {
>  	if (is_HTTP_REDIRECT(status))
> -	    table_set(r->headers_out, "Location", ret);
> +	    table_setn(r->headers_out, "Location", ret);
>  	return status;
>      }
>  
> Index: modules/standard/mod_dir.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_dir.c,v
> retrieving revision 1.44
> diff -u -r1.44 mod_dir.c
> --- mod_dir.c	1998/01/07 16:46:47	1.44
> +++ mod_dir.c	1998/01/24 20:51:44
> @@ -117,7 +117,7 @@
>              ifile = pstrcat(r->pool, escape_uri(r->pool, r->uri),
>                              "/", NULL);
>  
> -        table_set(r->headers_out, "Location",
> +        table_setn(r->headers_out, "Location",
>                    construct_url(r->pool, ifile, r->server));
>          return HTTP_MOVED_PERMANENTLY;
>      }
> Index: modules/standard/mod_expires.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_expires.c,v
> retrieving revision 1.21
> diff -u -r1.21 mod_expires.c
> --- mod_expires.c	1998/01/07 16:46:49	1.21
> +++ mod_expires.c	1998/01/24 20:51:45
> @@ -473,11 +473,11 @@
>  
>      expires = base + additional;
>      ap_snprintf(age, sizeof(age), "max-age=%d", (int) expires - (int) r->request_time);
> -    table_set(r->headers_out, "Cache-Control", age);
> +    table_setn(r->headers_out, "Cache-Control", pstrdup(r->pool, age));
>      tzset();                    /* redundant? called implicitly by localtime, at least 
>                                   * under FreeBSD
>                                   */
> -    table_set(r->headers_out, "Expires", gm_timestr_822(r->pool, expires));
> +    table_setn(r->headers_out, "Expires", gm_timestr_822(r->pool, expires));
>      return OK;
>  }
>  
> Index: modules/standard/mod_imap.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_imap.c,v
> retrieving revision 1.39
> diff -u -r1.39 mod_imap.c
> --- mod_imap.c	1998/01/22 23:18:07	1.39
> +++ mod_imap.c	1998/01/24 20:51:45
> @@ -543,7 +543,7 @@
>          return HTTP_NO_CONTENT; /* tell the client to keep the page it has */
>      }
>      if (redirect && *redirect) {
> -        table_set(r->headers_out, "Location", redirect);
> +        table_setn(r->headers_out, "Location", redirect);
>          return REDIRECT;        /* must be a URL, so redirect to it */
>      }
>      return SERVER_ERROR;
> Index: modules/standard/mod_include.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_include.c,v
> retrieving revision 1.65
> diff -u -r1.65 mod_include.c
> --- mod_include.c	1998/01/24 19:00:24	1.65
> +++ mod_include.c	1998/01/24 20:51:46
> @@ -112,36 +112,36 @@
>      char *t;
>      time_t date = r->request_time;
>  
> -    table_set(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
> -    table_set(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
> -    table_set(e, "LAST_MODIFIED",
> +    table_setn(e, "DATE_LOCAL", ht_time(r->pool, date, timefmt, 0));
> +    table_setn(e, "DATE_GMT", ht_time(r->pool, date, timefmt, 1));
> +    table_setn(e, "LAST_MODIFIED",
>                ht_time(r->pool, r->finfo.st_mtime, timefmt, 0));
> -    table_set(e, "DOCUMENT_URI", r->uri);
> -    table_set(e, "DOCUMENT_PATH_INFO", r->path_info);
> +    table_setn(e, "DOCUMENT_URI", r->uri);
> +    table_setn(e, "DOCUMENT_PATH_INFO", r->path_info);
>  #ifndef WIN32
>      pw = getpwuid(r->finfo.st_uid);
>      if (pw) {
> -        table_set(e, "USER_NAME", pw->pw_name);
> +        table_setn(e, "USER_NAME", pstrdup(r->pool, pw->pw_name));
>      }
>      else {
>          char uid[16];
>          ap_snprintf(uid, sizeof(uid), "user#%lu",
>                      (unsigned long) r->finfo.st_uid);
> -        table_set(e, "USER_NAME", uid);
> +        table_setn(e, "USER_NAME", pstrdup(r->pool, uid));
>      }
>  #endif /* ndef WIN32 */
>  
>      if ((t = strrchr(r->filename, '/'))) {
> -        table_set(e, "DOCUMENT_NAME", ++t);
> +        table_setn(e, "DOCUMENT_NAME", ++t);
>      }
>      else {
> -        table_set(e, "DOCUMENT_NAME", r->uri);
> +        table_setn(e, "DOCUMENT_NAME", r->uri);
>      }
>      if (r->args) {
>          char *arg_copy = pstrdup(r->pool, r->args);
>  
>          unescape_url(arg_copy);
> -        table_set(e, "QUERY_STRING_UNESCAPED",
> +        table_setn(e, "QUERY_STRING_UNESCAPED",
>                    escape_shell_cmd(r->pool, arg_copy));
>      }
>  }
> @@ -746,11 +746,11 @@
>      if (r->path_info && r->path_info[0] != '\0') {
>          request_rec *pa_req;
>  
> -        table_set(env, "PATH_INFO", escape_shell_cmd(r->pool, r->path_info));
> +        table_setn(env, "PATH_INFO", escape_shell_cmd(r->pool, r->path_info));
>  
>          pa_req = sub_req_lookup_uri(escape_uri(r->pool, r->path_info), r);
>          if (pa_req->filename) {
> -            table_set(env, "PATH_TRANSLATED",
> +            table_setn(env, "PATH_TRANSLATED",
>                        pstrcat(r->pool, pa_req->filename, pa_req->path_info,
>                                NULL));
>          }
> @@ -759,9 +759,9 @@
>      if (r->args) {
>          char *arg_copy = pstrdup(r->pool, r->args);
>  
> -        table_set(env, "QUERY_STRING", r->args);
> +        table_setn(env, "QUERY_STRING", r->args);
>          unescape_url(arg_copy);
> -        table_set(env, "QUERY_STRING_UNESCAPED",
> +        table_setn(env, "QUERY_STRING_UNESCAPED",
>                    escape_shell_cmd(r->pool, arg_copy));
>      }
>  
> @@ -951,9 +951,9 @@
>              time_t date = r->request_time;
>  
>              parse_string(r, tag_val, tf, MAX_STRING_LEN, 0);
> -            table_set(env, "DATE_LOCAL", ht_time(r->pool, date, tf, 0));
> -            table_set(env, "DATE_GMT", ht_time(r->pool, date, tf, 1));
> -            table_set(env, "LAST_MODIFIED",
> +            table_setn(env, "DATE_LOCAL", ht_time(r->pool, date, tf, 0));
> +            table_setn(env, "DATE_GMT", ht_time(r->pool, date, tf, 1));
> +            table_setn(env, "LAST_MODIFIED",
>                        ht_time(r->pool, r->finfo.st_mtime, tf, 0));
>          }
>          else if (!strcmp(tag, "sizefmt")) {
> @@ -2015,7 +2015,7 @@
>                  return -1;
>              }
>              parse_string(r, tag_val, parsed_string, sizeof(parsed_string), 0);
> -            table_set(r->subprocess_env, var, parsed_string);
> +            table_setn(r->subprocess_env, var, pstrdup(r->pool, parsed_string));
>          }
>          else {
>              aplog_error(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r->server,
> @@ -2080,9 +2080,9 @@
>      if (r->args) {              /* add QUERY stuff to env cause it ain't yet */
>          char *arg_copy = pstrdup(r->pool, r->args);
>  
> -        table_set(r->subprocess_env, "QUERY_STRING", r->args);
> +        table_setn(r->subprocess_env, "QUERY_STRING", r->args);
>          unescape_url(arg_copy);
> -        table_set(r->subprocess_env, "QUERY_STRING_UNESCAPED",
> +        table_setn(r->subprocess_env, "QUERY_STRING_UNESCAPED",
>                    escape_shell_cmd(r->pool, arg_copy));
>      }
>  
> Index: modules/standard/mod_log_config.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_log_config.c,v
> retrieving revision 1.42
> diff -u -r1.42 mod_log_config.c
> --- mod_log_config.c	1998/01/07 16:46:52	1.42
> +++ mod_log_config.c	1998/01/24 20:51:47
> @@ -764,7 +764,7 @@
>      mls->default_format = NULL;
>      mls->server_config_logs = NULL;
>      mls->formats = make_table(p, 4);
> -    table_set(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
> +    table_setn(mls->formats, "CLF", DEFAULT_LOG_FORMAT);
>  
>      return mls;
>  }
> Index: modules/standard/mod_negotiation.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_negotiation.c,v
> retrieving revision 1.64
> diff -u -r1.64 mod_negotiation.c
> --- mod_negotiation.c	1998/01/24 19:00:25	1.64
> +++ mod_negotiation.c	1998/01/24 20:51:48
> @@ -1889,24 +1889,24 @@
>          rec = pstrcat(r->pool, rec, "}", NULL);
>  
>          if (na_result != na_not_applied) {
> -            table_merge(hdrs, "Alternates", rec);
> +            table_mergen(hdrs, "Alternates", rec);
>          }
>      }
>  
>      if (na_result != na_not_applied) {
> -        table_merge(hdrs, "Vary", "negotiate");
> +        table_mergen(hdrs, "Vary", "negotiate");
>      }
>      if (vary_by_type) {
> -        table_merge(hdrs, "Vary", "accept");
> +        table_mergen(hdrs, "Vary", "accept");
>      }
>      if (vary_by_language) {
> -        table_merge(hdrs, "Vary", "accept-language");
> +        table_mergen(hdrs, "Vary", "accept-language");
>      }
>      if (vary_by_charset) {
> -        table_merge(hdrs, "Vary", "accept-charset");
> +        table_mergen(hdrs, "Vary", "accept-charset");
>      }
>      if (vary_by_encoding && na_result == na_not_applied) {
> -        table_merge(hdrs, "Vary", "accept-encoding");
> +        table_mergen(hdrs, "Vary", "accept-encoding");
>      }
>  }
>  
> @@ -1955,10 +1955,10 @@
>  static void store_variant_list(request_rec *r, negotiation_state *neg)
>  {
>      if (r->main == NULL) {
> -        table_set(r->notes, "variant-list", make_variant_list(r, neg));
> +        table_setn(r->notes, "variant-list", make_variant_list(r, neg));
>      }
>      else {
> -        table_set(r->main->notes, "variant-list",
> +        table_setn(r->main->notes, "variant-list",
>                    make_variant_list(r->main, neg));
>      }
>  }
> @@ -2004,9 +2004,10 @@
>      }
>  
>      if ((sub_vary = table_get(sub_req->err_headers_out, "Vary")) != NULL) {
> -        table_set(r->err_headers_out, "Variant-Vary", sub_vary);
> +        table_setn(r->err_headers_out, "Variant-Vary", sub_vary);
>      }
> -    table_set(r->err_headers_out, "Content-Location", variant->file_name);
> +    table_setn(r->err_headers_out, "Content-Location",
> +		pstrdup(r->pool, variant->file_name));
>      set_neg_headers(r, neg, na_choice);         /* add Alternates and Vary */
>      /* to do: add Expires */
>  
> Index: modules/standard/mod_rewrite.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_rewrite.c,v
> retrieving revision 1.62
> diff -u -r1.62 mod_rewrite.c
> --- mod_rewrite.c	1998/01/20 00:27:20	1.62
> +++ mod_rewrite.c	1998/01/24 20:51:50
> @@ -908,13 +908,13 @@
>           var = pstrcat(r->pool, "REDIRECT_", ENVVAR_SCRIPT_URL, NULL);
>           var = table_get(r->subprocess_env, var);
>           if (var == NULL) 
> -             table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, r->uri);
> +             table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, r->uri);
>           else 
> -             table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
> +             table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
>      } 
>      else {
>           var = table_get(r->main->subprocess_env, ENVVAR_SCRIPT_URL);
> -         table_set(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
> +         table_setn(r->subprocess_env, ENVVAR_SCRIPT_URL, var);
>      }
>  
>      /*
> @@ -943,7 +943,7 @@
>  #else
>      var = pstrcat(r->pool, "http://", thisserver, thisport, thisurl, NULL);
>  #endif
> -    table_set(r->subprocess_env, ENVVAR_SCRIPT_URI, var);
> +    table_setn(r->subprocess_env, ENVVAR_SCRIPT_URI, var);
>  
>  
>      /* if filename was not initially set,
> @@ -1028,7 +1028,7 @@
>                  n = REDIRECT;
>  
>              /* now do the redirection */
> -            table_set(r->headers_out, "Location", r->filename);
> +            table_setn(r->headers_out, "Location", r->filename);
>              rewritelog(r, 1, "redirect to %s [REDIRECT/%d]", r->filename, n);
>              return n;
>          }
> @@ -1298,7 +1298,7 @@
>                  n = REDIRECT;
>  
>              /* now do the redirection */
> -            table_set(r->headers_out, "Location", r->filename);
> +            table_setn(r->headers_out, "Location", r->filename);
>              rewritelog(r, 1, "[per-dir %s] redirect to %s [REDIRECT/%d]",
>                         dconf->directory, r->filename, n);
>              return n;
> @@ -1873,7 +1873,7 @@
>       *  MIME API-hook function.
>       */
>      if (p->forced_mimetype != NULL) {
> -        table_set(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR,
> +        table_setn(r->notes, REWRITE_FORCED_MIMETYPE_NOTEVAR,
>                    p->forced_mimetype);
>          if (perdir == NULL)
>              rewritelog(r, 2, "remember %s to have MIME-type '%s'",
> Index: modules/standard/mod_setenvif.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_setenvif.c,v
> retrieving revision 1.12
> diff -u -r1.12 mod_setenvif.c
> --- mod_setenvif.c	1998/01/24 19:00:26	1.12
> +++ mod_setenvif.c	1998/01/24 20:51:50
> @@ -310,7 +310,7 @@
>                      table_unset(r->subprocess_env, elts[j].key);
>                  }
>                  else {
> -                    table_set(r->subprocess_env, elts[j].key, elts[j].val);
> +                    table_setn(r->subprocess_env, elts[j].key, elts[j].val);
>                  }
>              }
>          }
> Index: modules/standard/mod_speling.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_speling.c,v
> retrieving revision 1.11
> diff -u -r1.11 mod_speling.c
> --- mod_speling.c	1998/01/13 23:29:13	1.11
> +++ mod_speling.c	1998/01/24 20:51:50
> @@ -338,7 +338,7 @@
>              nuri = pstrcat(r->pool, url, variant[0].name,
>                             r->path_info, NULL);
>  
> -            table_set(r->headers_out, "Location",
> +            table_setn(r->headers_out, "Location",
>                        construct_url(r->pool, nuri, r->server));
>  
>              aplog_error(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, r->server,
> @@ -408,7 +408,7 @@
>                  ref, "\">referring page</a> about the broken link.\n", NULL);
>  
>              /* Pass our table to http_protocol.c (see mod_negotiation): */
> -            table_set(notes, "variant-list", t);
> +            table_setn(notes, "variant-list", t);
>  
>              aplog_error(APLOG_MARK, APLOG_NOERRNO | APLOG_INFO, r->server,
>                          ref ? "Spelling fix: %s: %d candidates from %s"
> Index: modules/standard/mod_unique_id.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_unique_id.c,v
> retrieving revision 1.9
> diff -u -r1.9 mod_unique_id.c
> --- mod_unique_id.c	1998/01/07 16:46:58	1.9
> +++ mod_unique_id.c	1998/01/24 20:51:50
> @@ -311,7 +311,7 @@
>      str[18] = uuencoder[((x[1] & 0x0f) << 2) | ((0 & 0xc0) >> 6)];
>      str[19] = '\0';
>  
> -    table_set(r->subprocess_env, "UNIQUE_ID", str);
> +    table_setn(r->subprocess_env, "UNIQUE_ID", pstrdup(r->pool, str));
>  
>      /* and increment the identifier for the next call */
>      counter = ntohs(cur_unique_id.counter) + 1;
> Index: modules/standard/mod_userdir.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_userdir.c,v
> retrieving revision 1.25
> diff -u -r1.25 mod_userdir.c
> --- mod_userdir.c	1998/01/07 16:46:58	1.25
> +++ mod_userdir.c	1998/01/24 20:51:50
> @@ -194,7 +194,8 @@
>      (userdir_config *) get_module_config(server_conf, &userdir_module);
>      char *name = r->uri;
>      const char *userdirs = pstrdup(r->pool, s_cfg->userdir);
> -    const char *w, *dname, *redirect;
> +    const char *w, *dname;
> +    char *redirect;
>      char *x = NULL;
>      struct stat statbuf;
>  
> @@ -277,7 +278,7 @@
>                  if (strchr(x, ':')) {
>  #endif                          /* WIN32 */
>                      redirect = pstrcat(r->pool, x, w, userdir, dname, NULL);
> -                    table_set(r->headers_out, "Location", redirect);
> +                    table_setn(r->headers_out, "Location", redirect);
>                      return REDIRECT;
>                  }
>                  else
> @@ -288,7 +289,7 @@
>          }
>          else if (strchr(userdir, ':')) {
>              redirect = pstrcat(r->pool, userdir, "/", w, dname, NULL);
> -            table_set(r->headers_out, "Location", redirect);
> +            table_setn(r->headers_out, "Location", redirect);
>              return REDIRECT;
>          }
>          else {
> Index: modules/standard/mod_usertrack.c
> ===================================================================
> RCS file: /export/home/cvs/apachen/src/modules/standard/mod_usertrack.c,v
> retrieving revision 1.24
> diff -u -r1.24 mod_usertrack.c
> --- mod_usertrack.c	1998/01/07 16:46:59	1.24
> +++ mod_usertrack.c	1998/01/24 20:51:51
> @@ -135,8 +135,8 @@
>      struct timezone tz = {0, 0};
>  #endif
>      /* 1024 == hardcoded constants */
> -    char *new_cookie = palloc(r->pool, 1024);
> -    char *cookiebuf = palloc(r->pool, 1024);
> +    char new_cookie[1024];
> +    char cookiebuf[1024];
>      char *dot;
>      const char *rname = pstrdup(r->pool,
>                             get_remote_host(r->connection, r->per_dir_config,
> @@ -200,8 +200,8 @@
>      else
>          ap_snprintf(new_cookie, 1024, "%s%s; path=/", COOKIE_NAME, cookiebuf);
>  
> -    table_set(r->headers_out, "Set-Cookie", new_cookie);
> -    table_set(r->notes, "cookie", cookiebuf);   /* log first time */
> +    table_setn(r->headers_out, "Set-Cookie", pstrdup(r->pool, new_cookie));
> +    table_setn(r->notes, "cookie", pstrdup(r->pool, cookiebuf));   /* log first time */
>      return;
>  }
>  
> @@ -226,7 +226,7 @@
>                  *cookieend = '\0';      /* Ignore anything after a ; */
>  
>              /* Set the cookie in a note, for logging */
> -            table_set(r->notes, "cookie", cookiebuf);
> +            table_setn(r->notes, "cookie", cookiebuf);
>  
>              return DECLINED;    /* Theres already a cookie, no new one */
>          }
> 
> 

Mime
View raw message