Commits

Anonymous committed 07b7e42

Ported ModPython handler to 0.7-stable

Comments (0)

Files changed (3)

         if self.headers.has_key('Cookie'):
             self.incookie.load(self.headers['Cookie'])
 
+    def get_header(self, name):
+        return self.headers.get(name)
+
     def parse_path(self, path):
         m = self.url_re.findall(self.path)
         if not m:
         start = time.time()
         self.init_request()
 
-        db = self.env.get_db_cnx()
-
         self.remote_user = None
         if self.path_info == '/login':
             self.remote_user = self.env.auth.do_auth(self)
             if not self.remote_user:
                 return
 
+        db = self.env.get_db_cnx()
         Wiki.populate_page_dict(db, self.env)
 
-        authenticator = auth.Authenticator(db, self)
-        http_referer = self.headers.get('Referer', None)
-        if self.path_info == '/logout':
-            authenticator.logout()
-            try:
-                self.redirect (http_referer or self.env.href.wiki())
-            except trac.core.RedirectException:
-                pass
-            return
-        if self.remote_user and authenticator.authname == 'anonymous':
-            authenticator.login(self)
-        if self.path_info == '/login':
-            try:
-                self.redirect (http_referer or self.env.href.wiki())
-            except trac.core.RedirectException:
-                pass
-            return
-
-        self.authname = authenticator.authname
-        
         # Parse arguments
         args = trac.core.parse_args(self.command, self.path_info,
                                     self.query_string,
                                     self.rfile, None, self.headers)
-        trac.core.add_args_to_hdf(args, self.hdf)
-        try:
-            pool = None
-            # Load the selected module
-            module = trac.core.module_factory(args, self.env, db, self)
-            pool = module.pool
-            module.run()
-        finally:
-            if pool:
-                svn.core.svn_pool_destroy(pool)
+
+        trac.core.dispatch_request(self.path_info, args, self, self.env, db)
+
         self.log.debug('Total request time: %f s', time.time() - start)
 
 
-
 def usage():
     print 'usage: %s [options] <database> [database] ...' % sys.argv[0]
     print '\nOptions:\n'

trac/ModPythonHandler.py

+# -*- coding: iso8859-1 -*-
+#
+# Copyright (C) 2004 Edgewall Software
+# Copyright (C) 2004 Christopher Lenz <cmlenz@gmx.de>
+#
+# Trac is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# Trac is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# Author: Christopher Lenz <cmlenz@gmx.de>
+
+import os
+import re, threading
+import auth, core, Environment, Href, Session, Wiki
+from util import TracError, href_join
+from mod_python import apache, util
+
+class ModPythonRequest(core.Request):
+
+    def __init__(self, req):
+        self.req = req
+
+    def init_request(self):
+        core.Request.init_request(self)
+        options = self.req.get_options()
+
+        if options.has_key('TracEnvParentDir') and self.req.path_info:
+            # We have to remove one path element from path_info when we're
+            # using TracEnvParentDir
+            self.path_info = re.sub('/[^/]+', '', self.req.path_info, 1)
+        else:
+            self.path_info = self.req.path_info
+            
+        if len(self.path_info):
+            self.cgi_location = self.req.uri[:-len(self.path_info)]
+        else:
+            self.cgi_location = self.req.uri
+
+        if len(self.req.path_info):
+            self.idx_location = self.req.uri[:-len(self.req.path_info)]
+        else:
+            self.idx_location = self.req.uri
+
+        # TODO This will need proxy host name support (see #437 and [581])
+        host = self.req.hostname
+        port = self.req.connection.local_addr[1]
+        if port == 80:
+            self.base_url = 'http://%s%s' % (host, self.cgi_location)
+        elif port == 443:
+            self.base_url = 'https://%s%s' % (host, self.cgi_location)
+        else:
+            self.base_url = 'http://%s:%d%s' % (host, port, self.cgi_location)
+
+        self.remote_addr = self.req.connection.remote_ip
+        self.remote_user = self.req.user
+        self.command = self.req.method
+
+        if self.req.headers_in.has_key('Cookie'):
+            self.incookie.load(self.req.headers_in['Cookie'])
+
+        self.hdf.setValue('HTTP.Host', self.req.hostname)
+
+    def read(self, len):
+        return self.req.read(len)
+
+    def write(self, data):
+        self.req.write(data)
+
+    def get_header(self, name):
+        return self.req.headers_in.get(name)
+
+    def send_response(self, code):
+        self.req.status = code
+
+    def send_header(self, name, value):
+        if name.lower() == 'content-type':
+            self.req.content_type = value
+        else:
+            self.req.headers_out.add(name, str(value))
+
+    def end_headers(self):
+        pass
+
+
+class TracFieldStorage(util.FieldStorage):
+    """
+    FieldStorage class with an added get function.
+    """
+    def get(self, key, default=''):
+        return util.FieldStorage.get(self, key, default)
+
+
+def send_project_index(req, mpr, dir):
+    req.content_type = 'text/html'
+    req.write('<html><head><title>Available Projects</title></head>')
+    req.write('<body><h1>Available Projects</h1><ul>')
+    for project in os.listdir(dir):
+        req.write('<li><a href="%s">%s</a></li>' % (href_join(mpr.idx_location,
+                                                              project),
+                                                    project))
+    req.write('</ul></body><html>')
+
+def open_environment(env_path, mpr):
+    env = Environment.Environment(env_path)
+    version = env.get_version()
+    if version < Environment.db_version:
+        raise TracError('The Trac environment needs to be upgraded. '
+                        'Run "trac-admin %s upgrade"' % env_path)
+    elif version > Environment.db_version:
+        raise TracError('Unknown Trac Environment version (%d).' % version)
+
+    env.href = Href.Href(mpr.cgi_location)
+    env.abs_href = Href.Href(mpr.base_url)
+    # Let the wiki module build a dictionary of all page names
+    database = env.get_db_cnx()
+    Wiki.populate_page_dict(database, env)
+    return env
+
+env_cache = {}
+env_cache_lock = threading.Lock()
+
+def get_environment(req, mpr):
+    global env_cache, env_cache_lock
+    options = req.get_options()
+    
+    if not options.has_key('TracEnv') and not options.has_key('TracEnvParentDir'):
+        raise EnvironmentError, \
+              'Missing PythonOption "TracEnv". Trac requires this option '\
+              'to point to a valid Trac Environment.'
+    
+    if options.has_key('TracEnv'):
+        env_path = options['TracEnv']
+        
+    elif options.has_key('TracEnvParentDir'):
+        env_parent_dir = options['TracEnvParentDir']
+        env_name = mpr.cgi_location.split('/')[-1]
+        env_path = os.path.join(env_parent_dir, env_name)
+        if len(env_name) == 0 or not os.path.exists(env_path):
+            send_project_index(req, mpr, env_parent_dir)
+            return None
+        
+    env_cache_lock.acquire()
+    if not env_path in env_cache:
+        env_cache[env_path] = open_environment(env_path, mpr)
+    env = env_cache[env_path]
+    env_cache_lock.release()
+    return env
+
+def handler(req):
+    global projects, projects_lock
+
+    mpr = ModPythonRequest(req)
+    mpr.init_request()
+
+    env = get_environment(req, mpr)
+    if not env:
+        return apache.OK
+
+    args = TracFieldStorage(req)
+    core.parse_path_info(args, mpr.path_info)
+
+    req.content_type = 'text/html'
+    try:
+        core.dispatch_request(mpr.path_info, args, mpr, env)
+    except Exception, e:
+        core.send_pretty_error(e, env, mpr)
+    return apache.OK
         self.incookie = Cookie.SimpleCookie()
         self.outcookie = Cookie.SimpleCookie()
 
+    def get_header(self, name):
+        raise RuntimeError, 'Virtual method not implemented'
+
     def send_response(self, code):
         raise RuntimeError, 'Virtual method not implemented'
 
     def write(self, data):
         return sys.stdout.write(data)
 
+    def get_header(self, name):
+        return os.getenv('HTTP_' + re.sub('-', '_', name.upper()))
+
     def send_response(self, code):
         self.write('Status: %d\r\n' % code)
     
     def end_headers(self):
         self.write('\r\n')
 
+def dispatch_request(path_info, args, req, env, database=None):
+    if not database:
+        database = env.get_db_cnx()
+
+    authenticator = auth.Authenticator(database, req)
+    if path_info == '/logout':
+        authenticator.logout()
+        try:
+            req.redirect(req.get_header('Referer') or env.href.wiki())
+        except RedirectException:
+            pass
+    elif req.remote_user and authenticator.authname == 'anonymous':
+        auth_cookie = authenticator.login(req)
+    if path_info == '/login':
+        try:
+            req.redirect(req.get_header('Referer') or env.href.wiki())
+        except RedirectException:
+            pass
+    req.authname = authenticator.authname
+
+    add_args_to_hdf(args, req.hdf)
+    try:
+        pool = None
+        # Load the selected module
+        module = module_factory(args, env, database, req)
+        pool = module.pool
+        module.run()
+    finally:
+        # We do this even if the cgi will terminate directly after. A pool
+        # destruction might trigger important clean-up functions.
+        if pool:
+            import svn.core
+            svn.core.svn_pool_destroy(pool)
 
 def open_svn_repos(repos_dir):
     from svn import util, repos, core
 
 def real_cgi_start():
     import Wiki
-    path_info = os.getenv('PATH_INFO')
-    http_referer = os.getenv('HTTP_REFERER')
 
     env = open_environment()
     database = env.get_db_cnx()
     env.href = Href.Href(req.cgi_location)
     env.abs_href = Href.Href(req.base_url)
 
-    authenticator = auth.Authenticator(database, req)
-    if path_info == '/logout':
-        authenticator.logout()
-        try:
-            req.redirect (http_referer or env.href.wiki())
-        except RedirectException:
-            pass
-    elif req.remote_user and authenticator.authname == 'anonymous':
-        auth_cookie = authenticator.login(req)
-    if path_info == '/login':
-        try:
-            req.redirect (http_referer or env.href.wiki())
-        except RedirectException:
-            pass
-            
     # Parse arguments
+    path_info = os.getenv('PATH_INFO')
     args = parse_args(req.command,
                       path_info, os.getenv('QUERY_STRING'),
                       sys.stdin, os.environ)
-    add_args_to_hdf(args, req.hdf)
-    req.authname = authenticator.authname
-    try:
-        pool = None
-        # Load the selected module
-        module = module_factory(args, env, database, req)
-        pool = module.pool
-        module.run()
-    finally:
-        # We do this even if the cgi will terminate directly after. A pool
-        # destruction might trigger important clean-up functions.
-        if pool:
-            import svn.core
-            svn.core.svn_pool_destroy(pool)
+    dispatch_request(path_info, args, req, env, database)
 
 def cgi_start():
     try:
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.