]> granicus.if.org Git - apache/commitdiff
The underlying change here was to add the new WebDAV/DeltaV methods
authorGreg Stein <gstein@apache.org>
Tue, 19 Mar 2002 10:11:33 +0000 (10:11 +0000)
committerGreg Stein <gstein@apache.org>
Tue, 19 Mar 2002 10:11:33 +0000 (10:11 +0000)
now that it has an RFC. At the same time, I revamped a good chunk of
the name <-> number mapping code in http_protocol.c

* add M_FOO constants for the new RFC 3253 (DeltaV) methods. label
  where each of the builtin methods comes from.

* moved METHOD_NUMBER_FIRST/LAST from http_protocol.h into
  http_protocol.c since they weren't used anywhere else and they
  weren't namespace-protected.

* create register_one_method() and use it to insert all builtin
  methods (at _init() time) and extended methods into the registry.

* add a lookup_builtin_method() to quickly map a method name to a
  builtin method number.

* rebuild ap_method_number_of() to use the new lookup function.

* revamp ap_method_name_of() to use the registry to locate the name
  for any method number. add a pool argument (no callers in the core
  code needed to be updated)

* revamp make_allow() to deal with the new method numbers and all
  extended methods.

* in mod_dav, use the new method numbers rather than registering the
  DeltaV methods.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@94015 13f79535-47bb-0310-9956-ffa450edef68

include/http_protocol.h
include/httpd.h
modules/dav/main/mod_dav.c
modules/http/http_protocol.c

index fd04b436c77178c157cd201af3ff679c68f430a8..8aa5b0d3c54c3279b915cc1f033a413656a958f5 100644 (file)
@@ -232,16 +232,6 @@ AP_DECLARE(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset,
                              size_t length);
 #endif
 
-/* The index of the first bit field that is used to index into a limit
- * bitmask. M_INVALID + 1 to METHOD_NUMBER_LAST.
- */
-#define METHOD_NUMBER_FIRST M_INVALID + 1
-
-/* The max method number. Method numbers are used to shift bitmasks,
- * so this cannot exceed 63, and all bits high is equal to -1, which is a
- * special flag, so the last bit used has index 62.
- */
-#define METHOD_NUMBER_LAST  62
 
 /**
  * Register a new request method, and return the offset that will be
@@ -571,23 +561,23 @@ AP_DECLARE(apr_status_t) ap_rgetline(char **s, apr_size_t n,
 AP_DECLARE(apr_status_t) ap_rgetline_core(char **s, apr_size_t n, 
                                           apr_size_t *read,
                                           request_rec *r, int fold);
+
 /**
  * Get the method number associated with the given string, assumed to
  * contain an HTTP method.  Returns M_INVALID if not recognized.
  * @param method A string containing a valid HTTP method
  * @return The method number
- * @deffunc int ap_method_number_of(const char *method)
  */
 AP_DECLARE(int) ap_method_number_of(const char *method);
 
 /**
  * Get the method name associated with the given internal method
  * number.  Returns NULL if not recognized.
+ * @param p A pool to use for temporary allocations.
  * @param methnum An integer value corresponding to an internal method number
  * @return The name corresponding to the method number
- * @deffunc const char *ap_method_name_of(int methnum)
  */
-AP_DECLARE(const char *) ap_method_name_of(int methnum);
+AP_DECLARE(const char *) ap_method_name_of(apr_pool_t *p, int methnum);
 
 
   /* Hooks */
index a1b696263c5cbfde125915d095a6fed1e163ce80..143f00f8a031690082b13b4999a09328b598b7b3 100644 (file)
@@ -522,22 +522,33 @@ AP_DECLARE(const char *) ap_get_server_built(void);
  * This list must be tracked by the list in http_protocol.c in routine
  * ap_method_name_of().
  */
-#define M_GET        0
-#define M_PUT        1
-#define M_POST       2
-#define M_DELETE     3
-#define M_CONNECT    4
-#define M_OPTIONS    5
-#define M_TRACE      6
-#define M_PATCH      7
-#define M_PROPFIND   8
-#define M_PROPPATCH  9
-#define M_MKCOL     10
-#define M_COPY      11
-#define M_MOVE      12
-#define M_LOCK      13
-#define M_UNLOCK    14
-#define M_INVALID   15
+#define M_GET                   0       /* RFC 2616: HTTP */
+#define M_PUT                   1       /*  :             */
+#define M_POST                  2
+#define M_DELETE                3
+#define M_CONNECT               4
+#define M_OPTIONS               5
+#define M_TRACE                 6       /* RFC 2616: HTTP */
+#define M_PATCH                 7       /* no rfc(!)  ### remove this one? */
+#define M_PROPFIND              8       /* RFC 2518: WebDAV */
+#define M_PROPPATCH             9       /*  :               */
+#define M_MKCOL                 10
+#define M_COPY                  11
+#define M_MOVE                  12
+#define M_LOCK                  13
+#define M_UNLOCK                14      /* RFC 2518: WebDAV */
+#define M_VERSION_CONTROL       15      /* RFC 3253: WebDAV Versioning */
+#define M_CHECKOUT              16      /*  :                          */
+#define M_UNCHECKOUT            17
+#define M_CHECKIN               18
+#define M_UPDATE                19
+#define M_LABEL                 20
+#define M_REPORT                21
+#define M_MKWORKSPACE           22
+#define M_MKACTIVITY            23
+#define M_BASELINE_CONTROL      24
+#define M_MERGE                 25
+#define M_INVALID               26      /* RFC 3253: WebDAV Versioning */
 
 /**
  * METHODS needs to be equal to the number of bits
@@ -548,7 +559,7 @@ AP_DECLARE(const char *) ap_get_server_built(void);
 /**
  * The method mask bit to shift for anding with a bitmask.
  */
-#define AP_METHOD_BIT (apr_int64_t)1
+#define AP_METHOD_BIT ((apr_int64_t)1)
 /** @} */
 
 
index ccdc361965faa4aa38af161941143b411cfc09d4..e35cb3563ad564ad56fb7a12bab14523ceec3640 100644 (file)
@@ -132,40 +132,18 @@ extern module DAV_DECLARE_DATA dav_module;
 
 /* DAV methods */
 enum {
-    DAV_M_VERSION_CONTROL = 0,
-    DAV_M_CHECKOUT,
-    DAV_M_UNCHECKOUT,
-    DAV_M_CHECKIN,
-    DAV_M_UPDATE,
-    DAV_M_LABEL,
-    DAV_M_REPORT,
-    DAV_M_MKWORKSPACE,
-    DAV_M_MKACTIVITY,
-    DAV_M_BASELINE_CONTROL,
-    DAV_M_MERGE,
-    DAV_M_BIND,
+    DAV_M_BIND = 0,
     DAV_M_LAST
 };
-
 static int dav_methods[DAV_M_LAST];
 
+
 static int dav_init_handler(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp,
                              server_rec *s)
 {
     /* DBG0("dav_init_handler"); */
 
     /* Register DAV methods */
-    dav_methods[DAV_M_VERSION_CONTROL] = ap_method_register(p, "VERSION-CONTROL");
-    dav_methods[DAV_M_CHECKOUT] = ap_method_register(p, "CHECKOUT");
-    dav_methods[DAV_M_UNCHECKOUT] = ap_method_register(p, "UNCHECKOUT");
-    dav_methods[DAV_M_CHECKIN] = ap_method_register(p, "CHECKIN");
-    dav_methods[DAV_M_UPDATE] = ap_method_register(p, "UPDATE");
-    dav_methods[DAV_M_LABEL] = ap_method_register(p, "LABEL");
-    dav_methods[DAV_M_REPORT] = ap_method_register(p, "REPORT");
-    dav_methods[DAV_M_MKWORKSPACE] = ap_method_register(p, "MKWORKSPACE");
-    dav_methods[DAV_M_MKACTIVITY] = ap_method_register(p, "MKACTIVITY");
-    dav_methods[DAV_M_BASELINE_CONTROL] = ap_method_register(p, "BASELINE-CONTROL");
-    dav_methods[DAV_M_MERGE] = ap_method_register(p, "MERGE");
     dav_methods[DAV_M_BIND] = ap_method_register(p, "BIND");
 
     ap_add_version_component(p, "DAV/2");
@@ -3868,7 +3846,6 @@ static int dav_method_report(request_rec *r)
     int result;
     int label_allowed;
     ap_xml_doc *doc;
-    ap_text *t;
     dav_error *err;
 
     /* If no versioning provider, decline the request */
@@ -4488,47 +4465,47 @@ static int dav_handler(request_rec *r)
         return dav_method_unlock(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_VERSION_CONTROL]) {
+    if (r->method_number == M_VERSION_CONTROL) {
         return dav_method_vsn_control(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_CHECKOUT]) {
+    if (r->method_number == M_CHECKOUT) {
         return dav_method_checkout(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_UNCHECKOUT]) {
+    if (r->method_number == M_UNCHECKOUT) {
         return dav_method_uncheckout(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_CHECKIN]) {
+    if (r->method_number == M_CHECKIN) {
         return dav_method_checkin(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_UPDATE]) {
+    if (r->method_number == M_UPDATE) {
         return dav_method_update(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_LABEL]) {
+    if (r->method_number == M_LABEL) {
         return dav_method_label(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_REPORT]) {
+    if (r->method_number == M_REPORT) {
         return dav_method_report(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_MKWORKSPACE]) {
+    if (r->method_number == M_MKWORKSPACE) {
         return dav_method_make_workspace(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_MKACTIVITY]) {
+    if (r->method_number == M_MKACTIVITY) {
         return dav_method_make_activity(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_BASELINE_CONTROL]) {
+    if (r->method_number == M_BASELINE_CONTROL) {
         return dav_method_baseline_control(r);
     }
 
-    if (r->method_number == dav_methods[DAV_M_MERGE]) {
+    if (r->method_number == M_MERGE) {
         return dav_method_merge(r);
     }
 
index 205c8732bf0af75de2ef152a3dca6d4358732557..cffdcb7ddb0dba38183032327263cb2953ee59f3 100644 (file)
 #endif
 
 
+/* The index of the first bit field that is used to index into a limit
+ * bitmask. M_INVALID + 1 to METHOD_NUMBER_LAST.
+ */
+#define METHOD_NUMBER_FIRST (M_INVALID + 1)
+
+/* The max method number. Method numbers are used to shift bitmasks,
+ * so this cannot exceed 63, and all bits high is equal to -1, which is a
+ * special flag, so the last bit used has index 62.
+ */
+#define METHOD_NUMBER_LAST  62
+
+
 AP_DECLARE(int) ap_set_keepalive(request_rec *r)
 {
     int ka_sent = 0;
@@ -317,6 +329,16 @@ AP_DECLARE(int) ap_meets_conditions(request_rec *r)
 static apr_hash_t *methods_registry = NULL;
 static int cur_method_number = METHOD_NUMBER_FIRST;
 
+/* internal function to register one method/number pair */
+static void register_one_method(apr_pool_t *p, const char *methname,
+                                int methnum)
+{
+    int *pnum = apr_palloc(p, sizeof(*pnum));
+
+    *pnum = methnum;
+    apr_hash_set(methods_registry, methname, APR_HASH_KEY_STRING, pnum);
+}
+
 /* This internal function is used to clear the method registry
  * and reset the cur_method_number counter.
  */
@@ -333,6 +355,35 @@ AP_DECLARE(void) ap_method_registry_init(apr_pool_t *p)
     apr_pool_cleanup_register(p, NULL,
                               ap_method_registry_destroy,
                               apr_pool_cleanup_null);
+
+    /* put all the standard methods into the registry hash to ease the
+       mapping operations between name and number */
+    register_one_method(p, "GET", M_GET);
+    register_one_method(p, "PUT", M_PUT);
+    register_one_method(p, "POST", M_POST);
+    register_one_method(p, "DELETE", M_DELETE);
+    register_one_method(p, "CONNECT", M_CONNECT);
+    register_one_method(p, "OPTIONS", M_OPTIONS);
+    register_one_method(p, "TRACE", M_TRACE);
+    register_one_method(p, "PATCH", M_PATCH);
+    register_one_method(p, "PROPFIND", M_PROPFIND);
+    register_one_method(p, "PROPPATCH", M_PROPPATCH);
+    register_one_method(p, "MKCOL", M_MKCOL);
+    register_one_method(p, "COPY", M_COPY);
+    register_one_method(p, "MOVE", M_MOVE);
+    register_one_method(p, "LOCK", M_LOCK);
+    register_one_method(p, "UNLOCK", M_UNLOCK);
+    register_one_method(p, "VERSION-CONTROL", M_VERSION_CONTROL);
+    register_one_method(p, "CHECKOUT", M_CHECKOUT);
+    register_one_method(p, "UNCHECKOUT", M_UNCHECKOUT);
+    register_one_method(p, "CHECKIN", M_CHECKIN);
+    register_one_method(p, "UPDATE", M_UPDATE);
+    register_one_method(p, "LABEL", M_LABEL);
+    register_one_method(p, "REPORT", M_REPORT);
+    register_one_method(p, "MKWORKSPACE", M_MKWORKSPACE);
+    register_one_method(p, "MKACTIVITY", M_MKACTIVITY);
+    register_one_method(p, "BASELINE-CONTROL", M_BASELINE_CONTROL);
+    register_one_method(p, "MERGE", M_MERGE);
 }
 
 AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname)
@@ -366,11 +417,180 @@ AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname)
         return M_INVALID;
     }
 
-    methnum = (int *)apr_palloc(p, sizeof(int));
-    *methnum = cur_method_number++;
-    apr_hash_set(methods_registry, methname, APR_HASH_KEY_STRING, methnum);
+    register_one_method(p, methname, cur_method_number);
+    return cur_method_number++;
+}
+
+#define UNKNOWN_METHOD (-1)
 
-    return *methnum;
+static int lookup_builtin_method(const char *method, apr_size_t len)
+{
+    /* Note: the following code was generated by the "shilka" tool from
+       the "cocom" parsing/compilation toolkit. It is an optimized lookup
+       based on analysis of the input keywords. Postprocessing was done
+       on the shilka output, but the basic structure and analysis is
+       from there. Should new HTTP methods be added, then manual insertion
+       into this code is fine, or simply re-running the shilka tool on
+       the appropriate input. */
+
+    /* Note: it is also quite reasonable to just use our method_registry,
+       but I'm assuming (probably incorrectly) we want more speed here
+       (based on the optimizations the previous code was doing). */
+
+    switch (len)
+    {
+    case 3:
+        switch (method[0])
+        {
+        case 'P':
+            return (method[1] == 'U'
+                    && method[2] == 'T'
+                    ? M_PUT : UNKNOWN_METHOD);
+        case 'G':
+            return (method[1] == 'E'
+                    && method[2] == 'T'
+                    ? M_GET : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 4:
+        switch (method[0])
+        {
+        case 'P':
+            return (method[1] == 'O'
+                    && method[2] == 'S'
+                    && method[3] == 'T'
+                    ? M_POST : UNKNOWN_METHOD);
+        case 'M':
+            return (method[1] == 'O'
+                    && method[2] == 'V'
+                    && method[3] == 'E'
+                    ? M_MOVE : UNKNOWN_METHOD);
+        case 'L':
+            return (method[1] == 'O'
+                    && method[2] == 'C'
+                    && method[3] == 'K'
+                    ? M_LOCK : UNKNOWN_METHOD);
+        case 'C':
+            return (method[1] == 'O'
+                    && method[2] == 'P'
+                    && method[3] == 'Y'
+                    ? M_COPY : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 5:
+        switch (method[2])
+        {
+        case 'T':
+            return (memcmp(method, "PATCH", 5) == 0
+                    ? M_PATCH : UNKNOWN_METHOD);
+        case 'R':
+            return (memcmp(method, "MERGE", 5) == 0
+                    ? M_MERGE : UNKNOWN_METHOD);
+        case 'C':
+            return (memcmp(method, "MKCOL", 5) == 0
+                    ? M_MKCOL : UNKNOWN_METHOD);
+        case 'B':
+            return (memcmp(method, "LABEL", 5) == 0
+                    ? M_LABEL : UNKNOWN_METHOD);
+        case 'A':
+            return (memcmp(method, "TRACE", 5) == 0
+                    ? M_TRACE : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 6:
+        switch (method[0])
+        {
+        case 'U':
+            switch (method[5])
+            {
+            case 'K':
+                return (memcmp(method, "UNLOCK", 6) == 0
+                        ? M_UNLOCK : UNKNOWN_METHOD);
+            case 'E':
+                return (memcmp(method, "UPDATE", 6) == 0
+                        ? M_UPDATE : UNKNOWN_METHOD);
+            default:
+                return UNKNOWN_METHOD;
+            }
+        case 'R':
+            return (memcmp(method, "REPORT", 6) == 0
+                    ? M_REPORT : UNKNOWN_METHOD);
+        case 'D':
+            return (memcmp(method, "DELETE", 6) == 0
+                    ? M_DELETE : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 7:
+        switch (method[1])
+        {
+        case 'P':
+            return (memcmp(method, "OPTIONS", 7) == 0
+                    ? M_OPTIONS : UNKNOWN_METHOD);
+        case 'O':
+            return (memcmp(method, "CONNECT", 7) == 0
+                    ? M_CONNECT : UNKNOWN_METHOD);
+        case 'H':
+            return (memcmp(method, "CHECKIN", 7) == 0
+                    ? M_CHECKIN : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 8:
+        switch (method[0])
+        {
+        case 'P':
+            return (memcmp(method, "PROPFIND", 8) == 0
+                    ? M_PROPFIND : UNKNOWN_METHOD);
+        case 'C':
+            return (memcmp(method, "CHECKOUT", 8) == 0
+                    ? M_CHECKOUT : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 9:
+        return (memcmp(method, "PROPPATCH", 9) == 0
+                ? M_PROPPATCH : UNKNOWN_METHOD);
+
+    case 10:
+        switch (method[0])
+        {
+        case 'U':
+            return (memcmp(method, "UNCHECKOUT", 10) == 0
+                    ? M_UNCHECKOUT : UNKNOWN_METHOD);
+        case 'M':
+            return (memcmp(method, "MKACTIVITY", 10) == 0
+                    ? M_MKACTIVITY : UNKNOWN_METHOD);
+        default:
+            return UNKNOWN_METHOD;
+        }
+
+    case 11:
+        return (memcmp(method, "MKWORKSPACE", 11) == 0
+                ? M_MKWORKSPACE : UNKNOWN_METHOD);
+
+    case 15:
+        return (memcmp(method, "VERSION-CONTROL", 15) == 0
+                ? M_VERSION_CONTROL : UNKNOWN_METHOD);
+
+    case 16:
+        return (memcmp(method, "BASELINE-CONTROL", 16) == 0
+                ? M_BASELINE_CONTROL : UNKNOWN_METHOD);
+
+    default:
+        return UNKNOWN_METHOD;
+    }
+
+    /* NOTREACHED */
 }
 
 /* Get the method number associated with the given string, assumed to
@@ -382,84 +602,16 @@ AP_DECLARE(int) ap_method_register(apr_pool_t *p, const char *methname)
  */
 AP_DECLARE(int) ap_method_number_of(const char *method)
 {
-    int *methnum = NULL;
+    int len = strlen(method);
+    int which = lookup_builtin_method(method, len);
 
-    switch (*method) {
-    case 'H':
-        if (strcmp(method, "HEAD") == 0) {
-            return M_GET;   /* see header_only in request_rec */
-        }
-        break;
-    case 'G':
-        if (strcmp(method, "GET") == 0) {
-            return M_GET;
-        }
-        break;
-    case 'P':
-        if (strcmp(method, "POST") == 0) {
-            return M_POST;
-        }
-        if (strcmp(method, "PUT") == 0) {
-            return M_PUT;
-        }
-        if (strcmp(method, "PATCH") == 0) {
-            return M_PATCH;
-        }
-        if (strcmp(method, "PROPFIND") == 0) {
-            return M_PROPFIND;
-        }
-        if (strcmp(method, "PROPPATCH") == 0) {
-            return M_PROPPATCH;
-        }
-        break;
-    case 'D':
-        if (strcmp(method, "DELETE") == 0) {
-            return M_DELETE;
-        }
-        break;
-    case 'C':
-        if (strcmp(method, "CONNECT") == 0) {
-            return M_CONNECT;
-        }
-        if (strcmp(method, "COPY") == 0) {
-            return M_COPY;
-        }
-        break;
-    case 'M':
-        if (strcmp(method, "MKCOL") == 0) {
-            return M_MKCOL;
-        }
-        if (strcmp(method, "MOVE") == 0) {
-            return M_MOVE;
-        }
-        break;
-    case 'O':
-        if (strcmp(method, "OPTIONS") == 0) {
-            return M_OPTIONS;
-        }
-        break;
-    case 'T':
-        if (strcmp(method, "TRACE") == 0) {
-            return M_TRACE;
-        }
-        break;
-    case 'L':
-        if (strcmp(method, "LOCK") == 0) {
-            return M_LOCK;
-        }
-        break;
-    case 'U':
-        if (strcmp(method, "UNLOCK") == 0) {
-            return M_UNLOCK;
-        }
-        break;
-    }
+    if (which != UNKNOWN_METHOD)
+        return which;
 
     /* check if the method has been dynamically registered */
     if (methods_registry != NULL) {
-        methnum = (int*)apr_hash_get(methods_registry,
-                                     method,
-                                     APR_HASH_KEY_STRING);
+        int *methnum = apr_hash_get(methods_registry, method, len);
+
         if (methnum != NULL) {
             return *methnum;
         }
@@ -469,49 +621,25 @@ AP_DECLARE(int) ap_method_number_of(const char *method)
 }
 
 /*
- * Turn a known method number into a name.  Doesn't work for
- * extension methods, obviously.
+ * Turn a known method number into a name.
  */
-AP_DECLARE(const char *) ap_method_name_of(int methnum)
+AP_DECLARE(const char *) ap_method_name_of(apr_pool_t *p, int methnum)
 {
-    static const char *AP_HTTP_METHODS[METHODS] = { NULL };
+    apr_hash_index_t *hi = apr_hash_first(p, methods_registry);
 
-    /*
-     * This is ugly, but the previous incantation made Windows C
-     * varf.  I'm not even sure it was ANSI C.  However, ugly as it
-     * is, this works, and we only have to do it once.
-     */
-    if (AP_HTTP_METHODS[0] == NULL) {
-        AP_HTTP_METHODS[M_GET]       = "GET";
-        AP_HTTP_METHODS[M_PUT]       = "PUT";
-        AP_HTTP_METHODS[M_POST]      = "POST";
-        AP_HTTP_METHODS[M_DELETE]    = "DELETE";
-        AP_HTTP_METHODS[M_CONNECT]   = "CONNECT";
-        AP_HTTP_METHODS[M_OPTIONS]   = "OPTIONS";
-        AP_HTTP_METHODS[M_TRACE]     = "TRACE";
-        AP_HTTP_METHODS[M_PATCH]     = "PATCH";
-        AP_HTTP_METHODS[M_PROPFIND]  = "PROPFIND";
-        AP_HTTP_METHODS[M_PROPPATCH] = "PROPPATCH";
-        AP_HTTP_METHODS[M_MKCOL]     = "MKCOL";
-        AP_HTTP_METHODS[M_COPY]      = "COPY";
-        AP_HTTP_METHODS[M_MOVE]      = "MOVE";
-        AP_HTTP_METHODS[M_LOCK]      = "LOCK";
-        AP_HTTP_METHODS[M_UNLOCK]    = "UNLOCK";
-        AP_HTTP_METHODS[M_INVALID]   = NULL;
-        /*
-         * Since we're using symbolic names, make sure we only do
-         * this once by forcing a value into the first slot IFF it's
-         * still NULL.
-         */
-        if (AP_HTTP_METHODS[0] == NULL) {
-            AP_HTTP_METHODS[0] = "INVALID";
-        }
-    }
+    /* scan through the hash table, looking for a value that matches
+       the provided method number. */
+    for (; hi; hi = apr_hash_next(hi)) {
+        const void *key;
+        void *val;
 
-    if ((methnum == M_INVALID) || (methnum >= METHODS)) {
-        return NULL;
+        apr_hash_this(hi, &key, NULL, &val);
+        if (*(int *)val == methnum)
+            return key;
     }
-    return AP_HTTP_METHODS[methnum];
+
+    /* it wasn't found in the hash */
+    return NULL;
 }
 
 static long get_chunk_size(char *);
@@ -955,25 +1083,32 @@ static char *make_allow(request_rec *r)
 {
     char *list;
     apr_int64_t mask;
+    apr_array_header_t *allow = apr_array_make(r->pool, 10, sizeof(char *));
+    apr_hash_index_t *hi = apr_hash_first(r->pool, methods_registry);
 
     mask = r->allowed_methods->method_mask;
-    list = apr_pstrcat(r->pool,
-                   (mask & (AP_METHOD_BIT << M_GET))       ? ", GET, HEAD" : "",
-                   (mask & (AP_METHOD_BIT << M_POST))      ? ", POST"      : "",
-                   (mask & (AP_METHOD_BIT << M_PUT))       ? ", PUT"       : "",
-                   (mask & (AP_METHOD_BIT << M_DELETE))    ? ", DELETE"    : "",
-                   (mask & (AP_METHOD_BIT << M_CONNECT))   ? ", CONNECT"   : "",
-                   (mask & (AP_METHOD_BIT << M_OPTIONS))   ? ", OPTIONS"   : "",
-                   (mask & (AP_METHOD_BIT << M_PATCH))     ? ", PATCH"     : "",
-                   (mask & (AP_METHOD_BIT << M_PROPFIND))  ? ", PROPFIND"  : "",
-                   (mask & (AP_METHOD_BIT << M_PROPPATCH)) ? ", PROPPATCH" : "",
-                   (mask & (AP_METHOD_BIT << M_MKCOL))     ? ", MKCOL"     : "",
-                   (mask & (AP_METHOD_BIT << M_COPY))      ? ", COPY"      : "",
-                   (mask & (AP_METHOD_BIT << M_MOVE))      ? ", MOVE"      : "",
-                   (mask & (AP_METHOD_BIT << M_LOCK))      ? ", LOCK"      : "",
-                   (mask & (AP_METHOD_BIT << M_UNLOCK))    ? ", UNLOCK"    : "",
-                   ", TRACE",
-                   NULL);
+
+    for (; hi; hi = apr_hash_next(hi)) {
+        const void *key;
+        void *val;
+
+        apr_hash_this(hi, &key, NULL, &val);
+        if ((mask & (AP_METHOD_BIT << *(int *)val)) != 0) {
+            *(const char **)apr_array_push(allow) = key;
+
+            /* the M_GET method actually refers to two methods */
+            if (*(int *)val == M_GET)
+                *(const char **)apr_array_push(allow) = "HEAD";
+        }
+    }
+
+    /* TRACE is always allowed */
+    *(const char **)apr_array_push(allow) = "TRACE";
+
+    list = apr_array_pstrcat(r->pool, allow, ',');
+
+    /* ### this is rather annoying. we should enforce registration of
+       ### these methods */
     if ((mask & (AP_METHOD_BIT << M_INVALID))
         && (r->allowed_methods->method_list != NULL)
         && (r->allowed_methods->method_list->nelts != 0)) {
@@ -987,11 +1122,8 @@ static char *make_allow(request_rec *r)
             list = apr_pstrcat(r->pool, list, ", ", xmethod[i], NULL);
         }
     }
-    /*
-     * Space past the leading ", ".  Wastes two bytes, but that's better
-     * than futzing around to find the actual length.
-     */
-    return list + 2;
+
+    return list;
 }
 
 AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r)