diff options
author | Ryan Bloom <rbb@apache.org> | 2001-08-02 04:25:20 +0000 |
---|---|---|
committer | Ryan Bloom <rbb@apache.org> | 2001-08-02 04:25:20 +0000 |
commit | 85e8fbd0e21fec6cb8c6cb0af6cdb8c592bbec67 (patch) | |
tree | 1c5c5f4c5b2d63f794243cdc2732fce82ccf12c4 | |
parent | c0dbe658163fac90c3ee93efeca9886b18c83910 (diff) | |
download | httpd-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-- | CHANGES | 7 | ||||
-rw-r--r-- | include/http_config.h | 2 | ||||
-rw-r--r-- | include/http_core.h | 2 | ||||
-rw-r--r-- | include/http_protocol.h | 34 | ||||
-rw-r--r-- | include/httpd.h | 11 | ||||
-rw-r--r-- | modules/aaa/mod_access.c | 5 | ||||
-rw-r--r-- | modules/http/http_protocol.c | 76 | ||||
-rw-r--r-- | server/config.c | 24 | ||||
-rw-r--r-- | server/core.c | 45 | ||||
-rw-r--r-- | server/protocol.c | 23 |
10 files changed, 162 insertions, 67 deletions
@@ -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; |