def tearDown(self): self.repos.close() self.repos = None # clear cached repositories to avoid TypeError on termination (#11505) RepositoryManager(self.env).reload_repositories() self.env.reset_db() # needed to avoid issue with 'WindowsError: The process cannot access # the file ... being used by another process: ...\rep-cache.db' self.env.shutdown(get_thread_id())
def dispatch_request(environ, start_response): """Main entry point for the Trac web interface. :param environ: the WSGI environment dict :param start_response: the WSGI callback for starting the response """ global _warn_setuptools if _warn_setuptools is False: _warn_setuptools = True warn_setuptools_issue(out=environ.get('wsgi.errors')) # SCRIPT_URL is an Apache var containing the URL before URL rewriting # has been applied, so we can use it to reconstruct logical SCRIPT_NAME script_url = environ.get('SCRIPT_URL') if script_url is not None: path_info = environ.get('PATH_INFO') if not path_info: environ['SCRIPT_NAME'] = script_url else: # mod_wsgi squashes slashes in PATH_INFO (!) script_url = _slashes_re.sub('/', script_url) path_info = _slashes_re.sub('/', path_info) if script_url.endswith(path_info): environ['SCRIPT_NAME'] = script_url[:-len(path_info)] # If the expected configuration keys aren't found in the WSGI environment, # try looking them up in the process environment variables environ.setdefault('trac.env_path', os.getenv('TRAC_ENV')) environ.setdefault('trac.env_parent_dir', os.getenv('TRAC_ENV_PARENT_DIR')) environ.setdefault('trac.env_index_template', os.getenv('TRAC_ENV_INDEX_TEMPLATE')) environ.setdefault('trac.template_vars', os.getenv('TRAC_TEMPLATE_VARS')) environ.setdefault('trac.locale', '') environ.setdefault('trac.base_url', os.getenv('TRAC_BASE_URL')) locale.setlocale(locale.LC_ALL, environ['trac.locale']) # Determine the environment env_path = environ.get('trac.env_path') if not env_path: env_parent_dir = environ.get('trac.env_parent_dir') env_paths = environ.get('trac.env_paths') if env_parent_dir or env_paths: # The first component of the path is the base name of the # environment path_info = environ.get('PATH_INFO', '').lstrip('/').split('/') env_name = path_info.pop(0) if not env_name: # No specific environment requested, so render an environment # index page send_project_index(environ, start_response, env_parent_dir, env_paths) return [] errmsg = None # To make the matching patterns of request handlers work, we append # the environment name to the `SCRIPT_NAME` variable, and keep only # the remaining path in the `PATH_INFO` variable. script_name = environ.get('SCRIPT_NAME', '') try: script_name = unicode(script_name, 'utf-8') except UnicodeDecodeError: errmsg = 'Invalid URL encoding (was %r)' % script_name else: # (as Href expects unicode parameters) environ['SCRIPT_NAME'] = Href(script_name)(env_name) environ['PATH_INFO'] = '/' + '/'.join(path_info) if env_parent_dir: env_path = os.path.join(env_parent_dir, env_name) else: env_path = get_environments(environ).get(env_name) if not env_path or not os.path.isdir(env_path): errmsg = 'Environment not found' if errmsg: start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(errmsg)))]) return [errmsg] if not env_path: raise EnvironmentError('The environment options "TRAC_ENV" or ' '"TRAC_ENV_PARENT_DIR" or the mod_python ' 'options "TracEnv" or "TracEnvParentDir" are ' 'missing. Trac requires one of these options ' 'to locate the Trac environment(s).') run_once = environ['wsgi.run_once'] env = env_error = None try: env = open_environment(env_path, use_cache=not run_once) except Exception as e: env_error = e else: if env.base_url_for_redirect: environ['trac.base_url'] = env.base_url # Web front-end type and version information if not hasattr(env, 'webfrontend'): mod_wsgi_version = environ.get('mod_wsgi.version') if mod_wsgi_version: mod_wsgi_version = ( "%s (WSGIProcessGroup %s WSGIApplicationGroup %s)" % ('.'.join(str(x) for x in mod_wsgi_version), environ.get('mod_wsgi.process_group'), environ.get('mod_wsgi.application_group') or '%{GLOBAL}')) environ.update({ 'trac.web.frontend': 'mod_wsgi', 'trac.web.version': mod_wsgi_version}) env.webfrontend = environ.get('trac.web.frontend') if env.webfrontend: env.webfrontend_version = environ['trac.web.version'] req = RequestWithSession(environ, start_response) # fixup env.abs_href if `[trac] base_url` was not specified if env and not env.abs_href.base: env.abs_href = req.abs_href translation.make_activable(lambda: req.locale, env.path if env else None) resp = [] try: if env_error: raise HTTPInternalServerError(env_error) dispatcher = RequestDispatcher(env) dispatcher.set_default_callbacks(req) try: dispatcher.dispatch(req) except RequestDone as req_done: resp = req_done.iterable except HTTPException as e: if not req.response_started: _send_user_error(req, env, e) except Exception: if not req.response_started: send_internal_error(env, req, sys.exc_info()) else: resp = resp or req._response or [] finally: translation.deactivate() if env and not run_once: env.shutdown(get_thread_id()) # Now it's a good time to do some clean-ups # # Note: enable the '##' lines as soon as there's a suspicion # of memory leak due to uncollectable objects (typically # objects with a __del__ method caught in a cycle) # ##gc.set_debug(gc.DEBUG_UNCOLLECTABLE) unreachable = gc.collect() ##env.log.debug("%d unreachable objects found.", unreachable) ##uncollectable = len(gc.garbage) ##if uncollectable: ## del gc.garbage[:] ## env.log.warning("%d uncollectable objects found.", ## uncollectable) return resp
def tearDown(self): self.env.reset_db() # needed to avoid issue with 'WindowsError: The process cannot access # the file ... being used by another process: ...\rep-cache.db' self.env.shutdown(get_thread_id())
def get_cnx(self, connector, kwargs, timeout=None): cnx = None log = kwargs.get('log') key = unicode(kwargs) start = time_now() tid = get_thread_id() # Get a Connection, either directly or a deferred one with self._available: # First choice: Return the same cnx already used by the thread if (tid, key) in self._active: cnx, num = self._active[(tid, key)] num += 1 else: if self._waiters == 0: cnx = self._take_cnx(connector, kwargs, key, tid) if not cnx: self._waiters += 1 self._available.wait() self._waiters -= 1 cnx = self._take_cnx(connector, kwargs, key, tid) num = 1 if cnx: self._active[(tid, key)] = (cnx, num) deferred = num == 1 and isinstance(cnx, tuple) exc_info = (None, None, None) if deferred: # Potentially lengthy operations must be done without lock held op, cnx = cnx try: if op == 'ping': cnx.ping() elif op == 'close': cnx.close() if op in ('close', 'create'): cnx = connector.get_connection(**kwargs) except TracError: exc_info = sys.exc_info() cnx = None except Exception: exc_info = sys.exc_info() if log: log.error('Exception caught on %s', op, exc_info=True) cnx = None if cnx and not isinstance(cnx, tuple): if deferred: # replace placeholder with real Connection with self._available: self._active[(tid, key)] = (cnx, num) return PooledConnection(self, cnx, key, tid, log) if deferred: # cnx couldn't be reused, clear placeholder with self._available: del self._active[(tid, key)] if op == 'ping': # retry return self.get_cnx(connector, kwargs) # if we didn't get a cnx after wait(), something's fishy... if isinstance(exc_info[1], TracError): raise exc_info[0], exc_info[1], exc_info[2] timeout = time_now() - start errmsg = _( "Unable to get database connection within %(time)d seconds.", time=timeout) if exc_info[1]: errmsg += " (%s)" % exception_to_unicode(exc_info[1]) raise TimeoutError(errmsg)