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]) |