diff --git a/rhodecode/config/middleware.py b/rhodecode/config/middleware.py
--- a/rhodecode/config/middleware.py
+++ b/rhodecode/config/middleware.py
@@ -43,9 +43,10 @@ from rhodecode.config import patches
from rhodecode.config.routing import STATIC_FILE_PREFIX
from rhodecode.config.environment import (
load_environment, load_pyramid_environment)
+from rhodecode.lib.exceptions import VCSServerUnavailable
+from rhodecode.lib.vcs.exceptions import VCSCommunicationError
from rhodecode.lib.middleware import csrf
from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
-from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
from rhodecode.lib.middleware.https_fixup import HttpsFixup
from rhodecode.lib.middleware.vcs import VCSMiddleware
from rhodecode.lib.plugins.utils import register_rhodecode_plugin
@@ -188,10 +189,6 @@ def make_not_found_view(config):
pylons_app_as_view = wsgiapp(pylons_app)
- # Protect from VCS Server error related pages when server is not available
- if not vcs_server_enabled:
- pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
-
def pylons_app_with_error_handler(context, request):
"""
Handle exceptions from rc pylons app:
@@ -216,10 +213,17 @@ def make_not_found_view(config):
return error_handler(response, request)
except HTTPError as e: # pyramid type exceptions
return error_handler(e, request)
- except Exception:
+ except Exception as e:
+ log.exception(e)
+
if settings.get('debugtoolbar.enabled', False):
raise
+
+ if isinstance(e, VCSCommunicationError):
+ return error_handler(VCSServerUnavailable(), request)
+
return error_handler(HTTPInternalServerError(), request)
+
return response
return pylons_app_with_error_handler
diff --git a/rhodecode/lib/exceptions.py b/rhodecode/lib/exceptions.py
--- a/rhodecode/lib/exceptions.py
+++ b/rhodecode/lib/exceptions.py
@@ -23,6 +23,7 @@ Set of custom exceptions used in RhodeCo
"""
from webob.exc import HTTPClientError
+from pyramid.httpexceptions import HTTPBadGateway
class LdapUsernameError(Exception):
@@ -120,3 +121,14 @@ class NotAllowedToCreateUserError(Except
class RepositoryCreationError(Exception):
pass
+
+
+class VCSServerUnavailable(HTTPBadGateway):
+ """ HTTP Exception class for VCS Server errors """
+ code = 502
+ title = 'VCS Server Error'
+ def __init__(self, message=''):
+ self.explanation = 'Could not connect to VCS Server'
+ if message:
+ self.explanation += ': ' + message
+ super(VCSServerUnavailable, self).__init__()
diff --git a/rhodecode/lib/middleware/disable_vcs.py b/rhodecode/lib/middleware/disable_vcs.py
deleted file mode 100644
--- a/rhodecode/lib/middleware/disable_vcs.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (C) 2015-2016 RhodeCode GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License, version 3
-# (only), as published by the Free Software Foundation.
-#
-# 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 Affero General Public License
-# along with this program. If not, see .
-#
-# This program is dual-licensed. If you wish to learn more about the
-# RhodeCode Enterprise Edition, including its added features, Support services,
-# and proprietary license terms, please see https://rhodecode.com/licenses/
-
-"""
-Disable VCS pages when VCS Server is not available
-"""
-
-import logging
-import re
-from pyramid.httpexceptions import HTTPBadGateway
-
-log = logging.getLogger(__name__)
-
-
-class VCSServerUnavailable(HTTPBadGateway):
- """ HTTP Exception class for when VCS Server is unavailable """
- code = 502
- title = 'VCS Server Required'
- explanation = 'A VCS Server is required for this action. There is currently no VCS Server configured.'
-
-class DisableVCSPagesWrapper(object):
- """
- Pyramid view wrapper to disable all pages that require VCS Server to be
- running, avoiding that errors explode to the user.
-
- This Wrapper should be enabled only in case VCS Server is not available
- for the instance.
- """
-
- VCS_NOT_REQUIRED = [
- '^/$',
- ('/_admin(?!/settings/mapping)(?!/my_account/repos)'
- '(?!/create_repository)(?!/gists)(?!/notifications/)'
- ),
- ]
- _REGEX_VCS_NOT_REQUIRED = [re.compile(path) for path in VCS_NOT_REQUIRED]
-
- def _check_vcs_requirement(self, path_info):
- """
- Tries to match the current path to one of the safe URLs to be rendered.
- Displays an error message in case
- """
- for regex in self._REGEX_VCS_NOT_REQUIRED:
- safe_url = regex.match(path_info)
- if safe_url:
- return True
-
- # Url is not safe to be rendered without VCS Server
- log.debug('accessing: `%s` with VCS Server disabled', path_info)
- return False
-
- def __init__(self, handler):
- self.handler = handler
-
- def __call__(self, context, request):
- if not self._check_vcs_requirement(request.path):
- raise VCSServerUnavailable('VCS Server is not available')
-
- return self.handler(context, request)
diff --git a/rhodecode/lib/vcs/client.py b/rhodecode/lib/vcs/client.py
--- a/rhodecode/lib/vcs/client.py
+++ b/rhodecode/lib/vcs/client.py
@@ -305,7 +305,7 @@ def _get_proxy_method(proxy, name):
try:
return getattr(proxy, name)
except CommunicationError:
- raise CommunicationError(
+ raise exceptions.PyroVCSCommunicationError(
'Unable to connect to remote pyro server %s' % proxy)
diff --git a/rhodecode/lib/vcs/client_http.py b/rhodecode/lib/vcs/client_http.py
--- a/rhodecode/lib/vcs/client_http.py
+++ b/rhodecode/lib/vcs/client_http.py
@@ -36,6 +36,7 @@ import urllib2
import urlparse
import uuid
+import pycurl
import msgpack
import requests
@@ -172,7 +173,11 @@ class RemoteObject(object):
def _remote_call(url, payload, exceptions_map, session):
- response = session.post(url, data=msgpack.packb(payload))
+ try:
+ response = session.post(url, data=msgpack.packb(payload))
+ except pycurl.error as e:
+ raise exceptions.HttpVCSCommunicationError(e)
+
response = msgpack.unpackb(response.content)
error = response.get('error')
if error:
diff --git a/rhodecode/lib/vcs/exceptions.py b/rhodecode/lib/vcs/exceptions.py
--- a/rhodecode/lib/vcs/exceptions.py
+++ b/rhodecode/lib/vcs/exceptions.py
@@ -24,6 +24,19 @@ Custom vcs exceptions module.
import functools
import urllib2
+import pycurl
+from Pyro4.errors import CommunicationError
+
+class VCSCommunicationError(Exception):
+ pass
+
+
+class PyroVCSCommunicationError(VCSCommunicationError):
+ pass
+
+
+class HttpVCSCommunicationError(VCSCommunicationError):
+ pass
class VCSError(Exception):
@@ -161,7 +174,6 @@ def map_vcs_exceptions(func):
try:
return func(*args, **kwargs)
except Exception as e:
-
# The error middleware adds information if it finds
# __traceback_info__ in a frame object. This way the remote
# traceback information is made available in error reports.
@@ -182,5 +194,4 @@ def map_vcs_exceptions(func):
raise _EXCEPTION_MAP[kind](*e.args)
else:
raise
-
return wrapper
diff --git a/rhodecode/tests/lib/middleware/test_disable_vcs.py b/rhodecode/tests/lib/middleware/test_disable_vcs.py
deleted file mode 100644
--- a/rhodecode/tests/lib/middleware/test_disable_vcs.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# Copyright (C) 2010-2016 RhodeCode GmbH
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License, version 3
-# (only), as published by the Free Software Foundation.
-#
-# 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 Affero General Public License
-# along with this program. If not, see .
-#
-# This program is dual-licensed. If you wish to learn more about the
-# RhodeCode Enterprise Edition, including its added features, Support services,
-# and proprietary license terms, please see https://rhodecode.com/licenses/
-
-import pytest
-from pyramid.response import Response
-from pyramid.testing import DummyRequest
-from rhodecode.lib.middleware.disable_vcs import (
- DisableVCSPagesWrapper, VCSServerUnavailable)
-
-
-@pytest.mark.parametrize('url, should_raise', [
- ('/', False),
- ('/_admin/settings', False),
- ('/_admin/i_am_fine', False),
- ('/_admin/settings/mappings', True),
- ('/_admin/my_account/repos', True),
- ('/_admin/create_repository', True),
- ('/_admin/gists/1', True),
- ('/_admin/notifications/1', True),
-])
-def test_vcs_disabled(url, should_raise):
- wrapped_view = DisableVCSPagesWrapper(pyramid_view)
- request = DummyRequest(path=url)
-
- if should_raise:
- with pytest.raises(VCSServerUnavailable):
- response = wrapped_view(None, request)
- else:
- response = wrapped_view(None, request)
- assert response.status_int == 200
-
-def pyramid_view(context, request):
- """
- A mock pyramid view to be used in the wrapper
- """
- return Response('success')
diff --git a/rhodecode/tests/lib/middleware/test_vcs_unavailable.py b/rhodecode/tests/lib/middleware/test_vcs_unavailable.py
new file mode 100644
--- /dev/null
+++ b/rhodecode/tests/lib/middleware/test_vcs_unavailable.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+
+# Copyright (C) 2010-2016 RhodeCode GmbH
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License, version 3
+# (only), as published by the Free Software Foundation.
+#
+# 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 Affero General Public License
+# along with this program. If not, see .
+#
+# This program is dual-licensed. If you wish to learn more about the
+# RhodeCode Enterprise Edition, including its added features, Support services,
+# and proprietary license terms, please see https://rhodecode.com/licenses/
+
+import mock
+import pytest
+import rhodecode.lib.vcs.client as client
+
+@pytest.mark.usefixtures('autologin_user', 'app')
+def test_vcs_available_returns_summary_page(app, backend):
+ url = '/{repo_name}'.format(repo_name=backend.repo.repo_name)
+ response = app.get(url)
+ assert response.status_code == 200
+ assert 'Summary' in response.body
+
+
+@pytest.mark.usefixtures('autologin_user', 'app')
+def test_vcs_unavailable_returns_vcs_error_page(app, backend):
+ url = '/{repo_name}'.format(repo_name=backend.repo.repo_name)
+
+ with mock.patch.object(client, '_get_proxy_method') as p:
+ p.side_effect = client.exceptions.PyroVCSCommunicationError()
+ response = app.get(url, expect_errors=True)
+
+ assert response.status_code == 502
+ assert 'Could not connect to VCS Server' in response.body