You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by st...@apache.org on 2001/07/11 06:47:04 UTC

cvs commit: httpd-2.0/modules/http mod_mime.c

stoddard    01/07/10 21:47:03

  Modified:    .        CHANGES
               modules/http mod_mime.c
  Log:
  Performance improvement to mod_mime.c. find_ct() in mod_mime,
  spends a lot of time in apr_table_get calls.  Using the default
  httpd.conf, the tables for languages and charsets are somewhat
  large, so the time spent scanning them on each request is
  significant. Replacing the tables with hash tables provides
  a nice speedup. [Brian Pane <bp...@pacbell.net>]
  
  Had to handmerge a lot of this patch so please review! Dean had some suggestions
  for improvement which are not currently implemented.
  
  Submitted by:	Brian Pane
  Reviewed by:	Bill Stoddard
  
  Revision  Changes    Path
  1.244     +6 -0      httpd-2.0/CHANGES
  
  Index: CHANGES
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/CHANGES,v
  retrieving revision 1.243
  retrieving revision 1.244
  diff -u -r1.243 -r1.244
  --- CHANGES	2001/07/10 18:59:54	1.243
  +++ CHANGES	2001/07/11 04:46:59	1.244
  @@ -1,4 +1,10 @@
   Changes with Apache 2.0.21-dev
  +  *) Performance improvement to mod_mime.c. find_ct() in mod_mime, 
  +     spends a lot of time in apr_table_get calls.  Using the default 
  +     httpd.conf, the tables for languages and charsets are somewhat
  +     large, so the time spent scanning them on each request is
  +     significant. Replacing the tables with hash tables provides
  +     a nice speedup. [Brian Pane <bp...@pacbell.net>]
   
     *) Add two functions to allow modules to access random parts of the
        scoreboard.  This allows modules compiled for one MPM to access the
  
  
  
  1.43      +167 -69   httpd-2.0/modules/http/mod_mime.c
  
  Index: mod_mime.c
  ===================================================================
  RCS file: /home/cvs/httpd-2.0/modules/http/mod_mime.c,v
  retrieving revision 1.42
  retrieving revision 1.43
  diff -u -r1.42 -r1.43
  --- mod_mime.c	2001/06/18 05:36:31	1.42
  +++ mod_mime.c	2001/07/11 04:47:02	1.43
  @@ -66,6 +66,7 @@
   #include "apr.h"
   #include "apr_strings.h"
   #include "apr_lib.h"
  +#include "apr_hash.h"
   
   #define APR_WANT_STRFUNC
   #include "apr_want.h"
  @@ -96,12 +97,19 @@
       char *name;
   } attrib_info;
   
  +/* Information to which an extension can be mapped
  + */
  +typedef struct extension_info {
  +    char *forced_type;                /* Additional AddTyped stuff */
  +    char *encoding_type;              /* Added with AddEncoding... */
  +    char *language_type;              /* Added with AddLanguage... */
  +    char *handler;                    /* Added with AddHandler... */
  +    char *charset_type;               /* Added with AddCharset... */
  +} extension_info;
  +
   typedef struct {
  -    apr_table_t *forced_types;        /* Additional AddTyped stuff */
  -    apr_table_t *encoding_types;      /* Added with AddEncoding... */
  -    apr_table_t *language_types;      /* Added with AddLanguage... */
  -    apr_table_t *handlers;            /* Added with AddHandler...  */
  -    apr_table_t *charset_types;       /* Added with AddCharset... */       
  +    apr_hash_t  *extension_mappings;  /* Map from extension name to
  +                                       * extension_info structure */
       apr_array_header_t *handlers_remove;  /* List of handlers to remove */
       apr_array_header_t *types_remove;     /* List of MIME types to remove */
       apr_array_header_t *encodings_remove; /* List of encodings to remove */
  @@ -138,14 +146,10 @@
       mime_dir_config *new =
       (mime_dir_config *) apr_palloc(p, sizeof(mime_dir_config));
   
  -    new->forced_types = apr_table_make(p, 4);
  -    new->encoding_types = apr_table_make(p, 4);
  -    new->charset_types = apr_table_make(p, 4);
  -    new->language_types = apr_table_make(p, 4);
  -    new->handlers = apr_table_make(p, 4);
  -    new->handlers_remove = apr_array_make(p, 4, sizeof(attrib_info));
  -    new->types_remove = apr_array_make(p, 4, sizeof(attrib_info));
  -    new->encodings_remove = apr_array_make(p, 4, sizeof(attrib_info));
  +    new->extension_mappings = apr_hash_make(p);
  +    new->handlers_remove = NULL;
  +    new->types_remove = NULL;
  +    new->encodings_remove = NULL;
   
       new->type = NULL;
       new->handler = NULL;
  @@ -153,42 +157,107 @@
   
       return new;
   }
  +/*
  + * Overlay one hash table of extension_mappings onto another
  + */
  +static void overlay_extension_mappings(apr_pool_t *p,
  +                                       apr_hash_t *overlay, apr_hash_t *base)
  +{
  +    apr_hash_index_t *index;
  +    for (index = apr_hash_first(overlay); index;
  +         index = apr_hash_next(index)) {
  +        char *key;
  +        apr_ssize_t klen;
  +        extension_info *overlay_info, *base_info;
  +        
  +        apr_hash_this(index, (const void**)&key, &klen, (void**)&overlay_info);
  +        base_info = (extension_info*)apr_hash_get(base, key, klen);
  +        if (base_info) {
  +            if (overlay_info->forced_type) {
  +                base_info->forced_type = overlay_info->forced_type;
  +            }
  +            if (overlay_info->encoding_type) {
  +                base_info->encoding_type = overlay_info->encoding_type;
  +            }
  +            if (overlay_info->language_type) {
  +                base_info->language_type = overlay_info->language_type;
  +            }
  +            if (overlay_info->handler) {
  +                base_info->handler = overlay_info->handler;
  +            }
  +            if (overlay_info->charset_type) {
  +                base_info->charset_type = overlay_info->charset_type;
  +            }
  +        }
  +        else {
  +            base_info = (extension_info*)apr_palloc(p, sizeof(extension_info));
  +            memcpy(base_info, overlay_info, sizeof(extension_info));
  +            apr_hash_set(base, key, klen, base_info);
  +        }
  +    }
  +}
   
   static void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv)
   {
       mime_dir_config *base = (mime_dir_config *) basev;
       mime_dir_config *add = (mime_dir_config *) addv;
  -    mime_dir_config *new =
  -        (mime_dir_config *) apr_palloc(p, sizeof(mime_dir_config));
  +    mime_dir_config *new = apr_pcalloc(p, sizeof(mime_dir_config));
  +
       int i;
       attrib_info *suffix;
   
  -    new->forced_types = apr_table_overlay(p, add->forced_types,
  -					 base->forced_types);
  -    new->encoding_types = apr_table_overlay(p, add->encoding_types,
  -                                         base->encoding_types);
  -    new->charset_types = apr_table_overlay(p, add->charset_types,
  -					   base->charset_types);
  -    new->language_types = apr_table_overlay(p, add->language_types,
  -                                         base->language_types);
  -    new->handlers = apr_table_overlay(p, add->handlers,
  -                                   base->handlers);
  -
  -    suffix = (attrib_info *) add->handlers_remove->elts;
  -    for (i = 0; i < add->handlers_remove->nelts; i++) {
  -        apr_table_unset(new->handlers, suffix[i].name);
  -    }
  -
  -    suffix = (attrib_info *) add->types_remove->elts;
  -    for (i = 0; i < add->types_remove->nelts; i++) {
  -        apr_table_unset(new->forced_types, suffix[i].name);
  -    }
  -
  -    suffix = (attrib_info *) add->encodings_remove->elts;
  -    for (i = 0; i < add->encodings_remove->nelts; i++) {
  -        apr_table_unset(new->encoding_types, suffix[i].name);
  +    if (base->extension_mappings == NULL) {
  +        new->extension_mappings = add->extension_mappings;
  +    }
  +    else if (add->extension_mappings == NULL) {
  +        new->extension_mappings = base->extension_mappings;
  +    }
  +    else {
  +        new->extension_mappings = apr_hash_make(p);
  +        overlay_extension_mappings(p, base->extension_mappings,
  +                                   new->extension_mappings);
  +        overlay_extension_mappings(p, add->extension_mappings,
  +                                   new->extension_mappings);
  +    }
  +
  +    if (add->handlers_remove) {
  +        suffix = (attrib_info *) add->handlers_remove->elts;
  +        for (i = 0; i < add->handlers_remove->nelts; i++) {
  +            extension_info *exinfo =
  +                (extension_info*)apr_hash_get(new->extension_mappings,
  +                                              suffix[i].name,
  +                                              APR_HASH_KEY_STRING);
  +            if (exinfo) {
  +                exinfo->handler = NULL;
  +            }
  +        }
  +    }
  +    
  +    if (add->types_remove) {
  +        suffix = (attrib_info *) add->types_remove->elts;
  +        for (i = 0; i < add->types_remove->nelts; i++) {
  +            extension_info *exinfo =
  +                (extension_info*)apr_hash_get(new->extension_mappings,
  +                                              suffix[i].name,
  +                                              APR_HASH_KEY_STRING);
  +            if (exinfo) {
  +                exinfo->forced_type = NULL;
  +            }
  +        }
       }
   
  +    if (add->encodings_remove) {
  +        suffix = (attrib_info *) add->encodings_remove->elts;
  +        for (i = 0; i < add->encodings_remove->nelts; i++) {
  +            extension_info *exinfo =
  +                (extension_info*)apr_hash_get(new->extension_mappings,
  +                                              suffix[i].name,
  +                                              APR_HASH_KEY_STRING);
  +            if (exinfo) {
  +                exinfo->encoding_type = NULL;
  +            }
  +        }
  +    }
   
       new->type = add->type ? add->type : base->type;
       new->handler = add->handler ? add->handler : base->handler;
  @@ -197,18 +266,33 @@
   
       return new;
   }
  -
  +static extension_info *get_extension_info(apr_pool_t *p, mime_dir_config *m,
  +                                          const char* key)
  +{
  +    extension_info *exinfo;
  +    
  +    exinfo = (extension_info*)apr_hash_get(m->extension_mappings, key,
  +                                           APR_HASH_KEY_STRING);
  +    if (!exinfo) {
  +        exinfo = apr_pcalloc(p, sizeof(extension_info));
  +        apr_hash_set(m->extension_mappings, apr_pstrdup(p, key),
  +                     APR_HASH_KEY_STRING, exinfo);
  +    }
  +    return exinfo;
  +}
  + 
   static const char *add_type(cmd_parms *cmd, void *m_, const char *ct_,
                               const char *ext)
   {
       mime_dir_config *m=m_;
       char *ct=apr_pstrdup(cmd->pool,ct_);
  +    extension_info* exinfo;
   
       if (*ext == '.')
   	++ext;
  -	
  +    exinfo = get_extension_info(cmd->pool, m, ext);
       ap_str_tolower(ct);
  -    apr_table_setn(m->forced_types, ext, ct);
  +    exinfo->forced_type = ct;
       return NULL;
   }
   
  @@ -217,11 +301,13 @@
   {
       mime_dir_config *m=m_;
       char *enc=apr_pstrdup(cmd->pool,enc_);
  +    extension_info* exinfo;
   
       if (*ext == '.')
           ++ext;
  +    exinfo = get_extension_info(cmd->pool, m, ext);
       ap_str_tolower(enc);
  -    apr_table_setn(m->encoding_types, ext, enc);
  +    exinfo->encoding_type = enc;
       return NULL;
   }
   
  @@ -230,12 +316,14 @@
   {
       mime_dir_config *m=m_;
       char *charset=apr_pstrdup(cmd->pool,charset_);
  +    extension_info* exinfo;
   
       if (*ext == '.') {
   	++ext;
       }
  +    exinfo = get_extension_info(cmd->pool, m, ext);
       ap_str_tolower(charset);
  -    apr_table_setn(m->charset_types, ext, charset);
  +    exinfo->charset_type = charset;
       return NULL;
   }
   
  @@ -244,12 +332,14 @@
   {
       mime_dir_config *m=m_;
       char *lang=apr_pstrdup(cmd->pool,lang_);
  +    extension_info* exinfo;
   
       if (*ext == '.') {
   	++ext;
       }
  +    exinfo = get_extension_info(cmd->pool, m, ext);
       ap_str_tolower(lang);
  -    apr_table_setn(m->language_types, ext, lang);
  +    exinfo->language_type = lang;
       return NULL;
   }
   
  @@ -258,11 +348,14 @@
   {
       mime_dir_config *m=m_;
       char *hdlr=apr_pstrdup(cmd->pool,hdlr_);
  +    extension_info* exinfo;
   
  -    if (*ext == '.')
  +    if (*ext == '.') {
           ++ext;
  +    }
  +    exinfo = get_extension_info(cmd->pool, m, ext);
       ap_str_tolower(hdlr);
  -    apr_table_setn(m->handlers, ext, hdlr);
  +    exinfo->handler = hdlr;
       return NULL;
   }
   
  @@ -279,6 +372,10 @@
       if (*ext == '.') {
           ++ext;
       }
  +    if (mcfg->handlers_remove == NULL) {
  +        mcfg->handlers_remove =
  +            apr_array_make(cmd->pool, 4, sizeof(attrib_info));
  +    }
       suffix = (attrib_info *) apr_array_push(mcfg->handlers_remove);
       suffix->name = apr_pstrdup(cmd->pool, ext);
       return NULL;
  @@ -296,6 +393,10 @@
       if (*ext == '.') {
           ++ext;
       }
  +    if (mcfg->encodings_remove == NULL) {
  +        mcfg->encodings_remove =
  +            apr_array_make(cmd->pool, 4, sizeof(attrib_info));
  +    }
       suffix = (attrib_info *) apr_array_push(mcfg->encodings_remove);
       suffix->name = apr_pstrdup(cmd->pool, ext);
       return NULL;
  @@ -313,6 +414,9 @@
       if (*ext == '.') {
           ++ext;
       }
  +    if (mcfg->types_remove == NULL) {
  +        mcfg->types_remove = apr_array_make(cmd->pool, 4, sizeof(attrib_info));
  +    }
       suffix = (attrib_info *) apr_array_push(mcfg->types_remove);
       suffix->name = apr_pstrdup(cmd->pool, ext);
       return NULL;
  @@ -362,20 +466,12 @@
       {NULL}
   };
   
  -/* Hash apr_table_t  --- only one of these per daemon; virtual hosts can
  - * get private versions through AddType...
  - */
  -
  -#define MIME_HASHSIZE (32)
  -#define hash(i) (apr_tolower(i) % MIME_HASHSIZE)
  +static apr_hash_t *mime_type_extensions;
   
  -static apr_table_t *hash_buckets[MIME_HASHSIZE];
  -
   static void mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
   {
       ap_configfile_t *f;
       char l[MAX_STRING_LEN];
  -    int x;
       const char *types_confname = ap_get_module_config(s->module_config, &mime_module);
       apr_status_t status;
   
  @@ -390,8 +486,7 @@
           exit(1);
       }
   
  -    for (x = 0; x < MIME_HASHSIZE; x++)
  -        hash_buckets[x] = apr_table_make(p, 10);
  +    mime_type_extensions = apr_hash_make(p);
   
       while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
           const char *ll = l, *ct;
  @@ -403,7 +498,7 @@
           while (ll[0]) {
               char *ext = ap_getword_conf(p, &ll);
               ap_str_tolower(ext);   /* ??? */
  -            apr_table_setn(hash_buckets[hash(ext[0])], ext, ct);
  +            apr_hash_set(mime_type_extensions, ext, APR_HASH_KEY_STRING, ct);
           }
       }
       ap_cfg_closefile(f);
  @@ -682,6 +777,7 @@
       /* Parse filename extensions, which can be in any order */
       while ((ext = ap_getword(r->pool, &fn, '.')) && *ext) {
           int found = 0;
  +        extension_info *exinfo;
   
   #ifdef CASE_BLIND_FILESYSTEM
           /* We have a basic problem that folks on case-crippled systems
  @@ -689,22 +785,25 @@
            */
           ap_str_tolower(ext);
   #endif
  -
  +        exinfo = (extension_info*) apr_hash_get(conf->extension_mappings,
  +                                                ext, APR_HASH_KEY_STRING);
  +        
           /* Check for Content-Type */
  -        if ((type = apr_table_get(conf->forced_types, ext))
  -            || (type = apr_table_get(hash_buckets[hash(*ext)], ext))) {
  +        if ((exinfo && ((type = exinfo->forced_type)))
  +            || (type = apr_hash_get(mime_type_extensions, ext,
  +                                    APR_HASH_KEY_STRING))) {
               r->content_type = type;
               found = 1;
           }
   
   	/* Add charset to Content-Type */
  -	if ((type = apr_table_get(conf->charset_types, ext))) {
  +        if (exinfo && ((type = exinfo->charset_type))) {
   	    charset = type;
   	    found = 1;
   	}
   
           /* Check for Content-Language */
  -        if ((type = apr_table_get(conf->language_types, ext))) {
  +        if (exinfo && ((type = exinfo->language_type))) {
               const char **new;
   
               r->content_language = type;         /* back compat. only */
  @@ -716,19 +815,18 @@
           }
   
           /* Check for Content-Encoding */
  -        if ((type = apr_table_get(conf->encoding_types, ext))) {
  +        if (exinfo && ((type = exinfo->encoding_type))) {
               if (!r->content_encoding)
                   r->content_encoding = type;
               else
                   r->content_encoding = apr_pstrcat(r->pool, r->content_encoding,
  -                                              ", ", type, NULL);
  +                                                  ", ", type, NULL);
               found = 1;
           }
   
           /* Check for a special handler, but not for proxy request */
  -        if ((type = apr_table_get(conf->handlers, ext))
  -	    && (PROXYREQ_NONE == r->proxyreq) 
  -        ) {
  +        if ((exinfo && ((type = exinfo->handler)))
  +            && (PROXYREQ_NONE == r->proxyreq)) {
               r->handler = type;
               found = 1;
           }
  
  
  

Re: cvs commit: httpd-2.0/modules/http mod_mime.c

Posted by "William A. Rowe, Jr." <wr...@rowe-clan.net>.
This patch entirely blew up mod_mime.c.  -1 on beta for 2.0.22 and hold off on the
tag for 2.0.23.

It ends up corrupting extension_info members of the hash in merge_mime_dir_configs(),
since these elements aren't copies.

I'll continue to look at this.

Bill

From: <st...@apache.org>
Sent: Tuesday, July 10, 2001 11:47 PM


> stoddard    01/07/10 21:47:03
> 
>   Modified:    .        CHANGES
>                modules/http mod_mime.c
>   Log:
>   Performance improvement to mod_mime.c. find_ct() in mod_mime,
>   spends a lot of time in apr_table_get calls.  Using the default
>   httpd.conf, the tables for languages and charsets are somewhat
>   large, so the time spent scanning them on each request is
>   significant. Replacing the tables with hash tables provides
>   a nice speedup. [Brian Pane <bp...@pacbell.net>]
>   
>   Had to handmerge a lot of this patch so please review! Dean had some suggestions
>   for improvement which are not currently implemented.
>   
>   Submitted by: Brian Pane
>   Reviewed by: Bill Stoddard
>   
>   Revision  Changes    Path
>   1.244     +6 -0      httpd-2.0/CHANGES
>   
>   Index: CHANGES
>   ===================================================================
>   RCS file: /home/cvs/httpd-2.0/CHANGES,v
>   retrieving revision 1.243
>   retrieving revision 1.244
>   diff -u -r1.243 -r1.244
>   --- CHANGES 2001/07/10 18:59:54 1.243
>   +++ CHANGES 2001/07/11 04:46:59 1.244
>   @@ -1,4 +1,10 @@
>    Changes with Apache 2.0.21-dev
>   +  *) Performance improvement to mod_mime.c. find_ct() in mod_mime, 
>   +     spends a lot of time in apr_table_get calls.  Using the default 
>   +     httpd.conf, the tables for languages and charsets are somewhat
>   +     large, so the time spent scanning them on each request is
>   +     significant. Replacing the tables with hash tables provides
>   +     a nice speedup. [Brian Pane <bp...@pacbell.net>]
>    
>      *) Add two functions to allow modules to access random parts of the
>         scoreboard.  This allows modules compiled for one MPM to access the
>   
>   
>   
>   1.43      +167 -69   httpd-2.0/modules/http/mod_mime.c
>   
>   Index: mod_mime.c
>   ===================================================================
>   RCS file: /home/cvs/httpd-2.0/modules/http/mod_mime.c,v
>   retrieving revision 1.42
>   retrieving revision 1.43
>   diff -u -r1.42 -r1.43
>   --- mod_mime.c 2001/06/18 05:36:31 1.42
>   +++ mod_mime.c 2001/07/11 04:47:02 1.43
>   @@ -66,6 +66,7 @@
>    #include "apr.h"
>    #include "apr_strings.h"
>    #include "apr_lib.h"
>   +#include "apr_hash.h"
>    
>    #define APR_WANT_STRFUNC
>    #include "apr_want.h"
>   @@ -96,12 +97,19 @@
>        char *name;
>    } attrib_info;
>    
>   +/* Information to which an extension can be mapped
>   + */
>   +typedef struct extension_info {
>   +    char *forced_type;                /* Additional AddTyped stuff */
>   +    char *encoding_type;              /* Added with AddEncoding... */
>   +    char *language_type;              /* Added with AddLanguage... */
>   +    char *handler;                    /* Added with AddHandler... */
>   +    char *charset_type;               /* Added with AddCharset... */
>   +} extension_info;
>   +
>    typedef struct {
>   -    apr_table_t *forced_types;        /* Additional AddTyped stuff */
>   -    apr_table_t *encoding_types;      /* Added with AddEncoding... */
>   -    apr_table_t *language_types;      /* Added with AddLanguage... */
>   -    apr_table_t *handlers;            /* Added with AddHandler...  */
>   -    apr_table_t *charset_types;       /* Added with AddCharset... */       
>   +    apr_hash_t  *extension_mappings;  /* Map from extension name to
>   +                                       * extension_info structure */
>        apr_array_header_t *handlers_remove;  /* List of handlers to remove */
>        apr_array_header_t *types_remove;     /* List of MIME types to remove */
>        apr_array_header_t *encodings_remove; /* List of encodings to remove */
>   @@ -138,14 +146,10 @@
>        mime_dir_config *new =
>        (mime_dir_config *) apr_palloc(p, sizeof(mime_dir_config));
>    
>   -    new->forced_types = apr_table_make(p, 4);
>   -    new->encoding_types = apr_table_make(p, 4);
>   -    new->charset_types = apr_table_make(p, 4);
>   -    new->language_types = apr_table_make(p, 4);
>   -    new->handlers = apr_table_make(p, 4);
>   -    new->handlers_remove = apr_array_make(p, 4, sizeof(attrib_info));
>   -    new->types_remove = apr_array_make(p, 4, sizeof(attrib_info));
>   -    new->encodings_remove = apr_array_make(p, 4, sizeof(attrib_info));
>   +    new->extension_mappings = apr_hash_make(p);
>   +    new->handlers_remove = NULL;
>   +    new->types_remove = NULL;
>   +    new->encodings_remove = NULL;
>    
>        new->type = NULL;
>        new->handler = NULL;
>   @@ -153,42 +157,107 @@
>    
>        return new;
>    }
>   +/*
>   + * Overlay one hash table of extension_mappings onto another
>   + */
>   +static void overlay_extension_mappings(apr_pool_t *p,
>   +                                       apr_hash_t *overlay, apr_hash_t *base)
>   +{
>   +    apr_hash_index_t *index;
>   +    for (index = apr_hash_first(overlay); index;
>   +         index = apr_hash_next(index)) {
>   +        char *key;
>   +        apr_ssize_t klen;
>   +        extension_info *overlay_info, *base_info;
>   +        
>   +        apr_hash_this(index, (const void**)&key, &klen, (void**)&overlay_info);
>   +        base_info = (extension_info*)apr_hash_get(base, key, klen);
>   +        if (base_info) {
>   +            if (overlay_info->forced_type) {
>   +                base_info->forced_type = overlay_info->forced_type;
>   +            }
>   +            if (overlay_info->encoding_type) {
>   +                base_info->encoding_type = overlay_info->encoding_type;
>   +            }
>   +            if (overlay_info->language_type) {
>   +                base_info->language_type = overlay_info->language_type;
>   +            }
>   +            if (overlay_info->handler) {
>   +                base_info->handler = overlay_info->handler;
>   +            }
>   +            if (overlay_info->charset_type) {
>   +                base_info->charset_type = overlay_info->charset_type;
>   +            }
>   +        }
>   +        else {
>   +            base_info = (extension_info*)apr_palloc(p, sizeof(extension_info));
>   +            memcpy(base_info, overlay_info, sizeof(extension_info));
>   +            apr_hash_set(base, key, klen, base_info);
>   +        }
>   +    }
>   +}
>    
>    static void *merge_mime_dir_configs(apr_pool_t *p, void *basev, void *addv)
>    {
>        mime_dir_config *base = (mime_dir_config *) basev;
>        mime_dir_config *add = (mime_dir_config *) addv;
>   -    mime_dir_config *new =
>   -        (mime_dir_config *) apr_palloc(p, sizeof(mime_dir_config));
>   +    mime_dir_config *new = apr_pcalloc(p, sizeof(mime_dir_config));
>   +
>        int i;
>        attrib_info *suffix;
>    
>   -    new->forced_types = apr_table_overlay(p, add->forced_types,
>   - base->forced_types);
>   -    new->encoding_types = apr_table_overlay(p, add->encoding_types,
>   -                                         base->encoding_types);
>   -    new->charset_types = apr_table_overlay(p, add->charset_types,
>   -    base->charset_types);
>   -    new->language_types = apr_table_overlay(p, add->language_types,
>   -                                         base->language_types);
>   -    new->handlers = apr_table_overlay(p, add->handlers,
>   -                                   base->handlers);
>   -
>   -    suffix = (attrib_info *) add->handlers_remove->elts;
>   -    for (i = 0; i < add->handlers_remove->nelts; i++) {
>   -        apr_table_unset(new->handlers, suffix[i].name);
>   -    }
>   -
>   -    suffix = (attrib_info *) add->types_remove->elts;
>   -    for (i = 0; i < add->types_remove->nelts; i++) {
>   -        apr_table_unset(new->forced_types, suffix[i].name);
>   -    }
>   -
>   -    suffix = (attrib_info *) add->encodings_remove->elts;
>   -    for (i = 0; i < add->encodings_remove->nelts; i++) {
>   -        apr_table_unset(new->encoding_types, suffix[i].name);
>   +    if (base->extension_mappings == NULL) {
>   +        new->extension_mappings = add->extension_mappings;
>   +    }
>   +    else if (add->extension_mappings == NULL) {
>   +        new->extension_mappings = base->extension_mappings;
>   +    }
>   +    else {
>   +        new->extension_mappings = apr_hash_make(p);
>   +        overlay_extension_mappings(p, base->extension_mappings,
>   +                                   new->extension_mappings);
>   +        overlay_extension_mappings(p, add->extension_mappings,
>   +                                   new->extension_mappings);
>   +    }
>   +
>   +    if (add->handlers_remove) {
>   +        suffix = (attrib_info *) add->handlers_remove->elts;
>   +        for (i = 0; i < add->handlers_remove->nelts; i++) {
>   +            extension_info *exinfo =
>   +                (extension_info*)apr_hash_get(new->extension_mappings,
>   +                                              suffix[i].name,
>   +                                              APR_HASH_KEY_STRING);
>   +            if (exinfo) {
>   +                exinfo->handler = NULL;
>   +            }
>   +        }
>   +    }
>   +    
>   +    if (add->types_remove) {
>   +        suffix = (attrib_info *) add->types_remove->elts;
>   +        for (i = 0; i < add->types_remove->nelts; i++) {
>   +            extension_info *exinfo =
>   +                (extension_info*)apr_hash_get(new->extension_mappings,
>   +                                              suffix[i].name,
>   +                                              APR_HASH_KEY_STRING);
>   +            if (exinfo) {
>   +                exinfo->forced_type = NULL;
>   +            }
>   +        }
>        }
>    
>   +    if (add->encodings_remove) {
>   +        suffix = (attrib_info *) add->encodings_remove->elts;
>   +        for (i = 0; i < add->encodings_remove->nelts; i++) {
>   +            extension_info *exinfo =
>   +                (extension_info*)apr_hash_get(new->extension_mappings,
>   +                                              suffix[i].name,
>   +                                              APR_HASH_KEY_STRING);
>   +            if (exinfo) {
>   +                exinfo->encoding_type = NULL;
>   +            }
>   +        }
>   +    }
>    
>        new->type = add->type ? add->type : base->type;
>        new->handler = add->handler ? add->handler : base->handler;
>   @@ -197,18 +266,33 @@
>    
>        return new;
>    }
>   -
>   +static extension_info *get_extension_info(apr_pool_t *p, mime_dir_config *m,
>   +                                          const char* key)
>   +{
>   +    extension_info *exinfo;
>   +    
>   +    exinfo = (extension_info*)apr_hash_get(m->extension_mappings, key,
>   +                                           APR_HASH_KEY_STRING);
>   +    if (!exinfo) {
>   +        exinfo = apr_pcalloc(p, sizeof(extension_info));
>   +        apr_hash_set(m->extension_mappings, apr_pstrdup(p, key),
>   +                     APR_HASH_KEY_STRING, exinfo);
>   +    }
>   +    return exinfo;
>   +}
>   + 
>    static const char *add_type(cmd_parms *cmd, void *m_, const char *ct_,
>                                const char *ext)
>    {
>        mime_dir_config *m=m_;
>        char *ct=apr_pstrdup(cmd->pool,ct_);
>   +    extension_info* exinfo;
>    
>        if (*ext == '.')
>    ++ext;
>   - 
>   +    exinfo = get_extension_info(cmd->pool, m, ext);
>        ap_str_tolower(ct);
>   -    apr_table_setn(m->forced_types, ext, ct);
>   +    exinfo->forced_type = ct;
>        return NULL;
>    }
>    
>   @@ -217,11 +301,13 @@
>    {
>        mime_dir_config *m=m_;
>        char *enc=apr_pstrdup(cmd->pool,enc_);
>   +    extension_info* exinfo;
>    
>        if (*ext == '.')
>            ++ext;
>   +    exinfo = get_extension_info(cmd->pool, m, ext);
>        ap_str_tolower(enc);
>   -    apr_table_setn(m->encoding_types, ext, enc);
>   +    exinfo->encoding_type = enc;
>        return NULL;
>    }
>    
>   @@ -230,12 +316,14 @@
>    {
>        mime_dir_config *m=m_;
>        char *charset=apr_pstrdup(cmd->pool,charset_);
>   +    extension_info* exinfo;
>    
>        if (*ext == '.') {
>    ++ext;
>        }
>   +    exinfo = get_extension_info(cmd->pool, m, ext);
>        ap_str_tolower(charset);
>   -    apr_table_setn(m->charset_types, ext, charset);
>   +    exinfo->charset_type = charset;
>        return NULL;
>    }
>    
>   @@ -244,12 +332,14 @@
>    {
>        mime_dir_config *m=m_;
>        char *lang=apr_pstrdup(cmd->pool,lang_);
>   +    extension_info* exinfo;
>    
>        if (*ext == '.') {
>    ++ext;
>        }
>   +    exinfo = get_extension_info(cmd->pool, m, ext);
>        ap_str_tolower(lang);
>   -    apr_table_setn(m->language_types, ext, lang);
>   +    exinfo->language_type = lang;
>        return NULL;
>    }
>    
>   @@ -258,11 +348,14 @@
>    {
>        mime_dir_config *m=m_;
>        char *hdlr=apr_pstrdup(cmd->pool,hdlr_);
>   +    extension_info* exinfo;
>    
>   -    if (*ext == '.')
>   +    if (*ext == '.') {
>            ++ext;
>   +    }
>   +    exinfo = get_extension_info(cmd->pool, m, ext);
>        ap_str_tolower(hdlr);
>   -    apr_table_setn(m->handlers, ext, hdlr);
>   +    exinfo->handler = hdlr;
>        return NULL;
>    }
>    
>   @@ -279,6 +372,10 @@
>        if (*ext == '.') {
>            ++ext;
>        }
>   +    if (mcfg->handlers_remove == NULL) {
>   +        mcfg->handlers_remove =
>   +            apr_array_make(cmd->pool, 4, sizeof(attrib_info));
>   +    }
>        suffix = (attrib_info *) apr_array_push(mcfg->handlers_remove);
>        suffix->name = apr_pstrdup(cmd->pool, ext);
>        return NULL;
>   @@ -296,6 +393,10 @@
>        if (*ext == '.') {
>            ++ext;
>        }
>   +    if (mcfg->encodings_remove == NULL) {
>   +        mcfg->encodings_remove =
>   +            apr_array_make(cmd->pool, 4, sizeof(attrib_info));
>   +    }
>        suffix = (attrib_info *) apr_array_push(mcfg->encodings_remove);
>        suffix->name = apr_pstrdup(cmd->pool, ext);
>        return NULL;
>   @@ -313,6 +414,9 @@
>        if (*ext == '.') {
>            ++ext;
>        }
>   +    if (mcfg->types_remove == NULL) {
>   +        mcfg->types_remove = apr_array_make(cmd->pool, 4, sizeof(attrib_info));
>   +    }
>        suffix = (attrib_info *) apr_array_push(mcfg->types_remove);
>        suffix->name = apr_pstrdup(cmd->pool, ext);
>        return NULL;
>   @@ -362,20 +466,12 @@
>        {NULL}
>    };
>    
>   -/* Hash apr_table_t  --- only one of these per daemon; virtual hosts can
>   - * get private versions through AddType...
>   - */
>   -
>   -#define MIME_HASHSIZE (32)
>   -#define hash(i) (apr_tolower(i) % MIME_HASHSIZE)
>   +static apr_hash_t *mime_type_extensions;
>    
>   -static apr_table_t *hash_buckets[MIME_HASHSIZE];
>   -
>    static void mime_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
>    {
>        ap_configfile_t *f;
>        char l[MAX_STRING_LEN];
>   -    int x;
>        const char *types_confname = ap_get_module_config(s->module_config, &mime_module);
>        apr_status_t status;
>    
>   @@ -390,8 +486,7 @@
>            exit(1);
>        }
>    
>   -    for (x = 0; x < MIME_HASHSIZE; x++)
>   -        hash_buckets[x] = apr_table_make(p, 10);
>   +    mime_type_extensions = apr_hash_make(p);
>    
>        while (!(ap_cfg_getline(l, MAX_STRING_LEN, f))) {
>            const char *ll = l, *ct;
>   @@ -403,7 +498,7 @@
>            while (ll[0]) {
>                char *ext = ap_getword_conf(p, &ll);
>                ap_str_tolower(ext);   /* ??? */
>   -            apr_table_setn(hash_buckets[hash(ext[0])], ext, ct);
>   +            apr_hash_set(mime_type_extensions, ext, APR_HASH_KEY_STRING, ct);
>            }
>        }
>        ap_cfg_closefile(f);
>   @@ -682,6 +777,7 @@
>        /* Parse filename extensions, which can be in any order */
>        while ((ext = ap_getword(r->pool, &fn, '.')) && *ext) {
>            int found = 0;
>   +        extension_info *exinfo;
>    
>    #ifdef CASE_BLIND_FILESYSTEM
>            /* We have a basic problem that folks on case-crippled systems
>   @@ -689,22 +785,25 @@
>             */
>            ap_str_tolower(ext);
>    #endif
>   -
>   +        exinfo = (extension_info*) apr_hash_get(conf->extension_mappings,
>   +                                                ext, APR_HASH_KEY_STRING);
>   +        
>            /* Check for Content-Type */
>   -        if ((type = apr_table_get(conf->forced_types, ext))
>   -            || (type = apr_table_get(hash_buckets[hash(*ext)], ext))) {
>   +        if ((exinfo && ((type = exinfo->forced_type)))
>   +            || (type = apr_hash_get(mime_type_extensions, ext,
>   +                                    APR_HASH_KEY_STRING))) {
>                r->content_type = type;
>                found = 1;
>            }
>    
>    /* Add charset to Content-Type */
>   - if ((type = apr_table_get(conf->charset_types, ext))) {
>   +        if (exinfo && ((type = exinfo->charset_type))) {
>        charset = type;
>        found = 1;
>    }
>    
>            /* Check for Content-Language */
>   -        if ((type = apr_table_get(conf->language_types, ext))) {
>   +        if (exinfo && ((type = exinfo->language_type))) {
>                const char **new;
>    
>                r->content_language = type;         /* back compat. only */
>   @@ -716,19 +815,18 @@
>            }
>    
>            /* Check for Content-Encoding */
>   -        if ((type = apr_table_get(conf->encoding_types, ext))) {
>   +        if (exinfo && ((type = exinfo->encoding_type))) {
>                if (!r->content_encoding)
>                    r->content_encoding = type;
>                else
>                    r->content_encoding = apr_pstrcat(r->pool, r->content_encoding,
>   -                                              ", ", type, NULL);
>   +                                                  ", ", type, NULL);
>                found = 1;
>            }
>    
>            /* Check for a special handler, but not for proxy request */
>   -        if ((type = apr_table_get(conf->handlers, ext))
>   -     && (PROXYREQ_NONE == r->proxyreq) 
>   -        ) {
>   +        if ((exinfo && ((type = exinfo->handler)))
>   +            && (PROXYREQ_NONE == r->proxyreq)) {
>                r->handler = type;
>                found = 1;
>            }
>   
>   
>   
>