diff --git a/rhodecode/apps/ssh_support/lib/backends/svn.py b/rhodecode/apps/ssh_support/lib/backends/svn.py --- a/rhodecode/apps/ssh_support/lib/backends/svn.py +++ b/rhodecode/apps/ssh_support/lib/backends/svn.py @@ -25,6 +25,8 @@ import tempfile from subprocess import Popen, PIPE import urllib.parse +from rhodecode.lib.str_utils import safe_bytes +from rhodecode_tools.lib.utils import safe_str from .base import SshVcsServer log = logging.getLogger(__name__) @@ -81,7 +83,7 @@ class SubversionTunnelWrapper(object): def sync(self): while self.process.poll() is None: - next_byte = self.stdin.read(1) + next_byte = self.stdin.buffer.read(1) if not next_byte: break self.process.stdin.write(next_byte) @@ -106,7 +108,7 @@ class SubversionTunnelWrapper(object): data['url'] = self._svn_string(data['url']) data['ra_client'] = self._svn_string(data['ra_client']) data['client'] = data['client'] or '' - buffer_ = ( + buffer_ = safe_bytes( "( {version} ( {capabilities} ) {url}{ra_client}" "( {client}) ) ".format(**data)) self.process.stdin.write(buffer_) @@ -127,21 +129,21 @@ class SubversionTunnelWrapper(object): return f'{len(str_)}:{str_} ' def _read_first_client_response(self): - buffer_ = "" + buffer_ = b"" brackets_stack = [] while True: - next_byte = self.stdin.read(1) + next_byte = self.stdin.buffer.read(1) buffer_ += next_byte - if next_byte == "(": + if next_byte == b"(": brackets_stack.append(next_byte) - elif next_byte == ")": + elif next_byte == b")": brackets_stack.pop() - elif next_byte == " " and not brackets_stack: + elif next_byte == b" " and not brackets_stack: break return buffer_ - def _parse_first_client_response(self, buffer_): + def _parse_first_client_response(self, buffer_: bytes): """ According to the Subversion RA protocol, the first request should look like: @@ -151,16 +153,20 @@ class SubversionTunnelWrapper(object): Please check https://svn.apache.org/repos/asf/subversion/trunk/subversion/libsvn_ra_svn/protocol """ - version_re = r'(?P\d+)' - capabilities_re = r'\(\s(?P[\w\d\-\ ]+)\s\)' - url_re = r'\d+\:(?P[\W\w]+)' - ra_client_re = r'(\d+\:(?P[\W\w]+)\s)' - client_re = r'(\d+\:(?P[\W\w]+)\s)*' + version_re = br'(?P\d+)' + capabilities_re = br'\(\s(?P[\w\d\-\ ]+)\s\)' + url_re = br'\d+\:(?P[\W\w]+)' + ra_client_re = br'(\d+\:(?P[\W\w]+)\s)' + client_re = br'(\d+\:(?P[\W\w]+)\s)*' regex = re.compile( - r'^\(\s{version}\s{capabilities}\s{url}\s{ra_client}' - r'\(\s{client}\)\s\)\s*$'.format( - version=version_re, capabilities=capabilities_re, - url=url_re, ra_client=ra_client_re, client=client_re)) + br'^\(\s%b\s%b\s%b\s%b' + br'\(\s%b\)\s\)\s*$' % ( + version_re, + capabilities_re, + url_re, + ra_client_re, + client_re) + ) matcher = regex.match(buffer_) return matcher.groupdict() if matcher else None @@ -202,7 +208,7 @@ class SubversionTunnelWrapper(object): url_parts = urllib.parse.urlparse(first_response['url']) - self.server.repo_name = self._match_repo_name(url_parts.path.strip('/')) + self.server.repo_name = self._match_repo_name(safe_str(url_parts.path).strip('/')) exit_code = self.server._check_permissions(action) if exit_code: