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