annotate mercurial/httppeer.py @ 37669:1cb54e6193a6

py3: paper over differences in future exception handling It looks like Python 3's futures library lacks set_exception_info entirely. We'll just give up and use set_exception in that case. # no-check-commit because the underbar naming is just saner here Differential Revision: https://phab.mercurial-scm.org/D3336
author Augie Fackler <augie@google.com>
date Fri, 13 Apr 2018 18:17:45 -0400
parents 8cea0d57bf37
children 0664be4f0c1f
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
33842
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
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
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
16 import sys
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
17 import tempfile
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
18 import weakref
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
19
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
20 from .i18n import _
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
21 from .thirdparty import (
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
22 cbor,
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
23 )
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
24 from .thirdparty.zope import (
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
25 interface as zi,
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
26 )
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
27 from . import (
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
28 bundle2,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
29 error,
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
30 httpconnection,
30944
48dea083f66d py3: convert the mode argument of os.fdopen to unicodes (1 of 2)
Pulkit Goyal <7895pulkit@gmail.com>
parents: 30763
diff changeset
31 pycompat,
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
32 repository,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
33 statichttprepo,
36965
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36843
diff changeset
34 url as urlmod,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
35 util,
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
36 wireprotoframing,
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
37 wireprototypes,
37614
a81d02ea65db wireproto: move version 1 peer functionality to standalone module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37611
diff changeset
38 wireprotov1peer,
37545
93397c4633f6 wireproto: extract HTTP version 2 code to own module
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37544
diff changeset
39 wireprotov2server,
25954
7bbdb78d2842 httppeer: use absolute_import
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25660
diff changeset
40 )
4678
a814a5b11fff Work around urllib2 digest auth bug with Python < 2.5
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 4633
diff changeset
41
29455
0c741fd6158a py3: conditionalize httplib import
Pulkit Goyal <7895pulkit@gmail.com>
parents: 29241
diff changeset
42 httplib = util.httplib
28883
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
43 urlerr = util.urlerr
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
44 urlreq = util.urlreq
032c4c2f802a pycompat: switch to util.urlreq/util.urlerr for py3 compat
timeless <timeless@mozdev.org>
parents: 28666
diff changeset
45
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
46 def encodevalueinheaders(value, header, limit):
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
47 """Encode a string value into multiple HTTP headers.
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
48
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
49 ``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: 30569
diff changeset
50 ``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: 30569
diff changeset
51 name + value will be at most ``limit`` bytes long.
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
52
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
53 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
54 values as native strings.
30759
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
55 """
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
56 # 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
57 # 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
58 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
59 # 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
60 # 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
61 # 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
62 # 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
63 # instead of a carriage return.
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
64 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: 30569
diff changeset
65 result = []
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
66
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
67 n = 0
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
68 for i in xrange(0, len(value), valuelen):
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
69 n += 1
34732
67e9678efd98 httppeer: always produce native str header keys and values
Augie Fackler <augie@google.com>
parents: 34725
diff changeset
70 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: 30569
diff changeset
71
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
72 return result
3f5f0c98cd18 httppeer: extract code for HTTP header spanning
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30569
diff changeset
73
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
74 def _wraphttpresponse(resp):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
75 """Wrap an HTTPResponse with common error handlers.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
76
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
77 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: 30944
diff changeset
78 error and messaging.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
79 """
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
80 origread = resp.read
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
81
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
82 class readerproxy(resp.__class__):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
83 def read(self, size=None):
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
84 try:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
85 return origread(size)
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
86 except httplib.IncompleteRead as e:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
87 # e.expected is an integer if length known or None otherwise.
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
88 if e.expected:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
89 msg = _('HTTP request error (incomplete response; '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
90 'expected %d bytes got %d)') % (e.expected,
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
91 len(e.partial))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
92 else:
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
93 msg = _('HTTP request error (incomplete response)')
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
94
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: 30944
diff changeset
96 msg,
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
97 hint=_('this may be an intermittent network failure; '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
98 'if the error persists, consider contacting the '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
99 'network or server operator'))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
100 except httplib.HTTPException as e:
32023
a29580905771 error: rename RichIOError to PeerTransportError
Gregory Szorc <gregory.szorc@gmail.com>
parents: 32022
diff changeset
101 raise error.PeerTransportError(
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
102 _('HTTP request error (%s)') % e,
32086
b59a292d0a53 httppeer: unify hint message for PeerTransportError
FUJIWARA Katsunori <foozy@lares.dti.ne.jp>
parents: 32023
diff changeset
103 hint=_('this may be an intermittent network failure; '
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
104 'if the error persists, consider contacting the '
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
105 'network or server operator'))
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
106
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
107 resp.__class__ = readerproxy
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
108
33842
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
109 class _multifile(object):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
110 def __init__(self, *fileobjs):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
111 for f in fileobjs:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
112 if not util.safehasattr(f, 'length'):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
113 raise ValueError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
114 '_multifile only supports file objects that '
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
115 '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: 33827
diff changeset
116 self._fileobjs = fileobjs
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
117 self._index = 0
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
118
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
119 @property
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
120 def length(self):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
121 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: 33827
diff changeset
122
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
123 def read(self, amt=None):
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
124 if amt <= 0:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
125 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: 33827
diff changeset
126 parts = []
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
127 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: 33827
diff changeset
128 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: 33827
diff changeset
129 got = len(parts[-1])
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
130 if got < amt:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
131 self._index += 1
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
132 amt -= got
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
133 return ''.join(parts)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
134
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
135 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: 33827
diff changeset
136 if whence != os.SEEK_SET:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
137 raise NotImplementedError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
138 '_multifile does not support anything other'
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
139 ' 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: 33827
diff changeset
140 if offset != 0:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
141 raise NotImplementedError(
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
142 '_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: 33827
diff changeset
143 '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: 33827
diff changeset
144 for f in self._fileobjs:
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
145 f.seek(0)
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
146 self._index = 0
3c91cc0c5fde httppeer: add support for httppostargs when we're sending a file
Augie Fackler <augie@google.com>
parents: 33827
diff changeset
147
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
148 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
149 repobaseurl, cmd, args):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
150 """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
151
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
152 ``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
153 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
154
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
155 ``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
156
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
157 ``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
158 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
159 """
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
160 if cmd == 'pushkey':
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
161 args['data'] = ''
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
162 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
163 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
164
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
165 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
166 q = [('cmd', cmd)]
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
167 headersize = 0
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
168 # 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
169 # 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
170 # 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
171 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
172
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
173 # 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
174 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
175 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
176 if not data:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
177 data = strargs
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
178 else:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
179 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
180 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
181 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
182 data = i
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
183 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
184 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
185 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
186 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
187 elif args:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
188 # 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
189 # "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
190 # 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
191 assert cmd != 'capabilities'
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
192 httpheader = capablefn('httpheader')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
193 if httpheader:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
194 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
195
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
196 # 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
197 if headersize > 0:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
198 # 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
199 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
200 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
201 headersize):
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
202 headers[header] = value
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
203 # 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
204 else:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
205 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
206
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
207 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
208 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
209 size = 0
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
210 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
211 size = data.length
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
212 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
213 size = len(data)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
214 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
215 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
216
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
217 # 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
218 # 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
219 # payloads.
37556
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
220 # 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
221 # 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
222 protoparams = set()
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
223
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
224 mediatypes = set()
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
225 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
226 mt = capablefn('httpmediatype')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
227 if mt:
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.1')
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
229 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
230
37556
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
231 protoparams.add('partial-pull')
b77aa48ba690 httppeer: only advertise partial-pull if capabilities are known
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37555
diff changeset
232
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
233 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
234 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
235
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
236 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
237 # 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
238 # 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
239 # 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
240 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
241 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
242 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
243
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
244 if protoparams:
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
245 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
246 'X-HgProto',
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
247 headersize or 1024)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
248 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
249 headers[header] = value
37555
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
250
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
251 varyheaders = []
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
252 for header in headers:
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
253 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
254 varyheaders.append(header)
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
255
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
256 if varyheaders:
37555
930c433eb311 httppeer: always add x-hg* headers to Vary header
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37554
diff changeset
257 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
258
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
259 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
260
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
261 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
262 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
263 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
264
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
265 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
266
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
267 def sendrequest(ui, opener, req):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
268 """Send a prepared HTTP request.
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
269
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
270 Returns the response object.
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
271 """
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
272 if (ui.debugflag
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
273 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
274 dbg = ui.debug
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
275 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
276 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
277 hgargssize = None
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
278
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
279 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
280 if header.startswith('X-hgarg-'):
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
281 if hgargssize is None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
282 hgargssize = 0
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
283 hgargssize += len(value)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
284 else:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
285 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
286
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
287 if hgargssize is not None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
288 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
289 % hgargssize)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
290
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
291 if req.has_data():
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
292 data = req.get_data()
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
293 length = getattr(data, 'length', None)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
294 if length is None:
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
295 length = len(data)
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
296 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
297
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
298 start = util.timer()
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
299
37550
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
300 try:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
301 res = opener.open(req)
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
302 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
303 if inst.code == 401:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
304 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
305 raise
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
306 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
307 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
308 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
309 ui.traceback()
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
310 raise IOError(None, inst)
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
311 finally:
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
312 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
313 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
314 % (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
315
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
316 # 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
317 _wraphttpresponse(res)
37548
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
318
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
319 return res
8e7a4435ab6d httppeer: extract code for performing an HTTP request
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37547
diff changeset
320
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
321 def parsev1commandresponse(ui, baseurl, requrl, qs, resp, compressible,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
322 allowcbor=False):
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
323 # 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
324 respurl = pycompat.bytesurl(resp.geturl())
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
325 if respurl.endswith(qs):
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
326 respurl = respurl[:-len(qs)]
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
327 if baseurl.rstrip('/') != respurl.rstrip('/'):
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
328 if not ui.quiet:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
329 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
330
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
331 try:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
332 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
333 except AttributeError:
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
334 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
335
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
336 safeurl = util.hidepassword(baseurl)
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
337 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
338 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
339
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
340 # 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
341 # 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
342 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
343 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
344 raise error.RepoError(
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
345 _("'%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
346 "---%%<--- (%s)\n%s\n---%%<---\n")
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
347 % (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
348
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
349 try:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
350 subtype = proto.split('-', 1)[1]
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
351
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
352 # 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
353 # this should ONLY be encountered for the initial capabilities
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
354 # request during handshake.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
355 if subtype == 'cbor':
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
356 if allowcbor:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
357 return respurl, proto, resp
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
358 else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
359 raise error.RepoError(_('unexpected CBOR response from '
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
360 'server'))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
361
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
362 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
363 except ValueError:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
364 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
365 "header (%s)") % (safeurl, proto))
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 # 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
368 # generators.
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
369 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
370 if compressible:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
371 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
372
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
373 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
374 # 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
375 # 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
376 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
377 ename = resp.read(elen)
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
378 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
379
37554
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
380 resp = engine.decompressorreader(resp)
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
381 else:
301a1d2e8016 httppeer: don't accept very old media types (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37553
diff changeset
382 raise error.RepoError(_("'%s' uses newer protocol %s") %
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
383 (safeurl, subtype))
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
384
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
385 return respurl, proto, resp
37551
946eb204ba67 httppeer: extract common response handling into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37550
diff changeset
386
37614
a81d02ea65db wireproto: move version 1 peer functionality to standalone module (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37611
diff changeset
387 class httppeer(wireprotov1peer.wirepeer):
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
388 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
389 self.ui = ui
33731
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33730
diff changeset
390 self._path = path
37009
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
391 self._url = url
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
392 self._caps = caps
37009
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
393 self._urlopener = opener
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
394 self._requestbuilder = requestbuilder
4516
96d8a56d4ef9 Removed trailing whitespace and tabs from python files
Thomas Arendsen Hein <thomas@intevation.de>
parents: 4369
diff changeset
395
7752
998fc8f62539 close sockets on httprepository deletion (issue1487)
Steve Borho <steve@borho.org>
parents: 7641
diff changeset
396 def __del__(self):
37009
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
397 for h in self._urlopener.handlers:
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
398 h.close()
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
399 getattr(h, "close_all", lambda: None)()
7752
998fc8f62539 close sockets on httprepository deletion (issue1487)
Steve Borho <steve@borho.org>
parents: 7641
diff changeset
400
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37009
diff changeset
401 # Begin of ipeerconnection interface.
33826
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
402
2673
109a22f5434a hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2612
diff changeset
403 def url(self):
33731
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33730
diff changeset
404 return self._path
2673
109a22f5434a hooks: add url to changegroup, incoming, prechangegroup, pretxnchangegroup hooks
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2612
diff changeset
405
33826
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
406 def local(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
407 return None
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
408
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
409 def peer(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
410 return self
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
411
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
412 def canpush(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
413 return True
2442
c660691fb45d http: query server for capabilities
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2439
diff changeset
414
33826
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
415 def close(self):
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
416 pass
13603
395a84f78736 httprepo: use caps instead of between for compat check
Peter Arrenbrecht <peter.arrenbrecht@gmail.com>
parents: 13555
diff changeset
417
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37009
diff changeset
418 # End of ipeerconnection interface.
33826
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
419
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37009
diff changeset
420 # Begin of ipeercommands interface.
33826
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
421
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
422 def capabilities(self):
33731
73fd395ee29e httppeer: make several instance attributes internal (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33730
diff changeset
423 return self._caps
2442
c660691fb45d http: query server for capabilities
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2439
diff changeset
424
37320
39f7d4ee8bcd repository: port peer interfaces to zope.interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37009
diff changeset
425 # End of ipeercommands interface.
33826
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
426
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
427 # look up capabilities only when needed
f913e90f15a0 httppeer: use peer interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 33731
diff changeset
428
30473
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
429 def _callstream(self, cmd, _compressible=False, **args):
35368
98bc4c43f570 py3: handle keyword arguments correctly in httppeer.py
Pulkit Goyal <7895pulkit@gmail.com>
parents: 35208
diff changeset
430 args = pycompat.byteskwargs(args)
36256
e4ccd7a69f77 httppeer: change logic around argument handling
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35924
diff changeset
431
37549
66d1001e1500 httppeer: extract code for creating a request into own function
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37548
diff changeset
432 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
433 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
434 self._url, cmd, args)
30763
a520aefb96f1 httppeer: advertise and support application/mercurial-0.2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30759
diff changeset
435
37550
b5862ee01abe httppeer: move error handling and response wrapping into sendrequest
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37549
diff changeset
436 resp = sendrequest(self.ui, self._urlopener, req)
32002
bf855efe5664 httppeer: wrap HTTPResponse.read() globally
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30944
diff changeset
437
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
438 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
439 resp, _compressible)
30473
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
440
752
c693eafd5967 Simplify content type checking
mpm@selenic.com
parents: 751
diff changeset
441 return resp
60
e32fdbd97839 Add hg:// protocol
mpm@selenic.com
parents: 56
diff changeset
442
11589
e8d22fe2ddab protocol: clean up call-like functions in http and ssh clients
Matt Mackall <mpm@selenic.com>
parents: 11588
diff changeset
443 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
444 fp = self._callstream(cmd, **args)
2435
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
445 try:
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
446 return fp.read()
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
447 finally:
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
448 # if using keepalive, allow connection to be reused
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
449 fp.close()
ff2bac730b99 http client: support persistent connections.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2337
diff changeset
450
11592
26e0782b8380 protocol: unify client unbundle support
Matt Mackall <mpm@selenic.com>
parents: 11591
diff changeset
451 def _callpush(self, cmd, cg, **args):
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
452 # 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
453 # http 1.1 chunked transfer.
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
454
3662
f4dc02d7fb71 unduplicate bundle writing code from httprepo
Matt Mackall <mpm@selenic.com>
parents: 3661
diff changeset
455 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
456 try:
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
457 types = types.split(',')
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
458 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
459 # 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
460 # 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
461 # bundles.
3703
e674cae8efee fix push over HTTP to older servers
Alexis S. L. Carvalho <alexis@cecm.usp.br>
parents: 3662
diff changeset
462 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
463 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
464 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
465 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
466 break
3613
cbf352b9a3cd Client support for hgweb unbundle with versions.
Thomas Arendsen Hein <thomas@intevation.de>
parents: 3609
diff changeset
467
28666
ae53ecc47414 bundle: move writebundle() from changegroup.py to bundle2.py (API)
Martin von Zweigbergk <martinvonz@google.com>
parents: 28530
diff changeset
468 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
469 fp = httpconnection.httpsendfile(self.ui, tempname, "rb")
36330
a59ff82154b8 httppeer: headers are native strings
Augie Fackler <augie@google.com>
parents: 36303
diff changeset
470 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
471
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
472 try:
25085
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
473 r = self._call(cmd, data=fp, headers=headers, **args)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
474 vals = r.split('\n', 1)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
475 if len(vals) < 2:
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
476 raise error.ResponseError(_("unexpected response:"), r)
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
477 return vals
36460
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36456
diff changeset
478 except urlerr.httperror:
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36456
diff changeset
479 # 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: 36456
diff changeset
480 # like generic socket errors. They lack any values in
efebfa9b4cab httppeer: explicitly catch urlerr.httperror and re-raise
Augie Fackler <augie@google.com>
parents: 36456
diff changeset
481 # .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: 36456
diff changeset
482 raise
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25500
diff changeset
483 except socket.error as err:
25085
e05734cd7902 httppeer: use try/except/finally
Matt Mackall <mpm@selenic.com>
parents: 23895
diff changeset
484 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
485 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
486 raise error.Abort(err.args[1])
2465
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
487 finally:
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
488 fp.close()
c91118f425d0 push over http: client support.
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2447
diff changeset
489 os.unlink(tempname)
2439
e8c4f3d3df8c extend network protocol to stop clients from locking servers
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2435
diff changeset
490
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
491 def _calltwowaystream(self, cmd, fp, **args):
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
492 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
493 fp_ = None
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
494 filename = None
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
495 try:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
496 # dump bundle to disk
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
497 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
36843
5bc7ff103081 py3: use r'' instead of sysstr('') to get around code transformer
Yuya Nishihara <yuya@tcha.org>
parents: 36460
diff changeset
498 fh = os.fdopen(fd, r"wb")
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
499 d = fp.read(4096)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
500 while d:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
501 fh.write(d)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
502 d = fp.read(4096)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
503 fh.close()
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
504 # 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
505 fp_ = httpconnection.httpsendfile(self.ui, filename, "rb")
36330
a59ff82154b8 httppeer: headers are native strings
Augie Fackler <augie@google.com>
parents: 36303
diff changeset
506 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
507 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
508 finally:
23086
cde6904f1992 httppeer: close the temporary bundle file after two-way streaming it
Matt Harbison <matt_harbison@yahoo.com>
parents: 21188
diff changeset
509 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
510 fp_.close()
21074
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
511 if fh is not None:
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
512 fh.close()
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
513 os.unlink(filename)
f8a0d82b0463 httppeer: support for _calltwowaystream
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 20905
diff changeset
514
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
515 def _callcompressable(self, cmd, **args):
30473
e16e234b9ca3 httppeer: do decompression inside _callstream
Gregory Szorc <gregory.szorc@gmail.com>
parents: 30241
diff changeset
516 return self._callstream(cmd, _compressible=True, **args)
11370
db3f6f0e4e7d pushkey: add http support
Matt Mackall <mpm@selenic.com>
parents: 11153
diff changeset
517
21188
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
518 def _abort(self, exception):
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
519 raise exception
d36440d84328 httppeer: reintroduce _abort that accidentally was removed in 167047ba3cfa
Mads Kiilerich <madski@unity3d.com>
parents: 21074
diff changeset
520
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
521 def sendv2request(ui, opener, requestbuilder, apiurl, permission, requests):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
522 reactor = wireprotoframing.clientreactor(hasmultiplesend=False,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
523 buffersends=True)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
524
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
525 url = '%s/%s' % (apiurl, permission)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
526
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
527 if len(requests) > 1:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
528 url += '/multirequest'
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
529 else:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
530 url += '/%s' % requests[0][0]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
531
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
532 # Request ID to (request, future)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
533 requestmap = {}
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
534
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
535 for command, args, f in requests:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
536 request, action, meta = reactor.callcommand(command, args)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
537 assert action == 'noop'
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
538
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
539 requestmap[request.requestid] = (request, f)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
540
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
541 action, meta = reactor.flushcommands()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
542 assert action == 'sendframes'
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
543
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
544 # TODO stream this.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
545 body = b''.join(map(bytes, meta['framegen']))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
546
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
547 # TODO modify user-agent to reflect v2
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
548 headers = {
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
549 r'Accept': wireprotov2server.FRAMINGTYPE,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
550 r'Content-Type': wireprotov2server.FRAMINGTYPE,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
551 }
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
552
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
553 req = requestbuilder(pycompat.strurl(url), body, headers)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
554 req.add_unredirected_header(r'Content-Length', r'%d' % len(body))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
555
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
556 try:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
557 res = opener.open(req)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
558 except urlerr.httperror as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
559 if e.code == 401:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
560 raise error.Abort(_('authorization failed'))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
561
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
562 raise
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
563 except httplib.HTTPException as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
564 ui.traceback()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
565 raise IOError(None, e)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
566
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
567 return reactor, requestmap, res
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
568
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
569 class queuedcommandfuture(pycompat.futures.Future):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
570 """Wraps result() on command futures to trigger submission on call."""
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
571
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
572 def result(self, timeout=None):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
573 if self.done():
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
574 return pycompat.futures.Future.result(self, timeout)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
575
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
576 self._peerexecutor.sendcommands()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
577
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
578 # sendcommands() will restore the original __class__ and self.result
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
579 # will resolve to Future.result.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
580 return self.result(timeout)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
581
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
582 @zi.implementer(repository.ipeercommandexecutor)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
583 class httpv2executor(object):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
584 def __init__(self, ui, opener, requestbuilder, apiurl, descriptor):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
585 self._ui = ui
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
586 self._opener = opener
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
587 self._requestbuilder = requestbuilder
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
588 self._apiurl = apiurl
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
589 self._descriptor = descriptor
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
590 self._sent = False
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
591 self._closed = False
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
592 self._neededpermissions = set()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
593 self._calls = []
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
594 self._futures = weakref.WeakSet()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
595 self._responseexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
596 self._responsef = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
597
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
598 def __enter__(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
599 return self
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
600
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
601 def __exit__(self, exctype, excvalue, exctb):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
602 self.close()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
603
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
604 def callcommand(self, command, args):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
605 if self._sent:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
606 raise error.ProgrammingError('callcommand() cannot be used after '
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
607 'commands are sent')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
608
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
609 if self._closed:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
610 raise error.ProgrammingError('callcommand() cannot be used after '
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
611 'close()')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
612
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
613 # The service advertises which commands are available. So if we attempt
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
614 # to call an unknown command or pass an unknown argument, we can screen
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
615 # for this.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
616 if command not in self._descriptor['commands']:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
617 raise error.ProgrammingError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
618 'wire protocol command %s is not available' % command)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
619
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
620 cmdinfo = self._descriptor['commands'][command]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
621 unknownargs = set(args.keys()) - set(cmdinfo.get('args', {}))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
622
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
623 if unknownargs:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
624 raise error.ProgrammingError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
625 'wire protocol command %s does not accept argument: %s' % (
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
626 command, ', '.join(sorted(unknownargs))))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
627
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
628 self._neededpermissions |= set(cmdinfo['permissions'])
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
629
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
630 # TODO we /could/ also validate types here, since the API descriptor
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
631 # includes types...
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
632
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
633 f = pycompat.futures.Future()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
634
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
635 # Monkeypatch it so result() triggers sendcommands(), otherwise result()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
636 # could deadlock.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
637 f.__class__ = queuedcommandfuture
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
638 f._peerexecutor = self
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
639
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
640 self._futures.add(f)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
641 self._calls.append((command, args, f))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
642
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
643 return f
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
644
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
645 def sendcommands(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
646 if self._sent:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
647 return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
648
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
649 if not self._calls:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
650 return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
652 self._sent = True
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
653
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
654 # Unhack any future types so caller sees a clean type and so we
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
655 # break reference cycle.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
656 for f in self._futures:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
657 if isinstance(f, queuedcommandfuture):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
658 f.__class__ = pycompat.futures.Future
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
659 f._peerexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
660
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
661 # Mark the future as running and filter out cancelled futures.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
662 calls = [(command, args, f)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
663 for command, args, f in self._calls
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
664 if f.set_running_or_notify_cancel()]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
665
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
666 # Clear out references, prevent improper object usage.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
667 self._calls = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
668
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
669 if not calls:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
670 return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
671
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
672 permissions = set(self._neededpermissions)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
673
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
674 if 'push' in permissions and 'pull' in permissions:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
675 permissions.remove('pull')
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
676
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
677 if len(permissions) > 1:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
678 raise error.RepoError(_('cannot make request requiring multiple '
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
679 'permissions: %s') %
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
680 _(', ').join(sorted(permissions)))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
681
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
682 permission = {
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
683 'push': 'rw',
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
684 'pull': 'ro',
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
685 }[permissions.pop()]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
686
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
687 reactor, requests, resp = sendv2request(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
688 self._ui, self._opener, self._requestbuilder, self._apiurl,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
689 permission, calls)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
690
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
691 # TODO we probably want to validate the HTTP code, media type, etc.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
692
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
693 self._responseexecutor = pycompat.futures.ThreadPoolExecutor(1)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
694 self._responsef = self._responseexecutor.submit(self._handleresponse,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
695 reactor,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
696 requests,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
697 resp)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
698
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
699 def close(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
700 if self._closed:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
701 return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
702
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
703 self.sendcommands()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
704
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
705 self._closed = True
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
706
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
707 if not self._responsef:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
708 return
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
709
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
710 try:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
711 self._responsef.result()
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
712 finally:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
713 self._responseexecutor.shutdown(wait=True)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
714 self._responsef = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
715 self._responseexecutor = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
716
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
717 # If any of our futures are still in progress, mark them as
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
718 # errored, otherwise a result() could wait indefinitely.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
719 for f in self._futures:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
720 if not f.done():
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
721 f.set_exception(error.ResponseError(
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
722 _('unfulfilled command response')))
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
723
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
724 self._futures = None
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
725
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
726 def _handleresponse(self, reactor, requests, resp):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
727 # Called in a thread to read the response.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
728
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
729 results = {k: [] for k in requests}
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
730
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
731 while True:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
732 frame = wireprotoframing.readframe(resp)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
733 if frame is None:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
734 break
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
735
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
736 self._ui.note(_('received %r\n') % frame)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
737
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
738 # Guard against receiving a frame with a request ID that we
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
739 # didn't issue. This should never happen.
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
740 request, f = requests.get(frame.requestid, [None, None])
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
741
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
742 action, meta = reactor.onframerecv(frame)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
743
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
744 if action == 'responsedata':
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
745 assert request.requestid == meta['request'].requestid
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
746
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
747 result = results[request.requestid]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
748
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
749 if meta['cbor']:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
750 payload = util.bytesio(meta['data'])
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
751
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
752 decoder = cbor.CBORDecoder(payload)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
753 while payload.tell() + 1 < len(meta['data']):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
754 try:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
755 result.append(decoder.decode())
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
756 except Exception:
37669
1cb54e6193a6 py3: paper over differences in future exception handling
Augie Fackler <augie@google.com>
parents: 37654
diff changeset
757 pycompat.future_set_exception_info(
1cb54e6193a6 py3: paper over differences in future exception handling
Augie Fackler <augie@google.com>
parents: 37654
diff changeset
758 f, sys.exc_info()[1:])
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
759 continue
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
760 else:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
761 result.append(meta['data'])
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
762
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
763 if meta['eos']:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
764 f.set_result(result)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
765 del results[request.requestid]
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
766
37654
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
767 elif action == 'error':
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
768 e = error.RepoError(meta['message'])
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
769
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
770 if f:
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
771 f.set_exception(e)
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
772 else:
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
773 raise e
8cea0d57bf37 httppeer: handle error response from client reactor
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37651
diff changeset
774
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
775 else:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
776 e = error.ProgrammingError('unhandled action: %s' % action)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
777
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
778 if f:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
779 f.set_exception(e)
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
780 else:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
781 raise e
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
782
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
783 # TODO implement interface for version 2 peers
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
784 @zi.implementer(repository.ipeerconnection, repository.ipeercapabilities,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
785 repository.ipeerrequests)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
786 class httpv2peer(object):
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
787 def __init__(self, ui, repourl, apipath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
788 apidescriptor):
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
789 self.ui = ui
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
790
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
791 if repourl.endswith('/'):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
792 repourl = repourl[:-1]
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
793
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
794 self._url = repourl
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
795 self._apipath = apipath
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
796 self._apiurl = '%s/%s' % (repourl, apipath)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
797 self._opener = opener
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
798 self._requestbuilder = requestbuilder
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
799 self._descriptor = apidescriptor
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
800
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
801 # Start of ipeerconnection.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
802
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
803 def url(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
804 return self._url
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
805
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
806 def local(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
807 return None
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
808
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
809 def peer(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
810 return self
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
811
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
812 def canpush(self):
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
813 # TODO change once implemented.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
814 return False
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
815
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
816 def close(self):
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
817 pass
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
818
37609
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
819 # End of ipeerconnection.
01bfe5ad0c53 httppeer: implement ipeerconnection
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37558
diff changeset
820
37611
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
821 # Start of ipeercapabilities.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
822
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
823 def capable(self, name):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
824 # The capabilities used internally historically map to capabilities
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
825 # advertised from the "capabilities" wire protocol command. However,
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
826 # version 2 of that command works differently.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
827
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
828 # Maps to commands that are available.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
829 if name in ('branchmap', 'getbundle', 'known', 'lookup', 'pushkey'):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
830 return True
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
831
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
832 # Other concepts.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
833 if name in ('bundle2',):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
834 return True
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
835
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
836 return False
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
837
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
838 def requirecap(self, name, purpose):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
839 if self.capable(name):
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
840 return
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
841
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
842 raise error.CapabilityError(
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
843 _('cannot %s; client or remote repository does not support the %r '
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
844 'capability') % (purpose, name))
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
845
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
846 # End of ipeercapabilities.
ae8730877371 httppeer: basic implementation of capabilities interface
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37609
diff changeset
847
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
848 def _call(self, name, **args):
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
849 with self.commandexecutor() as e:
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
850 return e.callcommand(name, args).result()
37543
01361be9e2dc wireproto: introduce a reactor for client-side state
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37498
diff changeset
851
37651
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
852 def commandexecutor(self):
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
853 return httpv2executor(self.ui, self._opener, self._requestbuilder,
950294e28136 httppeer: implement command executor for version 2 peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37644
diff changeset
854 self._apiurl, self._descriptor)
37483
61e405fb6372 wireproto: crude support for version 2 HTTP peer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37411
diff changeset
855
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
856 # 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
857 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
858 # The following keys are meaningful:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
859 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
860 # init
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
861 # Callable receiving (ui, repourl, servicepath, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
862 # apidescriptor) to create a peer.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
863 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
864 # priority
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
865 # 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
866 # services, we choose the one with the highest priority.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
867 API_PEERS = {
37644
77c9ee77687c wireproto: rename HTTPV2 so it less like HTTP/2
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37614
diff changeset
868 wireprototypes.HTTP_WIREPROTO_V2: {
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
869 'init': httpv2peer,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
870 'priority': 50,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
871 },
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
872 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
873
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
874 def performhandshake(ui, url, opener, requestbuilder):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
875 # 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
876
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
877 caps = None
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
878 def capable(x):
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
879 raise error.ProgrammingError('should not be called')
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
880
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
881 args = {}
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
882
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
883 # 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
884 # 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
885 # X-HgProto-* header advertising which serializing formats it supports.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
886 # 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
887 # now.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
888 advertisev2 = ui.configbool('experimental', 'httppeer.advertise-v2')
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
889
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
890 if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
891 args['headers'] = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
892 r'X-HgProto-1': r'cbor',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
893 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
894
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
895 args['headers'].update(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
896 encodevalueinheaders(' '.join(sorted(API_PEERS)),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
897 'X-HgUpgrade',
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
898 # We don't know the header limit this early.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
899 # So make it small.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
900 1024))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
901
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
902 req, requrl, qs = makev1commandrequest(ui, requestbuilder, caps,
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
903 capable, url, 'capabilities',
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
904 args)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
905
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
906 resp = sendrequest(ui, opener, req)
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
907
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
908 respurl, ct, resp = parsev1commandresponse(ui, url, requrl, qs, resp,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
909 compressible=False,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
910 allowcbor=advertisev2)
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
911
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
912 try:
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
913 rawdata = resp.read()
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
914 finally:
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
915 resp.close()
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
916
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
917 if not ct.startswith('application/mercurial-'):
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
918 raise error.ProgrammingError('unexpected content-type: %s' % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
919
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
920 if advertisev2:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
921 if ct == 'application/mercurial-cbor':
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
922 try:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
923 info = cbor.loads(rawdata)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
924 except cbor.CBORDecodeError:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
925 raise error.Abort(_('error decoding CBOR from remote server'),
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
926 hint=_('try again and consider contacting '
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
927 'the server operator'))
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
928
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
929 # We got a legacy response. That's fine.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
930 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
931 info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
932 'v1capabilities': set(rawdata.split())
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
933 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
934
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
935 else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
936 raise error.RepoError(
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
937 _('unexpected response type from server: %s') % ct)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
938 else:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
939 info = {
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
940 'v1capabilities': set(rawdata.split())
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
941 }
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
942
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
943 return respurl, info
37552
8b8a845c85fc httppeer: perform capabilities request in makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37551
diff changeset
944
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
945 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
946 """Construct an appropriate HTTP peer instance.
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
947
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
948 ``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
949 connections, perform HTTP requests.
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
950
37547
835ccc2a5ef1 httppeer: move requestbuilder defaults into makepeer() argument
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37546
diff changeset
951 ``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
952 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
953 """
37009
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
954 u = util.url(path)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
955 if u.query or u.fragment:
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
956 raise error.Abort(_('unsupported URL component: "%s"') %
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
957 (u.query or u.fragment))
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
958
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
959 # urllib cannot handle URLs with embedded user or passwd.
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
960 url, authinfo = u.authinfo()
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
961 ui.debug('using %s\n' % url)
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
962
37553
6b08cf6b900f httppeer: allow opener to be passed to makepeer()
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37552
diff changeset
963 opener = opener or urlmod.opener(ui, authinfo)
37009
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
964
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
965 respurl, info = performhandshake(ui, url, opener, requestbuilder)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
966
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
967 # 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
968 # 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
969 #
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
970 # 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
971 # 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
972 # 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
973 # capabilities, we could filter out services not meeting the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
974 # requirements. Possibly by consulting the interfaces defined by the
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
975 # peer type.
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
976 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
977
37558
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
978 preferredchoices = sorted(apipeerchoices,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
979 key=lambda x: API_PEERS[x]['priority'],
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
980 reverse=True)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
981
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
982 for service in preferredchoices:
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
983 apipath = '%s/%s' % (info['apibase'].rstrip('/'), service)
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
984
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
985 return API_PEERS[service]['init'](ui, respurl, apipath, opener,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
986 requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
987 info['apis'][service])
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
988
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
989 # 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
990 return httppeer(ui, path, respurl, opener, requestbuilder,
8a73132214a3 httppeer: support protocol upgrade
Gregory Szorc <gregory.szorc@gmail.com>
parents: 37556
diff changeset
991 info['v1capabilities'])
37009
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
992
2740
386f04d6ecb3 clean up hg.py: move repo constructor code into each repo module
Vadim Gelfer <vadim.gelfer@gmail.com>
parents: 2673
diff changeset
993 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
994 if create:
26587
56b2bcea2529 error: get Abort from 'error' instead of 'util'
Pierre-Yves David <pierre-yves.david@fb.com>
parents: 25954
diff changeset
995 raise error.Abort(_('cannot create new http repository'))
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
996 try:
36965
43815d87c6aa httppeer: alias url as urlmod
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36843
diff changeset
997 if path.startswith('https:') and not urlmod.has_https:
36258
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36257
diff changeset
998 raise error.Abort(_('Python support for SSL and HTTPS '
874209855f5c httppeer: remove httpspeer
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36257
diff changeset
999 'is not installed'))
35924
197d10e157ce httppeer: remove support for connecting to <0.9.1 servers (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35698
diff changeset
1000
37009
8e89c2bec1f7 httppeer: refactor how httppeer is created (API)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 36967
diff changeset
1001 inst = makepeer(ui, path)
35924
197d10e157ce httppeer: remove support for connecting to <0.9.1 servers (BC)
Gregory Szorc <gregory.szorc@gmail.com>
parents: 35698
diff changeset
1002
7211
25c0dee16ee0 Autodetect static-http
Matt Mackall <mpm@selenic.com>
parents: 7207
diff changeset
1003 return inst
25660
328739ea70c3 global: mass rewrite to use modern exception syntax
Gregory Szorc <gregory.szorc@gmail.com>
parents: 25500
diff changeset
1004 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
1005 try:
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
1006 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
1007 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
1008 return r
cc9366a3751b httprepo: use the original exception after falling back to static-http failed
Mads Kiilerich <mads@kiilerich.com>
parents: 14094
diff changeset
1009 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
1010 raise httpexception # use the original http RepoError instead