changeset 1113:9485500daadf

read if-modified-since and if-none-match headers, first use for rss_rc action
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Tue, 01 Aug 2006 00:11:34 +0200
parents b27d720fbc8e
children a300349712b9
files MoinMoin/__init__.py MoinMoin/action/rss_rc.py MoinMoin/request/__init__.py
diffstat 3 files changed, 170 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/__init__.py	Mon Jul 31 01:07:59 2006 +0200
+++ b/MoinMoin/__init__.py	Tue Aug 01 00:11:34 2006 +0200
@@ -1,6 +1,6 @@
 # -*- coding: iso-8859-1 -*-
 """
-MoinMoin Version 1.6.0alpha 61142a50c41b+ tip
+MoinMoin Version 1.6.0alpha b27d720fbc8e tip
 
 @copyright: 2000-2006 by Jürgen Hermann <jh@web.de>
 @license: GNU GPL, see COPYING for details.
--- a/MoinMoin/action/rss_rc.py	Mon Jul 31 01:07:59 2006 +0200
+++ b/MoinMoin/action/rss_rc.py	Tue Aug 01 00:11:34 2006 +0200
@@ -45,18 +45,7 @@
     except ValueError:
         ddiffs = 0
 
-    # prepare output
-    out = StringIO.StringIO()
-    handler = RssGenerator(out)
-
     # get data
-    interwiki = request.getBaseURL()
-    if interwiki[-1] != "/": interwiki = interwiki + "/"
-
-    logo = re.search(r'src="([^"]*)"', cfg.logo_string)
-    if logo:
-        logo = request.getQualifiedURL(logo.group(1))
-
     log = editlog.EditLog(request)
     logdata = []
     counter = 0
@@ -81,145 +70,173 @@
             break
     del log
 
-    # start SAX stream
-    handler.startDocument()
-    handler._out.write(
-        '<!--\n'
-        '    Add an "items=nnn" URL parameter to get more than the default 15 items.\n'
-        '    You cannot get more than %d items though.\n'
-        '    \n'
-        '    Add "unique=1" to get a list of changes where page names are unique,\n'
-        '    i.e. where only the latest change of each page is reflected.\n'
-        '    \n'
-        '    Add "diffs=1" to add change diffs to the description of each items.\n'
-        '    \n'
-        '    Add "ddiffs=1" to link directly to the diff (good for FeedReader).\n'
-        '    Current settings: items=%i, unique=%i, diffs=%i, ddiffs=%i'
-        '-->\n' % (items_limit, max_items, unique, diffs, ddiffs)
-        )
+    timestamp = timefuncs.formathttpdate(lastmod)
+    etag = "%d-%d-%d-%d-%d" % (lastmod, max_items, diffs, ddiffs, unique)
 
-    # emit channel description
-    handler.startNode('channel', {
-        (handler.xmlns['rdf'], 'about'): request.getBaseURL(),
-        })
-    handler.simpleNode('title', cfg.sitename)
-    handler.simpleNode('link', interwiki + wikiutil.quoteWikinameURL(pagename))
-    handler.simpleNode('description', 'RecentChanges at %s' % cfg.sitename)
-    if logo:
-        handler.simpleNode('image', None, {
-            (handler.xmlns['rdf'], 'resource'): logo,
-            })
-    if cfg.interwikiname:
-        handler.simpleNode(('wiki', 'interwiki'), cfg.interwikiname)
+    # for 304, we look at if-modified-since and if-none-match headers,
+    # one of them must match and the other is either not there or must match.
+    if request.if_modified_since == timestamp:
+        if request.if_none_match:
+            if request.if_none_match == etag:
+                request.emit_http_headers(["Status: 304 Not modified"])
+        else:
+            request.emit_http_headers(["Status: 304 Not modified"])
+    elif request.if_none_match == etag:
+        if request.if_modified_since:
+            if request.if_modified_since == timestamp:
+                request.emit_http_headers(["Status: 304 Not modified"])
+        else:
+            request.emit_http_headers(["Status: 304 Not modified"])
+    else:
+        # generate an Expires header, using whatever setting the admin
+        # defined for suggested cache lifetime of the RecentChanges RSS doc
+        expires = timefuncs.formathttpdate(time.time() + cfg.rss_cache)
 
-    handler.startNode('items')
-    handler.startNode(('rdf', 'Seq'))
-    for item in logdata:
-        link = "%s%s#%04d%02d%02d%02d%02d%02d" % ((interwiki,
-                wikiutil.quoteWikinameURL(item.pagename),) + item.time[:6])
-        handler.simpleNode(('rdf', 'li'), None, attr={
-            (handler.xmlns['rdf'], 'resource'): link,
-        })
-    handler.endNode(('rdf', 'Seq'))
-    handler.endNode('items')
-    handler.endNode('channel')
+        httpheaders = ["Content-Type: text/xml; charset=%s" % config.charset,
+                       "Expires: %s" % expires,
+                       "Last-Modified: %s" % timestamp,
+                       "Etag: %s" % etag, ]
 
-    # emit logo data
-    if logo:
-        handler.startNode('image', attr={
-            (handler.xmlns['rdf'], 'about'): logo,
+        # send the generated XML document
+        request.emit_http_headers(httpheaders)
+
+        interwiki = request.getBaseURL()
+        if interwiki[-1] != "/":
+            interwiki = interwiki + "/"
+
+        logo = re.search(r'src="([^"]*)"', cfg.logo_string)
+        if logo:
+            logo = request.getQualifiedURL(logo.group(1))
+
+        # prepare output
+        out = StringIO.StringIO()
+        handler = RssGenerator(out)
+
+        # start SAX stream
+        handler.startDocument()
+        handler._out.write(
+            '<!--\n'
+            '    Add an "items=nnn" URL parameter to get more than the default 15 items.\n'
+            '    You cannot get more than %d items though.\n'
+            '    \n'
+            '    Add "unique=1" to get a list of changes where page names are unique,\n'
+            '    i.e. where only the latest change of each page is reflected.\n'
+            '    \n'
+            '    Add "diffs=1" to add change diffs to the description of each items.\n'
+            '    \n'
+            '    Add "ddiffs=1" to link directly to the diff (good for FeedReader).\n'
+            '    Current settings: items=%i, unique=%i, diffs=%i, ddiffs=%i'
+            '-->\n' % (items_limit, max_items, unique, diffs, ddiffs)
+            )
+
+        # emit channel description
+        handler.startNode('channel', {
+            (handler.xmlns['rdf'], 'about'): request.getBaseURL(),
             })
         handler.simpleNode('title', cfg.sitename)
-        handler.simpleNode('link', interwiki)
-        handler.simpleNode('url', logo)
-        handler.endNode('image')
-
-    # emit items
-    for item in logdata:
-        page = Page(request, item.pagename)
-        link = interwiki + wikiutil.quoteWikinameURL(item.pagename)
-        rdflink = "%s#%04d%02d%02d%02d%02d%02d" % ((link,) + item.time[:6])
-        handler.startNode('item', attr={
-            (handler.xmlns['rdf'], 'about'): rdflink,
-        })
-
-        # general attributes
-        handler.simpleNode('title', item.pagename)
-        if ddiffs:
-            handler.simpleNode('link', link+"?action=diff")
-        else:
-            handler.simpleNode('link', link)
-
-        handler.simpleNode(('dc', 'date'), timefuncs.W3CDate(item.time))
-
-        # description
-        desc_text = item.comment
-        if diffs:
-            # TODO: rewrite / extend wikiutil.pagediff
-            # searching for the matching pages doesn't really belong here
-            revisions = page.getRevList()
-
-            rl = len(revisions)
-            for idx in range(rl):
-                rev = revisions[idx]
-                if rev <= item.rev:
-                    if idx+1 < rl:
-                        lines = wikiutil.pagediff(request, item.pagename, revisions[idx+1], item.pagename, 0, ignorews=1)
-                        if len(lines) > 20:
-                            lines = lines[:20] + ['...\n']
-                        lines = '\n'.join(lines)
-                        lines = wikiutil.escape(lines)
-                        desc_text = '%s\n<pre>\n%s\n</pre>\n' % (desc_text, lines)
-                    break
-        if desc_text:
-            handler.simpleNode('description', desc_text)
+        handler.simpleNode('link', interwiki + wikiutil.quoteWikinameURL(pagename))
+        handler.simpleNode('description', 'RecentChanges at %s' % cfg.sitename)
+        if logo:
+            handler.simpleNode('image', None, {
+                (handler.xmlns['rdf'], 'resource'): logo,
+                })
+        if cfg.interwikiname:
+            handler.simpleNode(('wiki', 'interwiki'), cfg.interwikiname)
 
-        # contributor
-        edattr = {}
-        if cfg.show_hosts:
-            edattr[(handler.xmlns['wiki'], 'host')] = item.hostname
-        if item.editor[0] == 'interwiki':
-            edname = "%s:%s" % item.editor[1]
-            ##edattr[(None, 'link')] = interwiki + wikiutil.quoteWikiname(edname)
-        else: # 'ip'
-            edname = item.editor[1]
-            ##edattr[(None, 'link')] = link + "?action=info"
-
-        # this edattr stuff, esp. None as first tuple element breaks things (tracebacks)
-        # if you know how to do this right, please send us a patch
-
-        handler.startNode(('dc', 'contributor'))
-        handler.startNode(('rdf', 'Description'), attr=edattr)
-        handler.simpleNode(('rdf', 'value'), edname)
-        handler.endNode(('rdf', 'Description'))
-        handler.endNode(('dc', 'contributor'))
+        handler.startNode('items')
+        handler.startNode(('rdf', 'Seq'))
+        for item in logdata:
+            link = "%s%s#%04d%02d%02d%02d%02d%02d" % ((interwiki,
+                    wikiutil.quoteWikinameURL(item.pagename),) + item.time[:6])
+            handler.simpleNode(('rdf', 'li'), None, attr={
+                (handler.xmlns['rdf'], 'resource'): link,
+            })
+        handler.endNode(('rdf', 'Seq'))
+        handler.endNode('items')
+        handler.endNode('channel')
 
-        # wiki extensions
-        handler.simpleNode(('wiki', 'version'), "%i" % (item.ed_time_usecs))
-        handler.simpleNode(('wiki', 'status'), ('deleted', 'updated')[page.exists()])
-        handler.simpleNode(('wiki', 'diff'), link + "?action=diff")
-        handler.simpleNode(('wiki', 'history'), link + "?action=info")
-        # handler.simpleNode(('wiki', 'importance'), ) # ( major | minor ) 
-        # handler.simpleNode(('wiki', 'version'), ) # ( #PCDATA ) 
-
-        handler.endNode('item')
-
-    # end SAX stream
-    handler.endDocument()
+        # emit logo data
+        if logo:
+            handler.startNode('image', attr={
+                (handler.xmlns['rdf'], 'about'): logo,
+                })
+            handler.simpleNode('title', cfg.sitename)
+            handler.simpleNode('link', interwiki)
+            handler.simpleNode('url', logo)
+            handler.endNode('image')
 
-    # generate an Expires header, using whatever setting the admin
-    # defined for suggested cache lifetime of the RecentChanges RSS doc
-    expires = timefuncs.formathttpdate(time.time() + cfg.rss_cache)
-
-    httpheaders = ["Content-Type: text/xml; charset=%s" % config.charset,
-                   "Expires: %s" % expires]
+        # emit items
+        for item in logdata:
+            page = Page(request, item.pagename)
+            link = interwiki + wikiutil.quoteWikinameURL(item.pagename)
+            rdflink = "%s#%04d%02d%02d%02d%02d%02d" % ((link,) + item.time[:6])
+            handler.startNode('item', attr={
+                (handler.xmlns['rdf'], 'about'): rdflink,
+            })
 
-    # use a correct Last-Modified header, set to whatever the mod date
-    # on the most recent page was; if there were no mods, don't send one
-    if lastmod:
-        httpheaders.append("Last-Modified: %s" % timefuncs.formathttpdate(lastmod))
+            # general attributes
+            handler.simpleNode('title', item.pagename)
+            if ddiffs:
+                handler.simpleNode('link', link+"?action=diff")
+            else:
+                handler.simpleNode('link', link)
 
-    # send the generated XML document
-    request.emit_http_headers(httpheaders)
-    request.write(out.getvalue())
+            handler.simpleNode(('dc', 'date'), timefuncs.W3CDate(item.time))
 
+            # description
+            desc_text = item.comment
+            if diffs:
+                # TODO: rewrite / extend wikiutil.pagediff
+                # searching for the matching pages doesn't really belong here
+                revisions = page.getRevList()
+
+                rl = len(revisions)
+                for idx in range(rl):
+                    rev = revisions[idx]
+                    if rev <= item.rev:
+                        if idx+1 < rl:
+                            lines = wikiutil.pagediff(request, item.pagename, revisions[idx+1], item.pagename, 0, ignorews=1)
+                            if len(lines) > 20:
+                                lines = lines[:20] + ['...\n']
+                            lines = '\n'.join(lines)
+                            lines = wikiutil.escape(lines)
+                            desc_text = '%s\n<pre>\n%s\n</pre>\n' % (desc_text, lines)
+                        break
+            if desc_text:
+                handler.simpleNode('description', desc_text)
+
+            # contributor
+            edattr = {}
+            if cfg.show_hosts:
+                edattr[(handler.xmlns['wiki'], 'host')] = item.hostname
+            if item.editor[0] == 'interwiki':
+                edname = "%s:%s" % item.editor[1]
+                ##edattr[(None, 'link')] = interwiki + wikiutil.quoteWikiname(edname)
+            else: # 'ip'
+                edname = item.editor[1]
+                ##edattr[(None, 'link')] = link + "?action=info"
+
+            # this edattr stuff, esp. None as first tuple element breaks things (tracebacks)
+            # if you know how to do this right, please send us a patch
+
+            handler.startNode(('dc', 'contributor'))
+            handler.startNode(('rdf', 'Description'), attr=edattr)
+            handler.simpleNode(('rdf', 'value'), edname)
+            handler.endNode(('rdf', 'Description'))
+            handler.endNode(('dc', 'contributor'))
+
+            # wiki extensions
+            handler.simpleNode(('wiki', 'version'), "%i" % (item.ed_time_usecs))
+            handler.simpleNode(('wiki', 'status'), ('deleted', 'updated')[page.exists()])
+            handler.simpleNode(('wiki', 'diff'), link + "?action=diff")
+            handler.simpleNode(('wiki', 'history'), link + "?action=info")
+            # handler.simpleNode(('wiki', 'importance'), ) # ( major | minor ) 
+            # handler.simpleNode(('wiki', 'version'), ) # ( #PCDATA ) 
+
+            handler.endNode('item')
+
+        # end SAX stream
+        handler.endDocument()
+
+        request.write(out.getvalue())
+
--- a/MoinMoin/request/__init__.py	Mon Jul 31 01:07:59 2006 +0200
+++ b/MoinMoin/request/__init__.py	Tue Aug 01 00:11:34 2006 +0200
@@ -336,8 +336,8 @@
         self.setHost(env.get('HTTP_HOST'))
         self.fixURI(env)
         self.setURL(env)
-
-        ##self.debugEnvironment(env)
+        self.getCachingHeaders(env)
+        #self.debugEnvironment(env)
 
     def setHttpReferer(self, referer):
         """ Set http_referer, making sure its ascii
@@ -431,6 +431,13 @@
             self.request_uri = self.makeURI()
         self.url = self.http_host + self.request_uri
 
+    def getCachingHeaders(self, env):
+        self.if_modified_since = (env.get('If-modified-since') or
+                                  env.get(cgiMetaVariable('If-modified-since')))
+        self.if_none_match = (env.get('If-none-match') or
+                                  env.get(cgiMetaVariable('If-none-match')))
+        self.log("inm: %s ims: %s" % (self.if_none_match, self.if_modified_since))
+
     def rewriteHost(self, env):
         """ Rewrite http_host transparently
         
@@ -1361,7 +1368,7 @@
             environment.append('  %s = %r\n' % (key, env[key]))
         environment = ''.join(environment)
 
-        data = '\nRequest Attributes\n%s\nEnviroment\n%s' % (attributes, environment)
+        data = '\nRequest Attributes\n%s\nEnvironment\n%s' % (attributes, environment)
         f = open('/tmp/env.log', 'a')
         try:
             f.write(data)