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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
from __future__ import absolute_import
18
20
from cStringIO import StringIO
84
86
"Conventional" is used in the sense described in
85
87
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
89
98
def __init__(self, request_handler, responder):
90
99
MessageHandler.__init__(self)
91
100
self.request_handler = request_handler
92
101
self.responder = responder
93
self.args_received = False
102
self.expecting = 'args'
103
self._should_finish_body = False
104
self._response_sent = False
95
106
def protocol_error(self, exception):
96
107
if self.responder.response_sent:
100
111
self.responder.send_error(exception)
102
113
def byte_part_received(self, byte):
103
raise errors.SmartProtocolError(
104
'Unexpected message part: byte(%r)' % (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,))
106
128
def structure_part_received(self, structure):
107
if self.args_received:
129
if self.expecting == 'args':
130
self._args_received(structure)
131
elif self.expecting == 'error':
132
self._error_received(structure)
108
134
raise errors.SmartProtocolError(
109
135
'Unexpected message part: structure(%r)' % (structure,))
110
self.args_received = True
111
self.request_handler.dispatch_command(structure[0], structure[1:])
137
def _args_received(self, args):
138
self.expecting = 'body'
139
self.request_handler.args_received(args)
112
140
if self.request_handler.finished_reading:
141
self._response_sent = True
113
142
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)
115
149
def bytes_part_received(self, bytes):
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()
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()
122
164
if not self.request_handler.finished_reading:
123
165
raise errors.SmartProtocolError(
124
"Conventional request body was received, but request handler "
125
"has not finished reading.")
126
self.responder.send_response(self.request_handler.response)
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)
129
172
class ResponseHandler(object):
202
245
self._bytes_parts.append(bytes)
204
247
def structure_part_received(self, structure):
205
if type(structure) is not list:
248
if type(structure) is not tuple:
206
249
raise errors.SmartProtocolError(
207
250
'Args structure is not a sequence: %r' % (structure,))
208
structure = tuple(structure)
209
251
if not self._body_started:
210
252
if self.args is not None:
211
253
raise errors.SmartProtocolError(
243
285
self._protocol_decoder._get_in_buffer()[:10],
244
286
self._protocol_decoder.state_accept.__name__)
245
287
raise errors.ConnectionReset(
246
"please check connectivity and permissions",
247
"(and try -Dhpss if further diagnosis is required)")
288
"Unexpected end of message. "
289
"Please check connectivity and permissions, and report a bug "
290
"if problems persist.")
248
291
self._protocol_decoder.accept_bytes(bytes)
250
293
def protocol_error(self, exception):
262
305
mutter(' result: %r', self.args)
263
306
if self.status == 'E':
264
307
self._wait_for_response_end()
265
_translate_error(self.args)
308
_raise_smart_server_error(self.args)
266
309
return tuple(self.args)
268
311
def read_body_bytes(self, count=-1):
269
312
"""Read bytes from the body, decoding into a byte stream.
271
We read all bytes at once to ensure we've checked the trailer for
314
We read all bytes at once to ensure we've checked the trailer for
272
315
errors, and then feed the buffer back as read_body_bytes is called.
274
317
Like the builtin file.read in Python, a count of -1 (the default) means
289
332
while not self.finished_reading:
290
333
while self._bytes_parts:
291
334
bytes_part = self._bytes_parts.popleft()
292
if 'hpss' in debug.debug_flags:
335
if 'hpssdetail' in debug.debug_flags:
293
336
mutter(' %d byte part read', len(bytes_part))
295
338
self._read_more()
296
339
if self._body_stream_status == 'E':
297
_translate_error(self._body_error_args)
340
_raise_smart_server_error(self._body_error_args)
299
342
def cancel_read_body(self):
300
343
self._wait_for_response_end()
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)
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)