You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Roy T. Fielding" <fi...@kiwi.ics.uci.edu> on 1998/10/31 10:50:14 UTC

[PATCH] Enable all WebDAV methods

This needs to be tested before being committed.  I need someone else
to do it since I am leaving in the morning for a conference trip in
Orlando and won't have net access again til Thursday night.

   *) Enabled all of the WebDAV method names for use by third-party
      modules, Limit, and Script directives.  That includes PATCH,
      PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, and UNLOCK.
      Improved mod_actions.c so that it can use any of the methods
      defined in httpd.h.  Added ap_method_number_of(method) for
      getting the internal method number.  [Roy Fielding]

It also requires an MMN bump.  I could abstract it more by making the
methods a configurable array of pointers to static method name strings
and then replacing the functions in http_protocol.c with simple loops
through the array (the performance difference is negligible provided
that the array is ordered by method use frequency).  But that can wait.

....Roy

Index: include/http_protocol.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/http_protocol.h,v
retrieving revision 1.45
diff -u -r1.45 http_protocol.h
--- http_protocol.h	1998/08/09 14:33:10	1.45
+++ http_protocol.h	1998/10/31 09:35:05
@@ -209,6 +209,11 @@
 
 CORE_EXPORT(void) ap_parse_uri(request_rec *r, const char *uri);
 
+/* Get the method number associated with the given string, assumed to
+ * contain an HTTP method.  Returns M_INVALID if not recognized.
+ */
+API_EXPORT(int) ap_method_number_of(const char *method);
+
 #ifdef __cplusplus
 }
 #endif
Index: include/httpd.h
===================================================================
RCS file: /home/cvs/apache-1.3/src/include/httpd.h,v
retrieving revision 1.249
diff -u -r1.249 httpd.h
--- httpd.h	1998/10/28 19:26:28	1.249
+++ httpd.h	1998/10/31 09:35:05
@@ -531,16 +531,27 @@
                                     ((x) == HTTP_SERVICE_UNAVAILABLE) || \
 				    ((x) == HTTP_NOT_IMPLEMENTED))
 
-
-#define METHODS 8
-#define M_GET 0
-#define M_PUT 1
-#define M_POST 2
-#define M_DELETE 3
-#define M_CONNECT 4
-#define M_OPTIONS 5
-#define M_TRACE 6
-#define M_INVALID 7
+/* 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.
+ */
+#define M_GET        0
+#define M_PUT        1
+#define M_POST       2
+#define M_DELETE     3
+#define M_CONNECT    4
+#define M_OPTIONS    5
+#define M_TRACE      6
+#define M_INVALID    7
+#define M_PATCH      8
+#define M_PROPFIND   9
+#define M_PROPPATCH 10
+#define M_MKCOL     11
+#define M_COPY      12
+#define M_MOVE      13
+#define M_LOCK      14
+#define M_UNLOCK    15
+#define METHODS     16
 
 #define CGI_MAGIC_TYPE "application/x-httpd-cgi"
 #define INCLUDES_MAGIC_TYPE "text/x-server-parsed-html"
Index: main/http_core.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_core.c,v
retrieving revision 1.238
diff -u -r1.238 http_core.c
--- http_core.c	1998/10/30 03:08:55	1.238
+++ http_core.c	1998/10/31 09:35:06
@@ -1068,28 +1068,18 @@
     
     while (limited_methods[0]) {
         char *method = ap_getword_conf(cmd->pool, &limited_methods);
-	if (!strcmp(method, "GET")) {
-	    limited |= (1 << M_GET);
-	}
-	else if (!strcmp(method, "PUT")) {
-	    limited |= (1 << M_PUT);
-	}
-	else if (!strcmp(method, "POST")) {
-	    limited |= (1 << M_POST);
-	}
-	else if (!strcmp(method, "DELETE")) {
-	    limited |= (1 << M_DELETE);
-	}
-        else if (!strcmp(method, "CONNECT")) {
-	    limited |= (1 << M_CONNECT);
-	}
-	else if (!strcmp(method, "OPTIONS")) {
-	    limited |= (1 << M_OPTIONS);
-	}
-	else {
-	    return ap_pstrcat(cmd->pool, "unknown method \"",
-			      method, "\" in <Limit>", NULL);
-	}
+        int  methnum = ap_method_number_of(method);
+
+        if (methnum == M_TRACE) {
+            return "TRACE cannot be controlled by <Limit>";
+        }
+        else if (methnum == M_INVALID) {
+            return ap_pstrcat(cmd->pool, "unknown method \"",
+                              method, "\" in <Limit>", NULL);
+        }
+        else {
+            limited |= (1 << methnum);
+        }
     }
 
     cmd->limited = limited;
Index: main/http_protocol.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/main/http_protocol.c,v
retrieving revision 1.247
diff -u -r1.247 http_protocol.c
--- http_protocol.c	1998/10/30 22:41:24	1.247
+++ http_protocol.c	1998/10/31 09:35:06
@@ -517,6 +517,72 @@
               ap_gm_timestr_822(r->pool, mod_time));
 }
 
+/* Get the method number associated with the given string, assumed to
+ * contain an HTTP method.  Returns M_INVALID if not recognized.
+ *
+ * This is the first step toward placing method names in a configurable
+ * list.  Hopefully it (and other routines) can eventually be moved to
+ * something like a mod_http_methods.c, complete with config stuff.
+ */
+API_EXPORT(int) ap_method_number_of(const char *method)
+{
+    switch (*method) {
+        case 'H':
+           if (strcmp(method, "HEAD") == 0)
+               return M_GET;   /* see header_only in request_rec */
+           break;
+        case 'G':
+           if (strcmp(method, "GET") == 0)
+               return M_GET;
+           break;
+        case 'P':
+           if (strcmp(method, "POST") == 0)
+               return M_POST;
+           if (strcmp(method, "PUT") == 0)
+               return M_PUT;
+           if (strcmp(method, "PATCH") == 0)
+               return M_PATCH;
+           if (strcmp(method, "PROPFIND") == 0)
+               return M_PROPFIND;
+           if (strcmp(method, "PROPPATCH") == 0)
+               return M_PROPPATCH;
+           break;
+        case 'D':
+           if (strcmp(method, "DELETE") == 0)
+               return M_DELETE;
+           break;
+        case 'C':
+           if (strcmp(method, "CONNECT") == 0)
+               return M_CONNECT;
+           if (strcmp(method, "COPY") == 0)
+               return M_COPY;
+           break;
+        case 'M':
+           if (strcmp(method, "MKCOL") == 0)
+               return M_MKCOL;
+           if (strcmp(method, "MOVE") == 0)
+               return M_MOVE;
+           break;
+        case 'O':
+           if (strcmp(method, "OPTIONS") == 0)
+               return M_OPTIONS;
+           break;
+        case 'T':
+           if (strcmp(method, "TRACE") == 0)
+               return M_TRACE;
+           break;
+        case 'L':
+           if (strcmp(method, "LOCK") == 0)
+               return M_LOCK;
+           break;
+        case 'U':
+           if (strcmp(method, "UNLOCK") == 0)
+               return M_UNLOCK;
+           break;
+    }
+    return M_INVALID;
+}
+
 /* Get a line of protocol input, including any continuation lines
  * caused by MIME folding (or broken clients) if fold != 0, and place it
  * in the buffer s, of size n bytes, without the ending newline.
@@ -678,26 +744,11 @@
     uri = ap_getword_white(r->pool, &ll);
 
     /* Provide quick information about the request method as soon as known */
-    if (!strcmp(r->method, "HEAD")) {
+
+    r->method_number = ap_method_number_of(r->method);
+    if (r->method_number == M_GET && r->method[0] == 'H') {
         r->header_only = 1;
-        r->method_number = M_GET;
     }
-    else if (!strcmp(r->method, "GET"))
-        r->method_number = M_GET;
-    else if (!strcmp(r->method, "POST"))
-        r->method_number = M_POST;
-    else if (!strcmp(r->method, "PUT"))
-        r->method_number = M_PUT;
-    else if (!strcmp(r->method, "DELETE"))
-        r->method_number = M_DELETE;
-    else if (!strcmp(r->method, "CONNECT"))
-        r->method_number = M_CONNECT;
-    else if (!strcmp(r->method, "OPTIONS"))
-        r->method_number = M_OPTIONS;
-    else if (!strcmp(r->method, "TRACE"))
-        r->method_number = M_TRACE;
-    else
-        r->method_number = M_INVALID;   /* Will eventually croak. */
 
     ap_parse_uri(r, uri);
 
@@ -1237,13 +1288,22 @@
 static char *make_allow(request_rec *r)
 {
     return 2 + ap_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_OPTIONS)) ? ", OPTIONS" : "",
-                       ", TRACE",
-                       NULL);
+                   (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"    : "",
+                   ", TRACE",
+                   NULL);
 }
 
 API_EXPORT(int) ap_send_http_trace(request_rec *r)
Index: modules/standard/mod_actions.c
===================================================================
RCS file: /home/cvs/apache-1.3/src/modules/standard/mod_actions.c,v
retrieving revision 1.28
diff -u -r1.28 mod_actions.c
--- mod_actions.c	1998/08/06 17:30:53	1.28
+++ mod_actions.c	1998/10/31 09:35:07
@@ -56,7 +56,7 @@
  */
 
 /*
- * mod_actions.c: executes scripts based on MIME type
+ * mod_actions.c: executes scripts based on MIME type or HTTP method
  *
  * by Alexei Kosut; based on mod_cgi.c, mod_mime.c and mod_includes.c,
  * adapted by rst from original NCSA code by Rob McCool
@@ -69,6 +69,12 @@
  * requested. It sends the URL and file path of the requested document using 
  * the standard CGI PATH_INFO and PATH_TRANSLATED environment variables.
  *
+ * Script PUT /cgi-bin/script
+ *
+ * will activate /cgi-bin/script when a request is received with the
+ * HTTP method "PUT".  The available method names are defined in httpd.h.
+ * If the method is GET, the script will only be activated if the requested
+ * URI includes query information (stuff after a ?-mark).
  */
 
 #include "httpd.h"
@@ -81,11 +87,8 @@
 #include "util_script.h"
 
 typedef struct {
-    table *action_types;	/* Added with Action... */
-    char *get;			/* Added with Script GET */
-    char *post;			/* Added with Script POST */
-    char *put;			/* Added with Script PUT */
-    char *delete;		/* Added with Script DELETE */
+    table *action_types;       /* Added with Action... */
+    char *scripted[METHODS];   /* Added with Script... */
 } action_dir_config;
 
 module action_module;
@@ -96,10 +99,7 @@
     (action_dir_config *) ap_palloc(p, sizeof(action_dir_config));
 
     new->action_types = ap_make_table(p, 4);
-    new->get = NULL;
-    new->post = NULL;
-    new->put = NULL;
-    new->delete = NULL;
+    memset(new->scripted, 0, sizeof(new->scripted));
 
     return new;
 }
@@ -108,17 +108,17 @@
 {
     action_dir_config *base = (action_dir_config *) basev;
     action_dir_config *add = (action_dir_config *) addv;
-    action_dir_config *new =
-    (action_dir_config *) ap_palloc(p, sizeof(action_dir_config));
+    action_dir_config *new = (action_dir_config *) ap_palloc(p,
+                                  sizeof(action_dir_config));
+    int i;
 
     new->action_types = ap_overlay_tables(p, add->action_types,
 				       base->action_types);
 
-    new->get = add->get ? add->get : base->get;
-    new->post = add->post ? add->post : base->post;
-    new->put = add->put ? add->put : base->put;
-    new->delete = add->delete ? add->delete : base->delete;
-
+    for (i = 0; i < METHODS; ++i) {
+        new->scripted[i] = add->scripted[i] ? add->scripted[i]
+                                            : base->scripted[i];
+    }
     return new;
 }
 
@@ -129,19 +129,18 @@
     return NULL;
 }
 
-static const char *set_script(cmd_parms *cmd, action_dir_config * m, char *method,
-			      char *script)
+static const char *set_script(cmd_parms *cmd, action_dir_config * m,
+                              char *method, char *script)
 {
-    if (!strcmp(method, "GET"))
-	m->get = script;
-    else if (!strcmp(method, "POST"))
-	m->post = script;
-    else if (!strcmp(method, "PUT"))
-	m->put = script;
-    else if (!strcmp(method, "DELETE"))
-	m->delete = script;
+    int methnum;
+
+    methnum = ap_method_number_of(method);
+    if (methnum == M_TRACE)
+        return "TRACE not allowed for Script";
+    else if (methnum == M_INVALID)
+        return "Unknown method type for Script";
     else
-	return "Unknown method type for Script";
+        m->scripted[methnum] = script;
 
     return NULL;
 }
@@ -157,30 +156,28 @@
 
 static int action_handler(request_rec *r)
 {
-    action_dir_config *conf =
-    (action_dir_config *) ap_get_module_config(r->per_dir_config, &action_module);
+    action_dir_config *conf = (action_dir_config *)
+        ap_get_module_config(r->per_dir_config, &action_module);
     const char *t, *action = r->handler ? r->handler : r->content_type;
-    const char *script = NULL;
+    const char *script;
+    int i;
 
     /* Set allowed stuff */
-    if (conf->get)
-	r->allowed |= (1 << M_GET);
-    if (conf->post)
-	r->allowed |= (1 << M_POST);
-    if (conf->put)
-	r->allowed |= (1 << M_PUT);
-    if (conf->delete)
-	r->allowed |= (1 << M_DELETE);
+    for (i = 0; i < METHODS; ++i) {
+        if (conf->scripted[i])
+            r->allowed |= (1 << i);
+    }
 
     /* First, check for the method-handling scripts */
-    if ((r->method_number == M_GET) && r->args && conf->get)
-	script = conf->get;
-    else if ((r->method_number == M_POST) && conf->post)
-	script = conf->post;
-    else if ((r->method_number == M_PUT) && conf->put)
-	script = conf->put;
-    else if ((r->method_number == M_DELETE) && conf->delete)
-	script = conf->delete;
+    if (r->method_number == M_GET) {
+        if (r->args)
+            script = conf->scripted[M_GET];
+        else
+            script = NULL;
+    }
+    else {
+        script = conf->scripted[r->method_number];
+    }
 
     /* Check for looping, which can happen if the CGI script isn't */
     if (script && r->prev && r->prev->prev)

Re: [PATCH] Enable all WebDAV methods

Posted by Ben Laurie <be...@algroup.co.uk>.
Roy T. Fielding wrote:
> 
> This needs to be tested before being committed.  I need someone else
> to do it since I am leaving in the morning for a conference trip in
> Orlando and won't have net access again til Thursday night.
> 
>    *) Enabled all of the WebDAV method names for use by third-party
>       modules, Limit, and Script directives.  That includes PATCH,
>       PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, and UNLOCK.
>       Improved mod_actions.c so that it can use any of the methods
>       defined in httpd.h.  Added ap_method_number_of(method) for
>       getting the internal method number.  [Roy Fielding]
> 
> It also requires an MMN bump.  I could abstract it more by making the
> methods a configurable array of pointers to static method name strings
> and then replacing the functions in http_protocol.c with simple loops
> through the array (the performance difference is negligible provided
> that the array is ordered by method use frequency).  But that can wait.

Looks OK to me, but another 16 methods and we run out of bits... OK, so
we've got some breathing space, but I suppose this is something we
should look at more carefully for 2.0 (or should we rename that Apache
2000? :-).

Not tested.

Cheers,

Ben.

-- 
Ben Laurie            |Phone: +44 (181) 735 0686| Apache Group member
Freelance Consultant  |Fax:   +44 (181) 735 0689|http://www.apache.org/
and Technical Director|Email: ben@algroup.co.uk |
A.L. Digital Ltd,     |Apache-SSL author     http://www.apache-ssl.org/
London, England.      |"Apache: TDG" http://www.ora.com/catalog/apache/