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.
This commit is contained in:
RhodeCode Admin 2023-12-01 09:48:28 +01:00
parent 2bbbdccd2a
commit 25c079d921
3 changed files with 23 additions and 10 deletions

View file

@ -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

View file

@ -63,11 +63,12 @@ from rhodecode.model.settings import SettingsModel, VcsSettingsModel
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<txn_id>.*)')
@ -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)

View file

@ -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):