]> granicus.if.org Git - apache/commitdiff
Start introducing the extension-method elements so we're not
authorKen Coar <coar@apache.org>
Wed, 13 Sep 2000 01:58:15 +0000 (01:58 +0000)
committerKen Coar <coar@apache.org>
Wed, 13 Sep 2000 01:58:15 +0000 (01:58 +0000)
bound to hard-coded names and a bitmask.  We still use the
bitmask for known methods, but we also have an array for
extension method named.  Wherever we used the M_* constants
we need to use a routine that knows about the new structure instead.

This is far from complete, but AFAIK this interim work doesn't
break anything -- especially the compile.  The rest of the
work will be added in segments; this is just a checkpoint.

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

include/http_config.h
include/http_protocol.h
include/httpd.h
modules/http/http_core.c
modules/http/http_protocol.c
modules/http/http_request.c

index 8f6bb91e9a6351914874d2b64fe56e8a07161286..a7c0a3fb31698572b9ed4a9f4ca1d0d14de11990 100644 (file)
@@ -287,6 +287,7 @@ struct cmd_parms_struct {
     /** Which methods are <Limit>ed */
     int limited;
     apr_array_header_t *limited_xmethods;
+    ap_method_list_t *xlimited;
 
     /** Config file structure. */
     configfile_t *config_file;
index 08067a42c14b3cae5747c1b4ea801cf26d23cbcc..7a6921bd5b4436d534fa8d16436f0cc885dc64f9 100644 (file)
@@ -252,6 +252,69 @@ API_EXPORT(long) ap_send_fb_length(BUFF *f, request_rec *r, long length);
 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.
  */
index b9773360be0de494eb73f0350f3e2d6aafbfb231..f3f0492a2eb9a0ecb1347c2703b920079651f732 100644 (file)
@@ -484,6 +484,16 @@ API_EXPORT(const char *) ap_get_server_built(void);
 
 #define METHODS     16
 
+/*
+ * Structure for handling HTTP methods.  Methods known to the server are
+ * accessed via a bitmask shortcut; extension methods are handled by
+ * an array.
+ */
+typedef struct {
+    int method_mask;
+    apr_array_header_t *method_list;
+} ap_method_list_t;
+
 #define CGI_MAGIC_TYPE "application/x-httpd-cgi"
 #define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
 #define INCLUDES_MAGIC_TYPE3 "text/x-server-parsed-html3"
@@ -668,6 +678,7 @@ struct request_rec {
      */
     int allowed;               /* Allowed methods - for 405, OPTIONS, etc */
     apr_array_header_t *allowed_xmethods; /* Array of extension methods */
+    ap_method_list_t *allowed_methods; /* List of allowed methods */
 
     /** byte count in stream is for body */
     int sent_bodyct;
index e6efab16694f0069692883ec60f95dbb03ef212c..55aa71805c46693cf37522e70ebdcdf403f5a05a 100644 (file)
@@ -1497,9 +1497,7 @@ CORE_EXPORT_NONSTD(const char *) ap_limit_section(cmd_parms *cmd, void *dummy,
                }
            }
         }
-        else {
-            limited |= (1 << methnum);
-        }
+       limited |= (1 << methnum);
     }
 
     /* Killing two features with one function,
index e18e9e66602651f85b6b6f6e6d4e04f2a6767a3d..4ce47e612066aab729be39a6105d717b0446084c 100644 (file)
@@ -1181,6 +1181,8 @@ request_rec *ap_read_request(conn_rec *conn)
     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);
@@ -1645,40 +1647,210 @@ static void terminate_header(request_rec *r)
     (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);
        }
     }
index f6b0b1a5a790a2a1ee46f728d2765153296e9e01..fdc49b404fd60d5e0246f54a0be2a7d5716383d6 100644 (file)
@@ -864,6 +864,9 @@ API_EXPORT(request_rec *) ap_sub_req_lookup_file(const char *new_file,
     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;
 
@@ -1321,10 +1324,11 @@ static apr_table_t *rename_original_env(apr_pool_t *p, apr_table_t *t)
     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;
@@ -1338,6 +1342,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, request_rec
 
     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;
@@ -1365,6 +1370,7 @@ static request_rec *internal_internal_redirect(const char *new_uri, request_rec
     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;
@@ -1445,51 +1451,11 @@ API_EXPORT(void) ap_allow_methods(request_rec *r, int reset, ...) {
      * 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);
     }
 }