mercurial/httppeer.py
changeset 33821 3c91cc0c5fde
parent 33806 dedab036215d
child 34486 a57c938e7ac8
equal deleted inserted replaced
33820:fa7e30efe05a 33821:3c91cc0c5fde
     7 # GNU General Public License version 2 or any later version.
     7 # GNU General Public License version 2 or any later version.
     8 
     8 
     9 from __future__ import absolute_import
     9 from __future__ import absolute_import
    10 
    10 
    11 import errno
    11 import errno
       
    12 import io
    12 import os
    13 import os
    13 import socket
    14 import socket
    14 import struct
    15 import struct
    15 import tempfile
    16 import tempfile
    16 
    17 
    84                            'if the error persists, consider contacting the '
    85                            'if the error persists, consider contacting the '
    85                            'network or server operator'))
    86                            'network or server operator'))
    86 
    87 
    87     resp.__class__ = readerproxy
    88     resp.__class__ = readerproxy
    88 
    89 
       
    90 class _multifile(object):
       
    91     def __init__(self, *fileobjs):
       
    92         for f in fileobjs:
       
    93             if not util.safehasattr(f, 'length'):
       
    94                 raise ValueError(
       
    95                     '_multifile only supports file objects that '
       
    96                     'have a length but this one does not:', type(f), f)
       
    97         self._fileobjs = fileobjs
       
    98         self._index = 0
       
    99 
       
   100     @property
       
   101     def length(self):
       
   102         return sum(f.length for f in self._fileobjs)
       
   103 
       
   104     def read(self, amt=None):
       
   105         if amt <= 0:
       
   106             return ''.join(f.read() for f in self._fileobjs)
       
   107         parts = []
       
   108         while amt and self._index < len(self._fileobjs):
       
   109             parts.append(self._fileobjs[self._index].read(amt))
       
   110             got = len(parts[-1])
       
   111             if got < amt:
       
   112                 self._index += 1
       
   113             amt -= got
       
   114         return ''.join(parts)
       
   115 
       
   116     def seek(self, offset, whence=os.SEEK_SET):
       
   117         if whence != os.SEEK_SET:
       
   118             raise NotImplementedError(
       
   119                 '_multifile does not support anything other'
       
   120                 ' than os.SEEK_SET for whence on seek()')
       
   121         if offset != 0:
       
   122             raise NotImplementedError(
       
   123                 '_multifile only supports seeking to start, but that '
       
   124                 'could be fixed if you need it')
       
   125         for f in self._fileobjs:
       
   126             f.seek(0)
       
   127         self._index = 0
       
   128 
    89 class httppeer(wireproto.wirepeer):
   129 class httppeer(wireproto.wirepeer):
    90     def __init__(self, ui, path):
   130     def __init__(self, ui, path):
    91         self._path = path
   131         self._path = path
    92         self._caps = None
   132         self._caps = None
    93         self._urlopener = None
   133         self._urlopener = None
   167         varyheaders = []
   207         varyheaders = []
   168         # Important: don't use self.capable() here or else you end up
   208         # Important: don't use self.capable() here or else you end up
   169         # with infinite recursion when trying to look up capabilities
   209         # with infinite recursion when trying to look up capabilities
   170         # for the first time.
   210         # for the first time.
   171         postargsok = self._caps is not None and 'httppostargs' in self._caps
   211         postargsok = self._caps is not None and 'httppostargs' in self._caps
   172         # TODO: support for httppostargs when data is a file-like
   212         if postargsok and args:
   173         # object rather than a basestring
       
   174         canmungedata = not data or isinstance(data, basestring)
       
   175         if postargsok and canmungedata:
       
   176             strargs = urlreq.urlencode(sorted(args.items()))
   213             strargs = urlreq.urlencode(sorted(args.items()))
   177             if strargs:
   214             if not data:
   178                 if not data:
   215                 data = strargs
   179                     data = strargs
   216             else:
   180                 elif isinstance(data, basestring):
   217                 if isinstance(data, basestring):
   181                     data = strargs + data
   218                     i = io.BytesIO(data)
   182                 headers['X-HgArgs-Post'] = len(strargs)
   219                     i.length = len(data)
       
   220                     data = i
       
   221                 argsio = io.BytesIO(strargs)
       
   222                 argsio.length = len(strargs)
       
   223                 data = _multifile(argsio, data)
       
   224             headers['X-HgArgs-Post'] = len(strargs)
   183         else:
   225         else:
   184             if len(args) > 0:
   226             if len(args) > 0:
   185                 httpheader = self.capable('httpheader')
   227                 httpheader = self.capable('httpheader')
   186                 if httpheader:
   228                 if httpheader:
   187                     headersize = int(httpheader.split(',', 1)[0])
   229                     headersize = int(httpheader.split(',', 1)[0])