##// END OF EJS Templates
vcs: Skip error handling in case of responses from VCSMiddleware.
Martin Bornhold -
r601:e1a806ed default
parent child Browse files
Show More
@@ -1,454 +1,462 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Pylons middleware initialization
22 Pylons middleware initialization
23 """
23 """
24 import logging
24 import logging
25 from collections import OrderedDict
25 from collections import OrderedDict
26
26
27 from paste.registry import RegistryManager
27 from paste.registry import RegistryManager
28 from paste.gzipper import make_gzip_middleware
28 from paste.gzipper import make_gzip_middleware
29 from pylons.wsgiapp import PylonsApp
29 from pylons.wsgiapp import PylonsApp
30 from pyramid.authorization import ACLAuthorizationPolicy
30 from pyramid.authorization import ACLAuthorizationPolicy
31 from pyramid.config import Configurator
31 from pyramid.config import Configurator
32 from pyramid.settings import asbool, aslist
32 from pyramid.settings import asbool, aslist
33 from pyramid.wsgi import wsgiapp
33 from pyramid.wsgi import wsgiapp
34 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
34 from pyramid.httpexceptions import HTTPError, HTTPInternalServerError
35 from pylons.controllers.util import redirect
35 from pylons.controllers.util import redirect
36 from pyramid.events import ApplicationCreated
36 from pyramid.events import ApplicationCreated
37 import pyramid.httpexceptions as httpexceptions
37 import pyramid.httpexceptions as httpexceptions
38 from pyramid.renderers import render_to_response
38 from pyramid.renderers import render_to_response
39 from routes.middleware import RoutesMiddleware
39 from routes.middleware import RoutesMiddleware
40 import routes.util
40 import routes.util
41
41
42 import rhodecode
42 import rhodecode
43 import rhodecode.integrations # do not remove this as it registers celery tasks
43 import rhodecode.integrations # do not remove this as it registers celery tasks
44 from rhodecode.config import patches
44 from rhodecode.config import patches
45 from rhodecode.config.routing import STATIC_FILE_PREFIX
45 from rhodecode.config.routing import STATIC_FILE_PREFIX
46 from rhodecode.config.environment import (
46 from rhodecode.config.environment import (
47 load_environment, load_pyramid_environment)
47 load_environment, load_pyramid_environment)
48 from rhodecode.lib.middleware import csrf
48 from rhodecode.lib.middleware import csrf
49 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
49 from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
50 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
50 from rhodecode.lib.middleware.disable_vcs import DisableVCSPagesWrapper
51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
51 from rhodecode.lib.middleware.https_fixup import HttpsFixup
52 from rhodecode.lib.middleware.vcs import VCSMiddleware
52 from rhodecode.lib.middleware.vcs import VCSMiddleware
53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
53 from rhodecode.lib.plugins.utils import register_rhodecode_plugin
54 from rhodecode.subscribers import scan_repositories_if_enabled
54 from rhodecode.subscribers import scan_repositories_if_enabled
55
55
56
56
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59
59
60 # this is used to avoid avoid the route lookup overhead in routesmiddleware
60 # this is used to avoid avoid the route lookup overhead in routesmiddleware
61 # for certain routes which won't go to pylons to - eg. static files, debugger
61 # for certain routes which won't go to pylons to - eg. static files, debugger
62 # it is only needed for the pylons migration and can be removed once complete
62 # it is only needed for the pylons migration and can be removed once complete
63 class SkippableRoutesMiddleware(RoutesMiddleware):
63 class SkippableRoutesMiddleware(RoutesMiddleware):
64 """ Routes middleware that allows you to skip prefixes """
64 """ Routes middleware that allows you to skip prefixes """
65
65
66 def __init__(self, *args, **kw):
66 def __init__(self, *args, **kw):
67 self.skip_prefixes = kw.pop('skip_prefixes', [])
67 self.skip_prefixes = kw.pop('skip_prefixes', [])
68 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
68 super(SkippableRoutesMiddleware, self).__init__(*args, **kw)
69
69
70 def __call__(self, environ, start_response):
70 def __call__(self, environ, start_response):
71 for prefix in self.skip_prefixes:
71 for prefix in self.skip_prefixes:
72 if environ['PATH_INFO'].startswith(prefix):
72 if environ['PATH_INFO'].startswith(prefix):
73 # added to avoid the case when a missing /_static route falls
73 # added to avoid the case when a missing /_static route falls
74 # through to pylons and causes an exception as pylons is
74 # through to pylons and causes an exception as pylons is
75 # expecting wsgiorg.routingargs to be set in the environ
75 # expecting wsgiorg.routingargs to be set in the environ
76 # by RoutesMiddleware.
76 # by RoutesMiddleware.
77 if 'wsgiorg.routing_args' not in environ:
77 if 'wsgiorg.routing_args' not in environ:
78 environ['wsgiorg.routing_args'] = (None, {})
78 environ['wsgiorg.routing_args'] = (None, {})
79 return self.app(environ, start_response)
79 return self.app(environ, start_response)
80
80
81 return super(SkippableRoutesMiddleware, self).__call__(
81 return super(SkippableRoutesMiddleware, self).__call__(
82 environ, start_response)
82 environ, start_response)
83
83
84
84
85 def make_app(global_conf, static_files=True, **app_conf):
85 def make_app(global_conf, static_files=True, **app_conf):
86 """Create a Pylons WSGI application and return it
86 """Create a Pylons WSGI application and return it
87
87
88 ``global_conf``
88 ``global_conf``
89 The inherited configuration for this application. Normally from
89 The inherited configuration for this application. Normally from
90 the [DEFAULT] section of the Paste ini file.
90 the [DEFAULT] section of the Paste ini file.
91
91
92 ``app_conf``
92 ``app_conf``
93 The application's local configuration. Normally specified in
93 The application's local configuration. Normally specified in
94 the [app:<name>] section of the Paste ini file (where <name>
94 the [app:<name>] section of the Paste ini file (where <name>
95 defaults to main).
95 defaults to main).
96
96
97 """
97 """
98 # Apply compatibility patches
98 # Apply compatibility patches
99 patches.kombu_1_5_1_python_2_7_11()
99 patches.kombu_1_5_1_python_2_7_11()
100 patches.inspect_getargspec()
100 patches.inspect_getargspec()
101
101
102 # Configure the Pylons environment
102 # Configure the Pylons environment
103 config = load_environment(global_conf, app_conf)
103 config = load_environment(global_conf, app_conf)
104
104
105 # The Pylons WSGI app
105 # The Pylons WSGI app
106 app = PylonsApp(config=config)
106 app = PylonsApp(config=config)
107 if rhodecode.is_test:
107 if rhodecode.is_test:
108 app = csrf.CSRFDetector(app)
108 app = csrf.CSRFDetector(app)
109
109
110 expected_origin = config.get('expected_origin')
110 expected_origin = config.get('expected_origin')
111 if expected_origin:
111 if expected_origin:
112 # The API can be accessed from other Origins.
112 # The API can be accessed from other Origins.
113 app = csrf.OriginChecker(app, expected_origin,
113 app = csrf.OriginChecker(app, expected_origin,
114 skip_urls=[routes.util.url_for('api')])
114 skip_urls=[routes.util.url_for('api')])
115
115
116 # Establish the Registry for this application
116 # Establish the Registry for this application
117 app = RegistryManager(app)
117 app = RegistryManager(app)
118
118
119 app.config = config
119 app.config = config
120
120
121 return app
121 return app
122
122
123
123
124 def make_pyramid_app(global_config, **settings):
124 def make_pyramid_app(global_config, **settings):
125 """
125 """
126 Constructs the WSGI application based on Pyramid and wraps the Pylons based
126 Constructs the WSGI application based on Pyramid and wraps the Pylons based
127 application.
127 application.
128
128
129 Specials:
129 Specials:
130
130
131 * We migrate from Pylons to Pyramid. While doing this, we keep both
131 * We migrate from Pylons to Pyramid. While doing this, we keep both
132 frameworks functional. This involves moving some WSGI middlewares around
132 frameworks functional. This involves moving some WSGI middlewares around
133 and providing access to some data internals, so that the old code is
133 and providing access to some data internals, so that the old code is
134 still functional.
134 still functional.
135
135
136 * The application can also be integrated like a plugin via the call to
136 * The application can also be integrated like a plugin via the call to
137 `includeme`. This is accompanied with the other utility functions which
137 `includeme`. This is accompanied with the other utility functions which
138 are called. Changing this should be done with great care to not break
138 are called. Changing this should be done with great care to not break
139 cases when these fragments are assembled from another place.
139 cases when these fragments are assembled from another place.
140
140
141 """
141 """
142 # The edition string should be available in pylons too, so we add it here
142 # The edition string should be available in pylons too, so we add it here
143 # before copying the settings.
143 # before copying the settings.
144 settings.setdefault('rhodecode.edition', 'Community Edition')
144 settings.setdefault('rhodecode.edition', 'Community Edition')
145
145
146 # As long as our Pylons application does expect "unprepared" settings, make
146 # As long as our Pylons application does expect "unprepared" settings, make
147 # sure that we keep an unmodified copy. This avoids unintentional change of
147 # sure that we keep an unmodified copy. This avoids unintentional change of
148 # behavior in the old application.
148 # behavior in the old application.
149 settings_pylons = settings.copy()
149 settings_pylons = settings.copy()
150
150
151 sanitize_settings_and_apply_defaults(settings)
151 sanitize_settings_and_apply_defaults(settings)
152 config = Configurator(settings=settings)
152 config = Configurator(settings=settings)
153 add_pylons_compat_data(config.registry, global_config, settings_pylons)
153 add_pylons_compat_data(config.registry, global_config, settings_pylons)
154
154
155 load_pyramid_environment(global_config, settings)
155 load_pyramid_environment(global_config, settings)
156
156
157 includeme_first(config)
157 includeme_first(config)
158 includeme(config)
158 includeme(config)
159 pyramid_app = config.make_wsgi_app()
159 pyramid_app = config.make_wsgi_app()
160 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
160 pyramid_app = wrap_app_in_wsgi_middlewares(pyramid_app, config)
161 return pyramid_app
161 return pyramid_app
162
162
163
163
164 def make_not_found_view(config):
164 def make_not_found_view(config):
165 """
165 """
166 This creates the view which should be registered as not-found-view to
166 This creates the view which should be registered as not-found-view to
167 pyramid. Basically it contains of the old pylons app, converted to a view.
167 pyramid. Basically it contains of the old pylons app, converted to a view.
168 Additionally it is wrapped by some other middlewares.
168 Additionally it is wrapped by some other middlewares.
169 """
169 """
170 settings = config.registry.settings
170 settings = config.registry.settings
171 vcs_server_enabled = settings['vcs.server.enable']
171 vcs_server_enabled = settings['vcs.server.enable']
172
172
173 # Make pylons app from unprepared settings.
173 # Make pylons app from unprepared settings.
174 pylons_app = make_app(
174 pylons_app = make_app(
175 config.registry._pylons_compat_global_config,
175 config.registry._pylons_compat_global_config,
176 **config.registry._pylons_compat_settings)
176 **config.registry._pylons_compat_settings)
177 config.registry._pylons_compat_config = pylons_app.config
177 config.registry._pylons_compat_config = pylons_app.config
178
178
179 # Appenlight monitoring.
179 # Appenlight monitoring.
180 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
180 pylons_app, appenlight_client = wrap_in_appenlight_if_enabled(
181 pylons_app, settings)
181 pylons_app, settings)
182
182
183 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find
183 # The VCSMiddleware shall operate like a fallback if pyramid doesn't find
184 # a view to handle the request. Therefore we wrap it around the pylons app.
184 # a view to handle the request. Therefore we wrap it around the pylons app.
185 if vcs_server_enabled:
185 if vcs_server_enabled:
186 pylons_app = VCSMiddleware(
186 pylons_app = VCSMiddleware(
187 pylons_app, settings, appenlight_client, registry=config.registry)
187 pylons_app, settings, appenlight_client, registry=config.registry)
188
188
189 pylons_app_as_view = wsgiapp(pylons_app)
189 pylons_app_as_view = wsgiapp(pylons_app)
190
190
191 # Protect from VCS Server error related pages when server is not available
191 # Protect from VCS Server error related pages when server is not available
192 if not vcs_server_enabled:
192 if not vcs_server_enabled:
193 pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
193 pylons_app_as_view = DisableVCSPagesWrapper(pylons_app_as_view)
194
194
195 def pylons_app_with_error_handler(context, request):
195 def pylons_app_with_error_handler(context, request):
196 """
196 """
197 Handle exceptions from rc pylons app:
197 Handle exceptions from rc pylons app:
198
198
199 - old webob type exceptions get converted to pyramid exceptions
199 - old webob type exceptions get converted to pyramid exceptions
200 - pyramid exceptions are passed to the error handler view
200 - pyramid exceptions are passed to the error handler view
201 """
201 """
202 def is_vcs_response(request):
203 return True == request.environ.get(
204 'rhodecode.vcs.skip_error_handling')
205
206 def is_webob_error(response):
207 # webob type error responses
208 return (400 <= response.status_int <= 599)
209
202 try:
210 try:
203 response = pylons_app_as_view(context, request)
211 response = pylons_app_as_view(context, request)
204 if 400 <= response.status_int <= 599: # webob type error responses
212 if is_webob_error(response) and not is_vcs_response(request):
205 return error_handler(
213 return error_handler(
206 webob_to_pyramid_http_response(response), request)
214 webob_to_pyramid_http_response(response), request)
207 except HTTPError as e: # pyramid type exceptions
215 except HTTPError as e: # pyramid type exceptions
208 return error_handler(e, request)
216 return error_handler(e, request)
209 except Exception:
217 except Exception:
210 if settings.get('debugtoolbar.enabled', False):
218 if settings.get('debugtoolbar.enabled', False):
211 raise
219 raise
212 return error_handler(HTTPInternalServerError(), request)
220 return error_handler(HTTPInternalServerError(), request)
213 return response
221 return response
214
222
215 return pylons_app_with_error_handler
223 return pylons_app_with_error_handler
216
224
217
225
218 def add_pylons_compat_data(registry, global_config, settings):
226 def add_pylons_compat_data(registry, global_config, settings):
219 """
227 """
220 Attach data to the registry to support the Pylons integration.
228 Attach data to the registry to support the Pylons integration.
221 """
229 """
222 registry._pylons_compat_global_config = global_config
230 registry._pylons_compat_global_config = global_config
223 registry._pylons_compat_settings = settings
231 registry._pylons_compat_settings = settings
224
232
225
233
226 def webob_to_pyramid_http_response(webob_response):
234 def webob_to_pyramid_http_response(webob_response):
227 ResponseClass = httpexceptions.status_map[webob_response.status_int]
235 ResponseClass = httpexceptions.status_map[webob_response.status_int]
228 pyramid_response = ResponseClass(webob_response.status)
236 pyramid_response = ResponseClass(webob_response.status)
229 pyramid_response.status = webob_response.status
237 pyramid_response.status = webob_response.status
230 pyramid_response.headers.update(webob_response.headers)
238 pyramid_response.headers.update(webob_response.headers)
231 if pyramid_response.headers['content-type'] == 'text/html':
239 if pyramid_response.headers['content-type'] == 'text/html':
232 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
240 pyramid_response.headers['content-type'] = 'text/html; charset=UTF-8'
233 return pyramid_response
241 return pyramid_response
234
242
235
243
236 def error_handler(exception, request):
244 def error_handler(exception, request):
237 # TODO: dan: replace the old pylons error controller with this
245 # TODO: dan: replace the old pylons error controller with this
238 from rhodecode.model.settings import SettingsModel
246 from rhodecode.model.settings import SettingsModel
239 from rhodecode.lib.utils2 import AttributeDict
247 from rhodecode.lib.utils2 import AttributeDict
240
248
241 try:
249 try:
242 rc_config = SettingsModel().get_all_settings()
250 rc_config = SettingsModel().get_all_settings()
243 except Exception:
251 except Exception:
244 log.exception('failed to fetch settings')
252 log.exception('failed to fetch settings')
245 rc_config = {}
253 rc_config = {}
246
254
247 base_response = HTTPInternalServerError()
255 base_response = HTTPInternalServerError()
248 # prefer original exception for the response since it may have headers set
256 # prefer original exception for the response since it may have headers set
249 if isinstance(exception, HTTPError):
257 if isinstance(exception, HTTPError):
250 base_response = exception
258 base_response = exception
251
259
252 c = AttributeDict()
260 c = AttributeDict()
253 c.error_message = base_response.status
261 c.error_message = base_response.status
254 c.error_explanation = base_response.explanation or str(base_response)
262 c.error_explanation = base_response.explanation or str(base_response)
255 c.visual = AttributeDict()
263 c.visual = AttributeDict()
256
264
257 c.visual.rhodecode_support_url = (
265 c.visual.rhodecode_support_url = (
258 request.registry.settings.get('rhodecode_support_url') or
266 request.registry.settings.get('rhodecode_support_url') or
259 request.route_url('rhodecode_support')
267 request.route_url('rhodecode_support')
260 )
268 )
261 c.redirect_time = 0
269 c.redirect_time = 0
262 c.rhodecode_name = rc_config.get('rhodecode_title', '')
270 c.rhodecode_name = rc_config.get('rhodecode_title', '')
263 if not c.rhodecode_name:
271 if not c.rhodecode_name:
264 c.rhodecode_name = 'Rhodecode'
272 c.rhodecode_name = 'Rhodecode'
265
273
266 response = render_to_response(
274 response = render_to_response(
267 '/errors/error_document.html', {'c': c}, request=request,
275 '/errors/error_document.html', {'c': c}, request=request,
268 response=base_response)
276 response=base_response)
269
277
270 return response
278 return response
271
279
272
280
273 def includeme(config):
281 def includeme(config):
274 settings = config.registry.settings
282 settings = config.registry.settings
275
283
276 # plugin information
284 # plugin information
277 config.registry.rhodecode_plugins = OrderedDict()
285 config.registry.rhodecode_plugins = OrderedDict()
278
286
279 config.add_directive(
287 config.add_directive(
280 'register_rhodecode_plugin', register_rhodecode_plugin)
288 'register_rhodecode_plugin', register_rhodecode_plugin)
281
289
282 if asbool(settings.get('appenlight', 'false')):
290 if asbool(settings.get('appenlight', 'false')):
283 config.include('appenlight_client.ext.pyramid_tween')
291 config.include('appenlight_client.ext.pyramid_tween')
284
292
285 # Includes which are required. The application would fail without them.
293 # Includes which are required. The application would fail without them.
286 config.include('pyramid_mako')
294 config.include('pyramid_mako')
287 config.include('pyramid_beaker')
295 config.include('pyramid_beaker')
288 config.include('rhodecode.channelstream')
296 config.include('rhodecode.channelstream')
289 config.include('rhodecode.admin')
297 config.include('rhodecode.admin')
290 config.include('rhodecode.authentication')
298 config.include('rhodecode.authentication')
291 config.include('rhodecode.integrations')
299 config.include('rhodecode.integrations')
292 config.include('rhodecode.login')
300 config.include('rhodecode.login')
293 config.include('rhodecode.tweens')
301 config.include('rhodecode.tweens')
294 config.include('rhodecode.api')
302 config.include('rhodecode.api')
295 config.include('rhodecode.svn_support')
303 config.include('rhodecode.svn_support')
296 config.add_route(
304 config.add_route(
297 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
305 'rhodecode_support', 'https://rhodecode.com/help/', static=True)
298
306
299 # Add subscribers.
307 # Add subscribers.
300 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
308 config.add_subscriber(scan_repositories_if_enabled, ApplicationCreated)
301
309
302 # Set the authorization policy.
310 # Set the authorization policy.
303 authz_policy = ACLAuthorizationPolicy()
311 authz_policy = ACLAuthorizationPolicy()
304 config.set_authorization_policy(authz_policy)
312 config.set_authorization_policy(authz_policy)
305
313
306 # Set the default renderer for HTML templates to mako.
314 # Set the default renderer for HTML templates to mako.
307 config.add_mako_renderer('.html')
315 config.add_mako_renderer('.html')
308
316
309 # include RhodeCode plugins
317 # include RhodeCode plugins
310 includes = aslist(settings.get('rhodecode.includes', []))
318 includes = aslist(settings.get('rhodecode.includes', []))
311 for inc in includes:
319 for inc in includes:
312 config.include(inc)
320 config.include(inc)
313
321
314 # This is the glue which allows us to migrate in chunks. By registering the
322 # This is the glue which allows us to migrate in chunks. By registering the
315 # pylons based application as the "Not Found" view in Pyramid, we will
323 # pylons based application as the "Not Found" view in Pyramid, we will
316 # fallback to the old application each time the new one does not yet know
324 # fallback to the old application each time the new one does not yet know
317 # how to handle a request.
325 # how to handle a request.
318 config.add_notfound_view(make_not_found_view(config))
326 config.add_notfound_view(make_not_found_view(config))
319
327
320 if not settings.get('debugtoolbar.enabled', False):
328 if not settings.get('debugtoolbar.enabled', False):
321 # if no toolbar, then any exception gets caught and rendered
329 # if no toolbar, then any exception gets caught and rendered
322 config.add_view(error_handler, context=Exception)
330 config.add_view(error_handler, context=Exception)
323
331
324 config.add_view(error_handler, context=HTTPError)
332 config.add_view(error_handler, context=HTTPError)
325
333
326
334
327 def includeme_first(config):
335 def includeme_first(config):
328 # redirect automatic browser favicon.ico requests to correct place
336 # redirect automatic browser favicon.ico requests to correct place
329 def favicon_redirect(context, request):
337 def favicon_redirect(context, request):
330 return redirect(
338 return redirect(
331 request.static_path('rhodecode:public/images/favicon.ico'))
339 request.static_path('rhodecode:public/images/favicon.ico'))
332
340
333 config.add_view(favicon_redirect, route_name='favicon')
341 config.add_view(favicon_redirect, route_name='favicon')
334 config.add_route('favicon', '/favicon.ico')
342 config.add_route('favicon', '/favicon.ico')
335
343
336 config.add_static_view(
344 config.add_static_view(
337 '_static/deform', 'deform:static')
345 '_static/deform', 'deform:static')
338 config.add_static_view(
346 config.add_static_view(
339 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
347 '_static/rhodecode', path='rhodecode:public', cache_max_age=3600 * 24)
340
348
341
349
342 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
350 def wrap_app_in_wsgi_middlewares(pyramid_app, config):
343 """
351 """
344 Apply outer WSGI middlewares around the application.
352 Apply outer WSGI middlewares around the application.
345
353
346 Part of this has been moved up from the Pylons layer, so that the
354 Part of this has been moved up from the Pylons layer, so that the
347 data is also available if old Pylons code is hit through an already ported
355 data is also available if old Pylons code is hit through an already ported
348 view.
356 view.
349 """
357 """
350 settings = config.registry.settings
358 settings = config.registry.settings
351
359
352 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
360 # enable https redirects based on HTTP_X_URL_SCHEME set by proxy
353 pyramid_app = HttpsFixup(pyramid_app, settings)
361 pyramid_app = HttpsFixup(pyramid_app, settings)
354
362
355 # Add RoutesMiddleware to support the pylons compatibility tween during
363 # Add RoutesMiddleware to support the pylons compatibility tween during
356 # migration to pyramid.
364 # migration to pyramid.
357 pyramid_app = SkippableRoutesMiddleware(
365 pyramid_app = SkippableRoutesMiddleware(
358 pyramid_app, config.registry._pylons_compat_config['routes.map'],
366 pyramid_app, config.registry._pylons_compat_config['routes.map'],
359 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
367 skip_prefixes=(STATIC_FILE_PREFIX, '/_debug_toolbar'))
360
368
361 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
369 pyramid_app, _ = wrap_in_appenlight_if_enabled(pyramid_app, settings)
362
370
363 if settings['gzip_responses']:
371 if settings['gzip_responses']:
364 pyramid_app = make_gzip_middleware(
372 pyramid_app = make_gzip_middleware(
365 pyramid_app, settings, compress_level=1)
373 pyramid_app, settings, compress_level=1)
366
374
367 return pyramid_app
375 return pyramid_app
368
376
369
377
370 def sanitize_settings_and_apply_defaults(settings):
378 def sanitize_settings_and_apply_defaults(settings):
371 """
379 """
372 Applies settings defaults and does all type conversion.
380 Applies settings defaults and does all type conversion.
373
381
374 We would move all settings parsing and preparation into this place, so that
382 We would move all settings parsing and preparation into this place, so that
375 we have only one place left which deals with this part. The remaining parts
383 we have only one place left which deals with this part. The remaining parts
376 of the application would start to rely fully on well prepared settings.
384 of the application would start to rely fully on well prepared settings.
377
385
378 This piece would later be split up per topic to avoid a big fat monster
386 This piece would later be split up per topic to avoid a big fat monster
379 function.
387 function.
380 """
388 """
381
389
382 # Pyramid's mako renderer has to search in the templates folder so that the
390 # Pyramid's mako renderer has to search in the templates folder so that the
383 # old templates still work. Ported and new templates are expected to use
391 # old templates still work. Ported and new templates are expected to use
384 # real asset specifications for the includes.
392 # real asset specifications for the includes.
385 mako_directories = settings.setdefault('mako.directories', [
393 mako_directories = settings.setdefault('mako.directories', [
386 # Base templates of the original Pylons application
394 # Base templates of the original Pylons application
387 'rhodecode:templates',
395 'rhodecode:templates',
388 ])
396 ])
389 log.debug(
397 log.debug(
390 "Using the following Mako template directories: %s",
398 "Using the following Mako template directories: %s",
391 mako_directories)
399 mako_directories)
392
400
393 # Default includes, possible to change as a user
401 # Default includes, possible to change as a user
394 pyramid_includes = settings.setdefault('pyramid.includes', [
402 pyramid_includes = settings.setdefault('pyramid.includes', [
395 'rhodecode.lib.middleware.request_wrapper',
403 'rhodecode.lib.middleware.request_wrapper',
396 ])
404 ])
397 log.debug(
405 log.debug(
398 "Using the following pyramid.includes: %s",
406 "Using the following pyramid.includes: %s",
399 pyramid_includes)
407 pyramid_includes)
400
408
401 # TODO: johbo: Re-think this, usually the call to config.include
409 # TODO: johbo: Re-think this, usually the call to config.include
402 # should allow to pass in a prefix.
410 # should allow to pass in a prefix.
403 settings.setdefault('rhodecode.api.url', '/_admin/api')
411 settings.setdefault('rhodecode.api.url', '/_admin/api')
404
412
405 # Sanitize generic settings.
413 # Sanitize generic settings.
406 _list_setting(settings, 'default_encoding', 'UTF-8')
414 _list_setting(settings, 'default_encoding', 'UTF-8')
407 _bool_setting(settings, 'is_test', 'false')
415 _bool_setting(settings, 'is_test', 'false')
408 _bool_setting(settings, 'gzip_responses', 'false')
416 _bool_setting(settings, 'gzip_responses', 'false')
409
417
410 # Call split out functions that sanitize settings for each topic.
418 # Call split out functions that sanitize settings for each topic.
411 _sanitize_appenlight_settings(settings)
419 _sanitize_appenlight_settings(settings)
412 _sanitize_vcs_settings(settings)
420 _sanitize_vcs_settings(settings)
413
421
414 return settings
422 return settings
415
423
416
424
417 def _sanitize_appenlight_settings(settings):
425 def _sanitize_appenlight_settings(settings):
418 _bool_setting(settings, 'appenlight', 'false')
426 _bool_setting(settings, 'appenlight', 'false')
419
427
420
428
421 def _sanitize_vcs_settings(settings):
429 def _sanitize_vcs_settings(settings):
422 """
430 """
423 Applies settings defaults and does type conversion for all VCS related
431 Applies settings defaults and does type conversion for all VCS related
424 settings.
432 settings.
425 """
433 """
426 _string_setting(settings, 'vcs.svn.compatible_version', '')
434 _string_setting(settings, 'vcs.svn.compatible_version', '')
427 _string_setting(settings, 'git_rev_filter', '--all')
435 _string_setting(settings, 'git_rev_filter', '--all')
428 _string_setting(settings, 'vcs.hooks.protocol', 'pyro4')
436 _string_setting(settings, 'vcs.hooks.protocol', 'pyro4')
429 _string_setting(settings, 'vcs.server', '')
437 _string_setting(settings, 'vcs.server', '')
430 _string_setting(settings, 'vcs.server.log_level', 'debug')
438 _string_setting(settings, 'vcs.server.log_level', 'debug')
431 _string_setting(settings, 'vcs.server.protocol', 'pyro4')
439 _string_setting(settings, 'vcs.server.protocol', 'pyro4')
432 _bool_setting(settings, 'startup.import_repos', 'false')
440 _bool_setting(settings, 'startup.import_repos', 'false')
433 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
441 _bool_setting(settings, 'vcs.hooks.direct_calls', 'false')
434 _bool_setting(settings, 'vcs.server.enable', 'true')
442 _bool_setting(settings, 'vcs.server.enable', 'true')
435 _bool_setting(settings, 'vcs.start_server', 'false')
443 _bool_setting(settings, 'vcs.start_server', 'false')
436 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
444 _list_setting(settings, 'vcs.backends', 'hg, git, svn')
437
445
438
446
439 def _bool_setting(settings, name, default):
447 def _bool_setting(settings, name, default):
440 settings[name] = asbool(settings.get(name, default))
448 settings[name] = asbool(settings.get(name, default))
441
449
442
450
443 def _list_setting(settings, name, default):
451 def _list_setting(settings, name, default):
444 raw_value = settings.get(name, default)
452 raw_value = settings.get(name, default)
445
453
446 # Check if we get a setting with the old syntax (comma separated).
454 # Check if we get a setting with the old syntax (comma separated).
447 if ',' in raw_value:
455 if ',' in raw_value:
448 raw_value = raw_value.replace(',', ' ')
456 raw_value = raw_value.replace(',', ' ')
449
457
450 settings[name] = aslist(raw_value)
458 settings[name] = aslist(raw_value)
451
459
452
460
453 def _string_setting(settings, name, default):
461 def _string_setting(settings, name, default):
454 settings[name] = settings.get(name, default).lower()
462 settings[name] = settings.get(name, default).lower()
General Comments 0
You need to be logged in to leave comments. Login now