# HG changeset patch # User Marcin Kuzminski # Date 2016-09-06 17:49:28 # Node ID a5f278c1f8304a4ed901bfebb2e43b5ffdfbea56 # Parent 3d871443d0ab4f650e691b04a935c9ce2022a167 vcs: register repo_name as specialized middleware variables instead of relying on env variables. - use order of defined vcs.backends to detect middleware for handling requests diff --git a/rhodecode/lib/middleware/simplevcs.py b/rhodecode/lib/middleware/simplevcs.py --- a/rhodecode/lib/middleware/simplevcs.py +++ b/rhodecode/lib/middleware/simplevcs.py @@ -50,7 +50,6 @@ from rhodecode.lib.vcs.backends import b from rhodecode.model import meta from rhodecode.model.db import User, Repository from rhodecode.model.scm import ScmModel -from rhodecode.model.settings import SettingsModel log = logging.getLogger(__name__) @@ -88,8 +87,10 @@ class SimpleVCS(object): self.registry = registry self.application = application self.config = config - # re-populated by specialized middlewares + # re-populated by specialized middleware + self.repo_name = None self.repo_vcs_config = base.Config() + # base path of repo locations self.basepath = get_rhodecode_base_path() # authenticate this VCS request using authfunc @@ -115,9 +116,7 @@ class SimpleVCS(object): def _get_by_id(self, repo_name): """ Gets a special pattern _ from clone url and tries to replace it - with a repository_name for support of _ non changable urls - - :param repo_name: + with a repository_name for support of _ non changeable urls """ data = repo_name.split('/') @@ -234,6 +233,12 @@ class SimpleVCS(object): log.debug('User not allowed to proceed, %s', reason) return HTTPNotAcceptable(reason)(environ, start_response) + if not self.repo_name: + log.warning('Repository name is empty: %s', self.repo_name) + # failed to get repo name, we fail now + return HTTPNotFound()(environ, start_response) + log.debug('Extracted repo name is %s', self.repo_name) + ip_addr = get_ip_addr(environ) username = None @@ -241,17 +246,6 @@ class SimpleVCS(object): environ['pylons.status_code_redirect'] = True # ====================================================================== - # EXTRACT REPOSITORY NAME FROM ENV SET IN `class VCSMiddleware` - # ====================================================================== - repo_name = environ['REPO_NAME'] - log.debug('Extracted repo name is %s', repo_name) - - # check for type, presence in database and on filesystem - if not self.is_valid_and_existing_repo( - repo_name, self.basepath, self.SCM): - return HTTPNotFound()(environ, start_response) - - # ====================================================================== # GET ACTION PULL or PUSH # ====================================================================== action = self._get_action(environ) @@ -265,7 +259,7 @@ class SimpleVCS(object): if anonymous_user.active: # ONLY check permissions if the user is activated anonymous_perm = self._check_permission( - action, anonymous_user, repo_name, ip_addr) + action, anonymous_user, self.repo_name, ip_addr) else: anonymous_perm = False @@ -329,7 +323,8 @@ class SimpleVCS(object): return HTTPNotAcceptable(reason)(environ, start_response) # check permissions for this repository - perm = self._check_permission(action, user, repo_name, ip_addr) + perm = self._check_permission( + action, user, self.repo_name, ip_addr) if not perm: return HTTPForbidden()(environ, start_response) @@ -337,14 +332,14 @@ class SimpleVCS(object): # in hooks executed by rhodecode check_locking = _should_check_locking(environ.get('QUERY_STRING')) extras = vcs_operation_context( - environ, repo_name=repo_name, username=username, + environ, repo_name=self.repo_name, username=username, action=action, scm=self.SCM, check_locking=check_locking) # ====================================================================== # REQUEST HANDLING # ====================================================================== - str_repo_name = safe_str(repo_name) + str_repo_name = safe_str(self.repo_name) repo_path = os.path.join(safe_str(self.basepath), str_repo_name) log.debug('Repository path is %s', repo_path) @@ -355,7 +350,7 @@ class SimpleVCS(object): action, self.SCM, str_repo_name, safe_str(username), ip_addr) return self._generate_vcs_response( - environ, start_response, repo_path, repo_name, extras, action) + environ, start_response, repo_path, self.repo_name, extras, action) @initialize_generator def _generate_vcs_response( diff --git a/rhodecode/lib/middleware/vcs.py b/rhodecode/lib/middleware/vcs.py --- a/rhodecode/lib/middleware/vcs.py +++ b/rhodecode/lib/middleware/vcs.py @@ -24,12 +24,13 @@ import logging import tempfile import urlparse +from webob.exc import HTTPNotFound + import rhodecode from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled from rhodecode.lib.middleware.simplegit import SimpleGit, GIT_PROTO_PAT from rhodecode.lib.middleware.simplehg import SimpleHg from rhodecode.lib.middleware.simplesvn import SimpleSvn -from rhodecode.lib.vcs.backends import base from rhodecode.model.settings import VcsSettingsModel log = logging.getLogger(__name__) @@ -132,8 +133,14 @@ class VCSMiddleware(object): self.config = config self.appenlight_client = appenlight_client self.registry = registry - self.repo_vcs_config = base.Config() self.use_gzip = True + # order in which we check the middlewares, based on vcs.backends config + self.check_middlewares = config['vcs.backends'] + self.checks = { + 'hg': (is_hg, SimpleHg), + 'git': (is_git, SimpleGit), + 'svn': (is_svn, SimpleSvn), + } def vcs_config(self, repo_name=None): """ @@ -141,43 +148,50 @@ class VCSMiddleware(object): """ return VcsSettingsModel(repo=repo_name).get_ui_settings_as_config_obj() - def wrap_in_gzip_if_enabled(self, app): + def wrap_in_gzip_if_enabled(self, app, config): if self.use_gzip: app = GunzipMiddleware(app) return app def _get_handler_app(self, environ): app = None - - if is_hg(environ): - app = SimpleHg(self.application, self.config, self.registry) - - if is_git(environ): - app = SimpleGit(self.application, self.config, self.registry) - - if is_svn(environ): - app = SimpleSvn(self.application, self.config, self.registry) - - if app: - # translate the _REPO_ID into real repo NAME for usage - # in midddleware - environ['PATH_INFO'] = app._get_by_id(environ['PATH_INFO']) - repo_name = app._get_repository_name(environ) - environ['REPO_NAME'] = repo_name - - self.repo_vcs_config = self.vcs_config(repo_name) - app.repo_vcs_config = self.repo_vcs_config - - app = self.wrap_in_gzip_if_enabled(app) - app, _ = wrap_in_appenlight_if_enabled( - app, self.config, self.appenlight_client) + log.debug('Checking vcs types in order: %r', self.check_middlewares) + for vcs_type in self.check_middlewares: + vcs_check, handler = self.checks[vcs_type] + if vcs_check(environ): + log.debug( + 'Found VCS Middleware to handle the request %s', handler) + app = handler(self.application, self.config, self.registry) + break return app def __call__(self, environ, start_response): - # check if we handle one of interesting protocols ? + # check if we handle one of interesting protocols, optionally extract + # specific vcsSettings and allow changes of how things are wrapped vcs_handler = self._get_handler_app(environ) if vcs_handler: + # translate the _REPO_ID into real repo NAME for usage + # in middleware + environ['PATH_INFO'] = vcs_handler._get_by_id(environ['PATH_INFO']) + repo_name = vcs_handler._get_repository_name(environ) + + # check for type, presence in database and on filesystem + if not vcs_handler.is_valid_and_existing_repo( + repo_name, vcs_handler.basepath, vcs_handler.SCM): + return HTTPNotFound()(environ, start_response) + + # TODO(marcink): this is probably not needed anymore + environ['REPO_NAME'] = repo_name + + # register repo_name and it's config back to the handler + vcs_handler.repo_name = repo_name + vcs_handler.repo_vcs_config = self.vcs_config(repo_name) + + vcs_handler = self.wrap_in_gzip_if_enabled( + vcs_handler, self.config) + vcs_handler, _ = wrap_in_appenlight_if_enabled( + vcs_handler, self.config, self.appenlight_client) return vcs_handler(environ, start_response) return self.application(environ, start_response) diff --git a/rhodecode/tests/lib/middleware/test_simplevcs.py b/rhodecode/tests/lib/middleware/test_simplevcs.py --- a/rhodecode/tests/lib/middleware/test_simplevcs.py +++ b/rhodecode/tests/lib/middleware/test_simplevcs.py @@ -42,6 +42,10 @@ class StubVCSController(simplevcs.Simple SCM = 'hg' stub_response_body = tuple() + def __init__(self, *args, **kwargs): + super(StubVCSController, self).__init__(*args, **kwargs) + self.repo_name = HG_REPO + def _get_repository_name(self, environ): return HG_REPO diff --git a/rhodecode/tests/lib/middleware/test_vcs.py b/rhodecode/tests/lib/middleware/test_vcs.py --- a/rhodecode/tests/lib/middleware/test_vcs.py +++ b/rhodecode/tests/lib/middleware/test_vcs.py @@ -105,7 +105,7 @@ class TestVCSMiddleware(object): 'HTTP_DAV': 'http://subversion.tigris.org/xmlns/dav/svn/log' } application = Mock() - config = {'appenlight': False} + config = {'appenlight': False, 'vcs.backends': ['svn']} registry = Mock() middleware = vcs.VCSMiddleware( application, config=config, @@ -125,7 +125,7 @@ class TestVCSMiddleware(object): 'HTTP_DAV': 'http://subversion.tigris.org/xmlns/dav/svn/log' } application = Mock() - config = {'appenlight': False} + config = {'appenlight': False, 'vcs.backends': ['svn']} registry = Mock() middleware = vcs.VCSMiddleware( application, config=config,