13
13
# You should have received a copy of the GNU General Public License
14
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20
18
from cStringIO import StringIO
86
84
"Conventional" is used in the sense described in
87
85
doc/developers/network-protocol.txt: a simple message with arguments and an
91
* args: expecting args
92
* body: expecting body (terminated by receiving a post-body status)
93
* error: expecting post-body error
94
* end: expecting end of message
98
89
def __init__(self, request_handler, responder):
99
90
MessageHandler.__init__(self)
100
91
self.request_handler = request_handler
101
92
self.responder = responder
102
self.expecting = 'args'
103
self._should_finish_body = False
104
self._response_sent = False
93
self.args_received = False
106
95
def protocol_error(self, exception):
107
96
if self.responder.response_sent:
111
100
self.responder.send_error(exception)
113
102
def byte_part_received(self, byte):
114
if self.expecting == 'body':
116
# Success. Nothing more to come except the end of message.
117
self.expecting = 'end'
119
# Error. Expect an error structure.
120
self.expecting = 'error'
122
raise errors.SmartProtocolError(
123
'Non-success status byte in request body: %r' % (byte,))
125
raise errors.SmartProtocolError(
126
'Unexpected message part: byte(%r)' % (byte,))
103
raise errors.SmartProtocolError(
104
'Unexpected message part: byte(%r)' % (byte,))
128
106
def structure_part_received(self, structure):
129
if self.expecting == 'args':
130
self._args_received(structure)
131
elif self.expecting == 'error':
132
self._error_received(structure)
107
if self.args_received:
134
108
raise errors.SmartProtocolError(
135
109
'Unexpected message part: structure(%r)' % (structure,))
137
def _args_received(self, args):
138
self.expecting = 'body'
139
self.request_handler.args_received(args)
110
self.args_received = True
111
self.request_handler.dispatch_command(structure[0], structure[1:])
140
112
if self.request_handler.finished_reading:
141
self._response_sent = True
142
113
self.responder.send_response(self.request_handler.response)
143
self.expecting = 'end'
145
def _error_received(self, error_args):
146
self.expecting = 'end'
147
self.request_handler.post_body_error_received(error_args)
149
115
def bytes_part_received(self, bytes):
150
if self.expecting == 'body':
151
self._should_finish_body = True
152
self.request_handler.accept_body(bytes)
154
raise errors.SmartProtocolError(
155
'Unexpected message part: bytes(%r)' % (bytes,))
157
def end_received(self):
158
if self.expecting not in ['body', 'end']:
159
raise errors.SmartProtocolError(
160
'End of message received prematurely (while expecting %s)'
162
self.expecting = 'nothing'
163
self.request_handler.end_received()
116
# Note that there's no intrinsic way to distinguish a monolithic body
117
# from a chunk stream. A request handler knows which it is expecting
118
# (once the args have been received), so it should be able to do the
120
self.request_handler.accept_body(bytes)
121
self.request_handler.end_of_body()
164
122
if not self.request_handler.finished_reading:
165
raise errors.SmartProtocolError(
166
"Complete conventional request was received, but request "
167
"handler has not finished reading.")
168
if not self._response_sent:
169
self.responder.send_response(self.request_handler.response)
123
raise SmartProtocolError(
124
"Conventional request body was received, but request handler "
125
"has not finished reading.")
126
self.responder.send_response(self.request_handler.response)
172
129
class ResponseHandler(object):
245
202
self._bytes_parts.append(bytes)
247
204
def structure_part_received(self, structure):
248
if type(structure) is not tuple:
205
if type(structure) is not list:
249
206
raise errors.SmartProtocolError(
250
207
'Args structure is not a sequence: %r' % (structure,))
208
structure = tuple(structure)
251
209
if not self._body_started:
252
210
if self.args is not None:
253
211
raise errors.SmartProtocolError(
282
240
if 'hpss' in debug.debug_flags:
284
242
'decoder state: buf[:10]=%r, state_accept=%s',
285
self._protocol_decoder._get_in_buffer()[:10],
243
self._protocol_decoder._in_buffer[:10],
286
244
self._protocol_decoder.state_accept.__name__)
287
245
raise errors.ConnectionReset(
288
"Unexpected end of message. "
289
"Please check connectivity and permissions, and report a bug "
290
"if problems persist.")
246
"please check connectivity and permissions",
247
"(and try -Dhpss if further diagnosis is required)")
291
248
self._protocol_decoder.accept_bytes(bytes)
293
250
def protocol_error(self, exception):
305
262
mutter(' result: %r', self.args)
306
263
if self.status == 'E':
307
264
self._wait_for_response_end()
308
_raise_smart_server_error(self.args)
265
_translate_error(self.args)
309
266
return tuple(self.args)
311
268
def read_body_bytes(self, count=-1):
312
269
"""Read bytes from the body, decoding into a byte stream.
314
We read all bytes at once to ensure we've checked the trailer for
271
We read all bytes at once to ensure we've checked the trailer for
315
272
errors, and then feed the buffer back as read_body_bytes is called.
317
274
Like the builtin file.read in Python, a count of -1 (the default) means
332
289
while not self.finished_reading:
333
290
while self._bytes_parts:
334
291
bytes_part = self._bytes_parts.popleft()
335
if 'hpssdetail' in debug.debug_flags:
292
if 'hpss' in debug.debug_flags:
336
293
mutter(' %d byte part read', len(bytes_part))
338
295
self._read_more()
339
296
if self._body_stream_status == 'E':
340
_raise_smart_server_error(self._body_error_args)
297
_translate_error(self._body_error_args)
342
299
def cancel_read_body(self):
343
300
self._wait_for_response_end()
346
def _raise_smart_server_error(error_tuple):
347
"""Raise exception based on tuple received from smart server
349
Specific error translation is handled by bzrlib.remote._translate_error
351
if error_tuple[0] == 'UnknownMethod':
352
raise errors.UnknownSmartMethod(error_tuple[1])
353
raise errors.ErrorFromSmartServer(error_tuple)
303
def _translate_error(error_tuple):
304
# Many exceptions need some state from the requestor to be properly
305
# translated (e.g. they need a branch object). So this only translates a
306
# few errors, and the rest are turned into a generic ErrorFromSmartServer.
307
error_name = error_tuple[0]
308
error_args = error_tuple[1:]
309
if error_name == 'UnknownMethod':
310
raise errors.UnknownSmartMethod(error_args[0])
311
if error_name == 'LockContention':
312
raise errors.LockContention('(remote lock)')
313
elif error_name == 'LockFailed':
314
raise errors.LockFailed(*error_args[:2])
316
raise errors.ErrorFromSmartServer(error_tuple)