Changeset - 6c23e72437e3
[Not reviewed]
default
0 1 0
Marcin Kuzminski - 15 years ago 2010-07-04 00:52:47
marcin@python-works.com
mercurial middleware now returns 500's instead of 404 on errors and 404 when repo not found, added tracebacks
1 file changed with 17 insertions and 6 deletions:
0 comments (0 inline, 0 general)
pylons_app/lib/middleware/simplehg.py
Show inline comments
 
#!/usr/bin/env python
 
# encoding: utf-8
 
# middleware to handle mercurial api calls
 
# Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
 
from mercurial.error import RepoError
 
 
 
# This program is free software; you can redistribute it and/or
 
# modify it under the terms of the GNU General Public License
 
# as published by the Free Software Foundation; version 2
 
# of the License or (at your opinion) any later version of the license.
 
# 
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
# 
 
# You should have received a copy of the GNU General Public License
 
@@ -23,28 +24,29 @@ Created on 2010-04-28
 

	
 
@author: marcink
 
SimpleHG middleware for handling mercurial protocol request (push/clone etc.)
 
It's implemented with basic auth function
 
"""
 
from datetime import datetime
 
from itertools import chain
 
from mercurial.hgweb import hgweb
 
from mercurial.hgweb.request import wsgiapplication
 
from paste.auth.basic import AuthBasicAuthenticator
 
from paste.httpheaders import REMOTE_USER, AUTH_TYPE
 
from pylons_app.lib.auth import authfunc, HasPermissionAnyMiddleware
 
from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache
 
from pylons_app.lib.utils import is_mercurial, make_ui, invalidate_cache, \
 
    check_repo_fast
 
from pylons_app.model import meta
 
from pylons_app.model.db import UserLog, User
 
from webob.exc import HTTPNotFound, HTTPForbidden
 
from webob.exc import HTTPNotFound, HTTPForbidden, HTTPInternalServerError
 
import logging
 
import os
 
import traceback
 
log = logging.getLogger(__name__)
 

	
 
class SimpleHg(object):
 

	
 
    def __init__(self, application, config):
 
        self.application = application
 
        self.config = config
 
        #authenticate this mercurial request using 
 
        realm = '%s %s' % (self.config['hg_app_name'], 'mercurial repository')
 
@@ -59,40 +61,41 @@ class SimpleHg(object):
 
            #===================================================================
 
            username = REMOTE_USER(environ)
 
            if not username:
 
                result = self.authenticate(environ)
 
                if isinstance(result, str):
 
                    AUTH_TYPE.update(environ, 'basic')
 
                    REMOTE_USER.update(environ, result)
 
                else:
 
                    return result.wsgi_application(environ, start_response)
 
            
 
            try:
 
                repo_name = '/'.join(environ['PATH_INFO'].split('/')[1:])
 
            except Exception as e:
 
            except:
 
                log.error(traceback.format_exc())
 
                return HTTPNotFound()(environ, start_response)
 
                return HTTPInternalServerError()(environ, start_response)
 
            
 
            #===================================================================
 
            # CHECK PERMISSIONS FOR THIS REQUEST
 
            #===================================================================
 
            action = self.__get_action(environ)
 
            if action:
 
                username = self.__get_environ_user(environ)
 
                try:
 
                    sa = meta.Session
 
                    user = sa.query(User)\
 
                        .filter(User.username == username).one()
 
                except:
 
                    return HTTPNotFound()(environ, start_response)
 
                    log.error(traceback.format_exc())
 
                    return HTTPInternalServerError()(environ, start_response)
 
                #check permissions for this repository
 
                if action == 'pull':
 
                    if not HasPermissionAnyMiddleware('repository.read',
 
                                                      'repository.write',
 
                                                      'repository.admin')\
 
                                                        (user, repo_name):
 
                        return HTTPForbidden()(environ, start_response)
 
                if action == 'push':
 
                    if not HasPermissionAnyMiddleware('repository.write',
 
                                                      'repository.admin')\
 
                                                        (user, repo_name):
 
                        return HTTPForbidden()(environ, start_response)
 
@@ -101,29 +104,37 @@ class SimpleHg(object):
 
                proxy_key = 'HTTP_X_REAL_IP'
 
                def_key = 'REMOTE_ADDR'
 
                ipaddr = environ.get(proxy_key, environ.get(def_key, '0.0.0.0'))
 
                self.__log_user_action(user, action, repo_name, ipaddr)            
 
            
 
            #===================================================================
 
            # MERCURIAL REQUEST HANDLING
 
            #===================================================================
 
            environ['PATH_INFO'] = '/'#since we wrap into hgweb, reset the path
 
            self.baseui = make_ui(self.config['hg_app_repo_conf'])
 
            self.basepath = self.config['base_path']
 
            self.repo_path = os.path.join(self.basepath, repo_name)
 

	
 
            #quick check if that dir exists...
 
            if check_repo_fast(repo_name, self.basepath):
 
                return HTTPNotFound()(environ, start_response)
 
            
 
            try:
 
                app = wsgiapplication(self.__make_app)
 
            except RepoError as e:
 
                if str(e).find('not found') != -1:
 
                    return HTTPNotFound()(environ, start_response)
 
            except Exception:
 
                log.error(traceback.format_exc())
 
                return HTTPNotFound()(environ, start_response)
 
                return HTTPInternalServerError()(environ, start_response)
 
            
 
            
 
            #invalidate cache on push
 
            if action == 'push':
 
                self.__invalidate_cache(repo_name)
 
                
 
            messages = ['thanks for using hg app !']
 
            return self.msg_wrapper(app, environ, start_response, messages)            
 

	
 

	
 
    def msg_wrapper(self, app, environ, start_response, messages):
 
        """
0 comments (0 inline, 0 general)