##// END OF EJS Templates
vcsserver: http main added time measuring tween for debugging.
marcink -
r154:1e471c21 default
parent child Browse files
Show More
@@ -0,0 +1,60 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2017 RodeCode GmbH
3 #
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
8 #
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
13 #
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
18
19
20 import time
21 import logging
22
23
24 from vcsserver.utils import safe_str
25
26
27 log = logging.getLogger(__name__)
28
29
30 def get_access_path(request):
31 environ = request.environ
32 return environ.get('PATH_INFO')
33
34
35 class RequestWrapperTween(object):
36 def __init__(self, handler, registry):
37 self.handler = handler
38 self.registry = registry
39
40 # one-time configuration code goes here
41
42 def __call__(self, request):
43 start = time.time()
44 try:
45 response = self.handler(request)
46 finally:
47 end = time.time()
48
49 log.info('IP: %s Request to %s time: %.3fs' % (
50 '127.0.0.1',
51 safe_str(get_access_path(request)), end - start)
52 )
53
54 return response
55
56
57 def includeme(config):
58 config.add_tween(
59 'vcsserver.tweens.RequestWrapperTween',
60 )
@@ -1,403 +1,408 b''
1 # RhodeCode VCSServer provides access to different vcs backends via network.
1 # RhodeCode VCSServer provides access to different vcs backends via network.
2 # Copyright (C) 2014-2017 RodeCode GmbH
2 # Copyright (C) 2014-2017 RodeCode GmbH
3 #
3 #
4 # This program is free software; you can redistribute it and/or modify
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 3 of the License, or
6 # the Free Software Foundation; either version 3 of the License, or
7 # (at your option) any later version.
7 # (at your option) any later version.
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 General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software Foundation,
15 # along with this program; if not, write to the Free Software Foundation,
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
17
18 import base64
18 import base64
19 import locale
19 import locale
20 import logging
20 import logging
21 import uuid
21 import uuid
22 import wsgiref.util
22 import wsgiref.util
23 import traceback
23 import traceback
24 from itertools import chain
24 from itertools import chain
25
25
26 import msgpack
26 import msgpack
27 from beaker.cache import CacheManager
27 from beaker.cache import CacheManager
28 from beaker.util import parse_cache_config_options
28 from beaker.util import parse_cache_config_options
29 from pyramid.config import Configurator
29 from pyramid.config import Configurator
30 from pyramid.wsgi import wsgiapp
30 from pyramid.wsgi import wsgiapp
31
31
32 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
32 from vcsserver import remote_wsgi, scm_app, settings, hgpatches
33 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
33 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
34 from vcsserver.echo_stub.echo_app import EchoApp
34 from vcsserver.echo_stub.echo_app import EchoApp
35 from vcsserver.exceptions import HTTPRepoLocked
35 from vcsserver.exceptions import HTTPRepoLocked
36 from vcsserver.server import VcsServer
36 from vcsserver.server import VcsServer
37
37
38 try:
38 try:
39 from vcsserver.git import GitFactory, GitRemote
39 from vcsserver.git import GitFactory, GitRemote
40 except ImportError:
40 except ImportError:
41 GitFactory = None
41 GitFactory = None
42 GitRemote = None
42 GitRemote = None
43 try:
43 try:
44 from vcsserver.hg import MercurialFactory, HgRemote
44 from vcsserver.hg import MercurialFactory, HgRemote
45 except ImportError:
45 except ImportError:
46 MercurialFactory = None
46 MercurialFactory = None
47 HgRemote = None
47 HgRemote = None
48 try:
48 try:
49 from vcsserver.svn import SubversionFactory, SvnRemote
49 from vcsserver.svn import SubversionFactory, SvnRemote
50 except ImportError:
50 except ImportError:
51 SubversionFactory = None
51 SubversionFactory = None
52 SvnRemote = None
52 SvnRemote = None
53
53
54 log = logging.getLogger(__name__)
54 log = logging.getLogger(__name__)
55
55
56
56
57 class VCS(object):
57 class VCS(object):
58 def __init__(self, locale=None, cache_config=None):
58 def __init__(self, locale=None, cache_config=None):
59 self.locale = locale
59 self.locale = locale
60 self.cache_config = cache_config
60 self.cache_config = cache_config
61 self._configure_locale()
61 self._configure_locale()
62 self._initialize_cache()
62 self._initialize_cache()
63
63
64 if GitFactory and GitRemote:
64 if GitFactory and GitRemote:
65 git_repo_cache = self.cache.get_cache_region(
65 git_repo_cache = self.cache.get_cache_region(
66 'git', region='repo_object')
66 'git', region='repo_object')
67 git_factory = GitFactory(git_repo_cache)
67 git_factory = GitFactory(git_repo_cache)
68 self._git_remote = GitRemote(git_factory)
68 self._git_remote = GitRemote(git_factory)
69 else:
69 else:
70 log.info("Git client import failed")
70 log.info("Git client import failed")
71
71
72 if MercurialFactory and HgRemote:
72 if MercurialFactory and HgRemote:
73 hg_repo_cache = self.cache.get_cache_region(
73 hg_repo_cache = self.cache.get_cache_region(
74 'hg', region='repo_object')
74 'hg', region='repo_object')
75 hg_factory = MercurialFactory(hg_repo_cache)
75 hg_factory = MercurialFactory(hg_repo_cache)
76 self._hg_remote = HgRemote(hg_factory)
76 self._hg_remote = HgRemote(hg_factory)
77 else:
77 else:
78 log.info("Mercurial client import failed")
78 log.info("Mercurial client import failed")
79
79
80 if SubversionFactory and SvnRemote:
80 if SubversionFactory and SvnRemote:
81 svn_repo_cache = self.cache.get_cache_region(
81 svn_repo_cache = self.cache.get_cache_region(
82 'svn', region='repo_object')
82 'svn', region='repo_object')
83 svn_factory = SubversionFactory(svn_repo_cache)
83 svn_factory = SubversionFactory(svn_repo_cache)
84 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
84 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
85 else:
85 else:
86 log.info("Subversion client import failed")
86 log.info("Subversion client import failed")
87
87
88 self._vcsserver = VcsServer()
88 self._vcsserver = VcsServer()
89
89
90 def _initialize_cache(self):
90 def _initialize_cache(self):
91 cache_config = parse_cache_config_options(self.cache_config)
91 cache_config = parse_cache_config_options(self.cache_config)
92 log.info('Initializing beaker cache: %s' % cache_config)
92 log.info('Initializing beaker cache: %s' % cache_config)
93 self.cache = CacheManager(**cache_config)
93 self.cache = CacheManager(**cache_config)
94
94
95 def _configure_locale(self):
95 def _configure_locale(self):
96 if self.locale:
96 if self.locale:
97 log.info('Settings locale: `LC_ALL` to %s' % self.locale)
97 log.info('Settings locale: `LC_ALL` to %s' % self.locale)
98 else:
98 else:
99 log.info(
99 log.info(
100 'Configuring locale subsystem based on environment variables')
100 'Configuring locale subsystem based on environment variables')
101 try:
101 try:
102 # If self.locale is the empty string, then the locale
102 # If self.locale is the empty string, then the locale
103 # module will use the environment variables. See the
103 # module will use the environment variables. See the
104 # documentation of the package `locale`.
104 # documentation of the package `locale`.
105 locale.setlocale(locale.LC_ALL, self.locale)
105 locale.setlocale(locale.LC_ALL, self.locale)
106
106
107 language_code, encoding = locale.getlocale()
107 language_code, encoding = locale.getlocale()
108 log.info(
108 log.info(
109 'Locale set to language code "%s" with encoding "%s".',
109 'Locale set to language code "%s" with encoding "%s".',
110 language_code, encoding)
110 language_code, encoding)
111 except locale.Error:
111 except locale.Error:
112 log.exception(
112 log.exception(
113 'Cannot set locale, not configuring the locale system')
113 'Cannot set locale, not configuring the locale system')
114
114
115
115
116 class WsgiProxy(object):
116 class WsgiProxy(object):
117 def __init__(self, wsgi):
117 def __init__(self, wsgi):
118 self.wsgi = wsgi
118 self.wsgi = wsgi
119
119
120 def __call__(self, environ, start_response):
120 def __call__(self, environ, start_response):
121 input_data = environ['wsgi.input'].read()
121 input_data = environ['wsgi.input'].read()
122 input_data = msgpack.unpackb(input_data)
122 input_data = msgpack.unpackb(input_data)
123
123
124 error = None
124 error = None
125 try:
125 try:
126 data, status, headers = self.wsgi.handle(
126 data, status, headers = self.wsgi.handle(
127 input_data['environment'], input_data['input_data'],
127 input_data['environment'], input_data['input_data'],
128 *input_data['args'], **input_data['kwargs'])
128 *input_data['args'], **input_data['kwargs'])
129 except Exception as e:
129 except Exception as e:
130 data, status, headers = [], None, None
130 data, status, headers = [], None, None
131 error = {
131 error = {
132 'message': str(e),
132 'message': str(e),
133 '_vcs_kind': getattr(e, '_vcs_kind', None)
133 '_vcs_kind': getattr(e, '_vcs_kind', None)
134 }
134 }
135
135
136 start_response(200, {})
136 start_response(200, {})
137 return self._iterator(error, status, headers, data)
137 return self._iterator(error, status, headers, data)
138
138
139 def _iterator(self, error, status, headers, data):
139 def _iterator(self, error, status, headers, data):
140 initial_data = [
140 initial_data = [
141 error,
141 error,
142 status,
142 status,
143 headers,
143 headers,
144 ]
144 ]
145
145
146 for d in chain(initial_data, data):
146 for d in chain(initial_data, data):
147 yield msgpack.packb(d)
147 yield msgpack.packb(d)
148
148
149
149
150 class HTTPApplication(object):
150 class HTTPApplication(object):
151 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
151 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
152
152
153 remote_wsgi = remote_wsgi
153 remote_wsgi = remote_wsgi
154 _use_echo_app = False
154 _use_echo_app = False
155
155
156 def __init__(self, settings=None):
156 def __init__(self, settings=None):
157 self.config = Configurator(settings=settings)
157 self.config = Configurator(settings=settings)
158 locale = settings.get('locale', '') or 'en_US.UTF-8'
158 locale = settings.get('locale', '') or 'en_US.UTF-8'
159 vcs = VCS(locale=locale, cache_config=settings)
159 vcs = VCS(locale=locale, cache_config=settings)
160 self._remotes = {
160 self._remotes = {
161 'hg': vcs._hg_remote,
161 'hg': vcs._hg_remote,
162 'git': vcs._git_remote,
162 'git': vcs._git_remote,
163 'svn': vcs._svn_remote,
163 'svn': vcs._svn_remote,
164 'server': vcs._vcsserver,
164 'server': vcs._vcsserver,
165 }
165 }
166 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
166 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
167 self._use_echo_app = True
167 self._use_echo_app = True
168 log.warning("Using EchoApp for VCS operations.")
168 log.warning("Using EchoApp for VCS operations.")
169 self.remote_wsgi = remote_wsgi_stub
169 self.remote_wsgi = remote_wsgi_stub
170 self._configure_settings(settings)
170 self._configure_settings(settings)
171 self._configure()
171 self._configure()
172
172
173 def _configure_settings(self, app_settings):
173 def _configure_settings(self, app_settings):
174 """
174 """
175 Configure the settings module.
175 Configure the settings module.
176 """
176 """
177 git_path = app_settings.get('git_path', None)
177 git_path = app_settings.get('git_path', None)
178 if git_path:
178 if git_path:
179 settings.GIT_EXECUTABLE = git_path
179 settings.GIT_EXECUTABLE = git_path
180
180
181 def _configure(self):
181 def _configure(self):
182 self.config.add_renderer(
182 self.config.add_renderer(
183 name='msgpack',
183 name='msgpack',
184 factory=self._msgpack_renderer_factory)
184 factory=self._msgpack_renderer_factory)
185
185
186 self.config.add_route('service', '/_service')
186 self.config.add_route('service', '/_service')
187 self.config.add_route('status', '/status')
187 self.config.add_route('status', '/status')
188 self.config.add_route('hg_proxy', '/proxy/hg')
188 self.config.add_route('hg_proxy', '/proxy/hg')
189 self.config.add_route('git_proxy', '/proxy/git')
189 self.config.add_route('git_proxy', '/proxy/git')
190 self.config.add_route('vcs', '/{backend}')
190 self.config.add_route('vcs', '/{backend}')
191 self.config.add_route('stream_git', '/stream/git/*repo_name')
191 self.config.add_route('stream_git', '/stream/git/*repo_name')
192 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
192 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
193
193
194 self.config.add_view(
194 self.config.add_view(
195 self.status_view, route_name='status', renderer='json')
195 self.status_view, route_name='status', renderer='json')
196 self.config.add_view(
196 self.config.add_view(
197 self.service_view, route_name='service', renderer='msgpack')
197 self.service_view, route_name='service', renderer='msgpack')
198
198
199 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
199 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
200 self.config.add_view(self.git_proxy(), route_name='git_proxy')
200 self.config.add_view(self.git_proxy(), route_name='git_proxy')
201 self.config.add_view(
201 self.config.add_view(
202 self.vcs_view, route_name='vcs', renderer='msgpack',
202 self.vcs_view, route_name='vcs', renderer='msgpack',
203 custom_predicates=[self.is_vcs_view])
203 custom_predicates=[self.is_vcs_view])
204
204
205 self.config.add_view(self.hg_stream(), route_name='stream_hg')
205 self.config.add_view(self.hg_stream(), route_name='stream_hg')
206 self.config.add_view(self.git_stream(), route_name='stream_git')
206 self.config.add_view(self.git_stream(), route_name='stream_git')
207
207
208 def notfound(request):
208 def notfound(request):
209 return {'status': '404 NOT FOUND'}
209 return {'status': '404 NOT FOUND'}
210 self.config.add_notfound_view(notfound, renderer='json')
210 self.config.add_notfound_view(notfound, renderer='json')
211
211
212 self.config.add_view(
212 self.config.add_view(
213 self.handle_vcs_exception, context=Exception,
213 self.handle_vcs_exception, context=Exception,
214 custom_predicates=[self.is_vcs_exception])
214 custom_predicates=[self.is_vcs_exception])
215
215
216 self.config.add_view(
216 self.config.add_view(
217 self.general_error_handler, context=Exception)
217 self.general_error_handler, context=Exception)
218
218
219 self.config.add_tween(
220 'vcsserver.tweens.RequestWrapperTween',
221 )
222
219 def wsgi_app(self):
223 def wsgi_app(self):
220 return self.config.make_wsgi_app()
224 return self.config.make_wsgi_app()
221
225
222 def vcs_view(self, request):
226 def vcs_view(self, request):
223 remote = self._remotes[request.matchdict['backend']]
227 remote = self._remotes[request.matchdict['backend']]
224 payload = msgpack.unpackb(request.body, use_list=True)
228 payload = msgpack.unpackb(request.body, use_list=True)
225 method = payload.get('method')
229 method = payload.get('method')
226 params = payload.get('params')
230 params = payload.get('params')
227 wire = params.get('wire')
231 wire = params.get('wire')
228 args = params.get('args')
232 args = params.get('args')
229 kwargs = params.get('kwargs')
233 kwargs = params.get('kwargs')
230 if wire:
234 if wire:
231 try:
235 try:
232 wire['context'] = uuid.UUID(wire['context'])
236 wire['context'] = uuid.UUID(wire['context'])
233 except KeyError:
237 except KeyError:
234 pass
238 pass
235 args.insert(0, wire)
239 args.insert(0, wire)
236
240
241 log.debug('method called:%s with kwargs:%s', method, kwargs)
237 try:
242 try:
238 resp = getattr(remote, method)(*args, **kwargs)
243 resp = getattr(remote, method)(*args, **kwargs)
239 except Exception as e:
244 except Exception as e:
240 tb_info = traceback.format_exc()
245 tb_info = traceback.format_exc()
241
246
242 type_ = e.__class__.__name__
247 type_ = e.__class__.__name__
243 if type_ not in self.ALLOWED_EXCEPTIONS:
248 if type_ not in self.ALLOWED_EXCEPTIONS:
244 type_ = None
249 type_ = None
245
250
246 resp = {
251 resp = {
247 'id': payload.get('id'),
252 'id': payload.get('id'),
248 'error': {
253 'error': {
249 'message': e.message,
254 'message': e.message,
250 'traceback': tb_info,
255 'traceback': tb_info,
251 'type': type_
256 'type': type_
252 }
257 }
253 }
258 }
254 try:
259 try:
255 resp['error']['_vcs_kind'] = e._vcs_kind
260 resp['error']['_vcs_kind'] = e._vcs_kind
256 except AttributeError:
261 except AttributeError:
257 pass
262 pass
258 else:
263 else:
259 resp = {
264 resp = {
260 'id': payload.get('id'),
265 'id': payload.get('id'),
261 'result': resp
266 'result': resp
262 }
267 }
263
268
264 return resp
269 return resp
265
270
266 def status_view(self, request):
271 def status_view(self, request):
267 return {'status': 'OK'}
272 return {'status': 'OK'}
268
273
269 def service_view(self, request):
274 def service_view(self, request):
270 import vcsserver
275 import vcsserver
271 payload = msgpack.unpackb(request.body, use_list=True)
276 payload = msgpack.unpackb(request.body, use_list=True)
272 resp = {
277 resp = {
273 'id': payload.get('id'),
278 'id': payload.get('id'),
274 'result': dict(
279 'result': dict(
275 version=vcsserver.__version__,
280 version=vcsserver.__version__,
276 config={},
281 config={},
277 payload=payload,
282 payload=payload,
278 )
283 )
279 }
284 }
280 return resp
285 return resp
281
286
282 def _msgpack_renderer_factory(self, info):
287 def _msgpack_renderer_factory(self, info):
283 def _render(value, system):
288 def _render(value, system):
284 value = msgpack.packb(value)
289 value = msgpack.packb(value)
285 request = system.get('request')
290 request = system.get('request')
286 if request is not None:
291 if request is not None:
287 response = request.response
292 response = request.response
288 ct = response.content_type
293 ct = response.content_type
289 if ct == response.default_content_type:
294 if ct == response.default_content_type:
290 response.content_type = 'application/x-msgpack'
295 response.content_type = 'application/x-msgpack'
291 return value
296 return value
292 return _render
297 return _render
293
298
294 def hg_proxy(self):
299 def hg_proxy(self):
295 @wsgiapp
300 @wsgiapp
296 def _hg_proxy(environ, start_response):
301 def _hg_proxy(environ, start_response):
297 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
302 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
298 return app(environ, start_response)
303 return app(environ, start_response)
299 return _hg_proxy
304 return _hg_proxy
300
305
301 def git_proxy(self):
306 def git_proxy(self):
302 @wsgiapp
307 @wsgiapp
303 def _git_proxy(environ, start_response):
308 def _git_proxy(environ, start_response):
304 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
309 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
305 return app(environ, start_response)
310 return app(environ, start_response)
306 return _git_proxy
311 return _git_proxy
307
312
308 def hg_stream(self):
313 def hg_stream(self):
309 if self._use_echo_app:
314 if self._use_echo_app:
310 @wsgiapp
315 @wsgiapp
311 def _hg_stream(environ, start_response):
316 def _hg_stream(environ, start_response):
312 app = EchoApp('fake_path', 'fake_name', None)
317 app = EchoApp('fake_path', 'fake_name', None)
313 return app(environ, start_response)
318 return app(environ, start_response)
314 return _hg_stream
319 return _hg_stream
315 else:
320 else:
316 @wsgiapp
321 @wsgiapp
317 def _hg_stream(environ, start_response):
322 def _hg_stream(environ, start_response):
318 repo_path = environ['HTTP_X_RC_REPO_PATH']
323 repo_path = environ['HTTP_X_RC_REPO_PATH']
319 repo_name = environ['HTTP_X_RC_REPO_NAME']
324 repo_name = environ['HTTP_X_RC_REPO_NAME']
320 packed_config = base64.b64decode(
325 packed_config = base64.b64decode(
321 environ['HTTP_X_RC_REPO_CONFIG'])
326 environ['HTTP_X_RC_REPO_CONFIG'])
322 config = msgpack.unpackb(packed_config)
327 config = msgpack.unpackb(packed_config)
323 app = scm_app.create_hg_wsgi_app(
328 app = scm_app.create_hg_wsgi_app(
324 repo_path, repo_name, config)
329 repo_path, repo_name, config)
325
330
326 # Consitent path information for hgweb
331 # Consitent path information for hgweb
327 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
332 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
328 environ['REPO_NAME'] = repo_name
333 environ['REPO_NAME'] = repo_name
329 return app(environ, ResponseFilter(start_response))
334 return app(environ, ResponseFilter(start_response))
330 return _hg_stream
335 return _hg_stream
331
336
332 def git_stream(self):
337 def git_stream(self):
333 if self._use_echo_app:
338 if self._use_echo_app:
334 @wsgiapp
339 @wsgiapp
335 def _git_stream(environ, start_response):
340 def _git_stream(environ, start_response):
336 app = EchoApp('fake_path', 'fake_name', None)
341 app = EchoApp('fake_path', 'fake_name', None)
337 return app(environ, start_response)
342 return app(environ, start_response)
338 return _git_stream
343 return _git_stream
339 else:
344 else:
340 @wsgiapp
345 @wsgiapp
341 def _git_stream(environ, start_response):
346 def _git_stream(environ, start_response):
342 repo_path = environ['HTTP_X_RC_REPO_PATH']
347 repo_path = environ['HTTP_X_RC_REPO_PATH']
343 repo_name = environ['HTTP_X_RC_REPO_NAME']
348 repo_name = environ['HTTP_X_RC_REPO_NAME']
344 packed_config = base64.b64decode(
349 packed_config = base64.b64decode(
345 environ['HTTP_X_RC_REPO_CONFIG'])
350 environ['HTTP_X_RC_REPO_CONFIG'])
346 config = msgpack.unpackb(packed_config)
351 config = msgpack.unpackb(packed_config)
347
352
348 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
353 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
349 app = scm_app.create_git_wsgi_app(
354 app = scm_app.create_git_wsgi_app(
350 repo_path, repo_name, config)
355 repo_path, repo_name, config)
351 return app(environ, start_response)
356 return app(environ, start_response)
352 return _git_stream
357 return _git_stream
353
358
354 def is_vcs_view(self, context, request):
359 def is_vcs_view(self, context, request):
355 """
360 """
356 View predicate that returns true if given backend is supported by
361 View predicate that returns true if given backend is supported by
357 defined remotes.
362 defined remotes.
358 """
363 """
359 backend = request.matchdict.get('backend')
364 backend = request.matchdict.get('backend')
360 return backend in self._remotes
365 return backend in self._remotes
361
366
362 def is_vcs_exception(self, context, request):
367 def is_vcs_exception(self, context, request):
363 """
368 """
364 View predicate that returns true if the context object is a VCS
369 View predicate that returns true if the context object is a VCS
365 exception.
370 exception.
366 """
371 """
367 return hasattr(context, '_vcs_kind')
372 return hasattr(context, '_vcs_kind')
368
373
369 def handle_vcs_exception(self, exception, request):
374 def handle_vcs_exception(self, exception, request):
370 if exception._vcs_kind == 'repo_locked':
375 if exception._vcs_kind == 'repo_locked':
371 # Get custom repo-locked status code if present.
376 # Get custom repo-locked status code if present.
372 status_code = request.headers.get('X-RC-Locked-Status-Code')
377 status_code = request.headers.get('X-RC-Locked-Status-Code')
373 return HTTPRepoLocked(
378 return HTTPRepoLocked(
374 title=exception.message, status_code=status_code)
379 title=exception.message, status_code=status_code)
375
380
376 # Re-raise exception if we can not handle it.
381 # Re-raise exception if we can not handle it.
377 raise exception
382 raise exception
378
383
379 def general_error_handler(self, exception, request):
384 def general_error_handler(self, exception, request):
380 log.exception(
385 log.exception(
381 'error occurred handling this request for path: %s',
386 'error occurred handling this request for path: %s',
382 request.path)
387 request.path)
383 raise exception
388 raise exception
384
389
385
390
386 class ResponseFilter(object):
391 class ResponseFilter(object):
387
392
388 def __init__(self, start_response):
393 def __init__(self, start_response):
389 self._start_response = start_response
394 self._start_response = start_response
390
395
391 def __call__(self, status, response_headers, exc_info=None):
396 def __call__(self, status, response_headers, exc_info=None):
392 headers = tuple(
397 headers = tuple(
393 (h, v) for h, v in response_headers
398 (h, v) for h, v in response_headers
394 if not wsgiref.util.is_hop_by_hop(h))
399 if not wsgiref.util.is_hop_by_hop(h))
395 return self._start_response(status, headers, exc_info)
400 return self._start_response(status, headers, exc_info)
396
401
397
402
398 def main(global_config, **settings):
403 def main(global_config, **settings):
399 if MercurialFactory:
404 if MercurialFactory:
400 hgpatches.patch_largefiles_capabilities()
405 hgpatches.patch_largefiles_capabilities()
401 hgpatches.patch_subrepo_type_mapping()
406 hgpatches.patch_subrepo_type_mapping()
402 app = HTTPApplication(settings=settings)
407 app = HTTPApplication(settings=settings)
403 return app.wsgi_app()
408 return app.wsgi_app()
General Comments 0
You need to be logged in to leave comments. Login now