##// END OF EJS Templates
httppeer: extract code for creating a request into own function...
Gregory Szorc -
r37567:66d1001e default
parent child Browse files
Show More
@@ -138,6 +138,119 b' class _multifile(object):'
138 f.seek(0)
138 f.seek(0)
139 self._index = 0
139 self._index = 0
140
140
141 def makev1commandrequest(ui, requestbuilder, caps, capablefn,
142 repobaseurl, cmd, args):
143 """Make an HTTP request to run a command for a version 1 client.
144
145 ``caps`` is a set of known server capabilities. The value may be
146 None if capabilities are not yet known.
147
148 ``capablefn`` is a function to evaluate a capability.
149
150 ``cmd``, ``args``, and ``data`` define the command, its arguments, and
151 raw data to pass to it.
152 """
153 if cmd == 'pushkey':
154 args['data'] = ''
155 data = args.pop('data', None)
156 headers = args.pop('headers', {})
157
158 ui.debug("sending %s command\n" % cmd)
159 q = [('cmd', cmd)]
160 headersize = 0
161 varyheaders = []
162 # Important: don't use self.capable() here or else you end up
163 # with infinite recursion when trying to look up capabilities
164 # for the first time.
165 postargsok = caps is not None and 'httppostargs' in caps
166
167 # Send arguments via POST.
168 if postargsok and args:
169 strargs = urlreq.urlencode(sorted(args.items()))
170 if not data:
171 data = strargs
172 else:
173 if isinstance(data, bytes):
174 i = io.BytesIO(data)
175 i.length = len(data)
176 data = i
177 argsio = io.BytesIO(strargs)
178 argsio.length = len(strargs)
179 data = _multifile(argsio, data)
180 headers[r'X-HgArgs-Post'] = len(strargs)
181 elif args:
182 # Calling self.capable() can infinite loop if we are calling
183 # "capabilities". But that command should never accept wire
184 # protocol arguments. So this should never happen.
185 assert cmd != 'capabilities'
186 httpheader = capablefn('httpheader')
187 if httpheader:
188 headersize = int(httpheader.split(',', 1)[0])
189
190 # Send arguments via HTTP headers.
191 if headersize > 0:
192 # The headers can typically carry more data than the URL.
193 encargs = urlreq.urlencode(sorted(args.items()))
194 for header, value in encodevalueinheaders(encargs, 'X-HgArg',
195 headersize):
196 headers[header] = value
197 varyheaders.append(header)
198 # Send arguments via query string (Mercurial <1.9).
199 else:
200 q += sorted(args.items())
201
202 qs = '?%s' % urlreq.urlencode(q)
203 cu = "%s%s" % (repobaseurl, qs)
204 size = 0
205 if util.safehasattr(data, 'length'):
206 size = data.length
207 elif data is not None:
208 size = len(data)
209 if data is not None and r'Content-Type' not in headers:
210 headers[r'Content-Type'] = r'application/mercurial-0.1'
211
212 # Tell the server we accept application/mercurial-0.2 and multiple
213 # compression formats if the server is capable of emitting those
214 # payloads.
215 protoparams = {'partial-pull'}
216
217 mediatypes = set()
218 if caps is not None:
219 mt = capablefn('httpmediatype')
220 if mt:
221 protoparams.add('0.1')
222 mediatypes = set(mt.split(','))
223
224 if '0.2tx' in mediatypes:
225 protoparams.add('0.2')
226
227 if '0.2tx' in mediatypes and capablefn('compression'):
228 # We /could/ compare supported compression formats and prune
229 # non-mutually supported or error if nothing is mutually supported.
230 # For now, send the full list to the server and have it error.
231 comps = [e.wireprotosupport().name for e in
232 util.compengines.supportedwireengines(util.CLIENTROLE)]
233 protoparams.add('comp=%s' % ','.join(comps))
234
235 if protoparams:
236 protoheaders = encodevalueinheaders(' '.join(sorted(protoparams)),
237 'X-HgProto',
238 headersize or 1024)
239 for header, value in protoheaders:
240 headers[header] = value
241 varyheaders.append(header)
242
243 if varyheaders:
244 headers[r'Vary'] = r','.join(varyheaders)
245
246 req = requestbuilder(pycompat.strurl(cu), data, headers)
247
248 if data is not None:
249 ui.debug("sending %d bytes\n" % size)
250 req.add_unredirected_header(r'Content-Length', r'%d' % size)
251
252 return req, cu, qs
253
141 def sendrequest(ui, opener, req):
254 def sendrequest(ui, opener, req):
142 """Send a prepared HTTP request.
255 """Send a prepared HTTP request.
143
256
@@ -228,104 +341,11 b' class httppeer(wireproto.wirepeer):'
228
341
229 def _callstream(self, cmd, _compressible=False, **args):
342 def _callstream(self, cmd, _compressible=False, **args):
230 args = pycompat.byteskwargs(args)
343 args = pycompat.byteskwargs(args)
231 if cmd == 'pushkey':
232 args['data'] = ''
233 data = args.pop('data', None)
234 headers = args.pop('headers', {})
235
236 self.ui.debug("sending %s command\n" % cmd)
237 q = [('cmd', cmd)]
238 headersize = 0
239 varyheaders = []
240 # Important: don't use self.capable() here or else you end up
241 # with infinite recursion when trying to look up capabilities
242 # for the first time.
243 postargsok = self._caps is not None and 'httppostargs' in self._caps
244
245 # Send arguments via POST.
246 if postargsok and args:
247 strargs = urlreq.urlencode(sorted(args.items()))
248 if not data:
249 data = strargs
250 else:
251 if isinstance(data, bytes):
252 i = io.BytesIO(data)
253 i.length = len(data)
254 data = i
255 argsio = io.BytesIO(strargs)
256 argsio.length = len(strargs)
257 data = _multifile(argsio, data)
258 headers[r'X-HgArgs-Post'] = len(strargs)
259 elif args:
260 # Calling self.capable() can infinite loop if we are calling
261 # "capabilities". But that command should never accept wire
262 # protocol arguments. So this should never happen.
263 assert cmd != 'capabilities'
264 httpheader = self.capable('httpheader')
265 if httpheader:
266 headersize = int(httpheader.split(',', 1)[0])
267
268 # Send arguments via HTTP headers.
269 if headersize > 0:
270 # The headers can typically carry more data than the URL.
271 encargs = urlreq.urlencode(sorted(args.items()))
272 for header, value in encodevalueinheaders(encargs, 'X-HgArg',
273 headersize):
274 headers[header] = value
275 varyheaders.append(header)
276 # Send arguments via query string (Mercurial <1.9).
277 else:
278 q += sorted(args.items())
279
344
280 qs = '?%s' % urlreq.urlencode(q)
345 req, cu, qs = makev1commandrequest(self.ui, self._requestbuilder,
281 cu = "%s%s" % (self._url, qs)
346 self._caps, self.capable,
282 size = 0
347 self._url, cmd, args)
283 if util.safehasattr(data, 'length'):
284 size = data.length
285 elif data is not None:
286 size = len(data)
287 if data is not None and r'Content-Type' not in headers:
288 headers[r'Content-Type'] = r'application/mercurial-0.1'
289
290 # Tell the server we accept application/mercurial-0.2 and multiple
291 # compression formats if the server is capable of emitting those
292 # payloads.
293 protoparams = {'partial-pull'}
294
295 mediatypes = set()
296 if self._caps is not None:
297 mt = self.capable('httpmediatype')
298 if mt:
299 protoparams.add('0.1')
300 mediatypes = set(mt.split(','))
301
302 if '0.2tx' in mediatypes:
303 protoparams.add('0.2')
304
348
305 if '0.2tx' in mediatypes and self.capable('compression'):
306 # We /could/ compare supported compression formats and prune
307 # non-mutually supported or error if nothing is mutually supported.
308 # For now, send the full list to the server and have it error.
309 comps = [e.wireprotosupport().name for e in
310 util.compengines.supportedwireengines(util.CLIENTROLE)]
311 protoparams.add('comp=%s' % ','.join(comps))
312
313 if protoparams:
314 protoheaders = encodevalueinheaders(' '.join(sorted(protoparams)),
315 'X-HgProto',
316 headersize or 1024)
317 for header, value in protoheaders:
318 headers[header] = value
319 varyheaders.append(header)
320
321 if varyheaders:
322 headers[r'Vary'] = r','.join(varyheaders)
323
324 req = self._requestbuilder(pycompat.strurl(cu), data, headers)
325
326 if data is not None:
327 self.ui.debug("sending %d bytes\n" % size)
328 req.add_unredirected_header(r'Content-Length', r'%d' % size)
329 try:
349 try:
330 resp = sendrequest(self.ui, self._urlopener, req)
350 resp = sendrequest(self.ui, self._urlopener, req)
331 except urlerr.httperror as inst:
351 except urlerr.httperror as inst:
General Comments 0
You need to be logged in to leave comments. Login now