diff --git a/vcsserver/base.py b/vcsserver/base.py --- a/vcsserver/base.py +++ b/vcsserver/base.py @@ -134,3 +134,9 @@ def archive_repo(walker, archive_dest_pa archiver.addfile(f_path, 0o644, False, b'\n'.join(meta)) return archiver.done() + + +class BinaryEnvelope(object): + def __init__(self, value, bin_type=True): + self.value = value + self.bin_type = bin_type diff --git a/vcsserver/http_main.py b/vcsserver/http_main.py --- a/vcsserver/http_main.py +++ b/vcsserver/http_main.py @@ -37,6 +37,7 @@ from pyramid.config import Configurator from pyramid.wsgi import wsgiapp from pyramid.response import Response +from vcsserver.base import BinaryEnvelope from vcsserver.lib.rc_json import json from vcsserver.config.settings_maker import SettingsMaker from vcsserver.str_utils import safe_int, safe_bytes, safe_str @@ -501,7 +502,14 @@ class HTTPApplication(object): return resp def _msgpack_renderer_factory(self, info): + def _render(value, system): + bin_type = False + res = value.get('result') + if res and isinstance(res, BinaryEnvelope): + value['result'] = res.value + bin_type = res.bin_type + request = system.get('request') if request is not None: response = request.response @@ -509,7 +517,7 @@ class HTTPApplication(object): if ct == response.default_content_type: response.content_type = 'application/x-msgpack' - return msgpack.packb(value, use_bin_type=False) + return msgpack.packb(value, use_bin_type=bin_type) return _render def set_env_from_config(self, environ, config): diff --git a/vcsserver/remote/git.py b/vcsserver/remote/git.py --- a/vcsserver/remote/git.py +++ b/vcsserver/remote/git.py @@ -41,7 +41,7 @@ from dulwich.server import update_server from vcsserver import exceptions, settings, subprocessio from vcsserver.str_utils import safe_str, safe_int, safe_bytes, ascii_str, ascii_bytes -from vcsserver.base import RepoFactory, obfuscate_qs, ArchiveNode, archive_repo +from vcsserver.base import RepoFactory, obfuscate_qs, ArchiveNode, archive_repo, BinaryEnvelope from vcsserver.hgcompat import ( hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler) from vcsserver.git_lfs.lib import LFSOidStore @@ -207,8 +207,7 @@ class GitRemote(RemoteBase): repo_init = self._factory.repo_libgit2(wire) with repo_init as repo: blob_obj = repo[sha] - blob = blob_obj.data - return blob + return BinaryEnvelope(blob_obj.data) @reraise_safe_exceptions def blob_raw_length(self, wire, sha): @@ -506,12 +505,14 @@ class GitRemote(RemoteBase): blob = objects.Blob.from_string(node['content']) + node_path = safe_bytes(node['node_path']) + if dirnames: # If there are trees which should be created we need to build # them now (in reverse order) reversed_dirnames = list(reversed(dirnames)) curtree = objects.Tree() - curtree[node['node_path']] = node['mode'], blob.id + curtree[node_path] = node['mode'], blob.id new_trees.append(curtree) for dirname in reversed_dirnames[:-1]: newtree = objects.Tree() @@ -520,7 +521,7 @@ class GitRemote(RemoteBase): curtree = newtree parent[reversed_dirnames[-1]] = (DIR_STAT, curtree.id) else: - parent.add(name=node['node_path'], mode=node['mode'], hexsha=blob.id) + parent.add(name=node_path, mode=node['mode'], hexsha=blob.id) new_trees.append(parent) # Update ancestors @@ -1153,10 +1154,10 @@ class GitRemote(RemoteBase): if file_filter: for p in diff_obj: if p.delta.old_file.path == file_filter: - return p.data or '' + return BinaryEnvelope(p.data) or BinaryEnvelope(b'') # fo matching path == no diff - return '' - return diff_obj.patch or '' + return BinaryEnvelope(b'') + return BinaryEnvelope(diff_obj.patch) or BinaryEnvelope(b'') @reraise_safe_exceptions def node_history(self, wire, commit_id, path, limit): diff --git a/vcsserver/remote/hg.py b/vcsserver/remote/hg.py --- a/vcsserver/remote/hg.py +++ b/vcsserver/remote/hg.py @@ -32,7 +32,7 @@ from mercurial import repair import vcsserver from vcsserver import exceptions -from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original, archive_repo, ArchiveNode +from vcsserver.base import RepoFactory, obfuscate_qs, raise_from_original, archive_repo, ArchiveNode, BinaryEnvelope from vcsserver.hgcompat import ( archival, bin, clone, config as hgconfig, diffopts, hex, get_ctx, hg_url as url_parser, httpbasicauthhandler, httpdigestauthhandler, @@ -481,7 +481,7 @@ class HgRemote(RemoteBase): try: diff_iter = patch.diff( repo, node1=commit_id_1, node2=commit_id_2, match=match_filter, opts=opts) - return b"".join(diff_iter) + return BinaryEnvelope(b"".join(diff_iter)) except RepoLookupError as e: raise exceptions.LookupException(e)() @@ -555,7 +555,7 @@ class HgRemote(RemoteBase): repo = self._factory.repo(wire) ctx = self._get_ctx(repo, revision) fctx = ctx.filectx(safe_bytes(path)) - return fctx.data() + return BinaryEnvelope(fctx.data()) @reraise_safe_exceptions def fctx_flags(self, wire, commit_id, path): diff --git a/vcsserver/remote/svn.py b/vcsserver/remote/svn.py --- a/vcsserver/remote/svn.py +++ b/vcsserver/remote/svn.py @@ -36,7 +36,7 @@ import svn.fs import svn.repos from vcsserver import svn_diff, exceptions, subprocessio, settings -from vcsserver.base import RepoFactory, raise_from_original, ArchiveNode, archive_repo +from vcsserver.base import RepoFactory, raise_from_original, ArchiveNode, archive_repo, BinaryEnvelope from vcsserver.exceptions import NoContentException from vcsserver.str_utils import safe_str, safe_bytes from vcsserver.vcs_base import RemoteBase @@ -351,7 +351,7 @@ class SvnRemote(RemoteBase): rev = svn.fs.youngest_revision(fsobj) root = svn.fs.revision_root(fsobj, rev) content = svn.core.Stream(svn.fs.file_contents(root, path)) - return content.read() + return BinaryEnvelope(content.read()) def get_file_size(self, wire, path, revision=None): @@ -462,12 +462,12 @@ class SvnRemote(RemoteBase): diff_creator = SvnDiffer( repo, rev1, path1, rev2, path2, ignore_whitespace, context) try: - return diff_creator.generate_diff() + return BinaryEnvelope(diff_creator.generate_diff()) except svn.core.SubversionException as e: log.exception( "Error during diff operation operation. " - "Path might not exist %s, %s" % (path1, path2)) - return "" + "Path might not exist %s, %s", path1, path2) + return BinaryEnvelope(b'') @reraise_safe_exceptions def is_large_file(self, wire, path):