<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[15069] CalendarServer/trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.calendarserver.org//changeset/15069">15069</a></dd>
<dt>Author</dt> <dd>cdaboo@apple.com</dd>
<dt>Date</dt> <dd>2015-08-26 11:01:05 -0700 (Wed, 26 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Log sync and sync-home separately. Log more detail about POST requests. Include display of method usage in dashboard.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#CalendarServertrunkcalendarserveraccesslogpy">CalendarServer/trunk/calendarserver/accesslog.py</a></li>
<li><a href="#CalendarServertrunkcalendarserverlogAnalysispy">CalendarServer/trunk/calendarserver/logAnalysis.py</a></li>
<li><a href="#CalendarServertrunkcalendarservertoolsdashboardpy">CalendarServer/trunk/calendarserver/tools/dashboard.py</a></li>
<li><a href="#CalendarServertrunkcontribtoolsprotocolanalysispy">CalendarServer/trunk/contrib/tools/protocolanalysis.py</a></li>
<li><a href="#CalendarServertrunktwistedcaldavmethodpostpy">CalendarServer/trunk/twistedcaldav/method/post.py</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="CalendarServertrunkcalendarserveraccesslogpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/accesslog.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/accesslog.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/calendarserver/accesslog.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -493,6 +493,8 @@
</span><span class="cx">         current[&quot;user-agent&quot;][adjustedClient] += 1
</span><span class="cx">         if stats[&quot;statusCode&quot;] &gt;= 500:
</span><span class="cx">             current[&quot;500&quot;] += 1
</span><ins>+        elif stats[&quot;statusCode&quot;] == 401:
+            current[&quot;401&quot;] += 1
</ins><span class="cx">         current[&quot;t&quot;] += stats.get(&quot;t&quot;, 0.0)
</span><span class="cx">         current[&quot;t-resp-wr&quot;] += stats.get(&quot;t-resp-wr&quot;, 0.0)
</span><span class="cx">         current[&quot;slots&quot;] += stats.get(&quot;outstandingRequests&quot;, 0)
</span></span></pre></div>
<a id="CalendarServertrunkcalendarserverlogAnalysispy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/logAnalysis.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/logAnalysis.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/calendarserver/logAnalysis.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -36,10 +36,12 @@
</span><span class="cx"> METHOD_REPORT_CALENDAR_MULTIGET = &quot;REPORT cal-multi&quot;
</span><span class="cx"> METHOD_REPORT_CALENDAR_QUERY = &quot;REPORT cal-query&quot;
</span><span class="cx"> METHOD_REPORT_CALENDAR_FREEBUSY = &quot;REPORT freebusy&quot;
</span><ins>+METHOD_REPORT_CALENDAR_HOME_SYNC = &quot;REPORT cal-home-sync&quot;
</ins><span class="cx"> METHOD_REPORT_CALENDAR_SYNC = &quot;REPORT cal-sync&quot;
</span><span class="cx"> METHOD_REPORT_ADDRESSBOOK_MULTIGET = &quot;REPORT adbk-multi&quot;
</span><span class="cx"> METHOD_REPORT_ADDRESSBOOK_QUERY = &quot;REPORT adbk-query&quot;
</span><span class="cx"> METHOD_REPORT_DIRECTORY_QUERY = &quot;REPORT dir-query&quot;
</span><ins>+METHOD_REPORT_ADDRESSBOOK_HOME_SYNC = &quot;REPORT adbk-home-sync&quot;
</ins><span class="cx"> METHOD_REPORT_ADDRESSBOOK_SYNC = &quot;REPORT adbk-sync&quot;
</span><span class="cx"> METHOD_REPORT_P_SEARCH_P_SET = &quot;REPORT p-set&quot;
</span><span class="cx"> METHOD_REPORT_P_P_SEARCH = &quot;REPORT p-search&quot;
</span><span class="lines">@@ -48,9 +50,15 @@
</span><span class="cx"> # POSTs
</span><span class="cx"> METHOD_POST_CALENDAR_HOME = &quot;POST Calendar Home&quot;
</span><span class="cx"> METHOD_POST_CALENDAR = &quot;POST Calendar&quot;
</span><del>-METHOD_POST_CALENDAR_OBJECT = &quot;POST Calendar Object&quot;
</del><ins>+METHOD_POST_CALENDAR_ADD_MEMBER = &quot;POST Calendar-add&quot;
+METHOD_POST_CALENDAR_OBJECT = &quot;POST ics&quot;
+METHOD_POST_CALENDAR_OBJECT_SPLIT = &quot;POST split&quot;
+METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_ADD = &quot;POST att-add&quot;
+METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_UPDATE = &quot;POST att-update&quot;
+METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_REMOVE = &quot;POST att-remove&quot;
</ins><span class="cx"> METHOD_POST_ADDRESSBOOK_HOME = &quot;POST Adbk Home&quot;
</span><span class="cx"> METHOD_POST_ADDRESSBOOK = &quot;POST Adbk&quot;
</span><ins>+METHOD_POST_ADDRESSBOOK_ADD_MEMBER = &quot;POST Adbk-add&quot;
</ins><span class="cx"> METHOD_POST_ISCHEDULE_FREEBUSY = &quot;POST Freebusy iSchedule&quot;
</span><span class="cx"> METHOD_POST_ISCHEDULE = &quot;POST iSchedule&quot;
</span><span class="cx"> METHOD_POST_TIMEZONES = &quot;POST Timezones&quot;
</span><span class="lines">@@ -89,12 +97,15 @@
</span><span class="cx"> METHOD_DELETE_VCF = &quot;DELETE vcf&quot;
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-def getAdjustedMethodName(stats):
</del><ins>+def getAdjustedMethodName(stats, method=None, uri=None):
</ins><span class="cx"> 
</span><del>-    method = stats[&quot;method&quot;]
-    uribits = stats[&quot;uri&quot;].rstrip(&quot;/&quot;).split('/')[1:]
</del><ins>+    if method is None:
+        method = stats[&quot;method&quot;]
+    if uri is None:
+        uri = stats[&quot;uri&quot;]
+    uribits = uri.rstrip(&quot;/&quot;).split('/')[1:]
</ins><span class="cx">     if len(uribits) == 0:
</span><del>-        uribits = [stats[&quot;uri&quot;]]
</del><ins>+        uribits = [uri]
</ins><span class="cx"> 
</span><span class="cx">     calendar_specials = (&quot;attachments&quot;, &quot;dropbox&quot;, &quot;notification&quot;, &quot;freebusy&quot;, &quot;outbox&quot;,)
</span><span class="cx">     adbk_specials = (&quot;notification&quot;,)
</span><span class="lines">@@ -143,17 +154,25 @@
</span><span class="cx">                     report_type = &quot;directory-query&quot;
</span><span class="cx">             if report_type == &quot;sync-collection&quot;:
</span><span class="cx">                 if uribits[0] == &quot;calendars&quot;:
</span><del>-                    report_type = &quot;cal-sync&quot;
</del><ins>+                    if len(uribits) == 3:
+                        report_type = &quot;cal-home-sync&quot;
+                    else:
+                        report_type = &quot;cal-sync&quot;
</ins><span class="cx">                 elif uribits[0] == &quot;addressbooks&quot;:
</span><del>-                    report_type = &quot;adbk-sync&quot;
</del><ins>+                    if len(uribits) == 3:
+                        report_type = &quot;adbk-home-sync&quot;
+                    else:
+                        report_type = &quot;adbk-sync&quot;
</ins><span class="cx">             mappedNames = {
</span><span class="cx">                 &quot;calendar-multiget&quot;             : METHOD_REPORT_CALENDAR_MULTIGET,
</span><span class="cx">                 &quot;calendar-query&quot;                : METHOD_REPORT_CALENDAR_QUERY,
</span><span class="cx">                 &quot;free-busy-query&quot;               : METHOD_REPORT_CALENDAR_FREEBUSY,
</span><ins>+                &quot;cal-home-sync&quot;                 : METHOD_REPORT_CALENDAR_HOME_SYNC,
</ins><span class="cx">                 &quot;cal-sync&quot;                      : METHOD_REPORT_CALENDAR_SYNC,
</span><span class="cx">                 &quot;addressbook-multiget&quot;          : METHOD_REPORT_ADDRESSBOOK_MULTIGET,
</span><span class="cx">                 &quot;addressbook-query&quot;             : METHOD_REPORT_ADDRESSBOOK_QUERY,
</span><span class="cx">                 &quot;directory-query&quot;               : METHOD_REPORT_DIRECTORY_QUERY,
</span><ins>+                &quot;adbk-home-sync&quot;                : METHOD_REPORT_ADDRESSBOOK_HOME_SYNC,
</ins><span class="cx">                 &quot;adbk-sync&quot;                     : METHOD_REPORT_ADDRESSBOOK_SYNC,
</span><span class="cx">                 &quot;principal-search-property-set&quot; : METHOD_REPORT_P_SEARCH_P_SET,
</span><span class="cx">                 &quot;principal-property-search&quot;     : METHOD_REPORT_P_P_SEARCH,
</span><span class="lines">@@ -178,7 +197,18 @@
</span><span class="cx"> 
</span><span class="cx">         if uribits[0] == &quot;calendars&quot;:
</span><span class="cx"> 
</span><del>-            if len(uribits) == 3:
</del><ins>+            if &quot;(&quot; in method:
+                post_type = method.split(&quot;(&quot;)[1][:-1]
+                mappedNames = {
+                    &quot;add-member&quot;            : METHOD_POST_CALENDAR_ADD_MEMBER,
+                    &quot;split&quot;                 : METHOD_POST_CALENDAR_OBJECT_SPLIT,
+                    &quot;attachment-add&quot;        : METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_ADD,
+                    &quot;attachment-update&quot;     : METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_UPDATE,
+                    &quot;attachment-remove&quot;     : METHOD_POST_CALENDAR_OBJECT_ATTACHMENT_REMOVE,
+                }
+                return mappedNames.get(post_type, &quot;POST %s&quot; % (post_type,))
+
+            elif len(uribits) == 3:
</ins><span class="cx">                 return METHOD_POST_CALENDAR_HOME
</span><span class="cx">             elif len(uribits) == 4:
</span><span class="cx">                 if uribits[3] == &quot;outbox&quot;:
</span><span class="lines">@@ -334,6 +364,7 @@
</span><span class="cx"> 
</span><span class="cx"> osClients = (
</span><span class="cx">     &quot;Mac OS X/&quot;,
</span><ins>+    &quot;Mac+OS+X/&quot;,
</ins><span class="cx">     &quot;Mac_OS_X/&quot;,
</span><span class="cx">     &quot;iOS/&quot;,
</span><span class="cx"> )
</span></span></pre></div>
<a id="CalendarServertrunkcalendarservertoolsdashboardpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/calendarserver/tools/dashboard.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/calendarserver/tools/dashboard.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/calendarserver/tools/dashboard.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -195,6 +195,7 @@
</span><span class="cx">                         self.displayWindow(self.registered_windows[&quot;h&quot;])
</span><span class="cx"> 
</span><span class="cx">             self.resetWindows()
</span><ins>+
</ins><span class="cx">         # Reset the screen to the default config
</span><span class="cx">         else:
</span><span class="cx">             if self.windows:
</span><span class="lines">@@ -209,15 +210,18 @@
</span><span class="cx">                 self.windows.append(wtype(self.usesCurses, self.client).makeWindow(top=top))
</span><span class="cx">                 self.windows[-1].activate()
</span><span class="cx">                 top += self.windows[-1].nlines + 1
</span><ins>+
</ins><span class="cx">             # Don't display help panel if the window is too narrow
</span><del>-            term_w, term_h = terminal_size()
-            logging.debug(&quot;logger displayWindow: rows: %s  cols: %s&quot; % (term_h, term_w))
-            if int(term_w) &gt; 100:
-                logging.debug('term_w &gt; 100, making window with top at %d' % (top))
-                self.windows.append(HelpWindow(self.usesCurses, self.client).makeWindow(top=top))
-                self.windows[-1].activate()
</del><ins>+            if self.usesCurses:
+                term_w, term_h = terminal_size()
+                logging.debug(&quot;logger displayWindow: rows: %s  cols: %s&quot; % (term_h, term_w))
+                if int(term_w) &gt; 100:
+                    logging.debug('term_w &gt; 100, making window with top at %d' % (top))
+                    self.windows.append(HelpWindow(self.usesCurses, self.client).makeWindow(top=top))
+                    self.windows[-1].activate()
</ins><span class="cx"> 
</span><del>-        curses.panel.update_panels()
</del><ins>+        if self.usesCurses:
+            curses.panel.update_panels()
</ins><span class="cx">         self.updateDisplay(True)
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -350,7 +354,8 @@
</span><span class="cx">         Update the current data from the server.
</span><span class="cx">         &quot;&quot;&quot;
</span><span class="cx"> 
</span><del>-        self.currentData = self.readSock(self.items)
</del><ins>+        # Only read each item once
+        self.currentData = self.readSock(list(set(self.items)))
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getOneItem(self, item):
</span><span class="lines">@@ -513,6 +518,9 @@
</span><span class="cx">         x = 1
</span><span class="cx">         y = 1
</span><span class="cx"> 
</span><ins>+        if not self.usesCurses:
+            print(&quot;------------ {}&quot;.format(self.title))
+
</ins><span class="cx">         items = []
</span><span class="cx">         for keypress, wtype in sorted(
</span><span class="cx">             Dashboard.registered_windows.items(), key=lambda x: x[0]
</span><span class="lines">@@ -526,6 +534,9 @@
</span><span class="cx">                 print(item)
</span><span class="cx">             y += 1
</span><span class="cx"> 
</span><ins>+        if not self.usesCurses:
+            print(&quot;&quot;)
+
</ins><span class="cx">         if self.usesCurses:
</span><span class="cx">             self.window.refresh()
</span><span class="cx"> 
</span><span class="lines">@@ -574,6 +585,7 @@
</span><span class="cx">             self.window.addstr(y, x, s1, curses.A_REVERSE)
</span><span class="cx">             self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
</span><span class="cx">         else:
</span><ins>+            print(&quot;------------ {}&quot;.format(self.title))
</ins><span class="cx">             print(s1)
</span><span class="cx">             print(s2)
</span><span class="cx">         y += 2
</span><span class="lines">@@ -633,6 +645,7 @@
</span><span class="cx">             self.window.addstr(y, x, s)
</span><span class="cx">         else:
</span><span class="cx">             print(s)
</span><ins>+            print(&quot;&quot;)
</ins><span class="cx">         y += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -685,6 +698,7 @@
</span><span class="cx">         if self.usesCurses:
</span><span class="cx">             self.window.addstr(y, x, s, curses.A_REVERSE)
</span><span class="cx">         else:
</span><ins>+            print(&quot;------------ {}&quot;.format(self.title))
</ins><span class="cx">             print(s)
</span><span class="cx">         y += 1
</span><span class="cx">         total_assigned = 0
</span><span class="lines">@@ -727,6 +741,7 @@
</span><span class="cx">             self.window.addstr(y, x, s)
</span><span class="cx">         else:
</span><span class="cx">             print(s)
</span><ins>+            print(&quot;&quot;)
</ins><span class="cx">         y += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -780,6 +795,7 @@
</span><span class="cx">         if self.usesCurses:
</span><span class="cx">             self.window.addstr(y, x, s, curses.A_REVERSE)
</span><span class="cx">         else:
</span><ins>+            print(&quot;------------ {}&quot;.format(self.title))
</ins><span class="cx">             print(s)
</span><span class="cx">         y += 1
</span><span class="cx">         for record in sorted(records, key=lambda x: x[&quot;slot&quot;]):
</span><span class="lines">@@ -837,6 +853,7 @@
</span><span class="cx">             if data[&quot;overloaded&quot;]:
</span><span class="cx">                 s += &quot;    OVERLOADED&quot;
</span><span class="cx">             print(s)
</span><ins>+            print(&quot;&quot;)
</ins><span class="cx">         y += 1
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -887,6 +904,7 @@
</span><span class="cx">         if self.usesCurses:
</span><span class="cx">             self.window.addstr(y, x, s, curses.A_REVERSE)
</span><span class="cx">         else:
</span><ins>+            print(&quot;------------ {}&quot;.format(self.title))
</ins><span class="cx">             print(s)
</span><span class="cx">         y += 1
</span><span class="cx"> 
</span><span class="lines">@@ -917,6 +935,9 @@
</span><span class="cx">                 pass
</span><span class="cx">             y += 1
</span><span class="cx"> 
</span><ins>+        if not self.usesCurses:
+            print(&quot;&quot;)
+
</ins><span class="cx">         if self.usesCurses:
</span><span class="cx">             self.window.refresh()
</span><span class="cx"> 
</span><span class="lines">@@ -959,6 +980,7 @@
</span><span class="cx">             self.window.addstr(y, x, s1, curses.A_REVERSE)
</span><span class="cx">             self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
</span><span class="cx">         else:
</span><ins>+            print(&quot;------------ {}&quot;.format(self.title))
</ins><span class="cx">             print(s1)
</span><span class="cx">             print(s2)
</span><span class="cx">         y += 2
</span><span class="lines">@@ -992,6 +1014,9 @@
</span><span class="cx">                 pass
</span><span class="cx">             y += 1
</span><span class="cx"> 
</span><ins>+        if not self.usesCurses:
+            print(&quot;&quot;)
+
</ins><span class="cx">         if self.usesCurses:
</span><span class="cx">             self.window.refresh()
</span><span class="cx"> 
</span><span class="lines">@@ -999,6 +1024,128 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+class MethodsWindow(BaseWindow):
+    &quot;&quot;&quot;
+    Display the status of the server's request methods.
+    &quot;&quot;&quot;
+
+    help = &quot;server methods&quot;
+    clientItem = &quot;stats&quot;
+    FORMAT_WIDTH = 116
+    stats_keys = (&quot;current&quot;, &quot;1m&quot;, &quot;5m&quot;, &quot;1h&quot;,)
+
+    def makeWindow(self, top=0, left=0):
+        stats = defaultIfNone(self.clientData(), {})
+        methods = set()
+        for key in self.stats_keys:
+            methods.update(stats.get(key, {}).get(&quot;method&quot;, {}).keys())
+        nlines = len(methods)
+        self.rowCount = nlines
+        self._createWindow(&quot;Methods&quot;, self.rowCount + 7, ncols=self.FORMAT_WIDTH, begin_y=top, begin_x=left)
+        return self
+
+
+    def update(self):
+        stats = defaultIfNone(self.clientData(), {})
+        methods = set()
+        for key in self.stats_keys:
+            methods.update(stats.get(key, {}).get(&quot;method&quot;, {}).keys())
+
+        records = {}
+        records_t = {}
+        for key in self.stats_keys:
+            records[key] = defaultIfNone(self.clientData(), {}).get(key, {}).get(&quot;method&quot;, {})
+            records_t[key] = defaultIfNone(self.clientData(), {}).get(key, {}).get(&quot;method-t&quot;, {})
+        self.iter += 1
+
+        if self.usesCurses:
+            self.window.erase()
+            self.window.border()
+            self.window.addstr(
+                0, 2,
+                self.title + &quot; {} ({})&quot;.format(len(records), self.iter)
+            )
+
+        x = 1
+        y = 1
+        s1 = &quot; {:&lt;40}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10} &quot;.format(
+            &quot;&quot;, &quot;------&quot;, &quot;current---&quot;, &quot;------&quot;, &quot;1m--------&quot;, &quot;------&quot;, &quot;5m--------&quot;, &quot;------&quot;, &quot;1h--------&quot;,
+        )
+        s2 = &quot; {:&lt;40}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10} &quot;.format(
+            &quot;Method&quot;, &quot;Number&quot;, &quot;Av-Time&quot;, &quot;Number&quot;, &quot;Av-Time&quot;, &quot;Number&quot;, &quot;Av-Time&quot;, &quot;Number&quot;, &quot;Av-Time&quot;,
+        )
+        s3 = &quot; {:&lt;40}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10} &quot;.format(
+            &quot;&quot;, &quot;&quot;, &quot;(ms)&quot;, &quot;&quot;, &quot;(ms)&quot;, &quot;&quot;, &quot;(ms)&quot;, &quot;&quot;, &quot;(ms)&quot;,
+        )
+        if self.usesCurses:
+            self.window.addstr(y, x, s1, curses.A_REVERSE)
+            self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
+            self.window.addstr(y + 2, x, s3, curses.A_REVERSE)
+        else:
+            print(&quot;------------ {}&quot;.format(self.title))
+            print(s1)
+            print(s2)
+            print(s3)
+        y += 2
+        total_methods = dict([(key, 0) for key in self.stats_keys])
+        total_time = dict([(key, 0.0) for key in self.stats_keys])
+        for method_type in sorted(methods):
+            for key in self.stats_keys:
+                total_methods[key] += records[key].get(method_type, 0)
+                total_time[key] += records_t[key].get(method_type, 0.0)
+            changed = self.lastResult.get(method_type, 0) != records[&quot;current&quot;].get(method_type, 0)
+            items = [method_type]
+            for key in self.stats_keys:
+                items.append(records[key].get(method_type, 0))
+                items.append(safeDivision(records_t[key].get(method_type, 0), records[key].get(method_type, 0)))
+            s = &quot; {:&lt;40}{:&gt;8}{:&gt;10.1f}{:&gt;8}{:&gt;10.1f}{:&gt;8}{:&gt;10.1f}{:&gt;8}{:&gt;10.1f} &quot;.format(
+                *items
+            )
+            try:
+                if self.usesCurses:
+                    self.window.addstr(
+                        y, x, s,
+                        curses.A_REVERSE if changed else curses.A_NORMAL,
+                    )
+                else:
+                    print(s)
+            except curses.error:
+                pass
+            y += 1
+
+        items = [&quot;Total:&quot;]
+        for key in self.stats_keys:
+            items.append(total_methods[key])
+            items.append(safeDivision(total_time[key], total_methods[key]))
+        s1 = &quot; {:&lt;40}{:&gt;8}{:&gt;10.1f}{:&gt;8}{:&gt;10.1f}{:&gt;8}{:&gt;10.1f}{:&gt;8}{:&gt;10.1f} &quot;.format(
+            *items
+        )
+        items = [&quot;401s:&quot;]
+        for key in self.stats_keys:
+            items.append(defaultIfNone(self.clientData(), {}).get(key, {}).get(&quot;401&quot;, 0))
+            items.append(&quot;&quot;)
+        s2 = &quot; {:&lt;40}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10}{:&gt;8}{:&gt;10} &quot;.format(
+            *items
+        )
+        if self.usesCurses:
+            self.window.hline(y, x, &quot;-&quot;, self.FORMAT_WIDTH - 2)
+            y += 1
+            self.window.addstr(y, x, s1)
+            y += 1
+            self.window.addstr(y, x, s2)
+        else:
+            print(s1)
+            print(s2)
+            print(&quot;&quot;)
+        y += 1
+
+        if self.usesCurses:
+            self.window.refresh()
+
+        self.lastResult = defaultIfNone(self.clientData(), {}).get(&quot;current&quot;, {}).get(&quot;method&quot;, {})
+
+
+
</ins><span class="cx"> class DirectoryStatsWindow(BaseWindow):
</span><span class="cx">     &quot;&quot;&quot;
</span><span class="cx">     Displays the status of the server's directory service calls
</span><span class="lines">@@ -1044,6 +1191,7 @@
</span><span class="cx">             self.window.addstr(y, x, s1, curses.A_REVERSE)
</span><span class="cx">             self.window.addstr(y + 1, x, s2, curses.A_REVERSE)
</span><span class="cx">         else:
</span><ins>+            print(&quot;------------ {}&quot;.format(self.title))
</ins><span class="cx">             print(s1)
</span><span class="cx">             print(s2)
</span><span class="cx">         y += 2
</span><span class="lines">@@ -1111,6 +1259,7 @@
</span><span class="cx">             print(s)
</span><span class="cx">             print(s1)
</span><span class="cx">             print(s2)
</span><ins>+            print(&quot;&quot;)
</ins><span class="cx">         y += 3
</span><span class="cx"> 
</span><span class="cx">         if self.usesCurses:
</span><span class="lines">@@ -1122,6 +1271,7 @@
</span><span class="cx"> Dashboard.registerWindow(SystemWindow, &quot;s&quot;)
</span><span class="cx"> Dashboard.registerWindow(AssignmentsWindow, &quot;w&quot;)
</span><span class="cx"> Dashboard.registerWindow(RequestStatsWindow, &quot;r&quot;)
</span><ins>+Dashboard.registerWindow(MethodsWindow, &quot;m&quot;)
</ins><span class="cx"> Dashboard.registerWindow(JobsWindow, &quot;j&quot;)
</span><span class="cx"> Dashboard.registerWindow(HTTPSlotsWindow, &quot;c&quot;)
</span><span class="cx"> Dashboard.registerWindow(DirectoryStatsWindow, &quot;d&quot;)
</span></span></pre></div>
<a id="CalendarServertrunkcontribtoolsprotocolanalysispy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/contrib/tools/protocolanalysis.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/contrib/tools/protocolanalysis.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/contrib/tools/protocolanalysis.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -26,6 +26,13 @@
</span><span class="cx"> import tables
</span><span class="cx"> import traceback
</span><span class="cx"> import glob
</span><ins>+from calendarserver.logAnalysis import getAdjustedMethodName, METHOD_PUT_ICS, \
+    METHOD_PUT_ORGANIZER, METHOD_PUT_ATTENDEE, METHOD_PROPFIND_CALENDAR, \
+    METHOD_POST_FREEBUSY, METHOD_POST_ORGANIZER, METHOD_POST_ISCHEDULE_FREEBUSY, \
+    METHOD_POST_ISCHEDULE, METHOD_GET_DROPBOX, METHOD_PROPFIND_CALENDAR_HOME, \
+    METHOD_PROPFIND_CACHED_CALENDAR_HOME, METHOD_PROPFIND_ADDRESSBOOK_HOME, \
+    METHOD_PROPFIND_CACHED_ADDRESSBOOK_HOME, METHOD_PROPFIND_PRINCIPALS, \
+    METHOD_PROPFIND_CACHED_PRINCIPALS
</ins><span class="cx"> 
</span><span class="cx"> def safePercent(x, y, multiplier=100):
</span><span class="cx">     return ((multiplier * x) / y) if y else 0
</span><span class="lines">@@ -114,79 +121,6 @@
</span><span class="cx">     &quot;SEARCH&quot;,
</span><span class="cx"> ))
</span><span class="cx"> 
</span><del>-# Adjust method names
-
-# PROPFINDs
-METHOD_PROPFIND_CALENDAR_HOME = &quot;PROPFIND Calendar Home&quot;
-METHOD_PROPFIND_CACHED_CALENDAR_HOME = &quot;PROPFIND cached Calendar Home&quot;
-METHOD_PROPFIND_CALENDAR = &quot;PROPFIND Calendar&quot;
-METHOD_PROPFIND_INBOX = &quot;PROPFIND Inbox&quot;
-METHOD_PROPFIND_ADDRESSBOOK_HOME = &quot;PROPFIND Adbk Home&quot;
-METHOD_PROPFIND_CACHED_ADDRESSBOOK_HOME = &quot;PROPFIND cached Adbk Home&quot;
-METHOD_PROPFIND_ADDRESSBOOK = &quot;PROPFIND Adbk&quot;
-METHOD_PROPFIND_DIRECTORY = &quot;PROPFIND Directory&quot;
-METHOD_PROPFIND_PRINCIPALS = &quot;PROPFIND Principals&quot;
-METHOD_PROPFIND_CACHED_PRINCIPALS = &quot;PROPFIND cached Principals&quot;
-
-# PROPPATCHs
-METHOD_PROPPATCH_CALENDAR = &quot;PROPPATCH Calendar&quot;
-METHOD_PROPPATCH_ADDRESSBOOK = &quot;PROPPATCH Adbk Home&quot;
-
-# REPORTs
-METHOD_REPORT_CALENDAR_MULTIGET = &quot;REPORT cal-multi&quot;
-METHOD_REPORT_CALENDAR_QUERY = &quot;REPORT cal-query&quot;
-METHOD_REPORT_CALENDAR_FREEBUSY = &quot;REPORT freebusy&quot;
-METHOD_REPORT_CALENDAR_SYNC = &quot;REPORT cal-sync&quot;
-METHOD_REPORT_ADDRESSBOOK_MULTIGET = &quot;REPORT adbk-multi&quot;
-METHOD_REPORT_ADDRESSBOOK_QUERY = &quot;REPORT adbk-query&quot;
-METHOD_REPORT_DIRECTORY_QUERY = &quot;REPORT dir-query&quot;
-METHOD_REPORT_ADDRESSBOOK_SYNC = &quot;REPORT adbk-sync&quot;
-METHOD_REPORT_P_SEARCH_P_SET = &quot;REPORT p-set&quot;
-METHOD_REPORT_P_P_SEARCH = &quot;REPORT p-search&quot;
-METHOD_REPORT_EXPAND_P = &quot;REPORT expand&quot;
-
-# POSTs
-METHOD_POST_CALENDAR_HOME = &quot;POST Calendar Home&quot;
-METHOD_POST_CALENDAR = &quot;POST Calendar&quot;
-METHOD_POST_ADDRESSBOOK_HOME = &quot;POST Adbk Home&quot;
-METHOD_POST_ADDRESSBOOK = &quot;POST Adbk&quot;
-METHOD_POST_ISCHEDULE_FREEBUSY = &quot;POST Freebusy iSchedule&quot;
-METHOD_POST_ISCHEDULE = &quot;POST iSchedule&quot;
-METHOD_POST_TIMEZONES = &quot;POST Timezones&quot;
-METHOD_POST_FREEBUSY = &quot;POST Freebusy&quot;
-METHOD_POST_ORGANIZER = &quot;POST Organizer&quot;
-METHOD_POST_ATTENDEE = &quot;POST Attendee&quot;
-METHOD_POST_OUTBOX = &quot;POST Outbox&quot;
-METHOD_POST_APNS = &quot;POST apns&quot;
-
-# PUTs
-METHOD_PUT_ICS = &quot;PUT ics&quot;
-METHOD_PUT_ORGANIZER = &quot;PUT Organizer&quot;
-METHOD_PUT_ATTENDEE = &quot;PUT Attendee&quot;
-METHOD_PUT_DROPBOX = &quot;PUT dropbox&quot;
-METHOD_PUT_VCF = &quot;PUT VCF&quot;
-
-# GETs
-METHOD_GET_CALENDAR_HOME = &quot;GET Calendar Home&quot;
-METHOD_GET_CALENDAR = &quot;GET Calendar&quot;
-METHOD_GET_ICS = &quot;GET ics&quot;
-METHOD_GET_INBOX_ICS = &quot;GET inbox ics&quot;
-METHOD_GET_DROPBOX = &quot;GET dropbox&quot;
-METHOD_GET_ADDRESSBOOK_HOME = &quot;GET Adbk Home&quot;
-METHOD_GET_ADDRESSBOOK = &quot;GET Adbk&quot;
-METHOD_GET_VCF = &quot;GET VCF&quot;
-METHOD_GET_TIMEZONES = &quot;GET Timezones&quot;
-
-# DELETEs
-METHOD_DELETE_CALENDAR_HOME = &quot;DELETE Calendar Home&quot;
-METHOD_DELETE_CALENDAR = &quot;DELETE Calendar&quot;
-METHOD_DELETE_ICS = &quot;DELETE ics&quot;
-METHOD_DELETE_INBOX_ICS = &quot;DELETE inbox ics&quot;
-METHOD_DELETE_DROPBOX = &quot;DELETE dropbox&quot;
-METHOD_DELETE_ADDRESSBOOK_HOME = &quot;DELETE Adbk Home&quot;
-METHOD_DELETE_ADDRESSBOOK = &quot;DELETE Adbk&quot;
-METHOD_DELETE_VCF = &quot;DELETE vcf&quot;
-
</del><span class="cx"> # 401s
</span><span class="cx"> METHOD_401 = &quot;Z 401s&quot;
</span><span class="cx"> 
</span><span class="lines">@@ -332,7 +266,7 @@
</span><span class="cx">                     continue
</span><span class="cx"> 
</span><span class="cx">                 # Filter method
</span><del>-                if self.ignoreNonHTTPMethods and not self.currentLine.method.startswith(&quot;REPORT(&quot;) and self.currentLine.method not in httpMethods:
</del><ins>+                if self.ignoreNonHTTPMethods and not self.currentLine.method.startswith(&quot;REPORT(&quot;) and not self.currentLine.method.startswith(&quot;POST(&quot;) and self.currentLine.method not in httpMethods:
</ins><span class="cx">                     self.currentLine.method = &quot;???&quot;
</span><span class="cx"> 
</span><span class="cx">                 # Do hour ranges
</span><span class="lines">@@ -674,213 +608,9 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">     def getAdjustedMethodName(self):
</span><ins>+        return getAdjustedMethodName(self.currentLine.extended, self.currentLine.method, self.currentLine.uri)
</ins><span class="cx"> 
</span><del>-        uribits = self.currentLine.uri.rstrip(&quot;/&quot;).split('/')[1:]
-        if len(uribits) == 0:
-            uribits = [self.currentLine.uri]
</del><span class="cx"> 
</span><del>-        calendar_specials = (&quot;dropbox&quot;, &quot;notification&quot;, &quot;freebusy&quot;, &quot;outbox&quot;,)
-        adbk_specials = (&quot;notification&quot;,)
-
-        if self.currentLine.method == &quot;PROPFIND&quot;:
-
-            cached = &quot;cached&quot; in self.currentLine.extended
-
-            if uribits[0] == &quot;calendars&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_PROPFIND_CACHED_CALENDAR_HOME if cached else METHOD_PROPFIND_CALENDAR_HOME
-                elif len(uribits) &gt; 3:
-                    if uribits[3] in calendar_specials:
-                        return &quot;PROPFIND %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        if uribits[3] == &quot;inbox&quot;:
-                            return METHOD_PROPFIND_INBOX
-                        else:
-                            return METHOD_PROPFIND_CALENDAR
-
-            elif uribits[0] == &quot;addressbooks&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_PROPFIND_CACHED_ADDRESSBOOK_HOME if cached else METHOD_PROPFIND_ADDRESSBOOK_HOME
-                elif len(uribits) &gt; 3:
-                    if uribits[3] in adbk_specials:
-                        return &quot;PROPFIND %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        return METHOD_PROPFIND_ADDRESSBOOK
-
-            elif uribits[0] == &quot;directory&quot;:
-                return METHOD_PROPFIND_DIRECTORY
-
-            elif uribits[0] == &quot;principals&quot;:
-                return METHOD_PROPFIND_CACHED_PRINCIPALS if cached else METHOD_PROPFIND_PRINCIPALS
-
-        elif self.currentLine.method.startswith(&quot;REPORT&quot;):
-
-            if &quot;(&quot; in self.currentLine.method:
-                report_type = self.currentLine.method.split(&quot;}&quot; if &quot;}&quot; in self.currentLine.method else &quot;:&quot;)[1][:-1]
-                if report_type == &quot;addressbook-query&quot;:
-                    if uribits[0] == &quot;directory&quot;:
-                        report_type = &quot;directory-query&quot;
-                if report_type == &quot;sync-collection&quot;:
-                    if uribits[0] == &quot;calendars&quot;:
-                        report_type = &quot;cal-sync&quot;
-                    elif uribits[0] == &quot;addressbooks&quot;:
-                        report_type = &quot;adbk-sync&quot;
-                mappedNames = {
-                    &quot;calendar-multiget&quot;             : METHOD_REPORT_CALENDAR_MULTIGET,
-                    &quot;calendar-query&quot;                : METHOD_REPORT_CALENDAR_QUERY,
-                    &quot;free-busy-query&quot;               : METHOD_REPORT_CALENDAR_FREEBUSY,
-                    &quot;cal-sync&quot;                      : METHOD_REPORT_CALENDAR_SYNC,
-                    &quot;addressbook-multiget&quot;          : METHOD_REPORT_ADDRESSBOOK_MULTIGET,
-                    &quot;addressbook-query&quot;             : METHOD_REPORT_ADDRESSBOOK_QUERY,
-                    &quot;directory-query&quot;               : METHOD_REPORT_DIRECTORY_QUERY,
-                    &quot;adbk-sync&quot;                     : METHOD_REPORT_ADDRESSBOOK_SYNC,
-                    &quot;principal-search-property-set&quot; : METHOD_REPORT_P_SEARCH_P_SET,
-                    &quot;principal-property-search&quot;     : METHOD_REPORT_P_P_SEARCH,
-                    &quot;expand-property&quot;               : METHOD_REPORT_EXPAND_P,
-                }
-                return mappedNames.get(report_type, &quot;REPORT %s&quot; % (report_type,))
-
-        elif self.currentLine.method == &quot;PROPPATCH&quot;:
-
-            if uribits[0] == &quot;calendars&quot;:
-                return METHOD_PROPPATCH_CALENDAR
-            elif uribits[0] == &quot;addressbooks&quot;:
-                return METHOD_PROPPATCH_ADDRESSBOOK
-
-        elif self.currentLine.method == &quot;POST&quot;:
-
-            if uribits[0] == &quot;calendars&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_POST_CALENDAR_HOME
-                elif len(uribits) == 4:
-                    if uribits[3] == &quot;outbox&quot;:
-                        if &quot;recipients&quot; in self.currentLine.extended:
-                            return METHOD_POST_FREEBUSY
-                        elif &quot;freebusy&quot; in self.currentLine.extended:
-                            return METHOD_POST_FREEBUSY
-                        elif &quot;itip.request&quot; in self.currentLine.extended or &quot;itip.cancel&quot; in self.currentLine.extended:
-                            return METHOD_POST_ORGANIZER
-                        elif &quot;itip.reply&quot; in self.currentLine.extended:
-                            return METHOD_POST_ATTENDEE
-                        else:
-                            return METHOD_POST_OUTBOX
-                    elif uribits[3] in calendar_specials:
-                        pass
-                    else:
-                        return METHOD_POST_CALENDAR
-
-            elif uribits[0] == &quot;addressbooks&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_POST_ADDRESSBOOK_HOME
-                elif len(uribits) == 4:
-                    if uribits[3] in adbk_specials:
-                        pass
-                    else:
-                        return METHOD_POST_ADDRESSBOOK
-
-            elif uribits[0] == &quot;ischedule&quot;:
-                if &quot;fb-cached&quot; in self.currentLine.extended or &quot;fb-uncached&quot; in self.currentLine.extended or &quot;freebusy&quot; in self.currentLine.extended:
-                    return METHOD_POST_ISCHEDULE_FREEBUSY
-                else:
-                    return METHOD_POST_ISCHEDULE
-
-            elif uribits[0].startswith(&quot;timezones&quot;):
-                return METHOD_POST_TIMEZONES
-
-            elif uribits[0].startswith(&quot;apns&quot;):
-                return METHOD_POST_APNS
-
-        elif self.currentLine.method == &quot;PUT&quot;:
-
-            if uribits[0] == &quot;calendars&quot;:
-                if len(uribits) &gt; 3:
-                    if uribits[3] in calendar_specials:
-                        return &quot;PUT %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        pass
-                    else:
-                        if &quot;itip.requests&quot; in self.currentLine.extended:
-                            return METHOD_PUT_ORGANIZER
-                        elif &quot;itip.reply&quot; in self.currentLine.extended:
-                            return METHOD_PUT_ATTENDEE
-                        else:
-                            return METHOD_PUT_ICS
-
-            elif uribits[0] == &quot;addressbooks&quot;:
-                if len(uribits) &gt; 3:
-                    if uribits[3] in adbk_specials:
-                        return &quot;PUT %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        pass
-                    else:
-                        return METHOD_PUT_VCF
-
-        elif self.currentLine.method == &quot;GET&quot;:
-
-            if uribits[0] == &quot;calendars&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_GET_CALENDAR_HOME
-                elif len(uribits) &gt; 3:
-                    if uribits[3] in calendar_specials:
-                        return &quot;GET %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        return METHOD_GET_CALENDAR
-                    elif uribits[3] == &quot;inbox&quot;:
-                        return METHOD_GET_INBOX_ICS
-                    else:
-                        return METHOD_GET_ICS
-
-            elif uribits[0] == &quot;addressbooks&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_GET_ADDRESSBOOK_HOME
-                elif len(uribits) &gt; 3:
-                    if uribits[3] in adbk_specials:
-                        return &quot;GET %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        return METHOD_GET_ADDRESSBOOK
-                    else:
-                        return METHOD_GET_VCF
-
-            elif uribits[0].startswith(&quot;timezones&quot;):
-                return METHOD_GET_TIMEZONES
-
-        elif self.currentLine.method == &quot;DELETE&quot;:
-
-            if uribits[0] == &quot;calendars&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_DELETE_CALENDAR_HOME
-                elif len(uribits) &gt; 3:
-                    if uribits[3] in calendar_specials:
-                        return &quot;DELETE %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        return METHOD_DELETE_CALENDAR
-                    elif uribits[3] == &quot;inbox&quot;:
-                        return METHOD_DELETE_INBOX_ICS
-                    else:
-                        return METHOD_DELETE_ICS
-
-            elif uribits[0] == &quot;addressbooks&quot;:
-
-                if len(uribits) == 3:
-                    return METHOD_DELETE_ADDRESSBOOK_HOME
-                elif len(uribits) &gt; 3:
-                    if uribits[3] in adbk_specials:
-                        return &quot;DELETE %s&quot; % (uribits[3],)
-                    elif len(uribits) == 4:
-                        return METHOD_DELETE_ADDRESSBOOK
-                    else:
-                        return METHOD_DELETE_VCF
-
-        return self.currentLine.method
-
-
</del><span class="cx">     def getCountBucket(self, count, buckets):
</span><span class="cx"> 
</span><span class="cx">         for limit, key in buckets:
</span></span></pre></div>
<a id="CalendarServertrunktwistedcaldavmethodpostpy"></a>
<div class="modfile"><h4>Modified: CalendarServer/trunk/twistedcaldav/method/post.py (15068 => 15069)</h4>
<pre class="diff"><span>
<span class="info">--- CalendarServer/trunk/twistedcaldav/method/post.py        2015-08-26 17:25:45 UTC (rev 15068)
+++ CalendarServer/trunk/twistedcaldav/method/post.py        2015-08-26 18:01:05 UTC (rev 15069)
</span><span class="lines">@@ -36,6 +36,7 @@
</span><span class="cx">     if request.params:
</span><span class="cx">         if request.params == &quot;add-member&quot;:
</span><span class="cx">             if config.EnableAddMember and hasattr(self, &quot;POST_handler_add_member&quot;):
</span><ins>+                request.submethod = &quot;add-member&quot;
</ins><span class="cx">                 result = (yield self.POST_handler_add_member(request))
</span><span class="cx">                 returnValue(result)
</span><span class="cx"> 
</span><span class="lines">@@ -45,6 +46,7 @@
</span><span class="cx">         if len(action) == 1:
</span><span class="cx">             action = action[0]
</span><span class="cx">             if hasattr(self, &quot;POST_handler_action&quot;):
</span><ins>+                request.submethod = action
</ins><span class="cx">                 result = (yield self.POST_handler_action(request, action))
</span><span class="cx">                 returnValue(result)
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>