~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/message.py

  • Committer: John Arbash Meinel
  • Author(s): Mark Hammond
  • Date: 2008-09-09 17:02:21 UTC
  • mto: This revision was merged to the branch mainline in revision 3697.
  • Revision ID: john@arbash-meinel.com-20080909170221-svim3jw2mrz0amp3
An updated transparent icon for bzr.

Show diffs side-by-side

added added

removed removed

Lines of Context:
12
12
#
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
16
 
 
17
 
from __future__ import absolute_import
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
16
 
19
17
import collections
20
18
from cStringIO import StringIO
38
36
 
39
37
    def headers_received(self, headers):
40
38
        """Called when message headers are received.
41
 
 
 
39
        
42
40
        This default implementation just stores them in self.headers.
43
41
        """
44
42
        self.headers = headers
69
67
 
70
68
    def protocol_error(self, exception):
71
69
        """Called when there is a protocol decoding error.
72
 
 
 
70
        
73
71
        The default implementation just re-raises the exception.
74
72
        """
75
73
        raise
76
 
 
 
74
    
77
75
    def end_received(self):
78
76
        """Called when the end of the message is received."""
79
77
        # No-op by default.
86
84
    "Conventional" is used in the sense described in
87
85
    doc/developers/network-protocol.txt: a simple message with arguments and an
88
86
    optional body.
89
 
 
90
 
    Possible states:
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
95
 
     * nothing: finished
96
87
    """
97
88
 
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
105
94
 
106
95
    def protocol_error(self, exception):
107
96
        if self.responder.response_sent:
111
100
        self.responder.send_error(exception)
112
101
 
113
102
    def byte_part_received(self, byte):
114
 
        if self.expecting == 'body':
115
 
            if byte == 'S':
116
 
                # Success.  Nothing more to come except the end of message.
117
 
                self.expecting = 'end'
118
 
            elif byte == 'E':
119
 
                # Error.  Expect an error structure.
120
 
                self.expecting = 'error'
121
 
            else:
122
 
                raise errors.SmartProtocolError(
123
 
                    'Non-success status byte in request body: %r' % (byte,))
124
 
        else:
125
 
            raise errors.SmartProtocolError(
126
 
                'Unexpected message part: byte(%r)' % (byte,))
 
103
        raise errors.SmartProtocolError(
 
104
            'Unexpected message part: byte(%r)' % (byte,))
127
105
 
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)
133
 
        else:
 
107
        if self.args_received:
134
108
            raise errors.SmartProtocolError(
135
109
                'Unexpected message part: structure(%r)' % (structure,))
136
 
 
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'
144
 
 
145
 
    def _error_received(self, error_args):
146
 
        self.expecting = 'end'
147
 
        self.request_handler.post_body_error_received(error_args)
148
114
 
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)
153
 
        else:
154
 
            raise errors.SmartProtocolError(
155
 
                'Unexpected message part: bytes(%r)' % (bytes,))
156
 
 
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)'
161
 
                % (self.expecting,))
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
 
119
        # right thing.
 
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)
170
127
 
171
128
 
172
129
class ResponseHandler(object):
174
131
 
175
132
    def read_response_tuple(self, expect_body=False):
176
133
        """Reads and returns the response tuple for the current request.
177
 
 
 
134
        
178
135
        :keyword expect_body: a boolean indicating if a body is expected in the
179
136
            response.  Some protocol versions needs this information to know
180
137
            when a response is finished.  If False, read_body_bytes should
245
202
        self._bytes_parts.append(bytes)
246
203
 
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:
283
241
                mutter(
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)
292
249
 
293
250
    def protocol_error(self, exception):
295
252
        self.finished_reading = True
296
253
        self._medium_request.finished_reading()
297
254
        raise
298
 
 
 
255
        
299
256
    def read_response_tuple(self, expect_body=False):
300
257
        """Read a response tuple from the wire."""
301
258
        self._wait_for_response_args()
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)
310
267
 
311
268
    def read_body_bytes(self, count=-1):
312
269
        """Read bytes from the body, decoding into a byte stream.
313
 
 
314
 
        We read all bytes at once to ensure we've checked the trailer for
 
270
        
 
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.
316
273
 
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))
337
294
                yield 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)
341
298
 
342
299
    def cancel_read_body(self):
343
300
        self._wait_for_response_end()
344
301
 
345
302
 
346
 
def _raise_smart_server_error(error_tuple):
347
 
    """Raise exception based on tuple received from smart server
348
 
 
349
 
    Specific error translation is handled by bzrlib.remote._translate_error
350
 
    """
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])
 
315
    else:
 
316
        raise errors.ErrorFromSmartServer(error_tuple)