Changeset - aaacb075c3f3
[Not reviewed]
default
0 2 0
Mads Kiilerich - 9 years ago 2017-01-04 23:16:08
mads@kiilerich.com
hg: return 400 Bad Request for hg commands that not are commands

Avoid throwing bare Exceptions which requires framework specific testing.
Instead, return a reasonable http error code and make the test more framework
independent.

The "helpful" message will just be a description of the http exception and not
sent to the client.
2 files changed with 15 insertions and 21 deletions:
0 comments (0 inline, 0 general)
kallithea/lib/middleware/simplehg.py
Show inline comments
 
@@ -25,25 +25,25 @@ Original author and date, and relevant c
 
:copyright: (c) 2013 RhodeCode GmbH, and others.
 
:license: GPLv3, see LICENSE.md for more details.
 

	
 
"""
 

	
 

	
 
import os
 
import logging
 
import traceback
 

	
 
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError, \
 
    HTTPNotAcceptable
 
    HTTPNotAcceptable, HTTPBadRequest
 
from kallithea.model.db import User
 

	
 
from kallithea.lib.utils2 import safe_str, safe_unicode, fix_PATH, get_server_url, \
 
    _set_extras
 
from kallithea.lib.base import BaseVCSController, WSGIResultCloseCallback
 
from kallithea.lib.utils import make_ui, is_valid_repo, ui_sections
 
from kallithea.lib.vcs.utils.hgcompat import RepoError, hgweb_mod
 
from kallithea.lib.exceptions import HTTPLockedRC
 
from kallithea.lib import auth_modules
 

	
 
log = logging.getLogger(__name__)
 

	
 
@@ -56,25 +56,24 @@ def is_mercurial(environ):
 
    http_accept = environ.get('HTTP_ACCEPT')
 
    path_info = environ['PATH_INFO']
 
    if http_accept and http_accept.startswith('application/mercurial'):
 
        ishg_path = True
 
    else:
 
        ishg_path = False
 

	
 
    log.debug('pathinfo: %s detected as Mercurial %s',
 
        path_info, ishg_path
 
    )
 
    return ishg_path
 

	
 

	
 
class SimpleHg(BaseVCSController):
 

	
 
    def _handle_request(self, environ, start_response):
 
        if not is_mercurial(environ):
 
            return self.application(environ, start_response)
 

	
 
        ip_addr = self._get_ip_addr(environ)
 
        username = None
 
        # skip passing error to error controller
 
        environ['pylons.status_code_redirect'] = True
 

	
 
        #======================================================================
 
@@ -88,25 +87,28 @@ class SimpleHg(BaseVCSController):
 
            log.debug('Extracted repo name is %s', repo_name)
 
        except Exception as e:
 
            log.error('error extracting repo_name: %r', e)
 
            return HTTPInternalServerError()(environ, start_response)
 

	
 
        # quick check if that dir exists...
 
        if not is_valid_repo(repo_name, self.basepath, 'hg'):
 
            return HTTPNotFound()(environ, start_response)
 

	
 
        #======================================================================
 
        # GET ACTION PULL or PUSH
 
        #======================================================================
 
        action = self.__get_action(environ)
 
        try:
 
            action = self.__get_action(environ)
 
        except HTTPBadRequest as e:
 
            return e(environ, start_response)
 

	
 
        #======================================================================
 
        # CHECK ANONYMOUS PERMISSION
 
        #======================================================================
 
        if action in ['pull', 'push']:
 
            anonymous_user = User.get_default_user(cache=True)
 
            username = anonymous_user.username
 
            if anonymous_user.active:
 
                # ONLY check permissions if the user is activated
 
                anonymous_perm = self._check_permission(action, anonymous_user,
 
                                                        repo_name, ip_addr)
 
            else:
 
@@ -250,45 +252,37 @@ class SimpleHg(BaseVCSController):
 
            environ['PATH_INFO'] = self._get_by_id(environ['PATH_INFO'])
 
            repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            if repo_name.endswith('/'):
 
                repo_name = repo_name.rstrip('/')
 
        except Exception:
 
            log.error(traceback.format_exc())
 
            raise
 

	
 
        return repo_name
 

	
 
    def __get_action(self, environ):
 
        """
 
        Maps mercurial request commands into a clone,pull or push command.
 
        This should always return a valid command string
 
        Maps mercurial request commands into a pull or push command.
 

	
 
        :param environ:
 
        Raises HTTPBadRequest if the request environment doesn't look like a hg client.
 
        """
 
        mapping = {'changegroup': 'pull',
 
                   'changegroupsubset': 'pull',
 
                   'stream_out': 'pull',
 
                   'listkeys': 'pull',
 
                   'unbundle': 'push',
 
                   'pushkey': 'push', }
 
        mapping = {'unbundle': 'push',
 
                   'pushkey': 'push'}
 
        for qry in environ['QUERY_STRING'].split('&'):
 
            if qry.startswith('cmd'):
 
                cmd = qry.split('=')[-1]
 
                if cmd in mapping:
 
                    return mapping[cmd]
 
                return mapping.get(cmd, 'pull')
 

	
 
                return 'pull'
 

	
 
        raise Exception('Unable to detect pull/push action !!'
 
                        'Are you using non standard command or client ?')
 
        # Note: the client doesn't get the helpful error message
 
        raise HTTPBadRequest('Unable to detect pull/push action! Are you using non standard command or client?')
 

	
 
    def __inject_extras(self, repo_path, baseui, extras=None):
 
        """
 
        Injects some extra params into baseui instance
 

	
 
        also overwrites global settings with those takes from local hgrc file
 

	
 
        :param baseui: baseui instance
 
        :param extras: dict with extra params to put into baseui
 
        """
 

	
 
        hgrc = os.path.join(repo_path, '.hg', 'hgrc')
kallithea/tests/functional/test_admin_repos.py
Show inline comments
 
@@ -603,15 +603,15 @@ class TestAdminReposControllerGIT(_BaseT
 
    OTHER_TYPE_REPO = HG_REPO
 
    OTHER_TYPE = 'hg'
 

	
 

	
 
class TestAdminReposControllerHG(_BaseTestCase):
 
    REPO = HG_REPO
 
    REPO_TYPE = 'hg'
 
    NEW_REPO = NEW_HG_REPO
 
    OTHER_TYPE_REPO = GIT_REPO
 
    OTHER_TYPE = 'git'
 

	
 
    def test_permanent_url_protocol_access(self):
 
        with pytest.raises(Exception) as e:
 
            self.app.get(url('summary_home', repo_name='_1'), extra_environ={'HTTP_ACCEPT': 'application/mercurial'})
 
        assert 'Unable to detect pull/push action' in str(e)
 
        # 400 Bad Request - Unable to detect pull/push action
 
        self.app.get(url('summary_home', repo_name='_1'), extra_environ={'HTTP_ACCEPT': 'application/mercurial'},
 
                     status=400)
0 comments (0 inline, 0 general)