Index: trac/web/api.py
===================================================================
--- trac/web/api.py	(revision 2165)
+++ trac/web/api.py	(working copy)
@@ -239,6 +239,15 @@
         """
 
 
+class IRequestPreprocessor(Interface):
+    """Extension point interface for request preprocessors."""
+
+    def preprocess_request(req):
+        """Preprocess the request. This allows any last-minute processing before
+        the request is dispatched to the request handler.
+        """
+
+
 def absolute_url(req, path=None):
     """Reconstruct the absolute URL of the given request.
     
Index: trac/web/main.py
===================================================================
--- trac/web/main.py	(revision 2165)
+++ trac/web/main.py	(working copy)
@@ -23,7 +23,7 @@
 from trac.perm import PermissionCache, PermissionError
 from trac.util import escape, enum
 from trac.web.api import absolute_url, Request, RequestDone, IAuthenticator, \
-                         IRequestHandler
+                         IRequestPreprocessor, IRequestHandler
 from trac.web.chrome import Chrome
 from trac.web.clearsilver import HDFWrapper
 from trac.web.href import Href
@@ -59,6 +59,7 @@
     """Component responsible for dispatching requests to registered handlers."""
 
     authenticators = ExtensionPoint(IAuthenticator)
+    preprocessors = ExtensionPoint(IRequestPreprocessor)
     handlers = ExtensionPoint(IRequestHandler)
 
     def authenticate(self, req):
@@ -99,6 +100,9 @@
 
         chrome.populate_hdf(req, chosen_handler)
 
+        for preprocessor in self.preprocessors:
+            preprocessor.preprocess_request(req)
+
         if not chosen_handler:
             # FIXME: Should return '404 Not Found' to the client
             raise TracError, 'No handler matched request to %s' % req.path_info

