Browse Source

Introduce naming scheme for request handlers
The do_ prefix and upper case name allows easy
distinction between methods that handle requests
and other methods.
Without this distinction an attacker could
call arbitrary methods.
Currently there is no method that matches the
argument count, but that's easy to miss when new
methods are added.

Unrud 10 years ago
parent
commit
592537e37c
1 changed files with 25 additions and 23 deletions
  1. 25 23
      radicale/__init__.py

+ 25 - 23
radicale/__init__.py

@@ -267,7 +267,7 @@ class Application(object):
         path = environ["PATH_INFO"]
         path = environ["PATH_INFO"]
 
 
         # Get function corresponding to method
         # Get function corresponding to method
-        function = getattr(self, environ["REQUEST_METHOD"].lower())
+        function = getattr(self, "do_%s" % environ["REQUEST_METHOD"].upper())
 
 
         # Ask authentication backend to check rights
         # Ask authentication backend to check rights
         authorization = environ.get("HTTP_AUTHORIZATION", None)
         authorization = environ.get("HTTP_AUTHORIZATION", None)
@@ -325,8 +325,8 @@ class Application(object):
 
 
         if is_valid_user and (
         if is_valid_user and (
                 (read_allowed_items or write_allowed_items) or
                 (read_allowed_items or write_allowed_items) or
-                (is_authenticated and function == self.propfind) or
-                function == self.options):
+                (is_authenticated and function == self.do_PROPFIND) or
+                function == self.do_OPTIONS):
             status, headers, answer = function(
             status, headers, answer = function(
                 environ, read_allowed_items, write_allowed_items, content,
                 environ, read_allowed_items, write_allowed_items, content,
                 user)
                 user)
@@ -365,8 +365,8 @@ class Application(object):
     # All these functions must have the same parameters, some are useless
     # All these functions must have the same parameters, some are useless
     # pylint: disable=W0612,W0613,R0201
     # pylint: disable=W0612,W0613,R0201
 
 
-    def delete(self, environ, read_collections, write_collections, content,
-               user):
+    def do_DELETE(self, environ, read_collections, write_collections, content,
+                  user):
         """Manage DELETE request."""
         """Manage DELETE request."""
         if not len(write_collections):
         if not len(write_collections):
             return NOT_ALLOWED
             return NOT_ALLOWED
@@ -392,7 +392,8 @@ class Application(object):
         # No item or ETag precondition not verified, do not delete item
         # No item or ETag precondition not verified, do not delete item
         return client.PRECONDITION_FAILED, {}, None
         return client.PRECONDITION_FAILED, {}, None
 
 
-    def get(self, environ, read_collections, write_collections, content, user):
+    def do_GET(self, environ, read_collections, write_collections, content,
+               user):
         """Manage GET request.
         """Manage GET request.
 
 
         In Radicale, GET requests create collections when the URL is not
         In Radicale, GET requests create collections when the URL is not
@@ -449,15 +450,15 @@ class Application(object):
         answer = answer_text.encode(self.encoding)
         answer = answer_text.encode(self.encoding)
         return client.OK, headers, answer
         return client.OK, headers, answer
 
 
-    def head(self, environ, read_collections, write_collections, content,
-             user):
+    def do_HEAD(self, environ, read_collections, write_collections, content,
+                user):
         """Manage HEAD request."""
         """Manage HEAD request."""
         status, headers, answer = self.get(
         status, headers, answer = self.get(
             environ, read_collections, write_collections, content, user)
             environ, read_collections, write_collections, content, user)
         return status, headers, None
         return status, headers, None
 
 
-    def mkcalendar(self, environ, read_collections, write_collections, content,
-                   user):
+    def do_MKCALENDAR(self, environ, read_collections, write_collections,
+                      content, user):
         """Manage MKCALENDAR request."""
         """Manage MKCALENDAR request."""
         if not len(write_collections):
         if not len(write_collections):
             return NOT_ALLOWED
             return NOT_ALLOWED
@@ -475,8 +476,8 @@ class Application(object):
             collection.write()
             collection.write()
         return client.CREATED, {}, None
         return client.CREATED, {}, None
 
 
-    def mkcol(self, environ, read_collections, write_collections, content,
-              user):
+    def do_MKCOL(self, environ, read_collections, write_collections, content,
+                 user):
         """Manage MKCOL request."""
         """Manage MKCOL request."""
         if not len(write_collections):
         if not len(write_collections):
             return NOT_ALLOWED
             return NOT_ALLOWED
@@ -490,8 +491,8 @@ class Application(object):
         collection.write()
         collection.write()
         return client.CREATED, {}, None
         return client.CREATED, {}, None
 
 
-    def move(self, environ, read_collections, write_collections, content,
-             user):
+    def do_MOVE(self, environ, read_collections, write_collections, content,
+                user):
         """Manage MOVE request."""
         """Manage MOVE request."""
         if not len(write_collections):
         if not len(write_collections):
             return NOT_ALLOWED
             return NOT_ALLOWED
@@ -526,8 +527,8 @@ class Application(object):
             # Moving collections, not supported
             # Moving collections, not supported
             return client.FORBIDDEN, {}, None
             return client.FORBIDDEN, {}, None
 
 
-    def options(self, environ, read_collections, write_collections, content,
-                user):
+    def do_OPTIONS(self, environ, read_collections, write_collections,
+                   content, user):
         """Manage OPTIONS request."""
         """Manage OPTIONS request."""
         headers = {
         headers = {
             "Allow": ("DELETE, HEAD, GET, MKCALENDAR, MKCOL, MOVE, "
             "Allow": ("DELETE, HEAD, GET, MKCALENDAR, MKCOL, MOVE, "
@@ -535,8 +536,8 @@ class Application(object):
             "DAV": "1, 2, 3, calendar-access, addressbook, extended-mkcol"}
             "DAV": "1, 2, 3, calendar-access, addressbook, extended-mkcol"}
         return client.OK, headers, None
         return client.OK, headers, None
 
 
-    def propfind(self, environ, read_collections, write_collections, content,
-                 user):
+    def do_PROPFIND(self, environ, read_collections, write_collections,
+                    content, user):
         """Manage PROPFIND request."""
         """Manage PROPFIND request."""
         # Rights is handled by collection in xmlutils.propfind
         # Rights is handled by collection in xmlutils.propfind
         headers = {
         headers = {
@@ -547,8 +548,8 @@ class Application(object):
             environ["PATH_INFO"], content, collections, user)
             environ["PATH_INFO"], content, collections, user)
         return client.MULTI_STATUS, headers, answer
         return client.MULTI_STATUS, headers, answer
 
 
-    def proppatch(self, environ, read_collections, write_collections, content,
-                  user):
+    def do_PROPPATCH(self, environ, read_collections, write_collections,
+                     content, user):
         """Manage PROPPATCH request."""
         """Manage PROPPATCH request."""
         if not len(write_collections):
         if not len(write_collections):
             return NOT_ALLOWED
             return NOT_ALLOWED
@@ -562,7 +563,8 @@ class Application(object):
             "Content-Type": "text/xml"}
             "Content-Type": "text/xml"}
         return client.MULTI_STATUS, headers, answer
         return client.MULTI_STATUS, headers, answer
 
 
-    def put(self, environ, read_collections, write_collections, content, user):
+    def do_PUT(self, environ, read_collections, write_collections, content,
+               user):
         """Manage PUT request."""
         """Manage PUT request."""
         if not len(write_collections):
         if not len(write_collections):
             return NOT_ALLOWED
             return NOT_ALLOWED
@@ -597,8 +599,8 @@ class Application(object):
             status = client.PRECONDITION_FAILED
             status = client.PRECONDITION_FAILED
         return status, headers, None
         return status, headers, None
 
 
-    def report(self, environ, read_collections, write_collections, content,
-               user):
+    def do_REPORT(self, environ, read_collections, write_collections, content,
+                  user):
         """Manage REPORT request."""
         """Manage REPORT request."""
         if not len(read_collections):
         if not len(read_collections):
             return NOT_ALLOWED
             return NOT_ALLOWED