303 # Insert error handlers for common I/O failures. |
303 # Insert error handlers for common I/O failures. |
304 _wraphttpresponse(res) |
304 _wraphttpresponse(res) |
305 |
305 |
306 return res |
306 return res |
307 |
307 |
|
308 def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible): |
|
309 # record the url we got redirected to |
|
310 respurl = pycompat.bytesurl(resp.geturl()) |
|
311 if respurl.endswith(qs): |
|
312 respurl = respurl[:-len(qs)] |
|
313 if baseurl.rstrip('/') != respurl.rstrip('/'): |
|
314 if not ui.quiet: |
|
315 ui.warn(_('real URL is %s\n') % respurl) |
|
316 |
|
317 try: |
|
318 proto = pycompat.bytesurl(resp.getheader(r'content-type', r'')) |
|
319 except AttributeError: |
|
320 proto = pycompat.bytesurl(resp.headers.get(r'content-type', r'')) |
|
321 |
|
322 safeurl = util.hidepassword(baseurl) |
|
323 if proto.startswith('application/hg-error'): |
|
324 raise error.OutOfBandError(resp.read()) |
|
325 # accept old "text/plain" and "application/hg-changegroup" for now |
|
326 if not (proto.startswith('application/mercurial-') or |
|
327 (proto.startswith('text/plain') |
|
328 and not resp.headers.get('content-length')) or |
|
329 proto.startswith('application/hg-changegroup')): |
|
330 ui.debug("requested URL: '%s'\n" % util.hidepassword(requrl)) |
|
331 raise error.RepoError( |
|
332 _("'%s' does not appear to be an hg repository:\n" |
|
333 "---%%<--- (%s)\n%s\n---%%<---\n") |
|
334 % (safeurl, proto or 'no content-type', resp.read(1024))) |
|
335 |
|
336 if proto.startswith('application/mercurial-'): |
|
337 try: |
|
338 version = proto.split('-', 1)[1] |
|
339 version_info = tuple([int(n) for n in version.split('.')]) |
|
340 except ValueError: |
|
341 raise error.RepoError(_("'%s' sent a broken Content-Type " |
|
342 "header (%s)") % (safeurl, proto)) |
|
343 |
|
344 # TODO consider switching to a decompression reader that uses |
|
345 # generators. |
|
346 if version_info == (0, 1): |
|
347 if compressible: |
|
348 resp = util.compengines['zlib'].decompressorreader(resp) |
|
349 |
|
350 return respurl, resp |
|
351 |
|
352 elif version_info == (0, 2): |
|
353 # application/mercurial-0.2 always identifies the compression |
|
354 # engine in the payload header. |
|
355 elen = struct.unpack('B', resp.read(1))[0] |
|
356 ename = resp.read(elen) |
|
357 engine = util.compengines.forwiretype(ename) |
|
358 return respurl, engine.decompressorreader(resp) |
|
359 else: |
|
360 raise error.RepoError(_("'%s' uses newer protocol %s") % |
|
361 (safeurl, version)) |
|
362 |
|
363 if compressible: |
|
364 resp = util.compengines['zlib'].decompressorreader(resp) |
|
365 |
|
366 return respurl, resp |
|
367 |
308 class httppeer(wireproto.wirepeer): |
368 class httppeer(wireproto.wirepeer): |
309 def __init__(self, ui, path, url, opener, requestbuilder): |
369 def __init__(self, ui, path, url, opener, requestbuilder): |
310 self.ui = ui |
370 self.ui = ui |
311 self._path = path |
371 self._path = path |
312 self._url = url |
372 self._url = url |
360 self._caps, self.capable, |
420 self._caps, self.capable, |
361 self._url, cmd, args) |
421 self._url, cmd, args) |
362 |
422 |
363 resp = sendrequest(self.ui, self._urlopener, req) |
423 resp = sendrequest(self.ui, self._urlopener, req) |
364 |
424 |
365 # record the url we got redirected to |
425 self._url, resp = parsev1commandresponse(self.ui, self._url, cu, qs, |
366 resp_url = pycompat.bytesurl(resp.geturl()) |
426 resp, _compressible) |
367 if resp_url.endswith(qs): |
|
368 resp_url = resp_url[:-len(qs)] |
|
369 if self._url.rstrip('/') != resp_url.rstrip('/'): |
|
370 if not self.ui.quiet: |
|
371 self.ui.warn(_('real URL is %s\n') % resp_url) |
|
372 self._url = resp_url |
|
373 try: |
|
374 proto = pycompat.bytesurl(resp.getheader(r'content-type', r'')) |
|
375 except AttributeError: |
|
376 proto = pycompat.bytesurl(resp.headers.get(r'content-type', r'')) |
|
377 |
|
378 safeurl = util.hidepassword(self._url) |
|
379 if proto.startswith('application/hg-error'): |
|
380 raise error.OutOfBandError(resp.read()) |
|
381 # accept old "text/plain" and "application/hg-changegroup" for now |
|
382 if not (proto.startswith('application/mercurial-') or |
|
383 (proto.startswith('text/plain') |
|
384 and not resp.headers.get('content-length')) or |
|
385 proto.startswith('application/hg-changegroup')): |
|
386 self.ui.debug("requested URL: '%s'\n" % util.hidepassword(cu)) |
|
387 raise error.RepoError( |
|
388 _("'%s' does not appear to be an hg repository:\n" |
|
389 "---%%<--- (%s)\n%s\n---%%<---\n") |
|
390 % (safeurl, proto or 'no content-type', resp.read(1024))) |
|
391 |
|
392 if proto.startswith('application/mercurial-'): |
|
393 try: |
|
394 version = proto.split('-', 1)[1] |
|
395 version_info = tuple([int(n) for n in version.split('.')]) |
|
396 except ValueError: |
|
397 raise error.RepoError(_("'%s' sent a broken Content-Type " |
|
398 "header (%s)") % (safeurl, proto)) |
|
399 |
|
400 # TODO consider switching to a decompression reader that uses |
|
401 # generators. |
|
402 if version_info == (0, 1): |
|
403 if _compressible: |
|
404 return util.compengines['zlib'].decompressorreader(resp) |
|
405 return resp |
|
406 elif version_info == (0, 2): |
|
407 # application/mercurial-0.2 always identifies the compression |
|
408 # engine in the payload header. |
|
409 elen = struct.unpack('B', resp.read(1))[0] |
|
410 ename = resp.read(elen) |
|
411 engine = util.compengines.forwiretype(ename) |
|
412 return engine.decompressorreader(resp) |
|
413 else: |
|
414 raise error.RepoError(_("'%s' uses newer protocol %s") % |
|
415 (safeurl, version)) |
|
416 |
|
417 if _compressible: |
|
418 return util.compengines['zlib'].decompressorreader(resp) |
|
419 |
427 |
420 return resp |
428 return resp |
421 |
429 |
422 def _call(self, cmd, **args): |
430 def _call(self, cmd, **args): |
423 fp = self._callstream(cmd, **args) |
431 fp = self._callstream(cmd, **args) |