##// END OF EJS Templates
logs: added some added logging for stream hg/git.
marcink -
r247:73f3558e default
parent child Browse files
Show More
@@ -1,434 +1,441 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.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
33 from vcsserver.git_lfs.app import GIT_LFS_CONTENT_TYPE, GIT_LFS_PROTO_PAT
34 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
34 from vcsserver.echo_stub import remote_wsgi as remote_wsgi_stub
35 from vcsserver.echo_stub.echo_app import EchoApp
35 from vcsserver.echo_stub.echo_app import EchoApp
36 from vcsserver.exceptions import HTTPRepoLocked
36 from vcsserver.exceptions import HTTPRepoLocked
37 from vcsserver.server import VcsServer
37 from vcsserver.server import VcsServer
38
38
39 try:
39 try:
40 from vcsserver.git import GitFactory, GitRemote
40 from vcsserver.git import GitFactory, GitRemote
41 except ImportError:
41 except ImportError:
42 GitFactory = None
42 GitFactory = None
43 GitRemote = None
43 GitRemote = None
44
44
45 try:
45 try:
46 from vcsserver.hg import MercurialFactory, HgRemote
46 from vcsserver.hg import MercurialFactory, HgRemote
47 except ImportError:
47 except ImportError:
48 MercurialFactory = None
48 MercurialFactory = None
49 HgRemote = None
49 HgRemote = None
50
50
51 try:
51 try:
52 from vcsserver.svn import SubversionFactory, SvnRemote
52 from vcsserver.svn import SubversionFactory, SvnRemote
53 except ImportError:
53 except ImportError:
54 SubversionFactory = None
54 SubversionFactory = None
55 SvnRemote = None
55 SvnRemote = None
56
56
57 log = logging.getLogger(__name__)
57 log = logging.getLogger(__name__)
58
58
59
59
60 class VCS(object):
60 class VCS(object):
61 def __init__(self, locale=None, cache_config=None):
61 def __init__(self, locale=None, cache_config=None):
62 self.locale = locale
62 self.locale = locale
63 self.cache_config = cache_config
63 self.cache_config = cache_config
64 self._configure_locale()
64 self._configure_locale()
65 self._initialize_cache()
65 self._initialize_cache()
66
66
67 if GitFactory and GitRemote:
67 if GitFactory and GitRemote:
68 git_repo_cache = self.cache.get_cache_region(
68 git_repo_cache = self.cache.get_cache_region(
69 'git', region='repo_object')
69 'git', region='repo_object')
70 git_factory = GitFactory(git_repo_cache)
70 git_factory = GitFactory(git_repo_cache)
71 self._git_remote = GitRemote(git_factory)
71 self._git_remote = GitRemote(git_factory)
72 else:
72 else:
73 log.info("Git client import failed")
73 log.info("Git client import failed")
74
74
75 if MercurialFactory and HgRemote:
75 if MercurialFactory and HgRemote:
76 hg_repo_cache = self.cache.get_cache_region(
76 hg_repo_cache = self.cache.get_cache_region(
77 'hg', region='repo_object')
77 'hg', region='repo_object')
78 hg_factory = MercurialFactory(hg_repo_cache)
78 hg_factory = MercurialFactory(hg_repo_cache)
79 self._hg_remote = HgRemote(hg_factory)
79 self._hg_remote = HgRemote(hg_factory)
80 else:
80 else:
81 log.info("Mercurial client import failed")
81 log.info("Mercurial client import failed")
82
82
83 if SubversionFactory and SvnRemote:
83 if SubversionFactory and SvnRemote:
84 svn_repo_cache = self.cache.get_cache_region(
84 svn_repo_cache = self.cache.get_cache_region(
85 'svn', region='repo_object')
85 'svn', region='repo_object')
86 svn_factory = SubversionFactory(svn_repo_cache)
86 svn_factory = SubversionFactory(svn_repo_cache)
87 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
87 self._svn_remote = SvnRemote(svn_factory, hg_factory=hg_factory)
88 else:
88 else:
89 log.info("Subversion client import failed")
89 log.info("Subversion client import failed")
90
90
91 self._vcsserver = VcsServer()
91 self._vcsserver = VcsServer()
92
92
93 def _initialize_cache(self):
93 def _initialize_cache(self):
94 cache_config = parse_cache_config_options(self.cache_config)
94 cache_config = parse_cache_config_options(self.cache_config)
95 log.info('Initializing beaker cache: %s' % cache_config)
95 log.info('Initializing beaker cache: %s' % cache_config)
96 self.cache = CacheManager(**cache_config)
96 self.cache = CacheManager(**cache_config)
97
97
98 def _configure_locale(self):
98 def _configure_locale(self):
99 if self.locale:
99 if self.locale:
100 log.info('Settings locale: `LC_ALL` to %s' % self.locale)
100 log.info('Settings locale: `LC_ALL` to %s' % self.locale)
101 else:
101 else:
102 log.info(
102 log.info(
103 'Configuring locale subsystem based on environment variables')
103 'Configuring locale subsystem based on environment variables')
104 try:
104 try:
105 # If self.locale is the empty string, then the locale
105 # If self.locale is the empty string, then the locale
106 # module will use the environment variables. See the
106 # module will use the environment variables. See the
107 # documentation of the package `locale`.
107 # documentation of the package `locale`.
108 locale.setlocale(locale.LC_ALL, self.locale)
108 locale.setlocale(locale.LC_ALL, self.locale)
109
109
110 language_code, encoding = locale.getlocale()
110 language_code, encoding = locale.getlocale()
111 log.info(
111 log.info(
112 'Locale set to language code "%s" with encoding "%s".',
112 'Locale set to language code "%s" with encoding "%s".',
113 language_code, encoding)
113 language_code, encoding)
114 except locale.Error:
114 except locale.Error:
115 log.exception(
115 log.exception(
116 'Cannot set locale, not configuring the locale system')
116 'Cannot set locale, not configuring the locale system')
117
117
118
118
119 class WsgiProxy(object):
119 class WsgiProxy(object):
120 def __init__(self, wsgi):
120 def __init__(self, wsgi):
121 self.wsgi = wsgi
121 self.wsgi = wsgi
122
122
123 def __call__(self, environ, start_response):
123 def __call__(self, environ, start_response):
124 input_data = environ['wsgi.input'].read()
124 input_data = environ['wsgi.input'].read()
125 input_data = msgpack.unpackb(input_data)
125 input_data = msgpack.unpackb(input_data)
126
126
127 error = None
127 error = None
128 try:
128 try:
129 data, status, headers = self.wsgi.handle(
129 data, status, headers = self.wsgi.handle(
130 input_data['environment'], input_data['input_data'],
130 input_data['environment'], input_data['input_data'],
131 *input_data['args'], **input_data['kwargs'])
131 *input_data['args'], **input_data['kwargs'])
132 except Exception as e:
132 except Exception as e:
133 data, status, headers = [], None, None
133 data, status, headers = [], None, None
134 error = {
134 error = {
135 'message': str(e),
135 'message': str(e),
136 '_vcs_kind': getattr(e, '_vcs_kind', None)
136 '_vcs_kind': getattr(e, '_vcs_kind', None)
137 }
137 }
138
138
139 start_response(200, {})
139 start_response(200, {})
140 return self._iterator(error, status, headers, data)
140 return self._iterator(error, status, headers, data)
141
141
142 def _iterator(self, error, status, headers, data):
142 def _iterator(self, error, status, headers, data):
143 initial_data = [
143 initial_data = [
144 error,
144 error,
145 status,
145 status,
146 headers,
146 headers,
147 ]
147 ]
148
148
149 for d in chain(initial_data, data):
149 for d in chain(initial_data, data):
150 yield msgpack.packb(d)
150 yield msgpack.packb(d)
151
151
152
152
153 class HTTPApplication(object):
153 class HTTPApplication(object):
154 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
154 ALLOWED_EXCEPTIONS = ('KeyError', 'URLError')
155
155
156 remote_wsgi = remote_wsgi
156 remote_wsgi = remote_wsgi
157 _use_echo_app = False
157 _use_echo_app = False
158
158
159 def __init__(self, settings=None, global_config=None):
159 def __init__(self, settings=None, global_config=None):
160 self.config = Configurator(settings=settings)
160 self.config = Configurator(settings=settings)
161 self.global_config = global_config
161 self.global_config = global_config
162
162
163 locale = settings.get('locale', '') or 'en_US.UTF-8'
163 locale = settings.get('locale', '') or 'en_US.UTF-8'
164 vcs = VCS(locale=locale, cache_config=settings)
164 vcs = VCS(locale=locale, cache_config=settings)
165 self._remotes = {
165 self._remotes = {
166 'hg': vcs._hg_remote,
166 'hg': vcs._hg_remote,
167 'git': vcs._git_remote,
167 'git': vcs._git_remote,
168 'svn': vcs._svn_remote,
168 'svn': vcs._svn_remote,
169 'server': vcs._vcsserver,
169 'server': vcs._vcsserver,
170 }
170 }
171 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
171 if settings.get('dev.use_echo_app', 'false').lower() == 'true':
172 self._use_echo_app = True
172 self._use_echo_app = True
173 log.warning("Using EchoApp for VCS operations.")
173 log.warning("Using EchoApp for VCS operations.")
174 self.remote_wsgi = remote_wsgi_stub
174 self.remote_wsgi = remote_wsgi_stub
175 self._configure_settings(settings)
175 self._configure_settings(settings)
176 self._configure()
176 self._configure()
177
177
178 def _configure_settings(self, app_settings):
178 def _configure_settings(self, app_settings):
179 """
179 """
180 Configure the settings module.
180 Configure the settings module.
181 """
181 """
182 git_path = app_settings.get('git_path', None)
182 git_path = app_settings.get('git_path', None)
183 if git_path:
183 if git_path:
184 settings.GIT_EXECUTABLE = git_path
184 settings.GIT_EXECUTABLE = git_path
185
185
186 def _configure(self):
186 def _configure(self):
187 self.config.add_renderer(
187 self.config.add_renderer(
188 name='msgpack',
188 name='msgpack',
189 factory=self._msgpack_renderer_factory)
189 factory=self._msgpack_renderer_factory)
190
190
191 self.config.add_route('service', '/_service')
191 self.config.add_route('service', '/_service')
192 self.config.add_route('status', '/status')
192 self.config.add_route('status', '/status')
193 self.config.add_route('hg_proxy', '/proxy/hg')
193 self.config.add_route('hg_proxy', '/proxy/hg')
194 self.config.add_route('git_proxy', '/proxy/git')
194 self.config.add_route('git_proxy', '/proxy/git')
195 self.config.add_route('vcs', '/{backend}')
195 self.config.add_route('vcs', '/{backend}')
196 self.config.add_route('stream_git', '/stream/git/*repo_name')
196 self.config.add_route('stream_git', '/stream/git/*repo_name')
197 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
197 self.config.add_route('stream_hg', '/stream/hg/*repo_name')
198
198
199 self.config.add_view(
199 self.config.add_view(
200 self.status_view, route_name='status', renderer='json')
200 self.status_view, route_name='status', renderer='json')
201 self.config.add_view(
201 self.config.add_view(
202 self.service_view, route_name='service', renderer='msgpack')
202 self.service_view, route_name='service', renderer='msgpack')
203
203
204 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
204 self.config.add_view(self.hg_proxy(), route_name='hg_proxy')
205 self.config.add_view(self.git_proxy(), route_name='git_proxy')
205 self.config.add_view(self.git_proxy(), route_name='git_proxy')
206 self.config.add_view(
206 self.config.add_view(
207 self.vcs_view, route_name='vcs', renderer='msgpack',
207 self.vcs_view, route_name='vcs', renderer='msgpack',
208 custom_predicates=[self.is_vcs_view])
208 custom_predicates=[self.is_vcs_view])
209
209
210 self.config.add_view(self.hg_stream(), route_name='stream_hg')
210 self.config.add_view(self.hg_stream(), route_name='stream_hg')
211 self.config.add_view(self.git_stream(), route_name='stream_git')
211 self.config.add_view(self.git_stream(), route_name='stream_git')
212
212
213 def notfound(request):
213 def notfound(request):
214 return {'status': '404 NOT FOUND'}
214 return {'status': '404 NOT FOUND'}
215 self.config.add_notfound_view(notfound, renderer='json')
215 self.config.add_notfound_view(notfound, renderer='json')
216
216
217 self.config.add_view(self.handle_vcs_exception, context=Exception)
217 self.config.add_view(self.handle_vcs_exception, context=Exception)
218
218
219 self.config.add_tween(
219 self.config.add_tween(
220 'vcsserver.tweens.RequestWrapperTween',
220 'vcsserver.tweens.RequestWrapperTween',
221 )
221 )
222
222
223 def wsgi_app(self):
223 def wsgi_app(self):
224 return self.config.make_wsgi_app()
224 return self.config.make_wsgi_app()
225
225
226 def vcs_view(self, request):
226 def vcs_view(self, request):
227 remote = self._remotes[request.matchdict['backend']]
227 remote = self._remotes[request.matchdict['backend']]
228 payload = msgpack.unpackb(request.body, use_list=True)
228 payload = msgpack.unpackb(request.body, use_list=True)
229 method = payload.get('method')
229 method = payload.get('method')
230 params = payload.get('params')
230 params = payload.get('params')
231 wire = params.get('wire')
231 wire = params.get('wire')
232 args = params.get('args')
232 args = params.get('args')
233 kwargs = params.get('kwargs')
233 kwargs = params.get('kwargs')
234 if wire:
234 if wire:
235 try:
235 try:
236 wire['context'] = uuid.UUID(wire['context'])
236 wire['context'] = uuid.UUID(wire['context'])
237 except KeyError:
237 except KeyError:
238 pass
238 pass
239 args.insert(0, wire)
239 args.insert(0, wire)
240
240
241 log.debug('method called:%s with kwargs:%s', method, kwargs)
241 log.debug('method called:%s with kwargs:%s', method, kwargs)
242 try:
242 try:
243 resp = getattr(remote, method)(*args, **kwargs)
243 resp = getattr(remote, method)(*args, **kwargs)
244 except Exception as e:
244 except Exception as e:
245 tb_info = traceback.format_exc()
245 tb_info = traceback.format_exc()
246
246
247 type_ = e.__class__.__name__
247 type_ = e.__class__.__name__
248 if type_ not in self.ALLOWED_EXCEPTIONS:
248 if type_ not in self.ALLOWED_EXCEPTIONS:
249 type_ = None
249 type_ = None
250
250
251 resp = {
251 resp = {
252 'id': payload.get('id'),
252 'id': payload.get('id'),
253 'error': {
253 'error': {
254 'message': e.message,
254 'message': e.message,
255 'traceback': tb_info,
255 'traceback': tb_info,
256 'type': type_
256 'type': type_
257 }
257 }
258 }
258 }
259 try:
259 try:
260 resp['error']['_vcs_kind'] = e._vcs_kind
260 resp['error']['_vcs_kind'] = e._vcs_kind
261 except AttributeError:
261 except AttributeError:
262 pass
262 pass
263 else:
263 else:
264 resp = {
264 resp = {
265 'id': payload.get('id'),
265 'id': payload.get('id'),
266 'result': resp
266 'result': resp
267 }
267 }
268
268
269 return resp
269 return resp
270
270
271 def status_view(self, request):
271 def status_view(self, request):
272 return {'status': 'OK'}
272 return {'status': 'OK'}
273
273
274 def service_view(self, request):
274 def service_view(self, request):
275 import vcsserver
275 import vcsserver
276 import ConfigParser as configparser
276 import ConfigParser as configparser
277
277
278 payload = msgpack.unpackb(request.body, use_list=True)
278 payload = msgpack.unpackb(request.body, use_list=True)
279
279
280 try:
280 try:
281 path = self.global_config['__file__']
281 path = self.global_config['__file__']
282 config = configparser.ConfigParser()
282 config = configparser.ConfigParser()
283 config.read(path)
283 config.read(path)
284 parsed_ini = config
284 parsed_ini = config
285 if parsed_ini.has_section('server:main'):
285 if parsed_ini.has_section('server:main'):
286 parsed_ini = dict(parsed_ini.items('server:main'))
286 parsed_ini = dict(parsed_ini.items('server:main'))
287 except Exception:
287 except Exception:
288 log.exception('Failed to read .ini file for display')
288 log.exception('Failed to read .ini file for display')
289 parsed_ini = {}
289 parsed_ini = {}
290
290
291 resp = {
291 resp = {
292 'id': payload.get('id'),
292 'id': payload.get('id'),
293 'result': dict(
293 'result': dict(
294 version=vcsserver.__version__,
294 version=vcsserver.__version__,
295 config=parsed_ini,
295 config=parsed_ini,
296 payload=payload,
296 payload=payload,
297 )
297 )
298 }
298 }
299 return resp
299 return resp
300
300
301 def _msgpack_renderer_factory(self, info):
301 def _msgpack_renderer_factory(self, info):
302 def _render(value, system):
302 def _render(value, system):
303 value = msgpack.packb(value)
303 value = msgpack.packb(value)
304 request = system.get('request')
304 request = system.get('request')
305 if request is not None:
305 if request is not None:
306 response = request.response
306 response = request.response
307 ct = response.content_type
307 ct = response.content_type
308 if ct == response.default_content_type:
308 if ct == response.default_content_type:
309 response.content_type = 'application/x-msgpack'
309 response.content_type = 'application/x-msgpack'
310 return value
310 return value
311 return _render
311 return _render
312
312
313 def hg_proxy(self):
313 def hg_proxy(self):
314 @wsgiapp
314 @wsgiapp
315 def _hg_proxy(environ, start_response):
315 def _hg_proxy(environ, start_response):
316 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
316 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
317 return app(environ, start_response)
317 return app(environ, start_response)
318 return _hg_proxy
318 return _hg_proxy
319
319
320 def git_proxy(self):
320 def git_proxy(self):
321 @wsgiapp
321 @wsgiapp
322 def _git_proxy(environ, start_response):
322 def _git_proxy(environ, start_response):
323 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
323 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
324 return app(environ, start_response)
324 return app(environ, start_response)
325 return _git_proxy
325 return _git_proxy
326
326
327 def hg_stream(self):
327 def hg_stream(self):
328 if self._use_echo_app:
328 if self._use_echo_app:
329 @wsgiapp
329 @wsgiapp
330 def _hg_stream(environ, start_response):
330 def _hg_stream(environ, start_response):
331 app = EchoApp('fake_path', 'fake_name', None)
331 app = EchoApp('fake_path', 'fake_name', None)
332 return app(environ, start_response)
332 return app(environ, start_response)
333 return _hg_stream
333 return _hg_stream
334 else:
334 else:
335 @wsgiapp
335 @wsgiapp
336 def _hg_stream(environ, start_response):
336 def _hg_stream(environ, start_response):
337 log.debug('http-app: handling hg stream')
337 repo_path = environ['HTTP_X_RC_REPO_PATH']
338 repo_path = environ['HTTP_X_RC_REPO_PATH']
338 repo_name = environ['HTTP_X_RC_REPO_NAME']
339 repo_name = environ['HTTP_X_RC_REPO_NAME']
339 packed_config = base64.b64decode(
340 packed_config = base64.b64decode(
340 environ['HTTP_X_RC_REPO_CONFIG'])
341 environ['HTTP_X_RC_REPO_CONFIG'])
341 config = msgpack.unpackb(packed_config)
342 config = msgpack.unpackb(packed_config)
342 app = scm_app.create_hg_wsgi_app(
343 app = scm_app.create_hg_wsgi_app(
343 repo_path, repo_name, config)
344 repo_path, repo_name, config)
344
345
345 # Consitent path information for hgweb
346 # Consitent path information for hgweb
346 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
347 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
347 environ['REPO_NAME'] = repo_name
348 environ['REPO_NAME'] = repo_name
349 log.debug('http-app: starting app handler '
350 'with %s and process request', app)
348 return app(environ, ResponseFilter(start_response))
351 return app(environ, ResponseFilter(start_response))
349 return _hg_stream
352 return _hg_stream
350
353
351 def git_stream(self):
354 def git_stream(self):
352 if self._use_echo_app:
355 if self._use_echo_app:
353 @wsgiapp
356 @wsgiapp
354 def _git_stream(environ, start_response):
357 def _git_stream(environ, start_response):
355 app = EchoApp('fake_path', 'fake_name', None)
358 app = EchoApp('fake_path', 'fake_name', None)
356 return app(environ, start_response)
359 return app(environ, start_response)
357 return _git_stream
360 return _git_stream
358 else:
361 else:
359 @wsgiapp
362 @wsgiapp
360 def _git_stream(environ, start_response):
363 def _git_stream(environ, start_response):
364 log.debug('http-app: handling git stream')
361 repo_path = environ['HTTP_X_RC_REPO_PATH']
365 repo_path = environ['HTTP_X_RC_REPO_PATH']
362 repo_name = environ['HTTP_X_RC_REPO_NAME']
366 repo_name = environ['HTTP_X_RC_REPO_NAME']
363 packed_config = base64.b64decode(
367 packed_config = base64.b64decode(
364 environ['HTTP_X_RC_REPO_CONFIG'])
368 environ['HTTP_X_RC_REPO_CONFIG'])
365 config = msgpack.unpackb(packed_config)
369 config = msgpack.unpackb(packed_config)
366
370
367 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
371 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
368 content_type = environ.get('CONTENT_TYPE', '')
372 content_type = environ.get('CONTENT_TYPE', '')
369
373
370 path = environ['PATH_INFO']
374 path = environ['PATH_INFO']
371 is_lfs_request = GIT_LFS_CONTENT_TYPE in content_type
375 is_lfs_request = GIT_LFS_CONTENT_TYPE in content_type
372 log.debug(
376 log.debug(
373 'LFS: Detecting if request `%s` is LFS server path based '
377 'LFS: Detecting if request `%s` is LFS server path based '
374 'on content type:`%s`, is_lfs:%s',
378 'on content type:`%s`, is_lfs:%s',
375 path, content_type, is_lfs_request)
379 path, content_type, is_lfs_request)
376
380
377 if not is_lfs_request:
381 if not is_lfs_request:
378 # fallback detection by path
382 # fallback detection by path
379 if GIT_LFS_PROTO_PAT.match(path):
383 if GIT_LFS_PROTO_PAT.match(path):
380 is_lfs_request = True
384 is_lfs_request = True
381 log.debug(
385 log.debug(
382 'LFS: fallback detection by path of: `%s`, is_lfs:%s',
386 'LFS: fallback detection by path of: `%s`, is_lfs:%s',
383 path, is_lfs_request)
387 path, is_lfs_request)
384
388
385 if is_lfs_request:
389 if is_lfs_request:
386 app = scm_app.create_git_lfs_wsgi_app(
390 app = scm_app.create_git_lfs_wsgi_app(
387 repo_path, repo_name, config)
391 repo_path, repo_name, config)
388 else:
392 else:
389 app = scm_app.create_git_wsgi_app(
393 app = scm_app.create_git_wsgi_app(
390 repo_path, repo_name, config)
394 repo_path, repo_name, config)
395
396 log.debug('http-app: starting app handler '
397 'with %s and process request', app)
391 return app(environ, start_response)
398 return app(environ, start_response)
392
399
393 return _git_stream
400 return _git_stream
394
401
395 def is_vcs_view(self, context, request):
402 def is_vcs_view(self, context, request):
396 """
403 """
397 View predicate that returns true if given backend is supported by
404 View predicate that returns true if given backend is supported by
398 defined remotes.
405 defined remotes.
399 """
406 """
400 backend = request.matchdict.get('backend')
407 backend = request.matchdict.get('backend')
401 return backend in self._remotes
408 return backend in self._remotes
402
409
403 def handle_vcs_exception(self, exception, request):
410 def handle_vcs_exception(self, exception, request):
404 _vcs_kind = getattr(exception, '_vcs_kind', '')
411 _vcs_kind = getattr(exception, '_vcs_kind', '')
405 if _vcs_kind == 'repo_locked':
412 if _vcs_kind == 'repo_locked':
406 # Get custom repo-locked status code if present.
413 # Get custom repo-locked status code if present.
407 status_code = request.headers.get('X-RC-Locked-Status-Code')
414 status_code = request.headers.get('X-RC-Locked-Status-Code')
408 return HTTPRepoLocked(
415 return HTTPRepoLocked(
409 title=exception.message, status_code=status_code)
416 title=exception.message, status_code=status_code)
410
417
411 # Re-raise exception if we can not handle it.
418 # Re-raise exception if we can not handle it.
412 log.exception(
419 log.exception(
413 'error occurred handling this request for path: %s', request.path)
420 'error occurred handling this request for path: %s', request.path)
414 raise exception
421 raise exception
415
422
416
423
417 class ResponseFilter(object):
424 class ResponseFilter(object):
418
425
419 def __init__(self, start_response):
426 def __init__(self, start_response):
420 self._start_response = start_response
427 self._start_response = start_response
421
428
422 def __call__(self, status, response_headers, exc_info=None):
429 def __call__(self, status, response_headers, exc_info=None):
423 headers = tuple(
430 headers = tuple(
424 (h, v) for h, v in response_headers
431 (h, v) for h, v in response_headers
425 if not wsgiref.util.is_hop_by_hop(h))
432 if not wsgiref.util.is_hop_by_hop(h))
426 return self._start_response(status, headers, exc_info)
433 return self._start_response(status, headers, exc_info)
427
434
428
435
429 def main(global_config, **settings):
436 def main(global_config, **settings):
430 if MercurialFactory:
437 if MercurialFactory:
431 hgpatches.patch_largefiles_capabilities()
438 hgpatches.patch_largefiles_capabilities()
432 hgpatches.patch_subrepo_type_mapping()
439 hgpatches.patch_subrepo_type_mapping()
433 app = HTTPApplication(settings=settings, global_config=global_config)
440 app = HTTPApplication(settings=settings, global_config=global_config)
434 return app.wsgi_app()
441 return app.wsgi_app()
General Comments 0
You need to be logged in to leave comments. Login now