##// END OF EJS Templates
caches: optimized defaults for safer more reliable behaviour
caches: optimized defaults for safer more reliable behaviour

File last commit:

r4655:009d312e default
r4720:69c58338 default
Show More
vcs.py
280 lines | 9.2 KiB | text/x-python | PythonLexer
project: added all source files and assets
r1 # -*- coding: utf-8 -*-
code: update copyrights to 2020
r4306 # Copyright (C) 2010-2020 RhodeCode GmbH
project: added all source files and assets
r1 #
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
import gzip
import shutil
import logging
import tempfile
import urlparse
vcs: register repo_name as specialized middleware variables instead...
r757 from webob.exc import HTTPNotFound
project: added all source files and assets
r1 import rhodecode
from rhodecode.lib.middleware.appenlight import wrap_in_appenlight_if_enabled
from rhodecode.lib.middleware.simplegit import SimpleGit, GIT_PROTO_PAT
from rhodecode.lib.middleware.simplehg import SimpleHg
from rhodecode.lib.middleware.simplesvn import SimpleSvn
vcs: moved svn proxy settings into vcs related settings...
r754 from rhodecode.model.settings import VcsSettingsModel
project: added all source files and assets
r1
log = logging.getLogger(__name__)
vcs: do an early detection of vcs-type request....
r1297 VCS_TYPE_KEY = '_rc_vcs_type'
VCS_TYPE_SKIP = '_rc_vcs_skip'
project: added all source files and assets
r1
def is_git(environ):
"""
Returns True if requests should be handled by GIT wsgi middleware
"""
is_git_path = GIT_PROTO_PAT.match(environ['PATH_INFO'])
log.debug(
'request path: `%s` detected as GIT PROTOCOL %s', environ['PATH_INFO'],
is_git_path is not None)
return is_git_path
def is_hg(environ):
"""
Returns True if requests target is mercurial server - header
``HTTP_ACCEPT`` of such request would start with ``application/mercurial``.
"""
is_hg_path = False
http_accept = environ.get('HTTP_ACCEPT')
if http_accept and http_accept.startswith('application/mercurial'):
query = urlparse.parse_qs(environ['QUERY_STRING'])
if 'cmd' in query:
is_hg_path = True
log.debug(
'request path: `%s` detected as HG PROTOCOL %s', environ['PATH_INFO'],
is_hg_path)
return is_hg_path
def is_svn(environ):
"""
Returns True if requests target is Subversion server
"""
svn: extend detection of SVN to PROPFIND/PROPATCH methods....
r2262
project: added all source files and assets
r1 http_dav = environ.get('HTTP_DAV', '')
subversion: Detect requests also based on magic path.
r437 magic_path_segment = rhodecode.CONFIG.get(
'rhodecode_subversion_magic_path', '/!svn')
is_svn_path = (
'subversion' in http_dav or
svn: extend detection of SVN to PROPFIND/PROPATCH methods....
r2262 magic_path_segment in environ['PATH_INFO']
or environ['REQUEST_METHOD'] in ['PROPFIND', 'PROPPATCH']
)
project: added all source files and assets
r1 log.debug(
'request path: `%s` detected as SVN PROTOCOL %s', environ['PATH_INFO'],
is_svn_path)
return is_svn_path
class GunzipMiddleware(object):
"""
WSGI middleware that unzips gzip-encoded requests before
passing on to the underlying application.
"""
def __init__(self, application):
self.app = application
def __call__(self, environ, start_response):
accepts_encoding_header = environ.get('HTTP_CONTENT_ENCODING', b'')
if b'gzip' in accepts_encoding_header:
log.debug('gzip detected, now running gunzip wrapper')
wsgi_input = environ['wsgi.input']
if not hasattr(environ['wsgi.input'], 'seek'):
# The gzip implementation in the standard library of Python 2.x
# requires the '.seek()' and '.tell()' methods to be available
# on the input stream. Read the data into a temporary file to
# work around this limitation.
wsgi_input = tempfile.SpooledTemporaryFile(64 * 1024 * 1024)
shutil.copyfileobj(environ['wsgi.input'], wsgi_input)
wsgi_input.seek(0)
environ['wsgi.input'] = gzip.GzipFile(fileobj=wsgi_input, mode='r')
# since we "Ungzipped" the content we say now it's no longer gzip
# content encoding
del environ['HTTP_CONTENT_ENCODING']
# content length has changes ? or i'm not sure
if 'CONTENT_LENGTH' in environ:
del environ['CONTENT_LENGTH']
else:
log.debug('content not gzipped, gzipMiddleware passing '
'request further')
return self.app(environ, start_response)
vcs: do an early detection of vcs-type request....
r1297 def is_vcs_call(environ):
if VCS_TYPE_KEY in environ:
raw_type = environ[VCS_TYPE_KEY]
return raw_type and raw_type != VCS_TYPE_SKIP
return False
artifacts: skip vcs detection for artifact downloads.
r4475 def get_path_elem(route_path):
if not route_path:
return None
cleaned_route_path = route_path.lstrip('/')
if cleaned_route_path:
cleaned_route_path_elems = cleaned_route_path.split('/')
if cleaned_route_path_elems:
return cleaned_route_path_elems[0]
return None
vcs: do an early detection of vcs-type request....
r1297 def detect_vcs_request(environ, backends):
checks = {
'hg': (is_hg, SimpleHg),
'git': (is_git, SimpleGit),
'svn': (is_svn, SimpleSvn),
}
handler = None
artifacts: skip vcs detection for artifact downloads.
r4475 # List of path views first chunk we don't do any checks
white_list = [
# e.g /_file_store/download
core: optimize some calls to skip license/scm detection on them
r4655 '_file_store',
# static files no detection
'_static',
# full channelstream connect should be VCS skipped
'_admin/channelstream/connect',
artifacts: skip vcs detection for artifact downloads.
r4475 ]
path_info = environ['PATH_INFO']
core: optimize some calls to skip license/scm detection on them
r4655 path_elem = get_path_elem(path_info)
if path_elem in white_list:
artifacts: skip vcs detection for artifact downloads.
r4475 log.debug('path `%s` in whitelist, skipping...', path_info)
return handler
vcs: do an early detection of vcs-type request....
r1297
core: optimize some calls to skip license/scm detection on them
r4655 path_url = path_info.lstrip('/')
if path_url in white_list:
log.debug('full url path `%s` in whitelist, skipping...', path_url)
return handler
vcs: do an early detection of vcs-type request....
r1297 if VCS_TYPE_KEY in environ:
raw_type = environ[VCS_TYPE_KEY]
if raw_type == VCS_TYPE_SKIP:
log.debug('got `skip` marker for vcs detection, skipping...')
return handler
_check, handler = checks.get(raw_type) or [None, None]
if handler:
log.debug('got handler:%s from environ', handler)
if not handler:
core: optimize some calls to skip license/scm detection on them
r4655 log.debug('request start: checking if request for `%s` is of VCS type in order: %s', path_elem, backends)
vcs: do an early detection of vcs-type request....
r1297 for vcs_type in backends:
vcs_check, _handler = checks[vcs_type]
if vcs_check(environ):
log.debug('vcs handler found %s', _handler)
handler = _handler
break
return handler
project: added all source files and assets
r1 class VCSMiddleware(object):
pylons: remove pylons as dependency...
r2351 def __init__(self, app, registry, config, appenlight_client):
project: added all source files and assets
r1 self.application = app
pylons: remove pylons as dependency...
r2351 self.registry = registry
project: added all source files and assets
r1 self.config = config
self.appenlight_client = appenlight_client
vcs: moved svn proxy settings into vcs related settings...
r754 self.use_gzip = True
vcs: register repo_name as specialized middleware variables instead...
r757 # order in which we check the middlewares, based on vcs.backends config
self.check_middlewares = config['vcs.backends']
vcs: moved svn proxy settings into vcs related settings...
r754
def vcs_config(self, repo_name=None):
"""
returns serialized VcsSettings
"""
simplevcs: fixed logic of extraction of base_path
r2362 try:
return VcsSettingsModel(
repo=repo_name).get_ui_settings_as_config_obj()
except Exception:
pass
vcs: moved svn proxy settings into vcs related settings...
r754
vcs: register repo_name as specialized middleware variables instead...
r757 def wrap_in_gzip_if_enabled(self, app, config):
vcs: moved svn proxy settings into vcs related settings...
r754 if self.use_gzip:
app = GunzipMiddleware(app)
return app
project: added all source files and assets
r1
def _get_handler_app(self, environ):
app = None
vcs: do an early detection of vcs-type request....
r1297 log.debug('VCSMiddleware: detecting vcs type.')
handler = detect_vcs_request(environ, self.check_middlewares)
if handler:
pylons: remove pylons as dependency...
r2351 app = handler(self.config, self.registry)
project: added all source files and assets
r1
return app
def __call__(self, environ, start_response):
vcs: register repo_name as specialized middleware variables instead...
r757 # check if we handle one of interesting protocols, optionally extract
# specific vcsSettings and allow changes of how things are wrapped
project: added all source files and assets
r1 vcs_handler = self._get_handler_app(environ)
if vcs_handler:
vcs: register repo_name as specialized middleware variables instead...
r757 # translate the _REPO_ID into real repo NAME for usage
# in middleware
environ['PATH_INFO'] = vcs_handler._get_by_id(environ['PATH_INFO'])
Martin Bornhold
vcs: Clean up the shadow-repo-expose code and make some nicer comments.
r904 # Set acl, url and vcs repo names.
Martin Bornhold
vcs: Move code for parsing the repository names (url, vcs, acl) from vcs to simplevcs.
r889 vcs_handler.set_repo_names(environ)
vcs: Minimal change to expose the shadow repository...
r887
simplevcs: fixed logic of extraction of base_path
r2362 # register repo config back to the handler
vcs_conf = self.vcs_config(vcs_handler.acl_repo_name)
# maybe damaged/non existent settings. We still want to
# pass that point to validate on is_valid_and_existing_repo
# and return proper HTTP Code back to client
if vcs_conf:
vcs_handler.repo_vcs_config = vcs_conf
vcs: register repo_name as specialized middleware variables instead...
r757 # check for type, presence in database and on filesystem
if not vcs_handler.is_valid_and_existing_repo(
Martin Bornhold
vcs: Move code for parsing the repository names (url, vcs, acl) from vcs to simplevcs.
r889 vcs_handler.acl_repo_name,
pylons: remove pylons as dependency...
r2351 vcs_handler.base_path,
Martin Bornhold
vcs: Move code for parsing the repository names (url, vcs, acl) from vcs to simplevcs.
r889 vcs_handler.SCM):
vcs: register repo_name as specialized middleware variables instead...
r757 return HTTPNotFound()(environ, start_response)
Martin Bornhold
vcs: Move code for parsing the repository names (url, vcs, acl) from vcs to simplevcs.
r889 environ['REPO_NAME'] = vcs_handler.url_repo_name
vcs: register repo_name as specialized middleware variables instead...
r757
Martin Bornhold
vcs: Move code for parsing the repository names (url, vcs, acl) from vcs to simplevcs.
r889 # Wrap handler in middlewares if they are enabled.
vcs: register repo_name as specialized middleware variables instead...
r757 vcs_handler = self.wrap_in_gzip_if_enabled(
vcs_handler, self.config)
vcs_handler, _ = wrap_in_appenlight_if_enabled(
vcs_handler, self.config, self.appenlight_client)
Martin Bornhold
vcs: Move code for parsing the repository names (url, vcs, acl) from vcs to simplevcs.
r889
project: added all source files and assets
r1 return vcs_handler(environ, start_response)
return self.application(environ, start_response)