annotate mercurial/httppeer.py @ 37558:8a73132214a3

httppeer: support protocol upgrade With the new handshake defined and in place on the server, we can now implement it on the client. The HTTP handshake mechanism has been taught to add headers advertising its support for the new capabilities response. Response handling has been adjusted to allow CBOR responses through. And makepeer() has been taught to instantiate a mutually supported peer. The HTTPv2 peer class doesn't implement the full peer interface. So HTTPv2 is not yet usable as a peer. Like the server side, we support registering handlers for different API services. This allows extensions to easily implement API services and peers. A practical use case for this is to provide a previous implementation of the experimental version 2 wire protocol to a future version of Mercurial. We know there will be BC breaks after 4.6 ships. But someone could take the peer and server code from 4.6, drop it in an extension, and allow its use indefinitely. Differential Revision: https://phab.mercurial-scm.org/D3243
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 10 Apr 2018 18:16:47 -0700
parents b77aa48ba690
children 01bfe5ad0c53
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
17192
1ac628cd7113 peer: introduce real peer classes
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 15246
diff changeset
1 # httppeer.py - HTTP repository proxy classes for mercurial
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
2 #
2859
345bac2bc4ec update copyrights.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2740
diff changeset
3 # Copyright 2005, 2006 Matt Mackall <mpm@selenic.com>
345bac2bc4ec update copyrights.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2740
diff changeset
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
5 #
8225
46293a0c7e9f updated license to be explicit about GPL version 2
Martin Geisler <mg@lazybytes.net>
parents: 8206
diff changeset
6 # This software may be used and distributed according to the terms of the
10263
25e572394f5c Update license to GPLv2+
Matt Mackall <mpm@selenic.com>
parents: 9878
diff changeset
7 # GNU General Public License version 2 or any later version.
0
9117c6561b0b Add back links from file revisions to changeset revisions
mpm@selenic.com
parents:
diff changeset
8
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
9 from __future__ import absolute_import
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
10
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
11 import errno
33821
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
12 import io
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
13 import os
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
14 import socket
30763
a520aefb96f1 httppeer: advertise and support application/mercurial-0.2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
15 import struct
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
16 import tempfile
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
17
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
18 from .i18n import _
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
19 from .thirdparty import (
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
20 cbor,
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
21 )
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
22 from . import (
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
23 bundle2,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
24 error,
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
25 httpconnection,
30924
48dea083f66d py3: convert the mode argument of os.fdopen to unicodes (1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30763
diff changeset
26 pycompat,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
27 statichttprepo,
36959
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36835
diff changeset
28 url as urlmod,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
29 util,
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
30 wireproto,
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
31 wireprotoframing,
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
32 wireprototypes,
37545
93397c4633f6 wireproto: extract HTTP version 2 code to own module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37544
diff changeset
33 wireprotov2server,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
34 )
4678
a814a5b11fff Work around urllib2 digest auth bug with Python < 2.5
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4633
diff changeset
35
29455
0c741fd6158a py3: conditionalize httplib import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29241
diff changeset
36 httplib = util.httplib
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
37 urlerr = util.urlerr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
38 urlreq = util.urlreq
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
39
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
40 def encodevalueinheaders(value, header, limit):
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
41 """Encode a string value into multiple HTTP headers.
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
42
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
43 ``value`` will be encoded into 1 or more HTTP headers with the names
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
44 ``header-<N>`` where ``<N>`` is an integer starting at 1. Each header
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
45 name + value will be at most ``limit`` bytes long.
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
46
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
47 Returns an iterable of 2-tuples consisting of header names and
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
48 values as native strings.
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
49 """
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
50 # HTTP Headers are ASCII. Python 3 requires them to be unicodes,
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
51 # not bytes. This function always takes bytes in as arguments.
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
52 fmt = pycompat.strurl(header) + r'-%s'
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
53 # Note: it is *NOT* a bug that the last bit here is a bytestring
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
54 # and not a unicode: we're just getting the encoded length anyway,
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
55 # and using an r-string to make it portable between Python 2 and 3
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
56 # doesn't work because then the \r is a literal backslash-r
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
57 # instead of a carriage return.
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
58 valuelen = limit - len(fmt % r'000') - len(': \r\n')
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
59 result = []
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
60
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
61 n = 0
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
62 for i in xrange(0, len(value), valuelen):
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
63 n += 1
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
64 result.append((fmt % str(n), pycompat.strurl(value[i:i + valuelen])))
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
65
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
66 return result
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30564
diff changeset
67
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
68 def _wraphttpresponse(resp):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
69 """Wrap an HTTPResponse with common error handlers.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
70
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
71 This ensures that any I/O from any consumer raises the appropriate
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
72 error and messaging.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
73 """
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
74 origread = resp.read
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
75
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
76 class readerproxy(resp.__class__):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
77 def read(self, size=None):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
78 try:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
79 return origread(size)
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
80 except httplib.IncompleteRead as e:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
81 # e.expected is an integer if length known or None otherwise.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
82 if e.expected:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
83 msg = _('HTTP request error (incomplete response; '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
84 'expected %d bytes got %d)') % (e.expected,
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
85 len(e.partial))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
86 else:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
87 msg = _('HTTP request error (incomplete response)')
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
88
32023
a29580905771 error: rename RichIOError to PeerTransportError
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32022
diff changeset
89 raise error.PeerTransportError(
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
90 msg,
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
91 hint=_('this may be an intermittent network failure; '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
92 'if the error persists, consider contacting the '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
93 'network or server operator'))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
94 except httplib.HTTPException as e:
32023
a29580905771 error: rename RichIOError to PeerTransportError
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32022
diff changeset
95 raise error.PeerTransportError(
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
96 _('HTTP request error (%s)') % e,
32086
b59a292d0a53 httppeer: unify hint message for PeerTransportError
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32023
diff changeset
97 hint=_('this may be an intermittent network failure; '
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
98 'if the error persists, consider contacting the '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
99 'network or server operator'))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
100
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
101 resp.__class__ = readerproxy
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
102
33821
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
103 class _multifile(object):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
104 def __init__(self, *fileobjs):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
105 for f in fileobjs:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
106 if not util.safehasattr(f, 'length'):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
107 raise ValueError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
108 '_multifile only supports file objects that '
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
109 'have a length but this one does not:', type(f), f)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
110 self._fileobjs = fileobjs
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
111 self._index = 0
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
112
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
113 @property
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
114 def length(self):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
115 return sum(f.length for f in self._fileobjs)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
116
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
117 def read(self, amt=None):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
118 if amt <= 0:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
119 return ''.join(f.read() for f in self._fileobjs)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
120 parts = []
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
121 while amt and self._index < len(self._fileobjs):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
122 parts.append(self._fileobjs[self._index].read(amt))
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
123 got = len(parts[-1])
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
124 if got < amt:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
125 self._index += 1
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
126 amt -= got
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
127 return ''.join(parts)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
128
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
129 def seek(self, offset, whence=os.SEEK_SET):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
130 if whence != os.SEEK_SET:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
131 raise NotImplementedError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
132 '_multifile does not support anything other'
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
133 ' than os.SEEK_SET for whence on seek()')
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
134 if offset != 0:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
135 raise NotImplementedError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
136 '_multifile only supports seeking to start, but that '
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
137 'could be fixed if you need it')
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
138 for f in self._fileobjs:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
139 f.seek(0)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
140 self._index = 0
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33806
diff changeset
141
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
142 def makev1commandrequest(ui, requestbuilder, caps, capablefn,
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
143 repobaseurl, cmd, args):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
144 """Make an HTTP request to run a command for a version 1 client.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
145
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
146 ``caps`` is a set of known server capabilities. The value may be
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
147 None if capabilities are not yet known.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
148
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
149 ``capablefn`` is a function to evaluate a capability.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
150
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
151 ``cmd``, ``args``, and ``data`` define the command, its arguments, and
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
152 raw data to pass to it.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
153 """
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
154 if cmd == 'pushkey':
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
155 args['data'] = ''
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
156 data = args.pop('data', None)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
157 headers = args.pop('headers', {})
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
158
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
159 ui.debug("sending %s command\n" % cmd)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
160 q = [('cmd', cmd)]
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
161 headersize = 0
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
162 # Important: don't use self.capable() here or else you end up
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
163 # with infinite recursion when trying to look up capabilities
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
164 # for the first time.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
165 postargsok = caps is not None and 'httppostargs' in caps
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
166
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
167 # Send arguments via POST.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
168 if postargsok and args:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
169 strargs = urlreq.urlencode(sorted(args.items()))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
170 if not data:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
171 data = strargs
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
172 else:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
173 if isinstance(data, bytes):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
174 i = io.BytesIO(data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
175 i.length = len(data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
176 data = i
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
177 argsio = io.BytesIO(strargs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
178 argsio.length = len(strargs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
179 data = _multifile(argsio, data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
180 headers[r'X-HgArgs-Post'] = len(strargs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
181 elif args:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
182 # Calling self.capable() can infinite loop if we are calling
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
183 # "capabilities". But that command should never accept wire
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
184 # protocol arguments. So this should never happen.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
185 assert cmd != 'capabilities'
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
186 httpheader = capablefn('httpheader')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
187 if httpheader:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
188 headersize = int(httpheader.split(',', 1)[0])
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
189
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
190 # Send arguments via HTTP headers.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
191 if headersize > 0:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
192 # The headers can typically carry more data than the URL.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
193 encargs = urlreq.urlencode(sorted(args.items()))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
194 for header, value in encodevalueinheaders(encargs, 'X-HgArg',
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
195 headersize):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
196 headers[header] = value
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
197 # Send arguments via query string (Mercurial <1.9).
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
198 else:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
199 q += sorted(args.items())
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
200
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
201 qs = '?%s' % urlreq.urlencode(q)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
202 cu = "%s%s" % (repobaseurl, qs)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
203 size = 0
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
204 if util.safehasattr(data, 'length'):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
205 size = data.length
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
206 elif data is not None:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
207 size = len(data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
208 if data is not None and r'Content-Type' not in headers:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
209 headers[r'Content-Type'] = r'application/mercurial-0.1'
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
210
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
211 # Tell the server we accept application/mercurial-0.2 and multiple
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
212 # compression formats if the server is capable of emitting those
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
213 # payloads.
37556
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
214 # Note: Keep this set empty by default, as client advertisement of
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
215 # protocol parameters should only occur after the handshake.
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
216 protoparams = set()
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
217
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
218 mediatypes = set()
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
219 if caps is not None:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
220 mt = capablefn('httpmediatype')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
221 if mt:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
222 protoparams.add('0.1')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
223 mediatypes = set(mt.split(','))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
224
37556
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
225 protoparams.add('partial-pull')
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
226
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
227 if '0.2tx' in mediatypes:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
228 protoparams.add('0.2')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
229
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
230 if '0.2tx' in mediatypes and capablefn('compression'):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
231 # We /could/ compare supported compression formats and prune
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
232 # non-mutually supported or error if nothing is mutually supported.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
233 # For now, send the full list to the server and have it error.
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
234 comps = [e.wireprotosupport().name for e in
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
235 util.compengines.supportedwireengines(util.CLIENTROLE)]
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
236 protoparams.add('comp=%s' % ','.join(comps))
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
237
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
238 if protoparams:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
239 protoheaders = encodevalueinheaders(' '.join(sorted(protoparams)),
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
240 'X-HgProto',
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
241 headersize or 1024)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
242 for header, value in protoheaders:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
243 headers[header] = value
37555
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
244
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
245 varyheaders = []
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
246 for header in headers:
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
247 if header.lower().startswith(r'x-hg'):
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
248 varyheaders.append(header)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
249
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
250 if varyheaders:
37555
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
251 headers[r'Vary'] = r','.join(sorted(varyheaders))
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
252
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
253 req = requestbuilder(pycompat.strurl(cu), data, headers)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
254
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
255 if data is not None:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
256 ui.debug("sending %d bytes\n" % size)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
257 req.add_unredirected_header(r'Content-Length', r'%d' % size)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
258
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
259 return req, cu, qs
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
260
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
261 def sendrequest(ui, opener, req):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
262 """Send a prepared HTTP request.
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
263
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
264 Returns the response object.
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
265 """
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
266 if (ui.debugflag
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
267 and ui.configbool('devel', 'debug.peer-request')):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
268 dbg = ui.debug
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
269 line = 'devel-peer-request: %s\n'
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
270 dbg(line % '%s %s' % (req.get_method(), req.get_full_url()))
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
271 hgargssize = None
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
272
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
273 for header, value in sorted(req.header_items()):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
274 if header.startswith('X-hgarg-'):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
275 if hgargssize is None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
276 hgargssize = 0
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
277 hgargssize += len(value)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
278 else:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
279 dbg(line % ' %s %s' % (header, value))
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
280
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
281 if hgargssize is not None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
282 dbg(line % ' %d bytes of commands arguments in headers'
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
283 % hgargssize)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
284
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
285 if req.has_data():
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
286 data = req.get_data()
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
287 length = getattr(data, 'length', None)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
288 if length is None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
289 length = len(data)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
290 dbg(line % ' %d bytes of data' % length)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
291
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
292 start = util.timer()
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
293
37550
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
294 try:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
295 res = opener.open(req)
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
296 except urlerr.httperror as inst:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
297 if inst.code == 401:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
298 raise error.Abort(_('authorization failed'))
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
299 raise
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
300 except httplib.HTTPException as inst:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
301 ui.debug('http error requesting %s\n' %
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
302 util.hidepassword(req.get_full_url()))
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
303 ui.traceback()
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
304 raise IOError(None, inst)
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
305 finally:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
306 if ui.configbool('devel', 'debug.peer-request'):
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
307 dbg(line % ' finished in %.4f seconds (%s)'
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
308 % (util.timer() - start, res.code))
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
309
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
310 # Insert error handlers for common I/O failures.
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
311 _wraphttpresponse(res)
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
312
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
313 return res
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
314
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
315 def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
316 allowcbor=False):
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
317 # record the url we got redirected to
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
318 respurl = pycompat.bytesurl(resp.geturl())
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
319 if respurl.endswith(qs):
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
320 respurl = respurl[:-len(qs)]
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
321 if baseurl.rstrip('/') != respurl.rstrip('/'):
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
322 if not ui.quiet:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
323 ui.warn(_('real URL is %s\n') % respurl)
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
324
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
325 try:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
326 proto = pycompat.bytesurl(resp.getheader(r'content-type', r''))
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
327 except AttributeError:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
328 proto = pycompat.bytesurl(resp.headers.get(r'content-type', r''))
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
329
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
330 safeurl = util.hidepassword(baseurl)
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
331 if proto.startswith('application/hg-error'):
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
332 raise error.OutOfBandError(resp.read())
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
333
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
334 # Pre 1.0 versions of Mercurial used text/plain and
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
335 # application/hg-changegroup. We don't support such old servers.
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
336 if not proto.startswith('application/mercurial-'):
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
337 ui.debug("requested URL: '%s'\n" % util.hidepassword(requrl))
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
338 raise error.RepoError(
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
339 _("'%s' does not appear to be an hg repository:\n"
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
340 "---%%<--- (%s)\n%s\n---%%<---\n")
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
341 % (safeurl, proto or 'no content-type', resp.read(1024)))
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
342
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
343 try:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
344 subtype = proto.split('-', 1)[1]
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
345
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
346 # Unless we end up supporting CBOR in the legacy wire protocol,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
347 # this should ONLY be encountered for the initial capabilities
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
348 # request during handshake.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
349 if subtype == 'cbor':
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
350 if allowcbor:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
351 return respurl, proto, resp
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
352 else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
353 raise error.RepoError(_('unexpected CBOR response from '
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
354 'server'))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
355
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
356 version_info = tuple([int(n) for n in subtype.split('.')])
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
357 except ValueError:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
358 raise error.RepoError(_("'%s' sent a broken Content-Type "
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
359 "header (%s)") % (safeurl, proto))
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
360
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
361 # TODO consider switching to a decompression reader that uses
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
362 # generators.
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
363 if version_info == (0, 1):
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
364 if compressible:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
365 resp = util.compengines['zlib'].decompressorreader(resp)
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
366
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
367 elif version_info == (0, 2):
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
368 # application/mercurial-0.2 always identifies the compression
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
369 # engine in the payload header.
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
370 elen = struct.unpack('B', resp.read(1))[0]
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
371 ename = resp.read(elen)
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
372 engine = util.compengines.forwiretype(ename)
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
373
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
374 resp = engine.decompressorreader(resp)
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
375 else:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
376 raise error.RepoError(_("'%s' uses newer protocol %s") %
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
377 (safeurl, subtype))
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
378
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
379 return respurl, proto, resp
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
380
33806
dedab036215d wireproto: use new peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33805
diff changeset
381 class httppeer(wireproto.wirepeer):
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
382 def __init__(self, ui, path, url, opener, requestbuilder, caps):
37321
e826fe7a08c7 peer: make ui an attribute
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37320
diff changeset
383 self.ui = ui
33705
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33704
diff changeset
384 self._path = path
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
385 self._url = url
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
386 self._caps = caps
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
387 self._urlopener = opener
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
388 self._requestbuilder = requestbuilder
4516
96d8a56d4ef9 Removed trailing whitespace and tabs from python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4369
diff changeset
389
7752
998fc8f62539 close sockets on httprepository deletion (issue1487)
Steve Borho <steve@borho.org>
parents: 7641
diff changeset
390 def __del__(self):
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
391 for h in self._urlopener.handlers:
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
392 h.close()
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
393 getattr(h, "close_all", lambda: None)()
7752
998fc8f62539 close sockets on httprepository deletion (issue1487)
Steve Borho <steve@borho.org>
parents: 7641
diff changeset
394
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
395 # Begin of ipeerconnection interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
396
2673
109a22f5434a hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2612
diff changeset
397 def url(self):
33705
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33704
diff changeset
398 return self._path
2673
109a22f5434a hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2612
diff changeset
399
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
400 def local(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
401 return None
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
402
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
403 def peer(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
404 return self
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
405
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
406 def canpush(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
407 return True
2442
c660691fb45d http: query server for capabilities
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2439
diff changeset
408
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
409 def close(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
410 pass
13603
395a84f78736 httprepo: use caps instead of between for compat check
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 13555
diff changeset
411
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
412 # End of ipeerconnection interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
413
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
414 # Begin of ipeercommands interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
415
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
416 def capabilities(self):
33705
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33704
diff changeset
417 return self._caps
2442
c660691fb45d http: query server for capabilities
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2439
diff changeset
418
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37006
diff changeset
419 # End of ipeercommands interface.
33805
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
420
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
421 # look up capabilities only when needed
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33705
diff changeset
422
30464
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
423 def _callstream(self, cmd, _compressible=False, **args):
35359
98bc4c43f570 py3: handle keyword arguments correctly in httppeer.py
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35197
diff changeset
424 args = pycompat.byteskwargs(args)
36218
e4ccd7a69f77 httppeer: change logic around argument handling
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35884
diff changeset
425
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
426 req, cu, qs = makev1commandrequest(self.ui, self._requestbuilder,
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
427 self._caps, self.capable,
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
428 self._url, cmd, args)
30763
a520aefb96f1 httppeer: advertise and support application/mercurial-0.2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
429
37550
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
430 resp = sendrequest(self.ui, self._urlopener, req)
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30924
diff changeset
431
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
432 self._url, ct, resp = parsev1commandresponse(self.ui, self._url, cu, qs,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
433 resp, _compressible)
30464
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
434
752
c693eafd5967 Simplify content type checking
mpm@selenic.com
parents: 751
diff changeset
435 return resp
60
e32fdbd97839 Add hg:// protocol
mpm@selenic.com
parents: 56
diff changeset
436
11589
e8d22fe2ddab protocol: clean up call-like functions in http and ssh clients
Matt Mackall <mpm@selenic.com>
parents: 11588
diff changeset
437 def _call(self, cmd, **args):
e8d22fe2ddab protocol: clean up call-like functions in http and ssh clients
Matt Mackall <mpm@selenic.com>
parents: 11588
diff changeset
438 fp = self._callstream(cmd, **args)
2435
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
439 try:
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
440 return fp.read()
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
441 finally:
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
442 # if using keepalive, allow connection to be reused
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
443 fp.close()
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
444
11592
26e0782b8380 protocol: unify client unbundle support
Matt Mackall <mpm@selenic.com>
parents: 11591
diff changeset
445 def _callpush(self, cmd, cg, **args):
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
446 # have to stream bundle to a temp file because we do not have
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
447 # http 1.1 chunked transfer.
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
448
3662
f4dc02d7fb71 unduplicate bundle writing code from httprepo
Matt Mackall <mpm@selenic.com>
parents: 3661
diff changeset
449 types = self.capable('unbundle')
3703
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
450 try:
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
451 types = types.split(',')
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
452 except AttributeError:
14060
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
453 # servers older than d1b16a746db6 will send 'unbundle' as a
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
454 # boolean capability. They only support headerless/uncompressed
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
455 # bundles.
3703
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
456 types = [""]
14060
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
457 for x in types:
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
458 if x in bundle2.bundletypes:
14060
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
459 type = x
aaa9a5989405 bundle: more comments about the different header types, remove useless if
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents: 13819
diff changeset
460 break
3613
cbf352b9a3cd Client support for hgweb unbundle with versions.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3609
diff changeset
461
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
462 tempname = bundle2.writebundle(self.ui, cg, None, type)
14244
e7525a555a64 url: use new http support if requested by the user
Augie Fackler <durin42@gmail.com>
parents: 14149
diff changeset
463 fp = httpconnection.httpsendfile(self.ui, tempname, "rb")
36297
a59ff82154b8 httppeer: headers are native strings
Augie Fackler <augie@google.com>
parents: 36270
diff changeset
464 headers = {r'Content-Type': r'application/mercurial-0.1'}
11592
26e0782b8380 protocol: unify client unbundle support
Matt Mackall <mpm@selenic.com>
parents: 11591
diff changeset
465
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
466 try:
25085
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
467 r = self._call(cmd, data=fp, headers=headers, **args)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
468 vals = r.split('\n', 1)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
469 if len(vals) < 2:
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
470 raise error.ResponseError(_("unexpected response:"), r)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
471 return vals
36430
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
472 except urlerr.httperror:
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
473 # Catch and re-raise these so we don't try and treat them
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
474 # like generic socket errors. They lack any values in
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
475 # .args on Python 3 which breaks our socket.error block.
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36426
diff changeset
476 raise
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25500
diff changeset
477 except socket.error as err:
25085
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
478 if err.args[0] in (errno.ECONNRESET, errno.EPIPE):
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
479 raise error.Abort(_('push failed: %s') % err.args[1])
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
480 raise error.Abort(err.args[1])
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
481 finally:
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
482 fp.close()
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
483 os.unlink(tempname)
2439
e8c4f3d3df8c extend network protocol to stop clients from locking servers
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2435
diff changeset
484
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
485 def _calltwowaystream(self, cmd, fp, **args):
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
486 fh = None
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
487 fp_ = None
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
488 filename = None
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
489 try:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
490 # dump bundle to disk
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
491 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
36835
5bc7ff103081 py3: use r'' instead of sysstr('') to get around code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 36430
diff changeset
492 fh = os.fdopen(fd, r"wb")
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
493 d = fp.read(4096)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
494 while d:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
495 fh.write(d)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
496 d = fp.read(4096)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
497 fh.close()
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
498 # start http push
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
499 fp_ = httpconnection.httpsendfile(self.ui, filename, "rb")
36297
a59ff82154b8 httppeer: headers are native strings
Augie Fackler <augie@google.com>
parents: 36270
diff changeset
500 headers = {r'Content-Type': r'application/mercurial-0.1'}
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
501 return self._callstream(cmd, data=fp_, headers=headers, **args)
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
502 finally:
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
503 if fp_ is not None:
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
504 fp_.close()
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
505 if fh is not None:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
506 fh.close()
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
507 os.unlink(filename)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
508
20905
167047ba3cfa wireproto: drop the _decompress method in favor a new call type
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 18742
diff changeset
509 def _callcompressable(self, cmd, **args):
30464
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
510 return self._callstream(cmd, _compressible=True, **args)
11370
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 11153
diff changeset
511
21188
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
512 def _abort(self, exception):
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
513 raise exception
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
514
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
515 # TODO implement interface for version 2 peers
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
516 class httpv2peer(object):
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
517 def __init__(self, ui, repourl, apipath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
518 apidescriptor):
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
519 self.ui = ui
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
520
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
521 if repourl.endswith('/'):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
522 repourl = repourl[:-1]
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
523
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
524 self.url = repourl
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
525 self._apipath = apipath
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
526 self._opener = opener
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
527 self._requestbuilder = requestbuilder
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
528 self._descriptor = apidescriptor
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
529
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
530 def close(self):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
531 pass
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
532
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
533 # TODO require to be part of a batched primitive, use futures.
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
534 def _call(self, name, **args):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
535 """Call a wire protocol command with arguments."""
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
536
37546
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
537 # Having this early has a side-effect of importing wireprotov2server,
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
538 # which has the side-effect of ensuring commands are registered.
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
539
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
540 # TODO modify user-agent to reflect v2.
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
541 headers = {
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
542 r'Accept': wireprotov2server.FRAMINGTYPE,
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
543 r'Content-Type': wireprotov2server.FRAMINGTYPE,
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
544 }
3a2367e6c6f2 wireproto: move version 2 command handlers to wireprotov2server
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37545
diff changeset
545
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
546 # TODO permissions should come from capabilities results.
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
547 permission = wireproto.commandsv2[name].permission
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
548 if permission not in ('push', 'pull'):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
549 raise error.ProgrammingError('unknown permission type: %s' %
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
550 permission)
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
551
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
552 permission = {
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
553 'push': 'rw',
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
554 'pull': 'ro',
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
555 }[permission]
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
556
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
557 url = '%s/%s/%s/%s' % (self.url, self._apipath, permission, name)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
558
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
559 # TODO this should be part of a generic peer for the frame-based
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
560 # protocol.
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
561 reactor = wireprotoframing.clientreactor(hasmultiplesend=False,
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
562 buffersends=True)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
563
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
564 request, action, meta = reactor.callcommand(name, args)
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
565 assert action == 'noop'
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
566
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
567 action, meta = reactor.flushcommands()
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
568 assert action == 'sendframes'
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
569
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
570 body = b''.join(map(bytes, meta['framegen']))
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
571 req = self._requestbuilder(pycompat.strurl(url), body, headers)
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
572 req.add_unredirected_header(r'Content-Length', r'%d' % len(body))
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
573
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
574 # TODO unify this code with httppeer.
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
575 try:
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
576 res = self._opener.open(req)
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
577 except urlerr.httperror as e:
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
578 if e.code == 401:
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
579 raise error.Abort(_('authorization failed'))
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
580
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
581 raise
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
582 except httplib.HTTPException as e:
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
583 self.ui.traceback()
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
584 raise IOError(None, e)
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
585
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
586 # TODO validate response type, wrap response to handle I/O errors.
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
587 # TODO more robust frame receiver.
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
588 results = []
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
589
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
590 while True:
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
591 frame = wireprotoframing.readframe(res)
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
592 if frame is None:
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
593 break
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
594
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
595 self.ui.note(_('received %r\n') % frame)
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
596
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
597 action, meta = reactor.onframerecv(frame)
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
598
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
599 if action == 'responsedata':
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
600 if meta['cbor']:
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
601 payload = util.bytesio(meta['data'])
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
602
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
603 decoder = cbor.CBORDecoder(payload)
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
604 while payload.tell() + 1 < len(meta['data']):
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
605 results.append(decoder.decode())
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
606 else:
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
607 results.append(meta['data'])
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
608 else:
37544
55b5ba8d4e68 wireproto: client reactor support for receiving frames
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37543
diff changeset
609 error.ProgrammingError('unhandled action: %s' % action)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
610
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
611 return results
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
612
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
613 # Registry of API service names to metadata about peers that handle it.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
614 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
615 # The following keys are meaningful:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
616 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
617 # init
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
618 # Callable receiving (ui, repourl, servicepath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
619 # apidescriptor) to create a peer.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
620 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
621 # priority
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
622 # Integer priority for the service. If we could choose from multiple
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
623 # services, we choose the one with the highest priority.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
624 API_PEERS = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
625 wireprototypes.HTTPV2: {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
626 'init': httpv2peer,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
627 'priority': 50,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
628 },
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
629 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
630
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
631 def performhandshake(ui, url, opener, requestbuilder):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
632 # The handshake is a request to the capabilities command.
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
633
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
634 caps = None
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
635 def capable(x):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
636 raise error.ProgrammingError('should not be called')
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
637
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
638 args = {}
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
639
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
640 # The client advertises support for newer protocols by adding an
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
641 # X-HgUpgrade-* header with a list of supported APIs and an
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
642 # X-HgProto-* header advertising which serializing formats it supports.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
643 # We only support the HTTP version 2 transport and CBOR responses for
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
644 # now.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
645 advertisev2 = ui.configbool('experimental', 'httppeer.advertise-v2')
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
646
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
647 if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
648 args['headers'] = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
649 r'X-HgProto-1': r'cbor',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
650 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
651
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
652 args['headers'].update(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
653 encodevalueinheaders(' '.join(sorted(API_PEERS)),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
654 'X-HgUpgrade',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
655 # We don't know the header limit this early.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
656 # So make it small.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
657 1024))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
658
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
659 req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
660 capable, url, 'capabilities',
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
661 args)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
662
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
663 resp = sendrequest(ui, opener, req)
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
664
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
665 respurl, ct, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
666 compressible=False,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
667 allowcbor=advertisev2)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
668
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
669 try:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
670 rawdata = resp.read()
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
671 finally:
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
672 resp.close()
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
673
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
674 if not ct.startswith('application/mercurial-'):
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
675 raise error.ProgrammingError('unexpected content-type: %s' % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
676
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
677 if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
678 if ct == 'application/mercurial-cbor':
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
679 try:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
680 info = cbor.loads(rawdata)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
681 except cbor.CBORDecodeError:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
682 raise error.Abort(_('error decoding CBOR from remote server'),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
683 hint=_('try again and consider contacting '
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
684 'the server operator'))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
685
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
686 # We got a legacy response. That's fine.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
687 elif ct in ('application/mercurial-0.1', 'application/mercurial-0.2'):
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
688 info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
689 'v1capabilities': set(rawdata.split())
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
690 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
691
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
692 else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
693 raise error.RepoError(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
694 _('unexpected response type from server: %s') % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
695 else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
696 info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
697 'v1capabilities': set(rawdata.split())
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
698 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
699
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
700 return respurl, info
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
701
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
702 def makepeer(ui, path, opener=None, requestbuilder=urlreq.request):
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
703 """Construct an appropriate HTTP peer instance.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
704
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
705 ``opener`` is an ``url.opener`` that should be used to establish
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
706 connections, perform HTTP requests.
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
707
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
708 ``requestbuilder`` is the type used for constructing HTTP requests.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
709 It exists as an argument so extensions can override the default.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
710 """
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
711 u = util.url(path)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
712 if u.query or u.fragment:
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
713 raise error.Abort(_('unsupported URL component: "%s"') %
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
714 (u.query or u.fragment))
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
715
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
716 # urllib cannot handle URLs with embedded user or passwd.
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
717 url, authinfo = u.authinfo()
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
718 ui.debug('using %s\n' % url)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
719
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
720 opener = opener or urlmod.opener(ui, authinfo)
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
721
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
722 respurl, info = performhandshake(ui, url, opener, requestbuilder)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
723
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
724 # Given the intersection of APIs that both we and the server support,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
725 # sort by their advertised priority and pick the first one.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
726 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
727 # TODO consider making this request-based and interface driven. For
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
728 # example, the caller could say "I want a peer that does X." It's quite
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
729 # possible that not all peers would do that. Since we know the service
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
730 # capabilities, we could filter out services not meeting the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
731 # requirements. Possibly by consulting the interfaces defined by the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
732 # peer type.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
733 apipeerchoices = set(info.get('apis', {}).keys()) & set(API_PEERS.keys())
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
734
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
735 preferredchoices = sorted(apipeerchoices,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
736 key=lambda x: API_PEERS[x]['priority'],
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
737 reverse=True)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
738
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
739 for service in preferredchoices:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
740 apipath = '%s/%s' % (info['apibase'].rstrip('/'), service)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
741
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
742 return API_PEERS[service]['init'](ui, respurl, apipath, opener,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
743 requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
744 info['apis'][service])
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
745
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
746 # Failed to construct an API peer. Fall back to legacy.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
747 return httppeer(ui, path, respurl, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
748 info['v1capabilities'])
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
749
2740
386f04d6ecb3 clean up hg.py: move repo constructor code into each repo module
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2673
diff changeset
750 def instance(ui, path, create):
386f04d6ecb3 clean up hg.py: move repo constructor code into each repo module
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2673
diff changeset
751 if create:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
752 raise error.Abort(_('cannot create new http repository'))
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
753 try:
36959
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36835
diff changeset
754 if path.startswith('https:') and not urlmod.has_https:
36220
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36219
diff changeset
755 raise error.Abort(_('Python support for SSL and HTTPS '
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36219
diff changeset
756 'is not installed'))
35884
197d10e157ce httppeer: remove support for connecting to <0.9.1 servers (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35698
diff changeset
757
37006
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36961
diff changeset
758 inst = makepeer(ui, path)
35884
197d10e157ce httppeer: remove support for connecting to <0.9.1 servers (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35698
diff changeset
759
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
760 return inst
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25500
diff changeset
761 except error.RepoError as httpexception:
14148
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
762 try:
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
763 r = statichttprepo.instance(ui, "static-" + path, create)
29241
269f7ea08983 httppeer: make a message translatable
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 28883
diff changeset
764 ui.note(_('(falling back to static-http)\n'))
14148
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
765 return r
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
766 except error.RepoError:
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
767 raise httpexception # use the original http RepoError instead