Changeset - b88150a90804
[Not reviewed]
default
0 3 0
Mads Kiilerich - 7 years ago 2019-01-10 03:34:45
mads@kiilerich.com
middleware: unify Mercurial and Git _handle_request in the VCS base class

Finally, it is more clear in what the VCSs are different ... and what generic
setup code is needed.
3 files changed with 58 insertions and 114 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/base.py
Show inline comments
 
@@ -40,29 +40,29 @@ import paste.httpexceptions
 
import paste.auth.basic
 
import paste.httpheaders
 
from webhelpers.pylonslib import secure_form
 

	
 
from tg import config, tmpl_context as c, request, response, session, render_template
 
from tg import TGController
 
from tg.i18n import ugettext as _
 

	
 
from kallithea import __version__, BACKENDS
 

	
 
from kallithea.config.routing import url
 
from kallithea.lib.utils2 import str2bool, safe_unicode, AttributeDict, \
 
    safe_str, safe_int
 
    safe_str, safe_int, get_server_url, _set_extras
 
from kallithea.lib import auth_modules
 
from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware
 
from kallithea.lib.compat import json
 
from kallithea.lib.utils import get_repo_slug
 
from kallithea.lib.utils import get_repo_slug, is_valid_repo
 
from kallithea.lib.exceptions import UserCreationError
 
from kallithea.lib.vcs.exceptions import RepositoryError, EmptyRepositoryError, ChangesetDoesNotExistError
 
from kallithea.model import meta
 

	
 
from kallithea.model.db import PullRequest, Repository, User, Setting
 
from kallithea.model.scm import ScmModel
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def render(template_path):
 
    return render_template({'url': url}, 'mako', template_path)
 
@@ -297,33 +297,81 @@ class BaseVCSController(object):
 
                                              'repository.admin')(authuser,
 
                                                                  repo_name):
 
                return False
 

	
 
        return True
 

	
 
    def _get_ip_addr(self, environ):
 
        return _get_ip_addr(environ)
 

	
 
    def __call__(self, environ, start_response):
 
        start = time.time()
 
        try:
 
            # try parsing a request for this VCS - if it fails, call the wrapped app
 
            parsed_request = self.parse_request(environ)
 
            if parsed_request is None:
 
                return self.application(environ, start_response)
 
            return self._handle_request(parsed_request, environ, start_response)
 

	
 
            # skip passing error to error controller
 
            environ['pylons.status_code_redirect'] = True
 

	
 
            # quick check if repo exists...
 
            if not is_valid_repo(parsed_request.repo_name, self.basepath, self.scm_alias):
 
                raise webob.exc.HTTPNotFound()
 

	
 
            if parsed_request.action is None:
 
                # Note: the client doesn't get the helpful error message
 
                raise webob.exc.HTTPBadRequest('Unable to detect pull/push action for %r! Are you using a nonstandard command or client?' % parsed_request.repo_name)
 

	
 
            #======================================================================
 
            # CHECK PERMISSIONS
 
            #======================================================================
 
            ip_addr = self._get_ip_addr(environ)
 
            user, response_app = self._authorize(environ, parsed_request.action, parsed_request.repo_name, ip_addr)
 
            if response_app is not None:
 
                return response_app(environ, start_response)
 

	
 
            # extras are injected into Mercurial UI object and later available
 
            # in hooks executed by Kallithea
 
            from kallithea import CONFIG
 
            extras = {
 
                'ip': ip_addr,
 
                'username': user.username,
 
                'action': parsed_request.action,
 
                'repository': parsed_request.repo_name,
 
                'scm': self.scm_alias,
 
                'config': CONFIG['__file__'],
 
                'server_url': get_server_url(environ),
 
            }
 

	
 
            #======================================================================
 
            # REQUEST HANDLING
 
            #======================================================================
 
            log.debug('HOOKS extras is %s', extras)
 
            _set_extras(extras)
 

	
 
            try:
 
                log.info('%s action on %s repo "%s" by "%s" from %s',
 
                         parsed_request.action, self.scm_alias, parsed_request.repo_name, safe_str(user.username), ip_addr)
 
                app = self._make_app(parsed_request)
 
                return app(environ, start_response)
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                raise webob.exc.HTTPInternalServerError()
 

	
 
        except webob.exc.HTTPException as e:
 
            return e(environ, start_response)
 
        finally:
 
            log = logging.getLogger('kallithea.' + self.__class__.__name__)
 
            log.debug('Request time: %.3fs', time.time() - start)
 
            log_ = logging.getLogger('kallithea.' + self.__class__.__name__)
 
            log_.debug('Request time: %.3fs', time.time() - start)
 
            meta.Session.remove()
 

	
 

	
 
class BaseController(TGController):
 

	
 
    def _before(self, *args, **kwargs):
 
        """
 
        _before is called before controller methods and after __call__
 
        """
 
        if request.needs_csrf_check:
 
            # CSRF protection: Whenever a request has ambient authority (whether
 
            # through a session cookie or its origin IP address), it must include
kallithea/lib/middleware/simplegit.py
Show inline comments
 
@@ -21,33 +21,29 @@ It's implemented with basic auth functio
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 28, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 

	
 
"""
 

	
 

	
 
import re
 
import logging
 
import traceback
 

	
 
from webob.exc import HTTPNotFound, HTTPInternalServerError, HTTPBadRequest
 

	
 
from kallithea.model.db import Ui, Repository
 
from kallithea.lib.utils2 import safe_str, safe_unicode, get_server_url, \
 
    _set_extras
 
from kallithea.lib.utils2 import safe_unicode
 
from kallithea.lib.base import BaseVCSController
 
from kallithea.lib.utils import make_ui, is_valid_repo
 
from kallithea.lib.utils import make_ui
 
from kallithea.lib.hooks import log_pull_action
 
from kallithea.lib.middleware.pygrack import make_wsgi_app
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
GIT_PROTO_PAT = re.compile(r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)$')
 

	
 

	
 
cmd_mapping = {
 
    'git-receive-pack': 'push',
 
    'git-upload-pack': 'pull',
 
@@ -71,72 +67,24 @@ class SimpleGit(BaseVCSController):
 
            cmd = m.group(2)
 

	
 
            query_string = environ['QUERY_STRING']
 
            if cmd == 'info/refs' and query_string.startswith('service='):
 
                service = query_string.split('=', 1)[1]
 
                action = cmd_mapping.get(service)
 
            else:
 
                service = None
 
                action = cmd_mapping.get(cmd)
 

	
 
        return parsed_request
 

	
 
    def _handle_request(self, parsed_request, environ, start_response):
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        # quick check if repo exists...
 
        if not is_valid_repo(parsed_request.repo_name, self.basepath, self.scm_alias):
 
            raise HTTPNotFound()
 

	
 
        if parsed_request.action is None:
 
            # Note: the client doesn't get the helpful error message
 
            raise HTTPBadRequest('Unable to detect pull/push action for %r! Are you using a nonstandard command or client?' % parsed_request.repo_name)
 

	
 
        #======================================================================
 
        # CHECK PERMISSIONS
 
        #======================================================================
 
        ip_addr = self._get_ip_addr(environ)
 
        user, response_app = self._authorize(environ, parsed_request.action, parsed_request.repo_name, ip_addr)
 
        if response_app is not None:
 
            return response_app(environ, start_response)
 

	
 
        # extras are injected into Mercurial UI object and later available
 
        # in hooks executed by Kallithea
 
        from kallithea import CONFIG
 
        extras = {
 
            'ip': ip_addr,
 
            'username': user.username,
 
            'action': parsed_request.action,
 
            'repository': parsed_request.repo_name,
 
            'scm': self.scm_alias,
 
            'config': CONFIG['__file__'],
 
            'server_url': get_server_url(environ),
 
        }
 

	
 
        #======================================================================
 
        # REQUEST HANDLING
 
        #======================================================================
 
        log.debug('HOOKS extras is %s', extras)
 
        _set_extras(extras)
 

	
 
        try:
 
            log.info('%s action on %s repo "%s" by "%s" from %s',
 
                     parsed_request.action, self.scm_alias, parsed_request.repo_name, safe_str(user.username), ip_addr)
 
            app = self._make_app(parsed_request)
 
            return app(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise HTTPInternalServerError()
 

	
 
    def _make_app(self, parsed_request):
 
        """
 
        Return a pygrack wsgi application.
 
        """
 
        pygrack_app = make_wsgi_app(parsed_request.repo_name, self.basepath)
 

	
 
        def wrapper_app(environ, start_response):
 
            if (parsed_request.cmd == 'info/refs' and
 
                parsed_request.service == 'git-upload-pack'
 
                ):
 
                baseui = make_ui()
 
                repo = Repository.get_by_repo_name(parsed_request.repo_name)
kallithea/lib/middleware/simplehg.py
Show inline comments
 
@@ -21,34 +21,30 @@ It's implemented with basic auth functio
 
This file was forked by the Kallithea project in July 2014.
 
Original author and date, and relevant copyright and licensing information is below:
 
:created_on: Apr 28, 2010
 
:author: marcink
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 

	
 
"""
 

	
 

	
 
import os
 
import logging
 
import traceback
 
import urllib
 

	
 
from webob.exc import HTTPNotFound, HTTPInternalServerError, HTTPBadRequest
 

	
 
from kallithea.lib.utils2 import safe_str, safe_unicode, get_server_url, \
 
    _set_extras
 
from kallithea.lib.utils2 import safe_str, safe_unicode
 
from kallithea.lib.base import BaseVCSController
 
from kallithea.lib.utils import make_ui, is_valid_repo
 
from kallithea.lib.vcs.utils.hgcompat import RepoError, hgweb_mod
 
from kallithea.lib.utils import make_ui
 
from kallithea.lib.vcs.utils.hgcompat import hgweb_mod
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
def get_header_hgarg(environ):
 
    """Decode the special Mercurial encoding of big requests over multiple headers.
 
    >>> get_header_hgarg({})
 
    ''
 
    >>> get_header_hgarg({'HTTP_X_HGARG_0': ' ', 'HTTP_X_HGARG_1': 'a','HTTP_X_HGARG_2': '','HTTP_X_HGARG_3': 'b+c %20'})
 
    'ab+c %20'
 
    """
 
    chunks = []
 
@@ -126,72 +122,24 @@ class SimpleHg(BaseVCSController):
 
                            cmd, _args = urllib.unquote_plus(cmd_arg).split(' ', 1)
 
                            op = cmd_mapping.get(cmd, 'push')
 
                            if op != 'pull':
 
                                assert op == 'push'
 
                                action = 'push'
 
                                break
 
                    else:
 
                        action = cmd_mapping.get(cmd, 'push')
 
                    break # only process one cmd
 

	
 
        return parsed_request
 

	
 
    def _handle_request(self, parsed_request, environ, start_response):
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        # quick check if repo exists...
 
        if not is_valid_repo(parsed_request.repo_name, self.basepath, self.scm_alias):
 
            raise HTTPNotFound()
 

	
 
        if parsed_request.action is None:
 
            # Note: the client doesn't get the helpful error message
 
            raise HTTPBadRequest('Unable to detect pull/push action for %r! Are you using a nonstandard command or client?' % parsed_request.repo_name)
 

	
 
        #======================================================================
 
        # CHECK PERMISSIONS
 
        #======================================================================
 
        ip_addr = self._get_ip_addr(environ)
 
        user, response_app = self._authorize(environ, parsed_request.action, parsed_request.repo_name, ip_addr)
 
        if response_app is not None:
 
            return response_app(environ, start_response)
 

	
 
        # extras are injected into Mercurial UI object and later available
 
        # in hooks executed by Kallithea
 
        from kallithea import CONFIG
 
        extras = {
 
            'ip': ip_addr,
 
            'username': user.username,
 
            'action': parsed_request.action,
 
            'repository': parsed_request.repo_name,
 
            'scm': self.scm_alias,
 
            'config': CONFIG['__file__'],
 
            'server_url': get_server_url(environ),
 
        }
 

	
 
        #======================================================================
 
        # REQUEST HANDLING
 
        #======================================================================
 
        log.debug('HOOKS extras is %s', extras)
 
        _set_extras(extras)
 

	
 
        try:
 
            log.info('%s action on %s repo "%s" by "%s" from %s',
 
                     parsed_request.action, self.scm_alias, parsed_request.repo_name, safe_str(user.username), ip_addr)
 
            app = self._make_app(parsed_request)
 
            return app(environ, start_response)
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise HTTPInternalServerError()
 

	
 
    def _make_app(self, parsed_request):
 
        """
 
        Make an hgweb wsgi application.
 
        """
 
        str_repo_name = safe_str(parsed_request.repo_name)
 
        repo_path = os.path.join(safe_str(self.basepath), str_repo_name)
 
        baseui = make_ui(repo_path=repo_path)
 
        hgweb_app = hgweb_mod.hgweb(repo_path, name=str_repo_name, baseui=baseui)
 

	
 
        def wrapper_app(environ, start_response):
 
            environ['REPO_NAME'] = str_repo_name # used by hgweb_mod.hgweb
 
            return hgweb_app(environ, start_response)
0 comments (0 inline, 0 general)