# HG changeset patch # User RhodeCode Admin # Date 2023-12-01 08:48:28 # Node ID e17d6d1598604593fb59d27658a6bdc0a0792156 # Parent 2c6368b259dcd10f8d887592f08d6a80870d6ce5 feat(svn): improvements to handle SVN protocol 1.4 features - added support to actually allow HEAD type calls - support HEAD / DELETE calls properly with new requets - use request session for performance optimization on making a lot of calls. diff --git a/rhodecode/lib/middleware/simplesvn.py b/rhodecode/lib/middleware/simplesvn.py --- a/rhodecode/lib/middleware/simplesvn.py +++ b/rhodecode/lib/middleware/simplesvn.py @@ -48,6 +48,7 @@ class SimpleSvnApp(object): def __init__(self, config): self.config = config + self.session = requests.Session() def __call__(self, environ, start_response): request_headers = self._get_request_headers(environ) @@ -94,10 +95,17 @@ class SimpleSvnApp(object): log.debug('Calling SVN PROXY at `%s`, using method:%s. Stream: %s', path_info, req_method, stream) + call_kwargs = dict( + data=data_io, + headers=request_headers, + stream=stream + ) + if req_method in ['HEAD', 'DELETE']: + del call_kwargs['data'] + try: - response = requests.request( - req_method, path_info, - data=data_io, headers=request_headers, stream=stream) + response = self.session.request( + req_method, path_info, **call_kwargs) except requests.ConnectionError: log.exception('ConnectionError occurred for endpoint %s', path_info) raise diff --git a/rhodecode/lib/middleware/simplevcs.py b/rhodecode/lib/middleware/simplevcs.py --- a/rhodecode/lib/middleware/simplevcs.py +++ b/rhodecode/lib/middleware/simplevcs.py @@ -63,11 +63,12 @@ from rhodecode.model.settings import Set log = logging.getLogger(__name__) -def extract_svn_txn_id(acl_repo_name, data): +def extract_svn_txn_id(acl_repo_name, data: bytes): """ Helper method for extraction of svn txn_id from submitted XML data during POST operations """ + try: root = etree.fromstring(data) pat = re.compile(r'/txn/(?P.*)') @@ -609,13 +610,13 @@ class SimpleVCS(object): stream = environ['wsgi.input'] if isinstance(stream, io.BytesIO): - data: str = safe_str(stream.getvalue()) + data: bytes = stream.getvalue() elif hasattr(stream, 'buf'): # most likely gunicorn.http.body.Body - data: str = safe_str(stream.buf.getvalue()) + data: bytes = stream.buf.getvalue() else: # fallback to the crudest way, copy the iterator - data = safe_str(stream.read()) - environ['wsgi.input'] = io.BytesIO(safe_bytes(data)) + data = safe_bytes(stream.read()) + environ['wsgi.input'] = io.BytesIO(data) txn_id = extract_svn_txn_id(self.acl_repo_name, data) diff --git a/rhodecode/lib/middleware/vcs.py b/rhodecode/lib/middleware/vcs.py --- a/rhodecode/lib/middleware/vcs.py +++ b/rhodecode/lib/middleware/vcs.py @@ -84,10 +84,12 @@ def is_svn(environ): magic_path_segment = rhodecode.CONFIG.get( 'rhodecode_subversion_magic_path', '/!svn') path_info = get_path_info(environ) + req_method = environ['REQUEST_METHOD'] + is_svn_path = ( 'subversion' in http_dav or magic_path_segment in path_info - or environ['REQUEST_METHOD'] in ['PROPFIND', 'PROPPATCH'] + or req_method in ['PROPFIND', 'PROPPATCH', 'HEAD'] ) log.debug( 'request path: `%s` detected as SVN PROTOCOL %s', path_info, @@ -187,6 +189,7 @@ def detect_vcs_request(environ, backends ] path_info = get_path_info(environ) path_url = path_info.lstrip('/') + req_method = environ.get('REQUEST_METHOD') for item in white_list: if item.endswith('++') and path_url.startswith(item[:-2]): @@ -210,7 +213,8 @@ def detect_vcs_request(environ, backends log.debug('got handler:%s from environ', handler) if not handler: - log.debug('request start: checking if request for `%s` is of VCS type in order: %s', path_url, backends) + log.debug('request start: checking if request for `%s:%s` is of VCS type in order: %s', + req_method, path_url, backends) for vcs_type in backends: vcs_check, _handler = checks[vcs_type] if vcs_check(environ):