Robert Brewer avatar Robert Brewer committed 094d3db

New tools.referer, and moved test_response_headers into new test_misc_tools.

Comments (0)

Files changed (5)

cherrypy/_cptools.py

             request.handler = None
         else:
             # Note the devious technique here of adding hooks on the fly
-            request.hooks.attach('before_finalize', _caching.tee_output)
+            request.hooks.attach('before_finalize', _caching.tee_output,
+                                 priority = 90)
+    _wrapper.priority = 20
     
     def _setup(self):
         """Hook caching into cherrypy.request."""
 default_toolbox.tidy = Tool('before_finalize', tidy.tidy)
 default_toolbox.nsgmls = Tool('before_finalize', tidy.nsgmls)
 default_toolbox.ignore_headers = Tool('before_request_body', cptools.ignore_headers)
+default_toolbox.referer = Tool('before_request_body', cptools.referer)
 
 
 del cptools, encoding, static, tidy

cherrypy/lib/cptools.py

 """Functions for builtin CherryPy tools."""
 
+import re
+
 import cherrypy
 from cherrypy.lib import http as _http
 
 response_headers.failsafe = True
 
 
+def referer(pattern, accept=True, accept_missing=False, error=403,
+            message='Forbidden Referer header.'):
+    """Raise HTTPError if Referer header does not pass our test.
+    
+    pattern: a regular expression pattern to test against the Referer.
+    accept: if True, the Referer must match the pattern; if False,
+        the Referer must NOT match the pattern.
+    accept_missing: if True, permit requests with no Referer header.
+    error: the HTTP error code to return to the client on failure.
+    message: a string to include in the response body on failure.
+    """
+    try:
+        match = bool(re.match(pattern, cherrypy.request.headers['Referer']))
+        if accept == match:
+            return
+    except KeyError:
+        if accept_missing:
+            return
+    
+    raise cherrypy.HTTPError(error, message)
+
+
 class SessionAuth(object):
     """Assert that the user is logged in."""
     

cherrypy/test/test.py

         'test_etags',
         'test_gzip',
         'test_objectmapping',
-        'test_response_headers',
+        'test_misc_tools',
         'test_static',
         'test_tutorials',
         'test_virtualhost',

cherrypy/test/test_misc_tools.py

+from cherrypy.test import test
+test.prefer_parent_path()
+
+import cherrypy
+from cherrypy import tools
+
+
+def setup_server():
+    class Root:
+        def index(self):
+            yield "Hello, world"
+        index.exposed = True
+        h = [("Content-Language", "en-GB"), ('Content-Type', 'text/plain')]
+        tools.response_headers(headers=h)(index)
+        
+        def other(self):
+            return "salut"
+        other.exposed = True
+        other._cp_config = {
+            'tools.response_headers.on': True,
+            'tools.response_headers.headers': [("Content-Language", "fr"),
+                                               ('Content-Type', 'text/plain')],
+            }
+    
+    class Referer:
+        def accept(self):
+            return "Accepted!"
+        accept.exposed = True
+        reject = accept
+    
+    conf = {'/referer': {'tools.referer.on': True,
+                         'tools.referer.pattern': r'http://[^/]*thisdomain\.com',
+                         },
+            '/referer/reject': {'tools.referer.accept': False,
+                                'tools.referer.accept_missing': True,
+                                },
+            }
+    
+    root = Root()
+    root.referer = Referer()
+    cherrypy.tree.mount(root, config=conf)
+    cherrypy.config.update({'environment': 'test_suite'})
+
+
+from cherrypy.test import helper
+
+class ResponseHeadersTest(helper.CPWebCase):
+
+    def testResponseHeadersDecorator(self):
+        self.getPage('/')
+        self.assertHeader("Content-Language", "en-GB")
+        self.assertHeader('Content-Type', 'text/plain')
+
+    def testResponseHeaders(self):
+        self.getPage('/other')
+        self.assertHeader("Content-Language", "fr")
+        self.assertHeader('Content-Type', 'text/plain')
+
+
+class RefererTest(helper.CPWebCase):
+    
+    def testReferer(self):
+        self.getPage('/referer/accept')
+        self.assertErrorPage(403, 'Forbidden Referer header.')
+        
+        self.getPage('/referer/accept',
+                     headers=[('Referer', 'http://www.thisdomain.com/')])
+        self.assertStatus(200)
+        self.assertBody('Accepted!')
+        
+        # Reject
+        self.getPage('/referer/reject')
+        self.assertStatus(200)
+        self.assertBody('Accepted!')
+        
+        self.getPage('/referer/reject',
+                     headers=[('Referer', 'http://www.thisdomain.com/')])
+        self.assertErrorPage(403, 'Forbidden Referer header.')
+
+
+if __name__ == "__main__":
+    setup_server()
+    helper.testmain()

cherrypy/test/test_response_headers.py

-from cherrypy.test import test
-test.prefer_parent_path()
-
-import cherrypy
-from cherrypy import tools
-
-
-def setup_server():
-    class Root:
-        def index(self):
-            yield "Hello, world"
-        index.exposed = True
-        h = [("Content-Language", "en-GB"), ('Content-Type', 'text/plain')]
-        tools.response_headers(headers=h)(index)
-        
-        def other(self):
-            return "salut"
-        other.exposed = True
-        other._cp_config = {
-            'tools.response_headers.on': True,
-            'tools.response_headers.headers': [("Content-Language", "fr"),
-                                               ('Content-Type', 'text/plain')],
-            }
-    
-    cherrypy.tree.mount(Root())
-    cherrypy.config.update({'environment': 'test_suite'})
-
-
-from cherrypy.test import helper
-
-class ResponseHeadersTest(helper.CPWebCase):
-
-    def testResponseHeadersDecorator(self):
-        self.getPage('/')
-        self.assertHeader("Content-Language", "en-GB")
-        self.assertHeader('Content-Type', 'text/plain')
-
-    def testResponseHeaders(self):
-        self.getPage('/other')
-        self.assertHeader("Content-Language", "fr")
-        self.assertHeader('Content-Type', 'text/plain')
-
-if __name__ == "__main__":
-    setup_server()
-    helper.testmain()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.