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