14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
from bzrlib.smart import message, protocol
19
from bzrlib.trace import warning
17
from urlparse import urlparse
19
from bzrlib.smart import protocol
20
from bzrlib.urlutils import unescape
26
23
class _SmartClient(object):
28
def __init__(self, medium, headers=None):
31
:param medium: a SmartClientMedium
35
self._headers = {'Software version': bzrlib.__version__}
37
self._headers = dict(headers)
39
def _send_request(self, protocol_version, method, args, body=None,
40
readv_body=None, body_stream=None):
41
encoder, response_handler = self._construct_protocol(
43
encoder.set_headers(self._headers)
45
if readv_body is not None:
47
"body and readv_body are mutually exclusive.")
48
if body_stream is not None:
50
"body and body_stream are mutually exclusive.")
51
encoder.call_with_body_bytes((method, ) + args, body)
52
elif readv_body is not None:
53
if body_stream is not None:
55
"readv_body and body_stream are mutually exclusive.")
56
encoder.call_with_body_readv_array((method, ) + args, readv_body)
57
elif body_stream is not None:
58
encoder.call_with_body_stream((method, ) + args, body_stream)
60
encoder.call(method, *args)
61
return response_handler
63
def _run_call_hooks(self, method, args, body, readv_body):
64
if not _SmartClient.hooks['call']:
66
params = CallHookParams(method, args, body, readv_body, self._medium)
67
for hook in _SmartClient.hooks['call']:
70
def _call_and_read_response(self, method, args, body=None, readv_body=None,
71
body_stream=None, expect_response_body=True):
72
self._run_call_hooks(method, args, body, readv_body)
73
if self._medium._protocol_version is not None:
74
response_handler = self._send_request(
75
self._medium._protocol_version, method, args, body=body,
76
readv_body=readv_body, body_stream=body_stream)
77
return (response_handler.read_response_tuple(
78
expect_body=expect_response_body),
81
for protocol_version in [3, 2]:
82
if protocol_version == 2:
83
# If v3 doesn't work, the remote side is older than 1.6.
84
self._medium._remember_remote_is_before((1, 6))
85
response_handler = self._send_request(
86
protocol_version, method, args, body=body,
87
readv_body=readv_body, body_stream=body_stream)
89
response_tuple = response_handler.read_response_tuple(
90
expect_body=expect_response_body)
91
except errors.UnexpectedProtocolVersionMarker, err:
92
# TODO: We could recover from this without disconnecting if
93
# we recognise the protocol version.
95
'Server does not understand Bazaar network protocol %d,'
96
' reconnecting. (Upgrade the server to avoid this.)'
97
% (protocol_version,))
98
self._medium.disconnect()
100
except errors.ErrorFromSmartServer:
101
# If we received an error reply from the server, then it
102
# must be ok with this protocol version.
103
self._medium._protocol_version = protocol_version
106
self._medium._protocol_version = protocol_version
107
return response_tuple, response_handler
108
raise errors.SmartProtocolError(
109
'Server is not a Bazaar server: ' + str(err))
111
def _construct_protocol(self, version):
112
request = self._medium.get_request()
114
request_encoder = protocol.ProtocolThreeRequester(request)
115
response_handler = message.ConventionalResponseHandler()
116
response_proto = protocol.ProtocolThreeDecoder(
117
response_handler, expect_version_marker=True)
118
response_handler.setProtoAndMediumRequest(response_proto, request)
120
request_encoder = protocol.SmartClientRequestProtocolTwo(request)
121
response_handler = request_encoder
123
request_encoder = protocol.SmartClientRequestProtocolOne(request)
124
response_handler = request_encoder
125
return request_encoder, response_handler
25
def __init__(self, shared_medium):
26
self._shared_medium = shared_medium
28
def get_smart_medium(self):
29
return self._shared_medium.connection
127
31
def call(self, method, *args):
128
32
"""Call a method on the remote server."""
150
56
raise TypeError('args must be byte strings, not %r' % (args,))
151
57
if type(body) is not str:
152
58
raise TypeError('body must be byte string, not %r' % (body,))
153
response, response_handler = self._call_and_read_response(
154
method, args, body=body, expect_response_body=False)
157
def call_with_body_bytes_expecting_body(self, method, args, body):
158
"""Call a method on the remote server with body bytes."""
159
if type(method) is not str:
160
raise TypeError('method must be a byte string, not %r' % (method,))
162
if type(arg) is not str:
163
raise TypeError('args must be byte strings, not %r' % (args,))
164
if type(body) is not str:
165
raise TypeError('body must be byte string, not %r' % (body,))
166
response, response_handler = self._call_and_read_response(
167
method, args, body=body, expect_response_body=True)
168
return (response, response_handler)
170
def call_with_body_readv_array(self, args, body):
171
response, response_handler = self._call_and_read_response(
172
args[0], args[1:], readv_body=body, expect_response_body=True)
173
return (response, response_handler)
175
def call_with_body_stream(self, args, stream):
176
response, response_handler = self._call_and_read_response(
177
args[0], args[1:], body_stream=stream,
178
expect_response_body=False)
179
return (response, response_handler)
59
request = self.get_smart_medium().get_request()
60
smart_protocol = protocol.SmartClientRequestProtocolOne(request)
61
smart_protocol.call_with_body_bytes((method, ) + args, body)
62
return smart_protocol.read_response_tuple()
181
64
def remote_path_from_transport(self, transport):
182
65
"""Convert transport into a path suitable for using in a request.