##// END OF EJS Templates
http-app: added default not_found view.
marcink -
r151:0f43430b default
parent child Browse files
Show More
@@ -1,390 +1,395 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
203
204 self.config.add_view(self.hg_stream(), route_name='stream_hg')
204 self.config.add_view(self.hg_stream(), route_name='stream_hg')
205 self.config.add_view(self.git_stream(), route_name='stream_git')
205 self.config.add_view(self.git_stream(), route_name='stream_git')
206
207 def notfound(request):
208 return {'status': '404 NOT FOUND'}
209 self.config.add_notfound_view(notfound, renderer='json')
210
206 self.config.add_view(
211 self.config.add_view(
207 self.handle_vcs_exception, context=Exception,
212 self.handle_vcs_exception, context=Exception,
208 custom_predicates=[self.is_vcs_exception])
213 custom_predicates=[self.is_vcs_exception])
209
214
210 self.config.add_view(
215 self.config.add_view(
211 self.general_error_handler, context=Exception)
216 self.general_error_handler, context=Exception)
212
217
213
218
214 def wsgi_app(self):
219 def wsgi_app(self):
215 return self.config.make_wsgi_app()
220 return self.config.make_wsgi_app()
216
221
217 def vcs_view(self, request):
222 def vcs_view(self, request):
218 remote = self._remotes[request.matchdict['backend']]
223 remote = self._remotes[request.matchdict['backend']]
219 payload = msgpack.unpackb(request.body, use_list=True)
224 payload = msgpack.unpackb(request.body, use_list=True)
220 method = payload.get('method')
225 method = payload.get('method')
221 params = payload.get('params')
226 params = payload.get('params')
222 wire = params.get('wire')
227 wire = params.get('wire')
223 args = params.get('args')
228 args = params.get('args')
224 kwargs = params.get('kwargs')
229 kwargs = params.get('kwargs')
225 if wire:
230 if wire:
226 try:
231 try:
227 wire['context'] = uuid.UUID(wire['context'])
232 wire['context'] = uuid.UUID(wire['context'])
228 except KeyError:
233 except KeyError:
229 pass
234 pass
230 args.insert(0, wire)
235 args.insert(0, wire)
231
236
232 try:
237 try:
233 resp = getattr(remote, method)(*args, **kwargs)
238 resp = getattr(remote, method)(*args, **kwargs)
234 except Exception as e:
239 except Exception as e:
235 tb_info = traceback.format_exc()
240 tb_info = traceback.format_exc()
236
241
237 type_ = e.__class__.__name__
242 type_ = e.__class__.__name__
238 if type_ not in self.ALLOWED_EXCEPTIONS:
243 if type_ not in self.ALLOWED_EXCEPTIONS:
239 type_ = None
244 type_ = None
240
245
241 resp = {
246 resp = {
242 'id': payload.get('id'),
247 'id': payload.get('id'),
243 'error': {
248 'error': {
244 'message': e.message,
249 'message': e.message,
245 'traceback': tb_info,
250 'traceback': tb_info,
246 'type': type_
251 'type': type_
247 }
252 }
248 }
253 }
249 try:
254 try:
250 resp['error']['_vcs_kind'] = e._vcs_kind
255 resp['error']['_vcs_kind'] = e._vcs_kind
251 except AttributeError:
256 except AttributeError:
252 pass
257 pass
253 else:
258 else:
254 resp = {
259 resp = {
255 'id': payload.get('id'),
260 'id': payload.get('id'),
256 'result': resp
261 'result': resp
257 }
262 }
258
263
259 return resp
264 return resp
260
265
261 def status_view(self, request):
266 def status_view(self, request):
262 return {'status': 'OK'}
267 return {'status': 'OK'}
263
268
264 def service_view(self, request):
269 def service_view(self, request):
265 import vcsserver
270 import vcsserver
266 payload = msgpack.unpackb(request.body, use_list=True)
271 payload = msgpack.unpackb(request.body, use_list=True)
267 resp = {
272 resp = {
268 'id': payload.get('id'),
273 'id': payload.get('id'),
269 'result': dict(
274 'result': dict(
270 version=vcsserver.__version__,
275 version=vcsserver.__version__,
271 config={},
276 config={},
272 payload=payload,
277 payload=payload,
273 )
278 )
274 }
279 }
275 return resp
280 return resp
276
281
277 def _msgpack_renderer_factory(self, info):
282 def _msgpack_renderer_factory(self, info):
278 def _render(value, system):
283 def _render(value, system):
279 value = msgpack.packb(value)
284 value = msgpack.packb(value)
280 request = system.get('request')
285 request = system.get('request')
281 if request is not None:
286 if request is not None:
282 response = request.response
287 response = request.response
283 ct = response.content_type
288 ct = response.content_type
284 if ct == response.default_content_type:
289 if ct == response.default_content_type:
285 response.content_type = 'application/x-msgpack'
290 response.content_type = 'application/x-msgpack'
286 return value
291 return value
287 return _render
292 return _render
288
293
289 def hg_proxy(self):
294 def hg_proxy(self):
290 @wsgiapp
295 @wsgiapp
291 def _hg_proxy(environ, start_response):
296 def _hg_proxy(environ, start_response):
292 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
297 app = WsgiProxy(self.remote_wsgi.HgRemoteWsgi())
293 return app(environ, start_response)
298 return app(environ, start_response)
294 return _hg_proxy
299 return _hg_proxy
295
300
296 def git_proxy(self):
301 def git_proxy(self):
297 @wsgiapp
302 @wsgiapp
298 def _git_proxy(environ, start_response):
303 def _git_proxy(environ, start_response):
299 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
304 app = WsgiProxy(self.remote_wsgi.GitRemoteWsgi())
300 return app(environ, start_response)
305 return app(environ, start_response)
301 return _git_proxy
306 return _git_proxy
302
307
303 def hg_stream(self):
308 def hg_stream(self):
304 if self._use_echo_app:
309 if self._use_echo_app:
305 @wsgiapp
310 @wsgiapp
306 def _hg_stream(environ, start_response):
311 def _hg_stream(environ, start_response):
307 app = EchoApp('fake_path', 'fake_name', None)
312 app = EchoApp('fake_path', 'fake_name', None)
308 return app(environ, start_response)
313 return app(environ, start_response)
309 return _hg_stream
314 return _hg_stream
310 else:
315 else:
311 @wsgiapp
316 @wsgiapp
312 def _hg_stream(environ, start_response):
317 def _hg_stream(environ, start_response):
313 repo_path = environ['HTTP_X_RC_REPO_PATH']
318 repo_path = environ['HTTP_X_RC_REPO_PATH']
314 repo_name = environ['HTTP_X_RC_REPO_NAME']
319 repo_name = environ['HTTP_X_RC_REPO_NAME']
315 packed_config = base64.b64decode(
320 packed_config = base64.b64decode(
316 environ['HTTP_X_RC_REPO_CONFIG'])
321 environ['HTTP_X_RC_REPO_CONFIG'])
317 config = msgpack.unpackb(packed_config)
322 config = msgpack.unpackb(packed_config)
318 app = scm_app.create_hg_wsgi_app(
323 app = scm_app.create_hg_wsgi_app(
319 repo_path, repo_name, config)
324 repo_path, repo_name, config)
320
325
321 # Consitent path information for hgweb
326 # Consitent path information for hgweb
322 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
327 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
323 environ['REPO_NAME'] = repo_name
328 environ['REPO_NAME'] = repo_name
324 return app(environ, ResponseFilter(start_response))
329 return app(environ, ResponseFilter(start_response))
325 return _hg_stream
330 return _hg_stream
326
331
327 def git_stream(self):
332 def git_stream(self):
328 if self._use_echo_app:
333 if self._use_echo_app:
329 @wsgiapp
334 @wsgiapp
330 def _git_stream(environ, start_response):
335 def _git_stream(environ, start_response):
331 app = EchoApp('fake_path', 'fake_name', None)
336 app = EchoApp('fake_path', 'fake_name', None)
332 return app(environ, start_response)
337 return app(environ, start_response)
333 return _git_stream
338 return _git_stream
334 else:
339 else:
335 @wsgiapp
340 @wsgiapp
336 def _git_stream(environ, start_response):
341 def _git_stream(environ, start_response):
337 repo_path = environ['HTTP_X_RC_REPO_PATH']
342 repo_path = environ['HTTP_X_RC_REPO_PATH']
338 repo_name = environ['HTTP_X_RC_REPO_NAME']
343 repo_name = environ['HTTP_X_RC_REPO_NAME']
339 packed_config = base64.b64decode(
344 packed_config = base64.b64decode(
340 environ['HTTP_X_RC_REPO_CONFIG'])
345 environ['HTTP_X_RC_REPO_CONFIG'])
341 config = msgpack.unpackb(packed_config)
346 config = msgpack.unpackb(packed_config)
342
347
343 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
348 environ['PATH_INFO'] = environ['HTTP_X_RC_PATH_INFO']
344 app = scm_app.create_git_wsgi_app(
349 app = scm_app.create_git_wsgi_app(
345 repo_path, repo_name, config)
350 repo_path, repo_name, config)
346 return app(environ, start_response)
351 return app(environ, start_response)
347 return _git_stream
352 return _git_stream
348
353
349 def is_vcs_exception(self, context, request):
354 def is_vcs_exception(self, context, request):
350 """
355 """
351 View predicate that returns true if the context object is a VCS
356 View predicate that returns true if the context object is a VCS
352 exception.
357 exception.
353 """
358 """
354 return hasattr(context, '_vcs_kind')
359 return hasattr(context, '_vcs_kind')
355
360
356 def handle_vcs_exception(self, exception, request):
361 def handle_vcs_exception(self, exception, request):
357 if exception._vcs_kind == 'repo_locked':
362 if exception._vcs_kind == 'repo_locked':
358 # Get custom repo-locked status code if present.
363 # Get custom repo-locked status code if present.
359 status_code = request.headers.get('X-RC-Locked-Status-Code')
364 status_code = request.headers.get('X-RC-Locked-Status-Code')
360 return HTTPRepoLocked(
365 return HTTPRepoLocked(
361 title=exception.message, status_code=status_code)
366 title=exception.message, status_code=status_code)
362
367
363 # Re-raise exception if we can not handle it.
368 # Re-raise exception if we can not handle it.
364 raise exception
369 raise exception
365
370
366 def general_error_handler(self, exception, request):
371 def general_error_handler(self, exception, request):
367 log.exception(
372 log.exception(
368 'error occurred handling this request for path: %s',
373 'error occurred handling this request for path: %s',
369 request.path)
374 request.path)
370 raise exception
375 raise exception
371
376
372
377
373 class ResponseFilter(object):
378 class ResponseFilter(object):
374
379
375 def __init__(self, start_response):
380 def __init__(self, start_response):
376 self._start_response = start_response
381 self._start_response = start_response
377
382
378 def __call__(self, status, response_headers, exc_info=None):
383 def __call__(self, status, response_headers, exc_info=None):
379 headers = tuple(
384 headers = tuple(
380 (h, v) for h, v in response_headers
385 (h, v) for h, v in response_headers
381 if not wsgiref.util.is_hop_by_hop(h))
386 if not wsgiref.util.is_hop_by_hop(h))
382 return self._start_response(status, headers, exc_info)
387 return self._start_response(status, headers, exc_info)
383
388
384
389
385 def main(global_config, **settings):
390 def main(global_config, **settings):
386 if MercurialFactory:
391 if MercurialFactory:
387 hgpatches.patch_largefiles_capabilities()
392 hgpatches.patch_largefiles_capabilities()
388 hgpatches.patch_subrepo_type_mapping()
393 hgpatches.patch_subrepo_type_mapping()
389 app = HTTPApplication(settings=settings)
394 app = HTTPApplication(settings=settings)
390 return app.wsgi_app()
395 return app.wsgi_app()
General Comments 0
You need to be logged in to leave comments. Login now