# HG changeset patch # User Marcin Kuzminski # Date 1317328487 -10800 # Node ID f4fed0b32103e8818faaaecbc2e3659a158163ad # Parent 5bd42279930c52e0457dac236ec6b246c968753f Rewrote git middleware with the same pattern as recent fix for #176 - additionally fixed dulwich server bug, that used old deprecated method. This fix caused huge improvement of speed for fetching git repos - moved simplehg and simplegit middleware into begining of pylons callstack. This low level middleware don't need to run any of the middlewares except each other. diff -r 5bd42279930c -r f4fed0b32103 rhodecode/config/middleware.py --- a/rhodecode/config/middleware.py Thu Sep 29 23:32:13 2011 +0300 +++ b/rhodecode/config/middleware.py Thu Sep 29 23:34:47 2011 +0300 @@ -51,9 +51,6 @@ from rhodecode.lib.profiler import ProfilingMiddleware app = ProfilingMiddleware(app) - app = SimpleHg(app, config) - app = SimpleGit(app, config) - if asbool(full_stack): # Handle Python exceptions app = ErrorHandler(app, global_conf, **config['pylons.errorware']) @@ -77,6 +74,11 @@ app = Cascade([static_app, app]) app = make_gzip_middleware(app, global_conf, compress_level=1) + # we want our low level middleware to get to the request ASAP. We don't + # need any pylons stack middleware in them + app = SimpleHg(app, config) + app = SimpleGit(app, config) + app.config = config return app diff -r 5bd42279930c -r f4fed0b32103 rhodecode/lib/middleware/simplegit.py --- a/rhodecode/lib/middleware/simplegit.py Thu Sep 29 23:32:13 2011 +0300 +++ b/rhodecode/lib/middleware/simplegit.py Thu Sep 29 23:34:47 2011 +0300 @@ -44,11 +44,11 @@ get_tagged=self.get_tagged) # Do they want any objects? - if len(objects_iter) == 0: + if objects_iter is None or len(objects_iter) == 0: return self.progress("counting objects: %d, done.\n" % len(objects_iter)) - dulserver.write_pack_data(dulserver.ProtocolFile(None, write), + dulserver.write_pack_objects(dulserver.ProtocolFile(None, write), objects_iter, len(objects_iter)) messages = [] messages.append('thank you for using rhodecode') @@ -96,12 +96,10 @@ def __init__(self, application, config): self.application = application self.config = config - #authenticate this git request using + # base path of repo locations + self.basepath = self.config['base_path'] + #authenticate this mercurial request using authfunc self.authenticate = AuthBasicAuthenticator('', authfunc) - self.ipaddr = '0.0.0.0' - self.repo_name = None - self.username = None - self.action = None def __call__(self, environ, start_response): if not is_git(environ): @@ -109,31 +107,34 @@ proxy_key = 'HTTP_X_REAL_IP' def_key = 'REMOTE_ADDR' - self.ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0')) + ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0')) + username = None # skip passing error to error controller environ['pylons.status_code_redirect'] = True #====================================================================== + # EXTRACT REPOSITORY NAME FROM ENV + #====================================================================== + try: + repo_name = self.__get_repository(environ) + log.debug('Extracted repo name is %s' % repo_name) + except: + return HTTPInternalServerError()(environ, start_response) + + #====================================================================== # GET ACTION PULL or PUSH #====================================================================== - self.action = self.__get_action(environ) - try: - #================================================================== - # GET REPOSITORY NAME - #================================================================== - self.repo_name = self.__get_repository(environ) - except: - return HTTPInternalServerError()(environ, start_response) + action = self.__get_action(environ) #====================================================================== # CHECK ANONYMOUS PERMISSION #====================================================================== - if self.action in ['pull', 'push']: + if action in ['pull', 'push']: anonymous_user = self.__get_user('default') - self.username = anonymous_user.username - anonymous_perm = self.__check_permission(self.action, + username = anonymous_user.username + anonymous_perm = self.__check_permission(action, anonymous_user, - self.repo_name) + repo_name) if anonymous_perm is not True or anonymous_user.active is False: if anonymous_perm is not True: @@ -162,56 +163,66 @@ # BASIC AUTH #============================================================== - if self.action in ['pull', 'push']: + if action in ['pull', 'push']: username = REMOTE_USER(environ) try: user = self.__get_user(username) - self.username = user.username + username = user.username except: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) #check permissions for this repository - perm = self.__check_permission(self.action, user, - self.repo_name) + perm = self.__check_permission(action, user, + repo_name) if perm is not True: return HTTPForbidden()(environ, start_response) - self.extras = {'ip': self.ipaddr, - 'username': self.username, - 'action': self.action, - 'repository': self.repo_name} + extras = {'ip': ipaddr, + 'username': username, + 'action': action, + 'repository': repo_name} #=================================================================== # GIT REQUEST HANDLING #=================================================================== - self.basepath = self.config['base_path'] - self.repo_path = os.path.join(self.basepath, self.repo_name) - #quick check if that dir exists... - if check_repo_fast(self.repo_name, self.basepath): + + repo_path = safe_str(os.path.join(self.basepath, repo_name)) + log.debug('Repository path is %s' % repo_path) + + # quick check if that dir exists... + if check_repo_fast(repo_name, self.basepath): return HTTPNotFound()(environ, start_response) + try: - app = self.__make_app() - except: + #invalidate cache on push + if action == 'push': + self.__invalidate_cache(repo_name) + + app = self.__make_app(repo_name, repo_path) + return app(environ, start_response) + except Exception: log.error(traceback.format_exc()) return HTTPInternalServerError()(environ, start_response) - #invalidate cache on push - if self.action == 'push': - self.__invalidate_cache(self.repo_name) + def __make_app(self, repo_name, repo_path): + """ + Make an wsgi application using dulserver + + :param repo_name: name of the repository + :param repo_path: full path to the repository + """ - return app(environ, start_response) - - def __make_app(self): - _d = {'/' + self.repo_name: Repo(self.repo_path)} + _d = {'/' + repo_name: Repo(repo_path)} backend = dulserver.DictBackend(_d) gitserve = HTTPGitApplication(backend) return gitserve def __check_permission(self, action, user, repo_name): - """Checks permissions using action (push/pull) user and repository + """ + Checks permissions using action (push/pull) user and repository name :param action: push or pull action @@ -235,7 +246,8 @@ return True def __get_repository(self, environ): - """Get's repository name out of PATH_INFO header + """ + Get's repository name out of PATH_INFO header :param environ: environ where PATH_INFO is stored """ @@ -274,3 +286,4 @@ invalidate the cache to see the changes right away but only for push requests""" invalidate_cache('get_repo_cached_%s' % repo_name) +