[CalendarServer-changes] [3570] CalendarServer/trunk/calendarserver/tools/doublequotefix.py

source_changes at macosforge.org source_changes at macosforge.org
Mon Jan 5 10:57:19 PST 2009


Revision: 3570
          http://trac.macosforge.org/projects/calendarserver/changeset/3570
Author:   cdaboo at apple.com
Date:     2009-01-05 10:57:18 -0800 (Mon, 05 Jan 2009)
Log Message:
-----------
Fix invalid double-quote escaping in .ics files for REPORTs failing with a 500 error.

Added Paths:
-----------
    CalendarServer/trunk/calendarserver/tools/doublequotefix.py

Added: CalendarServer/trunk/calendarserver/tools/doublequotefix.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/doublequotefix.py	                        (rev 0)
+++ CalendarServer/trunk/calendarserver/tools/doublequotefix.py	2009-01-05 18:57:18 UTC (rev 3570)
@@ -0,0 +1,206 @@
+#!/usr/bin/env python
+#
+##
+# Copyright (c) 2008 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+import datetime
+import getopt
+import hashlib
+import os
+import sys
+import xattr
+
+ICALSERVER_DOCROOT = "/Library/CalendarServer/Documents"
+DEFAULT_URIS = "uris.txt"
+
+totalProblems = 0
+totalErrors = 0
+totalScanned = 0
+
+def usage(e=None):
+    if e:
+        print e
+        print ""
+
+    name = os.path.basename(sys.argv[0])
+    print "usage: %s [options]" % (name,)
+    print ""
+    print "Fix double-quote/escape bugs in iCalendar data."
+    print ""
+    print "options:"
+    print "  -h --help: print this help and exit"
+    print "  -p <path>: path to calendar server document root [icalserver default]"
+    print "  -u <path>: path to file containing uris to process [uris.txt]"
+    print "  --fix: Apply fixes, otherwise only check for problems"
+    print ""
+    print "uris: list of uris to process"
+
+    if e:
+        sys.exit(64)
+    else:
+        sys.exit(0)
+
+def updateEtag(path, caldata):
+
+    x = xattr.xattr(path)
+    x["WebDAV:{http:%2F%2Ftwistedmatrix.com%2Fxml_namespace%2Fdav%2F}getcontentmd5"] = """<?xml version='1.0' encoding='UTF-8'?>
+<getcontentmd5 xmlns='http://twistedmatrix.com/xml_namespace/dav/'>%s</getcontentmd5>
+""" % (hashlib.md5(caldata).hexdigest(),)
+
+def updateCtag(path):
+
+    x = xattr.xattr(path)
+    x["WebDAV:{http:%2F%2Fcalendarserver.org%2Fns%2F}getctag"] = """<?xml version='1.0' encoding='UTF-8'?>
+<getctag xmlns='http://calendarserver.org/ns/'>%s</getctag>
+""" % (str(datetime.datetime.now()),)
+
+def scanURI(uri, basePath, doFix):
+    
+    global totalProblems
+    global totalErrors
+    global totalScanned
+
+    # Verify we have a valid path
+    pathBits = uri.strip("/").rstrip("/").split("/")
+    if len(pathBits) != 4 or pathBits[0] != "calendars" or pathBits[1] != "__uids__":
+        print "Invalid uri (ignoring): %s" % (uri,)
+        totalErrors += 1
+        return
+
+    # Absolute hashed directory path to calendar collection
+    calendarPath = os.path.join(
+        basePath,
+        pathBits[0],
+        pathBits[1],
+        pathBits[2][0:2],
+        pathBits[2][2:4],
+        pathBits[2],
+        pathBits[3],
+    )
+    
+    if not os.path.exists(calendarPath):
+        print "Calendar path does not exist: %s" % (calendarPath,)
+        totalErrors += 1
+        return
+
+    # Look at each .ics in the calendar collection
+    didFix = False
+    basePathLength = len(basePath)
+    for item in os.listdir(calendarPath):
+        if not item.endswith(".ics"):
+            continue
+        totalScanned += 1
+        icsPath = os.path.join(calendarPath, item)
+        
+        try:
+            f = open(icsPath)
+            icsData = f.read()
+        except Exception, e:
+            print "Failed to read file %s due to %s" % (icsPath, str(e),)
+            totalErrors += 1
+            continue
+        finally:
+            f.close()
+
+        # See whether there is a \" that needs fixing.
+        # NB Have to handle the case of a folded line... 
+        if icsData.find('\\"') != -1 or icsData.find('\\\r\n "') != -1:
+            if doFix:
+                # Fix by continuously replacing \" with " until no more replacements occur
+                while True:
+                    newIcsData = icsData.replace('\\"', '"').replace('\\\r\n "', '\r\n "')
+                    if newIcsData == icsData:
+                        break
+                    else:
+                        icsData = newIcsData
+                
+                try:
+                    f = open(icsPath, "w")
+                    f.write(icsData)
+                except Exception, e:
+                    print "Failed to write file %s due to %s" % (icsPath, str(e),)
+                    totalErrors += 1
+                    continue
+                finally:
+                    f.close()
+
+                # Change ETag on written resource
+                updateEtag(icsPath, icsData)
+                didFix = True
+                print "Problem fixed in: <BasePath>%s" % (icsPath[basePathLength:],)
+            else:
+                print "Problem found in: <BasePath>%s" % (icsPath[basePathLength:],)
+            totalProblems += 1
+     
+    # Change CTag on calendar collection if any resource was written
+    if didFix:
+        updateCtag(calendarPath)
+
+def main():
+    
+    basePath = ICALSERVER_DOCROOT
+    urisFile = DEFAULT_URIS
+    doFix = False
+    
+    # Parse command line options
+    opts, _ignore_args = getopt.getopt(sys.argv[1:], "hp:u:", ["fix", "help",])
+    for option, value in opts:
+        if option in ("-h", "--help"):
+            usage()
+        elif option == "-p":
+            basePath = value
+            if not os.path.exists(basePath):
+                usage("Path does not exist: %s" % (basePath,))
+            elif not os.path.isdir(basePath):
+                usage("Path is not a directory: %s" % (basePath,))
+        elif option == "-u":
+            urisFile = value
+        elif option == "--fix":
+            doFix = True
+        else:
+            usage("Invalid option")
+
+    if not urisFile:
+        usage("Need to specify a file listing each URI to process")
+    
+    # Get all the uris to process
+    f = open(urisFile)
+    uris = set()
+    for line in f:
+        pos = line.find("/calendars/")
+        if pos == -1:
+            print "Ignored log line: %s" % (line,)
+            continue
+        uris.add(line[pos:].split()[0])
+    uris = list(uris)
+    uris.sort()
+    f.close()
+
+    print "Base Path is: %s" % (basePath,)
+    print "Number of unique URIs to fix: %d" % (len(uris),)
+    print ""
+    for uri in uris:
+        scanURI(uri, basePath, doFix)
+
+    print ""
+    print "---------------------"
+    print "Total Problems %s: %d of %d" % ("Fixed" if doFix else "Found", totalProblems, totalScanned,)
+    if totalErrors:
+        print "Total Errors: %s" % (totalErrors,)
+
+if __name__ == '__main__':
+    
+    main()


Property changes on: CalendarServer/trunk/calendarserver/tools/doublequotefix.py
___________________________________________________________________
Added: svn:executable
   + *
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090105/5b8d6ec2/attachment.html>


More information about the calendarserver-changes mailing list