Explorar el Código

Check ETag before modifying or adding items.

Guillaume Ayoub hace 16 años
padre
commit
f479b4ba67
Se han modificado 3 ficheros con 33 adiciones y 19 borrados
  1. 23 15
      radicale/__init__.py
  2. 6 0
      radicale/ical.py
  3. 4 4
      radicale/xmlutils.py

+ 23 - 15
radicale/__init__.py

@@ -153,14 +153,18 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
     @check_rights
     def do_DELETE(self):
         """Manage DELETE request."""
-        # TODO: Check etag before deleting
-        etag = self.headers.get("If-Match", None)
-        answer = xmlutils.delete(self.path, self._calendar)
-
-        self.send_response(client.NO_CONTENT)
-        self.send_header("Content-Length", len(answer))
-        self.end_headers()
-        self.wfile.write(answer)
+        item = self._calendar.get_item(xmlutils.name_from_path(self.path))
+        if item and self.headers.get("If-Match", item.etag) == item.etag:
+            # No ETag precondition or precondition verified, delete item
+            answer = xmlutils.delete(self.path, self._calendar)
+
+            self.send_response(client.NO_CONTENT)
+            self.send_header("Content-Length", len(answer))
+            self.end_headers()
+            self.wfile.write(answer)
+        else:
+            # No item or ETag precondition not verified, do not delete item
+            self.send_response(client.PRECONDITION_FAILED)
 
     def do_OPTIONS(self):
         """Manage OPTIONS request."""
@@ -183,13 +187,17 @@ class CalendarHTTPHandler(server.BaseHTTPRequestHandler):
     @check_rights
     def do_PUT(self):
         """Manage PUT request."""
-        # TODO: Check etag before putting
-        etag = self.headers.get("If-Match", None)
-        ical_request = self._decode(
-            self.rfile.read(int(self.headers["Content-Length"])))
-        xmlutils.put(self.path, ical_request, self._calendar)
-
-        self.send_response(client.CREATED)
+        item = self._calendar.get_item(xmlutils.name_from_path(self.path))
+        if not item or self.headers.get("If-Match", item.etag) == item.etag:
+            # No item, no ETag precondition or precondition verified, put item
+            ical_request = self._decode(
+                self.rfile.read(int(self.headers["Content-Length"])))
+            xmlutils.put(self.path, ical_request, self._calendar)
+
+            self.send_response(client.CREATED)
+        else:
+            # ETag precondition not verified, do not put item
+            self.send_response(client.PRECONDITION_FAILED)
 
     @check_rights
     def do_REPORT(self):

+ 6 - 0
radicale/ical.py

@@ -174,6 +174,12 @@ class Calendar(object):
 
         return items
 
+    def get_item(self, name):
+        """Get calendar item called ``name``."""
+        for item in self.items:
+            if item.name == name:
+                return item
+
     def append(self, name, text):
         """Append items from ``text`` to calendar.
 

+ 4 - 4
radicale/xmlutils.py

@@ -50,7 +50,7 @@ def _response(code):
     return "HTTP/1.1 %i %s" % (code, client.responses[code])
 
 
-def _name_from_path(path):
+def name_from_path(path):
     """Return Radicale item name from ``path``."""
     return path.split("/")[-1]
 
@@ -62,7 +62,7 @@ def delete(path, calendar):
 
     """
     # Reading request
-    calendar.remove(_name_from_path(path))
+    calendar.remove(name_from_path(path))
 
     # Writing answer
     multistatus = ET.Element(_tag("D", "multistatus"))
@@ -142,7 +142,7 @@ def propfind(path, xml_request, calendar):
 
 def put(path, ical_request, calendar):
     """Read PUT requests."""
-    name = _name_from_path(path)
+    name = name_from_path(path)
     if name in (item.name for item in calendar.items):
         # PUT is modifying an existing item
         calendar.replace(name, ical_request)
@@ -176,7 +176,7 @@ def report(path, xml_request, calendar):
 
     for hreference in hreferences:
         # Check if the reference is an item or a calendar
-        name = hreference.split("/")[-1]
+        name = name_from_path(hreference)
         if name:
             # Reference is an item
             path = "/".join(hreference.split("/")[:-1]) + "/"