summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Bloom <rbb@apache.org>2001-08-02 04:25:20 +0000
committerRyan Bloom <rbb@apache.org>2001-08-02 04:25:20 +0000
commit85e8fbd0e21fec6cb8c6cb0af6cdb8c592bbec67 (patch)
tree1c5c5f4c5b2d63f794243cdc2732fce82ccf12c4
parentc0dbe658163fac90c3ee93efeca9886b18c83910 (diff)
downloadhttpd-85e8fbd0e21fec6cb8c6cb0af6cdb8c592bbec67.tar.gz
Add the ability to extend the methods that Apache understands
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. Submitted by: Cody Sherr <csherr@covalent.net> git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@89869 13f79535-47bb-0310-9956-ffa450edef68
-rw-r--r--CHANGES7
-rw-r--r--include/http_config.h2
-rw-r--r--include/http_core.h2
-rw-r--r--include/http_protocol.h34
-rw-r--r--include/httpd.h11
-rw-r--r--modules/aaa/mod_access.c5
-rw-r--r--modules/http/http_protocol.c76
-rw-r--r--server/config.c24
-rw-r--r--server/core.c45
-rw-r--r--server/protocol.c23
10 files changed, 162 insertions, 67 deletions
diff --git a/CHANGES b/CHANGES
index 21b5ade14f..32a9510be3 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,12 @@
Changes with Apache 2.0.23-dev
+ *) Add the ability to extend the methods that Apache understands
+ 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. [Cody Sherr <csherr@covalent.net>]
+
*) Fix broken mod_mime behavior in merging its arguments. Possible
cause of unexplicable crashes introduced in 2.0.20. [William Rowe]
diff --git a/include/http_config.h b/include/http_config.h
index 5fe4825439..9e4a524d47 100644
--- a/include/http_config.h
+++ b/include/http_config.h
@@ -260,7 +260,7 @@ struct cmd_parms_struct {
/** 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;
diff --git a/include/http_core.h b/include/http_core.h
index 4e0d2ecfd6..1bf9f485e2 100644
--- a/include/http_core.h
+++ b/include/http_core.h
@@ -277,7 +277,7 @@ typedef struct require_line require_line;
/** 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;
};
diff --git a/include/http_protocol.h b/include/http_protocol.h
index 5ab522cd2b..a27d5e77b8 100644
--- a/include/http_protocol.h
+++ b/include/http_protocol.h
@@ -227,6 +227,40 @@ 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
+ * 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);
+
+/*
+ * This is a convenience macro to ease with checking a mask
+ * against a method name.
+ */
+#define AP_METHOD_CHECK_ALLOWED(mask, methname) ((mask) & (1 << ap_method_number_of((methname))))
+
/**
* Create a new method list with the specified number of preallocated
* slots for extension methods.
diff --git a/include/httpd.h b/include/httpd.h
index c2eba3bc8f..e32ed8ef4a 100644
--- a/include/httpd.h
+++ b/include/httpd.h
@@ -498,7 +498,10 @@ AP_DECLARE(const char *) ap_get_server_built(void);
#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 +511,8 @@ typedef struct ap_method_list_t ap_method_list_t;
*/
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 +682,7 @@ struct request_rec {
* 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 */
diff --git a/modules/aaa/mod_access.c b/modules/aaa/mod_access.c
index d51df93a40..41d6133879 100644
--- a/modules/aaa/mod_access.c
+++ b/modules/aaa/mod_access.c
@@ -91,7 +91,7 @@ enum allowdeny_type {
};
typedef struct {
- int limited;
+ apr_int64_t limited;
union {
char *from;
apr_ipsubnet_t *ip;
@@ -237,8 +237,9 @@ static int in_domain(const char *domain, const char *what)
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;
diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c
index cf74ccfce9..fffb619090 100644
--- a/modules/http/http_protocol.c
+++ b/modules/http/http_protocol.c
@@ -299,6 +299,64 @@ AP_DECLARE(int) ap_meets_conditions(request_rec *r)
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;
+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;
+}
+
+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);
+}
+
+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,6 +366,8 @@ AP_DECLARE(int) ap_meets_conditions(request_rec *r)
*/
AP_DECLARE(int) ap_method_number_of(const char *method)
{
+ int *methnum = NULL;
+
switch (*method) {
case 'H':
if (strcmp(method, "HEAD") == 0)
@@ -362,6 +422,16 @@ AP_DECLARE(int) ap_method_number_of(const char *method)
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 +974,7 @@ static void terminate_header(apr_bucket_brigade *bb)
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 +2143,8 @@ AP_DECLARE(void) ap_method_list_remove(ap_method_list_t *l,
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);
diff --git a/server/config.c b/server/config.c
index 7b7cf32f74..1896d61772 100644
--- a/server/config.c
+++ b/server/config.c
@@ -354,30 +354,18 @@ AP_CORE_DECLARE(int) ap_invoke_handler(request_rec *r)
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);
+ return (cmd->limited & (1<<methnum));
}
- /*
- * 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 0;
+
+ return 0; /* not found */
}
AP_DECLARE(void) ap_register_hooks(module *m, apr_pool_t *p)
diff --git a/server/core.c b/server/core.c
index e65316c4ea..093efce4fd 100644
--- a/server/core.c
+++ b/server/core.c
@@ -1466,7 +1466,7 @@ AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dumm
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;
const char *err = ap_check_cmd_context(cmd, NOT_IN_LIMIT);
@@ -1476,46 +1476,21 @@ AP_CORE_DECLARE_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dumm
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.
- */
- 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--;
- }
- }
- }
+ /* method has not been registered yet, but resorce restriction
+ * is always checked before method handling, so register it.
+ */
+ methnum = ap_method_register(cmd->pool, method);
}
- limited |= (1 << methnum);
+ limited |= (1 << methnum);
}
/* Killing two features with one function,
diff --git a/server/protocol.c b/server/protocol.c
index 2d1a69e191..210d9078e4 100644
--- a/server/protocol.c
+++ b/server/protocol.c
@@ -1135,14 +1135,31 @@ AP_DECLARE(int) ap_rwrite(const void *buf, int nbyte, request_rec *r)
AP_DECLARE(int) ap_vrprintf(request_rec *r, const char *fmt, va_list va)
{
- char buf[4096];
+ char *buf;
+ int buf_size = 4096; /* start with a 4k buffer */
apr_size_t written;
if (r->connection->aborted)
return -1;
- /* ### fix this mechanism to allow more than 4K of output */
- written = apr_vsnprintf(buf, sizeof(buf), fmt, va);
+ buf = apr_palloc(r->pool, buf_size);
+ while (1) {
+ written = apr_vsnprintf(buf, buf_size, fmt, va);
+
+ /*
+ * Per the apr_vsnprintf comments, in no event does apr_snprintf return a negative number.
+ * Therefore, it's not possible to distinguish between an output which was truncated,
+ * and an output which exactly filled the buffer.
+ */
+ if (written == buf_size) {
+ buf_size *= 2;
+ buf = apr_palloc(r->pool, buf_size); /* want realloc */
+ }
+ else {
+ break;
+ }
+ }
+
if (buffer_output(r, buf, written) != APR_SUCCESS)
return -1;