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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18
18
from cStringIO import StringIO
84
84
"Conventional" is used in the sense described in
85
85
doc/developers/network-protocol.txt: a simple message with arguments and an
89
* args: expecting args
90
* body: expecting body (terminated by receiving a post-body status)
91
* error: expecting post-body error
92
* end: expecting end of message
96
89
def __init__(self, request_handler, responder):
97
90
MessageHandler.__init__(self)
98
91
self.request_handler = request_handler
99
92
self.responder = responder
100
self.expecting = 'args'
101
self._should_finish_body = False
102
self._response_sent = False
93
self.args_received = False
104
95
def protocol_error(self, exception):
105
96
if self.responder.response_sent:
109
100
self.responder.send_error(exception)
111
102
def byte_part_received(self, byte):
112
if self.expecting == 'body':
114
# Success. Nothing more to come except the end of message.
115
self.expecting = 'end'
117
# Error. Expect an error structure.
118
self.expecting = 'error'
120
raise errors.SmartProtocolError(
121
'Non-success status byte in request body: %r' % (byte,))
123
raise errors.SmartProtocolError(
124
'Unexpected message part: byte(%r)' % (byte,))
103
raise errors.SmartProtocolError(
104
'Unexpected message part: byte(%r)' % (byte,))
126
106
def structure_part_received(self, structure):
127
if self.expecting == 'args':
128
self._args_received(structure)
129
elif self.expecting == 'error':
130
self._error_received(structure)
107
if self.args_received:
132
108
raise errors.SmartProtocolError(
133
109
'Unexpected message part: structure(%r)' % (structure,))
135
def _args_received(self, args):
136
self.expecting = 'body'
137
self.request_handler.args_received(args)
110
self.args_received = True
111
self.request_handler.dispatch_command(structure[0], structure[1:])
138
112
if self.request_handler.finished_reading:
139
self._response_sent = True
140
113
self.responder.send_response(self.request_handler.response)
141
self.expecting = 'end'
143
def _error_received(self, error_args):
144
self.expecting = 'end'
145
self.request_handler.post_body_error_received(error_args)
147
115
def bytes_part_received(self, bytes):
148
if self.expecting == 'body':
149
self._should_finish_body = True
150
self.request_handler.accept_body(bytes)
152
raise errors.SmartProtocolError(
153
'Unexpected message part: bytes(%r)' % (bytes,))
155
def end_received(self):
156
if self.expecting not in ['body', 'end']:
157
raise errors.SmartProtocolError(
158
'End of message received prematurely (while expecting %s)'
160
self.expecting = 'nothing'
161
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()
162
122
if not self.request_handler.finished_reading:
163
123
raise errors.SmartProtocolError(
164
"Complete conventional request was received, but request "
165
"handler has not finished reading.")
166
if not self._response_sent:
167
self.responder.send_response(self.request_handler.response)
124
"Conventional request body was received, but request handler "
125
"has not finished reading.")
126
self.responder.send_response(self.request_handler.response)
170
129
class ResponseHandler(object):
243
202
self._bytes_parts.append(bytes)
245
204
def structure_part_received(self, structure):
246
if type(structure) is not tuple:
205
if type(structure) is not list:
247
206
raise errors.SmartProtocolError(
248
207
'Args structure is not a sequence: %r' % (structure,))
208
structure = tuple(structure)
249
209
if not self._body_started:
250
210
if self.args is not None:
251
211
raise errors.SmartProtocolError(
280
240
if 'hpss' in debug.debug_flags:
282
242
'decoder state: buf[:10]=%r, state_accept=%s',
283
self._protocol_decoder._get_in_buffer()[:10],
243
self._protocol_decoder._in_buffer[:10],
284
244
self._protocol_decoder.state_accept.__name__)
285
245
raise errors.ConnectionReset(
286
"Unexpected end of message. "
287
"Please check connectivity and permissions, and report a bug "
288
"if problems persist.")
246
"please check connectivity and permissions",
247
"(and try -Dhpss if further diagnosis is required)")
289
248
self._protocol_decoder.accept_bytes(bytes)
291
250
def protocol_error(self, exception):
303
262
mutter(' result: %r', self.args)
304
263
if self.status == 'E':
305
264
self._wait_for_response_end()
306
_raise_smart_server_error(self.args)
265
_translate_error(self.args)
307
266
return tuple(self.args)
309
268
def read_body_bytes(self, count=-1):
310
269
"""Read bytes from the body, decoding into a byte stream.
312
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
313
272
errors, and then feed the buffer back as read_body_bytes is called.
315
274
Like the builtin file.read in Python, a count of -1 (the default) means
330
289
while not self.finished_reading:
331
290
while self._bytes_parts:
332
291
bytes_part = self._bytes_parts.popleft()
333
if 'hpssdetail' in debug.debug_flags:
292
if 'hpss' in debug.debug_flags:
334
293
mutter(' %d byte part read', len(bytes_part))
336
295
self._read_more()
337
296
if self._body_stream_status == 'E':
338
_raise_smart_server_error(self._body_error_args)
297
_translate_error(self._body_error_args)
340
299
def cancel_read_body(self):
341
300
self._wait_for_response_end()
344
def _raise_smart_server_error(error_tuple):
345
"""Raise exception based on tuple received from smart server
347
Specific error translation is handled by bzrlib.remote._translate_error
349
if error_tuple[0] == 'UnknownMethod':
350
raise errors.UnknownSmartMethod(error_tuple[1])
351
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)