|  | @@ -23,7 +23,7 @@ from .helpers import sysinfo
 | 
	
		
			
				|  |  |  from .helpers import bin_to_hex
 | 
	
		
			
				|  |  |  from .helpers import replace_placeholders
 | 
	
		
			
				|  |  |  from .helpers import yes
 | 
	
		
			
				|  |  | -from .repository import Repository
 | 
	
		
			
				|  |  | +from .repository import Repository, MAX_OBJECT_SIZE, LIST_SCAN_LIMIT
 | 
	
		
			
				|  |  |  from .version import parse_version, format_version
 | 
	
		
			
				|  |  |  from .logger import create_logger
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -57,6 +57,27 @@ def os_write(fd, data):
 | 
	
		
			
				|  |  |      return amount
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +def get_limited_unpacker(kind):
 | 
	
		
			
				|  |  | +    """return a limited Unpacker because we should not trust msgpack data received from remote"""
 | 
	
		
			
				|  |  | +    args = dict(use_list=False,  # return tuples, not lists
 | 
	
		
			
				|  |  | +                max_bin_len=0,  # not used
 | 
	
		
			
				|  |  | +                max_ext_len=0,  # not used
 | 
	
		
			
				|  |  | +                max_buffer_size=3 * max(BUFSIZE, MAX_OBJECT_SIZE),
 | 
	
		
			
				|  |  | +                max_str_len=MAX_OBJECT_SIZE,  # a chunk or other repo object
 | 
	
		
			
				|  |  | +                )
 | 
	
		
			
				|  |  | +    if kind == 'server':
 | 
	
		
			
				|  |  | +        args.update(dict(max_array_len=100,  # misc. cmd tuples
 | 
	
		
			
				|  |  | +                         max_map_len=100,  # misc. cmd dicts
 | 
	
		
			
				|  |  | +                         ))
 | 
	
		
			
				|  |  | +    elif kind == 'client':
 | 
	
		
			
				|  |  | +        args.update(dict(max_array_len=LIST_SCAN_LIMIT,  # result list from repo.list() / .scan()
 | 
	
		
			
				|  |  | +                         max_map_len=100,  # misc. result dicts
 | 
	
		
			
				|  |  | +                         ))
 | 
	
		
			
				|  |  | +    else:
 | 
	
		
			
				|  |  | +        raise ValueError('kind must be "server" or "client"')
 | 
	
		
			
				|  |  | +    return msgpack.Unpacker(**args)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |  class ConnectionClosed(Error):
 | 
	
		
			
				|  |  |      """Connection closed by remote host"""
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -185,7 +206,7 @@ class RepositoryServer:  # pragma: no cover
 | 
	
		
			
				|  |  |          # Make stderr blocking
 | 
	
		
			
				|  |  |          fl = fcntl.fcntl(stderr_fd, fcntl.F_GETFL)
 | 
	
		
			
				|  |  |          fcntl.fcntl(stderr_fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
 | 
	
		
			
				|  |  | -        unpacker = msgpack.Unpacker(use_list=False)
 | 
	
		
			
				|  |  | +        unpacker = get_limited_unpacker('server')
 | 
	
		
			
				|  |  |          while True:
 | 
	
		
			
				|  |  |              r, w, es = select.select([stdin_fd], [], [], 10)
 | 
	
		
			
				|  |  |              if r:
 | 
	
	
		
			
				|  | @@ -487,8 +508,7 @@ class RemoteRepository:
 | 
	
		
			
				|  |  |          self.ignore_responses = set()
 | 
	
		
			
				|  |  |          self.responses = {}
 | 
	
		
			
				|  |  |          self.ratelimit = SleepingBandwidthLimiter(args.remote_ratelimit * 1024 if args and args.remote_ratelimit else 0)
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        self.unpacker = msgpack.Unpacker(use_list=False)
 | 
	
		
			
				|  |  | +        self.unpacker = get_limited_unpacker('client')
 | 
	
		
			
				|  |  |          self.server_version = parse_version('1.0.8')  # fallback version if server is too old to send version information
 | 
	
		
			
				|  |  |          self.p = None
 | 
	
		
			
				|  |  |          testing = location.host == '__testsuite__'
 |