You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by Cody Sherr <cs...@covalent.net> on 2001/08/01 07:13:41 UTC

directive extended to arbitrary methods

The purpose of this patch is to allow modules to register request methods,
and have those methods <limit>able in the httpd.conf. It uses the same bit
mask/shifted offset as the original HTTP methods such as M_GET or M_POST,
but expands the total bits from an int to an ap_int64_t to handle more
bits for new request methods than an int provides.

regards,

-- 
Cody Sherr

Engineer
Covalent Technologies

phone: (415)536-5292
email: csherr@covalent.net


Index: include/http_config.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/http_config.h,v
retrieving revision 1.82
diff -u -r1.82 http_config.h
--- include/http_config.h	2001/05/28 15:32:50	1.82
+++ include/http_config.h	2001/08/01 05:02:51
@@ -260,7 +260,7 @@
     /** Which allow-override bits are set */
     int override;
     /** Which methods are <Limit>ed */
-    int limited;
+    apr_int64_t limited;
     apr_array_header_t *limited_xmethods;
     ap_method_list_t *xlimited;

Index: include/http_core.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/http_core.h,v
retrieving revision 1.46
diff -u -r1.46 http_core.h
--- include/http_core.h	2001/07/30 18:51:57	1.46
+++ include/http_core.h	2001/08/01 05:02:51
@@ -277,7 +277,7 @@
 /** A structure to keep track of authorization requirements */
 struct require_line {
     /** Where the require line is in the config file. */
-    int method_mask;
+    apr_int64_t method_mask;
     /** The complete string from the command line */
     char *requirement;
 };
Index: include/http_protocol.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/http_protocol.h,v
retrieving revision 1.60
diff -u -r1.60 http_protocol.h
--- include/http_protocol.h	2001/07/27 21:01:16	1.60
+++ include/http_protocol.h	2001/08/01 05:02:51
@@ -227,6 +227,34 @@
                              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
+ * associated with that method.
+ *
+ * @param p        The pool to create registered method numbers from.
+ * @param methname The name of the new method to register.
+ * @return         Ab int value representing an offset into a bitmask.
+ */
+AP_DECLARE(int) ap_method_register(apr_pool_t *p, char *methname);
+
+/**
+ * Initialize the method_registry and allocate memory for it.
+ *
+ * @param p Pool to allocate memory for the registry from.
+ */
+AP_DECLARE(void) ap_method_registry_init(apr_pool_t *p);
+
 /**
  * Create a new method list with the specified number of preallocated
  * slots for extension methods.
Index: include/httpd.h
===================================================================
RCS file: /home/cvspublic/httpd-2.0/include/httpd.h,v
retrieving revision 1.156
diff -u -r1.156 httpd.h
--- include/httpd.h	2001/07/26 15:53:15	1.156
+++ include/httpd.h	2001/08/01 05:02:51
@@ -478,8 +478,6 @@
 /* Methods recognized (but not necessarily handled) by the server.
  * These constants are used in bit shifting masks of size int, so it is
  * unsafe to have more methods than bits in an int.  HEAD == M_GET.
- * 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
@@ -498,7 +496,10 @@
 #define M_UNLOCK    14
 #define M_INVALID   15

-#define METHODS     16
+/* METHODS needs to be equal to the number of bits
+ * we are using for limit masks.
+ */
+#define METHODS     64

 typedef struct ap_method_list_t ap_method_list_t;
 /**
@@ -508,8 +509,8 @@
  */
 struct ap_method_list_t {
     /* The bitmask used for known methods */
-    int method_mask;
-    /* The array used for extension methods */
+    apr_int64_t method_mask;
+    /* the array used for extension methods */
     apr_array_header_t *method_list;
 };

@@ -679,7 +680,7 @@
      *  HTTP_METHOD_NOT_ALLOWED.  Unfortunately this means that a Script GET
      *  handler can't be installed by mod_actions.
      */
-    int allowed;
+    apr_int64_t allowed;
     /** Array of extension methods */
     apr_array_header_t *allowed_xmethods;
     /** List of allowed methods */
Index: modules/aaa/mod_access.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/aaa/mod_access.c,v
retrieving revision 1.32
diff -u -r1.32 mod_access.c
--- modules/aaa/mod_access.c	2001/04/12 13:35:39	1.32
+++ modules/aaa/mod_access.c	2001/08/01 05:02:51
@@ -91,7 +91,7 @@
 };

 typedef struct {
-    int limited;
+    apr_int64_t limited;
     union {
 	char *from;
         apr_ipsubnet_t *ip;
@@ -237,8 +237,9 @@

 static int find_allowdeny(request_rec *r, apr_array_header_t *a, int method)
 {
+
     allowdeny *ap = (allowdeny *) a->elts;
-    int mmask = (1 << method);
+    apr_int64_t mmask = (1 << method);
     int i;
     int gothost = 0;
     const char *remotehost = NULL;
Index: modules/http/http_protocol.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/modules/http/http_protocol.c,v
retrieving revision 1.339
diff -u -r1.339 http_protocol.c
--- modules/http/http_protocol.c	2001/08/01 04:08:36	1.339
+++ modules/http/http_protocol.c	2001/08/01 05:02:52
@@ -299,6 +299,83 @@
     return OK;
 }

+/**
+ * Singleton registry of additional methods. This maps new method names
+ * such as "MYGET" to methnums, which are int offsets into bitmasks.
+ *
+ * This follows the same technique as standard M_GET, M_POST, etc. These
+ * are dynamically assigned when modules are loaded and <Limit GET MYGET>
+ * directives are processed.
+ */
+static apr_hash_t *methods_registry=NULL;
+
+/**
+ * This keeps track of the currently available method number.
+ */
+static int cur_method_number = METHOD_NUMBER_FIRST;
+
+/* This internal function is used to clear the method registry
+ * and reset the cur_method_number counter.
+ */
+static apr_status_t ap_method_registry_destroy(void *notused)
+{
+    methods_registry = NULL;
+    cur_method_number = METHOD_NUMBER_FIRST;
+    return APR_SUCCESS;
+}
+
+/**
+ * Initialize the method_registry and allocate memory for it.
+ *
+ * @param p Pool to allocate memory for the registry from.
+ */
+AP_DECLARE(void) ap_method_registry_init(apr_pool_t *p)
+{
+    methods_registry = apr_hash_make(p);
+    apr_pool_cleanup_register(p, NULL,
+			      ap_method_registry_destroy,
+			      apr_pool_cleanup_null);
+}
+
+/**
+ * Register a new request method, and return the offset that will be
+ * associated with that method.
+ *
+ * @param p        The pool to create registered method numbers from.
+ * @param methname The name of the new method to register.
+ * @return         An int value representing an offset into a bitmask.
+ *                 M_INVALID is return if methname is NULL or we
+ *                 have run out of space in the allowed mask.
+ */
+AP_DECLARE(int) ap_method_register(apr_pool_t *p, char *methname)
+{
+    int *newmethnum;
+
+    if (methods_registry == NULL) {
+	ap_method_registry_init(p);
+    }
+
+    if (methname == NULL) {
+	return M_INVALID;
+    }
+
+    if (cur_method_number > METHOD_NUMBER_LAST) {
+	/* The method registry  has run out of dynamically
+	 * assignable method numbers. Log this and return M_INVALID.
+	 */
+	ap_log_perror(APLOG_MARK, APLOG_ERR|APLOG_NOERRNO, 0, p,
+		      "Maximum new request methods %d reached while registering method %s.",
+		      METHOD_NUMBER_LAST, methname);
+	return M_INVALID;
+    }
+
+    newmethnum  = (int*)apr_palloc(p,sizeof(int));
+    *newmethnum = cur_method_number++;
+    apr_hash_set(methods_registry, methname, APR_HASH_KEY_STRING, newmethnum);
+
+    return *newmethnum;
+}
+
 /* Get the method number associated with the given string, assumed to
  * contain an HTTP method.  Returns M_INVALID if not recognized.
  *
@@ -308,11 +385,13 @@
  */
 AP_DECLARE(int) ap_method_number_of(const char *method)
 {
+    int *methnum = NULL;
+
     switch (*method) {
         case 'H':
            if (strcmp(method, "HEAD") == 0)
                return M_GET;   /* see header_only in request_rec */
-           break;
+           break;
         case 'G':
            if (strcmp(method, "GET") == 0)
                return M_GET;
@@ -361,7 +440,17 @@
            if (strcmp(method, "UNLOCK") == 0)
                return M_UNLOCK;
            break;
+    }
+
+    /* check if the method has been dynamically registered */
+    if (methods_registry != NULL) {
+	methnum = (int*)apr_hash_get(methods_registry,
+				     method,
+				     APR_HASH_KEY_STRING);
+	if (methnum != NULL)
+	    return *methnum;
     }
+
     return M_INVALID;
 }

@@ -904,7 +993,7 @@
 static char *make_allow(request_rec *r)
 {
     char *list;
-    int mask;
+    apr_int64_t mask;

     mask = r->allowed_methods->method_mask;
     list = apr_pstrcat(r->pool,
@@ -2073,8 +2162,8 @@
     char **methods;

     /*
-     * If it's one of our known methods, use the shortcut and use the
-     * bitmask.
+     * If it's a known methods, either builtin or registered
+     * by a module, use the bitmask.
      */
     methnum = ap_method_number_of(method);
     l->method_mask |= ~(1 << methnum);
Index: server/config.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/config.c,v
retrieving revision 1.130
diff -u -r1.130 config.c
--- server/config.c	2001/07/04 03:16:33	1.130
+++ server/config.c	2001/08/01 05:02:52
@@ -354,30 +354,18 @@

 AP_DECLARE(int) ap_method_is_limited(cmd_parms *cmd, const char *method) {
     int methnum;
-    int i;
-    char **xmethod;

     methnum = ap_method_number_of(method);
+
     /*
-     * The simple case: a method hard-coded into Apache.
+     * A method number either hardcoded into apache or
+     * added by a module and registered.
      */
     if (methnum != M_INVALID) {
-	return (methnum & cmd->limited);
-    }
-    /*
-     * Some extension method we don't know implicitly.
-     */
-    if ((cmd->limited_xmethods == NULL)
-	|| (cmd->limited_xmethods->nelts == 0)) {
-	return 0;
-    }
-    xmethod = (char **) cmd->limited_xmethods->elts;
-    for (i = 0; i < cmd->limited_xmethods->nelts; ++i) {
-	if (strcmp(method, xmethod[i]) == 0) {
-	    return 1;
-	}
+	return  (cmd->limited & (1<<methnum));
     }
-    return 0;
+
+    return 0; /* not found */
 }

 AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p)
Index: server/core.c
===================================================================
RCS file: /home/cvspublic/httpd-2.0/server/core.c,v
retrieving revision 1.31
diff -u -r1.31 core.c
--- server/core.c	2001/07/30 18:51:57	1.31
+++ server/core.c	2001/08/01 05:02:53
@@ -1466,55 +1466,31 @@
 						  const char *arg) {
     const char *limited_methods = ap_getword(cmd->pool, &arg, '>');
     void *tog = cmd->cmd->cmd_data;
-    int limited = 0;
+    apr_int64_t limited = 0;
     const char *errmsg;
-
+    int i = 0;
     const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
+
     if (err != NULL) {
         return err;
     }

     while (limited_methods[0]) {
         char *method = ap_getword_conf(cmd->pool, &limited_methods);
-        int  methnum = ap_method_number_of(method);
+	int methnum;
+
+	/* check for builtin or module registered method number */
+	methnum = ap_method_number_of(method);

         if (methnum == M_TRACE && !tog) {
             return "TRACE cannot be controlled by <Limit>";
         }
-        else if (methnum == M_INVALID) {
-	    char **xmethod;
-	    register int i, j, k;
-
-	    /*
-	     * Deal with <Limit> by adding the method to the list.
+	else if (methnum == M_INVALID) {
+	    /* method has not been registered yet, but resorce restriction
+	     * is always checked before method handling, so register it.
 	     */
-	    if (!tog) {
-		if (cmd->limited_xmethods == NULL) {
-		    cmd->limited_xmethods = apr_array_make(cmd->pool, 2,
-							   sizeof(char *));
-		}
-		xmethod = (char **) apr_array_push(cmd->limited_xmethods);
-		*xmethod = apr_pstrdup(cmd->pool, method);
-	    }
-	    /*
-	     * <LimitExcept>, so remove any/all occurrences of the method
-	     * in the extension array.
-	     */
-	    else if ((cmd->limited_xmethods != NULL)
-		     && (cmd->limited_xmethods->nelts != 0)) {
-		xmethod = (char **) cmd->limited_xmethods->elts;
-		for (i = 0; i < cmd->limited_xmethods->nelts; i++) {
-		    if (strcmp(xmethod[i], method) == 0) {
-			for (j = i, k = i + 1;
-			     k < cmd->limited_xmethods->nelts;
-			     ++j, ++k) {
-			    xmethod[j] = xmethod[k];
-			}
-			cmd->limited_xmethods->nelts--;
-		    }
-		}
-	    }
-        }
+	    methnum = ap_method_register(cmd->pool, method);
+	}
 	limited |= (1 << methnum);
     }