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