httpd-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Roy T. Fielding" <field...@kiwi.ics.uci.edu>
Subject [PATCH] Enable all WebDAV methods
Date Sat, 31 Oct 1998 09:50:14 GMT
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)

Mime
View raw message