API_EXPORT(size_t) ap_send_mmap(apr_mmap_t *mm, request_rec *r, size_t offset,
size_t length);
+/**
+ * Create a new method list with the specified number of preallocated
+ * slots for extension methods.
+ *
+ * @param p Pointer to a pool in which the structure should be
+ * allocated.
+ * @param nelts Number of preallocated extension slots
+ * @return Pointer to the newly created structure.
+ * @deffunc ap_method_list_t ap_make_method_list(apr_pool_t *p, int nelts)
+ */
+API_EXPORT(ap_method_list_t *) ap_make_method_list(apr_pool_t *p, int nelts);
+API_EXPORT(void) ap_copy_method_list(ap_method_list_t *dest,
+ ap_method_list_t *src);
+API_EXPORT(void) ap_method_list_do(int (*comp) (void *urec, const char *mname,
+ int mnum),
+ void *rec,
+ const ap_method_list_t *ml, ...);
+API_EXPORT(void) ap_method_list_vdo(int (*comp) (void *urec, const char *mname,
+ int mnum),
+ void *rec, const ap_method_list_t *ml,
+ va_list vp);
+/**
+ * Search for an HTTP method name in an ap_method_list_t structure, and
+ * return true if found.
+ *
+ * @param method String containing the name of the method to check.
+ * @param l Pointer to a method list, such as cmd->methods_limited.
+ * @return 1 if method is in the list, otherwise 0
+ * @deffunc int ap_method_in_list(const char *method, ap_method_list_t *l)
+ */
+API_EXPORT(int) ap_method_in_list(ap_method_list_t *l, const char *method);
+
+/**
+ * Add an HTTP method name to an ap_method_list_t structure if it isn't
+ * already listed.
+ *
+ * @param method String containing the name of the method to check.
+ * @param l Pointer to a method list, such as cmd->methods_limited.
+ * @return None.
+ * @deffunc void ap_method_in_list(ap_method_list_t *l, const char *method)
+ */
+API_EXPORT(void) ap_method_list_add(ap_method_list_t *l, const char *method);
+
+/**
+ * Remove an HTTP method name from an ap_method_list_t structure.
+ *
+ * @param l Pointer to a method list, such as cmd->methods_limited.
+ * @param method String containing the name of the method to remove.
+ * @return None.
+ * @deffunc void ap_method_list_remove(ap_method_list_t *l, const char *method)
+ */
+API_EXPORT(void) ap_method_list_remove(ap_method_list_t *l,
+ const char *method);
+
+/**
+ * Reset a method list to be completely empty.
+ *
+ * @param l Pointer to a method list, such as cmd->methods_limited.
+ * @return None.
+ * @deffunc void ap_clear_method_list(ap_method_list_t *l)
+ */
+API_EXPORT(void) ap_clear_method_list(ap_method_list_t *l);
+
/* Hmmm... could macrofy these for now, and maybe forever, though the
* definitions of the macros would get a whole lot hairier.
*/
r->user = NULL;
r->ap_auth_type = NULL;
+ r->allowed_methods = ap_make_method_list(p, 2);
+
r->headers_in = apr_make_table(r->pool, 50);
r->subprocess_env = apr_make_table(r->pool, 50);
r->headers_out = apr_make_table(r->pool, 12);
(void) checked_bputs(CRLF, r); /* Send the terminating empty line */
}
+/*
+ * Create a new method list with the specified number of preallocated
+ * extension slots.
+ */
+API_EXPORT(ap_method_list_t *) ap_make_method_list(apr_pool_t *p, int nelts)
+{
+ ap_method_list_t *ml;
+
+ ml = (ap_method_list_t *) apr_palloc(p, sizeof(ap_method_list_t));
+ ml->method_mask = 0;
+ ml->method_list = apr_make_array(p, sizeof(char *), nelts);
+ return ml;
+}
+
+/*
+ * Make a copy of a method list (primarily for subrequests that may
+ * subsequently change it; don't want them changing the parent's, too!).
+ */
+API_EXPORT(void) ap_copy_method_list(ap_method_list_t *dest,
+ ap_method_list_t *src)
+{
+ int i;
+ char **imethods;
+ char **omethods;
+
+ dest->method_mask = src->method_mask;
+ imethods = (char **) src->method_list->elts;
+ for (i = 0; i < src->method_list->nelts; ++i) {
+ omethods = (char **) apr_push_array(dest->method_list);
+ *omethods = apr_pstrdup(dest->method_list->cont, imethods[i]);
+ }
+}
+
+/*
+ * Invoke a callback routine for each method in the specified list.
+ */
+API_EXPORT(void) ap_method_list_do(int (*comp) (void *urec, const char *mname,
+ int mnum),
+ void *rec,
+ const ap_method_list_t *ml, ...)
+{
+ va_list vp;
+ va_start(vp, ml);
+ ap_method_list_vdo(comp, rec, ml, vp);
+ va_end(vp);
+}
+
+API_EXPORT(void) ap_method_list_vdo(int (*comp) (void *mrec,
+ const char *mname,
+ int mnum),
+ void *rec, const ap_method_list_t *ml,
+ va_list vp)
+{
+
+}
+
+/*
+ * Return true if the specified HTTP method is in the provided
+ * method list.
+ */
+API_EXPORT(int) ap_method_in_list(ap_method_list_t *l, const char *method)
+{
+ int methnum;
+ int i;
+ char **methods;
+
+ /*
+ * If it's one of our known methods, use the shortcut and check the
+ * bitmask.
+ */
+ methnum = ap_method_number_of(method);
+ if (methnum != M_INVALID) {
+ return (l->method_mask & (1 << methnum));
+ }
+ /*
+ * Otherwise, see if the method name is in the array or string names
+ */
+ if ((l->method_list = NULL) || (l->method_list->nelts == 0)) {
+ return 0;
+ }
+ for (i = 0; i < l->method_list->nelts; ++i) {
+ if (strcmp(method, methods[i]) == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Add the specified method to a method list (if it isn't already there).
+ */
+API_EXPORT(void) ap_method_list_add(ap_method_list_t *l, const char *method)
+{
+ int methnum;
+ int i;
+ const char **xmethod;
+ char **methods;
+
+ /*
+ * If it's one of our known methods, use the shortcut and use the
+ * bitmask.
+ */
+ methnum = ap_method_number_of(method);
+ l->method_mask |= (1 << methnum);
+ if (methnum != M_INVALID) {
+ return;
+ }
+ /*
+ * Otherwise, see if the method name is in the array of string names.
+ */
+ if (l->method_list->nelts != 0) {
+ for (i = 0; i < l->method_list->nelts; ++i) {
+ if (strcmp(method, methods[i]) == 0) {
+ return;
+ }
+ }
+ }
+ xmethod = (const char **) apr_push_array(l->method_list);
+ *xmethod = method;
+}
+
+/*
+ * Remove the specified method from a method list.
+ */
+API_EXPORT(void) ap_method_list_remove(ap_method_list_t *l,
+ const char *method)
+{
+ int methnum;
+ const char **xmethod;
+ char **methods;
+
+ /*
+ * If it's one of our known methods, use the shortcut and use the
+ * bitmask.
+ */
+ methnum = ap_method_number_of(method);
+ l->method_mask |= ~(1 << methnum);
+ if (methnum != M_INVALID) {
+ return;
+ }
+ /*
+ * Otherwise, see if the method name is in the array of string names.
+ */
+ if (l->method_list->nelts != 0) {
+ register int i, j, k;
+ for (i = 0; i < l->method_list->nelts; ) {
+ if (strcmp(method, methods[i]) == 0) {
+ for (j = i, k = i + 1; k < l->method_list->nelts; ++j, ++k) {
+ methods[j] = methods[k];
+ }
+ --l->method_list->nelts;
+ }
+ else {
+ ++i;
+ }
+ }
+ }
+}
+
+/*
+ * Reset a method list to be completely empty.
+ */
+API_EXPORT(void) ap_clear_method_list(ap_method_list_t *l)
+{
+ l->method_mask = 0;
+ l->method_list->nelts = 0;
+}
+
/* Build the Allow field-value from the request handler method mask.
* Note that we always allow TRACE, since it is handled below.
*/
static char *make_allow(request_rec *r)
{
char *list;
+ int mask;
+ mask = r->allowed_methods->method_mask;
list = apr_pstrcat(r->pool,
- (r->allowed & (1 << M_GET)) ? ", GET, HEAD" : "",
- (r->allowed & (1 << M_POST)) ? ", POST" : "",
- (r->allowed & (1 << M_PUT)) ? ", PUT" : "",
- (r->allowed & (1 << M_DELETE)) ? ", DELETE" : "",
- (r->allowed & (1 << M_CONNECT)) ? ", CONNECT" : "",
- (r->allowed & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
- (r->allowed & (1 << M_PATCH)) ? ", PATCH" : "",
- (r->allowed & (1 << M_PROPFIND)) ? ", PROPFIND" : "",
- (r->allowed & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "",
- (r->allowed & (1 << M_MKCOL)) ? ", MKCOL" : "",
- (r->allowed & (1 << M_COPY)) ? ", COPY" : "",
- (r->allowed & (1 << M_MOVE)) ? ", MOVE" : "",
- (r->allowed & (1 << M_LOCK)) ? ", LOCK" : "",
- (r->allowed & (1 << M_UNLOCK)) ? ", UNLOCK" : "",
+ (mask & (1 << M_GET)) ? ", GET, HEAD" : "",
+ (mask & (1 << M_POST)) ? ", POST" : "",
+ (mask & (1 << M_PUT)) ? ", PUT" : "",
+ (mask & (1 << M_DELETE)) ? ", DELETE" : "",
+ (mask & (1 << M_CONNECT)) ? ", CONNECT" : "",
+ (mask & (1 << M_OPTIONS)) ? ", OPTIONS" : "",
+ (mask & (1 << M_PATCH)) ? ", PATCH" : "",
+ (mask & (1 << M_PROPFIND)) ? ", PROPFIND" : "",
+ (mask & (1 << M_PROPPATCH)) ? ", PROPPATCH" : "",
+ (mask & (1 << M_MKCOL)) ? ", MKCOL" : "",
+ (mask & (1 << M_COPY)) ? ", COPY" : "",
+ (mask & (1 << M_MOVE)) ? ", MOVE" : "",
+ (mask & (1 << M_LOCK)) ? ", LOCK" : "",
+ (mask & (1 << M_UNLOCK)) ? ", UNLOCK" : "",
", TRACE",
NULL);
- if ((r->allowed & (1 << M_INVALID))
- && (r->allowed_xmethods != NULL)
- && (r->allowed_xmethods->nelts != 0)) {
+ if ((mask & (1 << M_INVALID))
+ && (r->allowed_methods->method_list != NULL)
+ && (r->allowed_methods->method_list->nelts != 0)) {
int i;
- char **xmethod = (char **) r->allowed_xmethods->elts;
+ char **xmethod = (char **) r->allowed_methods->method_list->elts;
/*
- * Append all of the elements of r->allowed_xmethods
+ * Append all of the elements of r->allowed_methods->method_list
*/
- for (i = 0; i < r->allowed_xmethods->nelts; ++i) {
+ for (i = 0; i < r->allowed_methods->method_list->nelts; ++i) {
list = apr_pstrcat(r->pool, list, ", ", xmethod[i], NULL);
}
}
rnew->htaccess = r->htaccess;
rnew->chunked = r->chunked;
+ /* make a copy of the allowed-methods list */
+ ap_copy_method_list(rnew->allowed_methods, r->allowed_methods);
+
/* start with the same set of output filters */
rnew->filters = r->filters;
return new;
}
-static request_rec *internal_internal_redirect(const char *new_uri, request_rec *r)
-{
+static request_rec *internal_internal_redirect(const char *new_uri,
+ request_rec *r) {
int access_status;
- request_rec *new = (request_rec *) apr_pcalloc(r->pool, sizeof(request_rec));
+ request_rec *new = (request_rec *) apr_pcalloc(r->pool,
+ sizeof(request_rec));
new->connection = r->connection;
new->server = r->server;
new->method = r->method;
new->method_number = r->method_number;
+ new->allowed_methods = ap_make_method_list(new->pool, 2);
ap_parse_uri(new, new_uri);
new->request_config = ap_create_request_config(r->pool);
new->per_dir_config = r->server->lookup_defaults;
new->err_headers_out = r->err_headers_out;
new->subprocess_env = rename_original_env(r->pool, r->subprocess_env);
new->notes = apr_make_table(r->pool, 5);
+ new->allowed_methods = ap_make_method_list(new->pool, 2);
new->htaccess = r->htaccess;
new->no_cache = r->no_cache;
* well-known methods but any extensions as well.
*/
if (reset) {
- r->allowed = 0;
- if (r->allowed_xmethods != NULL) {
- r->allowed_xmethods->nelts = 0;
- }
+ ap_clear_method_list(r->allowed_methods);
}
va_start(methods, reset);
while ((method = va_arg(methods, const char *)) != NULL) {
- /*
- * Look up our internal number for this particular method.
- * Even if it isn't one of the ones we know about, the return
- * value is used in the same way.
- */
- mnum = ap_method_number_of(method);
- r->allowed |= (1 << mnum);
- /*
- * Now, if we don't know about it, we regard it as an
- * extension method. Add it to our array of such. This means
- * that anything that checks for M_INVALID needs to make an
- * additional check of this array if it *is* invalid.
- */
- if (mnum == M_INVALID) {
- int i;
- int found;
- char **xmethods;
-
- if (r->allowed_xmethods == NULL) {
- r->allowed_xmethods = apr_make_array(r->pool, 2,
- sizeof(char *));
- }
- /*
- * Don't add it to the array if it's already listed.
- */
- xmethods = (char **) r->allowed_xmethods->elts;
- found = 0;
- for (i = 0; i < r->allowed_xmethods->nelts; ++i) {
- if (strcmp(method, xmethods[i]) == 0) {
- found++;
- break;
- }
- }
- if (!found) {
- xmethod = (const char **) apr_push_array(r->allowed_xmethods);
- *xmethod = method;
- }
- }
+ ap_method_list_add(r->allowed_methods, method);
}
}