/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to bzrlib/smart/protocol.py

  • Committer: Richard Wilbur
  • Date: 2016-02-04 19:07:28 UTC
  • mto: This revision was merged to the branch mainline in revision 6618.
  • Revision ID: richard.wilbur@gmail.com-20160204190728-p0zvfii6zase0fw7
Update COPYING.txt from the original http://www.gnu.org/licenses/gpl-2.0.txt  (Only differences were in whitespace.)  Thanks to Petr Stodulka for pointing out the discrepancy.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
from __future__ import absolute_import
22
22
 
23
23
import collections
 
24
from cStringIO import StringIO
24
25
import struct
25
26
import sys
26
 
try:
27
 
    import _thread
28
 
except ImportError:
29
 
    import thread as _thread
 
27
import thread
30
28
import time
31
29
 
32
 
import breezy
33
 
from ... import (
 
30
import bzrlib
 
31
from bzrlib import (
34
32
    debug,
35
33
    errors,
36
34
    osutils,
37
35
    )
38
 
from ...sixish import (
39
 
    BytesIO,
40
 
    reraise,
41
 
)
42
 
from . import message, request
43
 
from ...sixish import text_type
44
 
from ...trace import log_exception_quietly, mutter
45
 
from ...bencode import bdecode_as_tuple, bencode
 
36
from bzrlib.smart import message, request
 
37
from bzrlib.trace import log_exception_quietly, mutter
 
38
from bzrlib.bencode import bdecode_as_tuple, bencode
46
39
 
47
40
 
48
41
# Protocol version strings.  These are sent as prefixes of bzr requests and
49
42
# responses to identify the protocol version being used. (There are no version
50
43
# one strings because that version doesn't send any).
51
 
REQUEST_VERSION_TWO = b'bzr request 2\n'
52
 
RESPONSE_VERSION_TWO = b'bzr response 2\n'
 
44
REQUEST_VERSION_TWO = 'bzr request 2\n'
 
45
RESPONSE_VERSION_TWO = 'bzr response 2\n'
53
46
 
54
 
MESSAGE_VERSION_THREE = b'bzr message 3 (bzr 1.6)\n'
 
47
MESSAGE_VERSION_THREE = 'bzr message 3 (bzr 1.6)\n'
55
48
RESPONSE_VERSION_THREE = REQUEST_VERSION_THREE = MESSAGE_VERSION_THREE
56
49
 
57
50
 
61
54
 
62
55
 
63
56
def _decode_tuple(req_line):
64
 
    if req_line is None or req_line == b'':
 
57
    if req_line is None or req_line == '':
65
58
        return None
66
 
    if req_line[-1] != b'\n':
 
59
    if req_line[-1] != '\n':
67
60
        raise errors.SmartProtocolError("request %r not terminated" % req_line)
68
61
    return tuple(req_line[:-1].split('\x01'))
69
62
 
70
63
 
71
64
def _encode_tuple(args):
72
65
    """Encode the tuple args to a bytestream."""
73
 
    joined = b'\x01'.join(args) + b'\n'
74
 
    if isinstance(joined, text_type):
 
66
    joined = '\x01'.join(args) + '\n'
 
67
    if type(joined) is unicode:
75
68
        # XXX: We should fix things so this never happens!  -AJB, 20100304
76
69
        mutter('response args contain unicode, should be only bytes: %r',
77
70
               joined)
120
113
    # support multiple chunks?
121
114
    def _encode_bulk_data(self, body):
122
115
        """Encode body as a bulk data chunk."""
123
 
        return b''.join((b'%d\n' % len(body), body, b'done\n'))
 
116
        return ''.join(('%d\n' % len(body), body, 'done\n'))
124
117
 
125
118
    def _serialise_offsets(self, offsets):
126
119
        """Serialise a readv offset list."""
127
120
        txt = []
128
121
        for start, length in offsets:
129
 
            txt.append(b'%d,%d' % (start, length))
130
 
        return b'\n'.join(txt)
 
122
            txt.append('%d,%d' % (start, length))
 
123
        return '\n'.join(txt)
131
124
 
132
125
 
133
126
class SmartServerRequestProtocolOne(SmartProtocolBase):
138
131
        self._backing_transport = backing_transport
139
132
        self._root_client_path = root_client_path
140
133
        self._jail_root = jail_root
141
 
        self.unused_data = b''
 
134
        self.unused_data = ''
142
135
        self._finished = False
143
 
        self.in_buffer = b''
 
136
        self.in_buffer = ''
144
137
        self._has_dispatched = False
145
138
        self.request = None
146
139
        self._body_decoder = None
147
140
        self._write_func = write_func
148
141
 
149
 
    def accept_bytes(self, data):
 
142
    def accept_bytes(self, bytes):
150
143
        """Take bytes, and advance the internal state machine appropriately.
151
144
 
152
 
        :param data: must be a byte string
 
145
        :param bytes: must be a byte string
153
146
        """
154
 
        if not isinstance(data, bytes):
155
 
            raise ValueError(data)
156
 
        self.in_buffer += data
 
147
        if not isinstance(bytes, str):
 
148
            raise ValueError(bytes)
 
149
        self.in_buffer += bytes
157
150
        if not self._has_dispatched:
158
 
            if b'\n' not in self.in_buffer:
 
151
            if '\n' not in self.in_buffer:
159
152
                # no command line yet
160
153
                return
161
154
            self._has_dispatched = True
162
155
            try:
163
 
                first_line, self.in_buffer = self.in_buffer.split(b'\n', 1)
164
 
                first_line += b'\n'
 
156
                first_line, self.in_buffer = self.in_buffer.split('\n', 1)
 
157
                first_line += '\n'
165
158
                req_args = _decode_tuple(first_line)
166
159
                self.request = request.SmartServerRequestHandler(
167
160
                    self._backing_transport, commands=request.request_handlers,
171
164
                if self.request.finished_reading:
172
165
                    # trivial request
173
166
                    self.unused_data = self.in_buffer
174
 
                    self.in_buffer = b''
 
167
                    self.in_buffer = ''
175
168
                    self._send_response(self.request.response)
176
169
            except KeyboardInterrupt:
177
170
                raise
178
 
            except errors.UnknownSmartMethod as err:
 
171
            except errors.UnknownSmartMethod, err:
179
172
                protocol_error = errors.SmartProtocolError(
180
173
                    "bad request %r" % (err.verb,))
181
174
                failure = request.FailedSmartServerResponse(
182
175
                    ('error', str(protocol_error)))
183
176
                self._send_response(failure)
184
177
                return
185
 
            except Exception as exception:
 
178
            except Exception, exception:
186
179
                # everything else: pass to client, flush, and quit
187
180
                log_exception_quietly()
188
181
                self._send_response(request.FailedSmartServerResponse(
194
187
                # nothing to do.XXX: this routine should be a single state
195
188
                # machine too.
196
189
                self.unused_data += self.in_buffer
197
 
                self.in_buffer = b''
 
190
                self.in_buffer = ''
198
191
                return
199
192
            if self._body_decoder is None:
200
193
                self._body_decoder = LengthPrefixedBodyDecoder()
209
202
            if self.request.response is not None:
210
203
                self._send_response(self.request.response)
211
204
                self.unused_data = self.in_buffer
212
 
                self.in_buffer = b''
 
205
                self.in_buffer = ''
213
206
            else:
214
207
                if self.request.finished_reading:
215
208
                    raise AssertionError(
266
259
    def _write_success_or_failure_prefix(self, response):
267
260
        """Write the protocol specific success/failure prefix."""
268
261
        if response.is_successful():
269
 
            self._write_func(b'success\n')
 
262
            self._write_func('success\n')
270
263
        else:
271
 
            self._write_func(b'failed\n')
 
264
            self._write_func('failed\n')
272
265
 
273
266
    def _write_protocol_version(self):
274
267
        r"""Write any prefixes this protocol requires.
347
340
        self.finished_reading = False
348
341
        self._in_buffer_list = []
349
342
        self._in_buffer_len = 0
350
 
        self.unused_data = b''
 
343
        self.unused_data = ''
351
344
        self.bytes_left = None
352
345
        self._number_needed_bytes = None
353
346
 
354
347
    def _get_in_buffer(self):
355
348
        if len(self._in_buffer_list) == 1:
356
349
            return self._in_buffer_list[0]
357
 
        in_buffer = b''.join(self._in_buffer_list)
 
350
        in_buffer = ''.join(self._in_buffer_list)
358
351
        if len(in_buffer) != self._in_buffer_len:
359
352
            raise AssertionError(
360
353
                "Length of buffer did not match expected value: %s != %s"
416
409
                #     _NeedMoreBytes).
417
410
                current_state = self.state_accept
418
411
                self.state_accept()
419
 
        except _NeedMoreBytes as e:
 
412
        except _NeedMoreBytes, e:
420
413
            self._number_needed_bytes = e.count
421
414
 
422
415
 
466
459
 
467
460
    def _extract_line(self):
468
461
        in_buf = self._get_in_buffer()
469
 
        pos = in_buf.find(b'\n')
 
462
        pos = in_buf.find('\n')
470
463
        if pos == -1:
471
464
            # We haven't read a complete line yet, so request more bytes before
472
465
            # we continue.
489
482
 
490
483
    def _state_accept_expecting_header(self):
491
484
        prefix = self._extract_line()
492
 
        if prefix == b'chunked':
 
485
        if prefix == 'chunked':
493
486
            self.state_accept = self._state_accept_expecting_length
494
487
        else:
495
488
            raise errors.SmartProtocolError(
497
490
 
498
491
    def _state_accept_expecting_length(self):
499
492
        prefix = self._extract_line()
500
 
        if prefix == b'ERR':
 
493
        if prefix == 'ERR':
501
494
            self.error = True
502
495
            self.error_in_progress = []
503
496
            self._state_accept_expecting_length()
504
497
            return
505
 
        elif prefix == b'END':
 
498
        elif prefix == 'END':
506
499
            # We've read the end-of-body marker.
507
500
            # Any further bytes are unused data, including the bytes left in
508
501
            # the _in_buffer.
510
503
            return
511
504
        else:
512
505
            self.bytes_left = int(prefix, 16)
513
 
            self.chunk_in_progress = b''
 
506
            self.chunk_in_progress = ''
514
507
            self.state_accept = self._state_accept_reading_chunk
515
508
 
516
509
    def _state_accept_reading_chunk(self):
541
534
        _StatefulDecoder.__init__(self)
542
535
        self.state_accept = self._state_accept_expecting_length
543
536
        self.state_read = self._state_read_no_data
544
 
        self._body = b''
545
 
        self._trailer_buffer = b''
 
537
        self._body = ''
 
538
        self._trailer_buffer = ''
546
539
 
547
540
    def next_read_size(self):
548
541
        if self.bytes_left is not None:
566
559
 
567
560
    def _state_accept_expecting_length(self):
568
561
        in_buf = self._get_in_buffer()
569
 
        pos = in_buf.find(b'\n')
 
562
        pos = in_buf.find('\n')
570
563
        if pos == -1:
571
564
            return
572
565
        self.bytes_left = int(in_buf[:pos])
592
585
        self._set_in_buffer(None)
593
586
        # TODO: what if the trailer does not match "done\n"?  Should this raise
594
587
        # a ProtocolViolation exception?
595
 
        if self._trailer_buffer.startswith(b'done\n'):
596
 
            self.unused_data = self._trailer_buffer[len(b'done\n'):]
 
588
        if self._trailer_buffer.startswith('done\n'):
 
589
            self.unused_data = self._trailer_buffer[len('done\n'):]
597
590
            self.state_accept = self._state_accept_reading_unused
598
591
            self.finished_reading = True
599
592
 
602
595
        self._set_in_buffer(None)
603
596
 
604
597
    def _state_read_no_data(self):
605
 
        return b''
 
598
        return ''
606
599
 
607
600
    def _state_read_body_buffer(self):
608
601
        result = self._body
609
 
        self._body = b''
 
602
        self._body = ''
610
603
        return result
611
604
 
612
605
 
777
770
 
778
771
        while not _body_decoder.finished_reading:
779
772
            bytes = self._request.read_bytes(_body_decoder.next_read_size())
780
 
            if bytes == b'':
 
773
            if bytes == '':
781
774
                # end of file encountered reading from server
782
775
                raise errors.ConnectionReset(
783
776
                    "Connection lost while reading response body.")
784
777
            _body_decoder.accept_bytes(bytes)
785
778
        self._request.finished_reading()
786
 
        self._body_buffer = BytesIO(_body_decoder.read_pending_data())
 
779
        self._body_buffer = StringIO(_body_decoder.read_pending_data())
787
780
        # XXX: TODO check the trailer result.
788
781
        if 'hpss' in debug.debug_flags:
789
782
            mutter('              %d body bytes read',
796
789
 
797
790
    def query_version(self):
798
791
        """Return protocol version number of the server."""
799
 
        self.call(b'hello')
 
792
        self.call('hello')
800
793
        resp = self.read_response_tuple()
801
 
        if resp == (b'ok', '1'):
 
794
        if resp == ('ok', '1'):
802
795
            return 1
803
 
        elif resp == (b'ok', '2'):
 
796
        elif resp == ('ok', '2'):
804
797
            return 2
805
798
        else:
806
799
            raise errors.SmartProtocolError("bad response %r" % (resp,))
866
859
        _body_decoder = ChunkedBodyDecoder()
867
860
        while not _body_decoder.finished_reading:
868
861
            bytes = self._request.read_bytes(_body_decoder.next_read_size())
869
 
            if bytes == b'':
 
862
            if bytes == '':
870
863
                # end of file encountered reading from server
871
864
                raise errors.ConnectionReset(
872
865
                    "Connection lost while reading streamed body.")
873
866
            _body_decoder.accept_bytes(bytes)
874
867
            for body_bytes in iter(_body_decoder.read_next_chunk, None):
875
 
                if 'hpss' in debug.debug_flags and isinstance(body_bytes, str):
 
868
                if 'hpss' in debug.debug_flags and type(body_bytes) is str:
876
869
                    mutter('              %d byte chunk read',
877
870
                           len(body_bytes))
878
871
                yield body_bytes
915
908
            _StatefulDecoder.accept_bytes(self, bytes)
916
909
        except KeyboardInterrupt:
917
910
            raise
918
 
        except errors.SmartMessageHandlerError as exception:
 
911
        except errors.SmartMessageHandlerError, exception:
919
912
            # We do *not* set self.decoding_failed here.  The message handler
920
913
            # has raised an error, but the decoder is still able to parse bytes
921
914
            # and determine when this message ends.
926
919
            # exception has interrupted the loop that runs the state machine.
927
920
            # So we call accept_bytes again to restart it.
928
921
            self.accept_bytes('')
929
 
        except Exception as exception:
 
922
        except Exception, exception:
930
923
            # The decoder itself has raised an exception.  We cannot continue
931
924
            # decoding.
932
925
            self.decoding_failed = True
1000
993
 
1001
994
    def _state_accept_expecting_headers(self):
1002
995
        decoded = self._extract_prefixed_bencoded_data()
1003
 
        if not isinstance(decoded, dict):
 
996
        if type(decoded) is not dict:
1004
997
            raise errors.SmartProtocolError(
1005
998
                'Header object %r is not a dict' % (decoded,))
1006
999
        self.state_accept = self._state_accept_expecting_message_part
1101
1094
 
1102
1095
    def flush(self):
1103
1096
        if self._buf:
1104
 
            self._real_write_func(b''.join(self._buf))
 
1097
            self._real_write_func(''.join(self._buf))
1105
1098
            del self._buf[:]
1106
1099
            self._buf_len = 0
1107
1100
 
1109
1102
        """Serialise a readv offset list."""
1110
1103
        txt = []
1111
1104
        for start, length in offsets:
1112
 
            txt.append(b'%d,%d' % (start, length))
1113
 
        return b'\n'.join(txt)
 
1105
            txt.append('%d,%d' % (start, length))
 
1106
        return '\n'.join(txt)
1114
1107
 
1115
1108
    def _write_protocol_version(self):
1116
1109
        self._write_func(MESSAGE_VERSION_THREE)
1124
1117
        self._write_prefixed_bencode(headers)
1125
1118
 
1126
1119
    def _write_structure(self, args):
1127
 
        self._write_func(b's')
 
1120
        self._write_func('s')
1128
1121
        utf8_args = []
1129
1122
        for arg in args:
1130
 
            if isinstance(arg, text_type):
 
1123
            if type(arg) is unicode:
1131
1124
                utf8_args.append(arg.encode('utf8'))
1132
1125
            else:
1133
1126
                utf8_args.append(arg)
1134
1127
        self._write_prefixed_bencode(utf8_args)
1135
1128
 
1136
1129
    def _write_end(self):
1137
 
        self._write_func(b'e')
 
1130
        self._write_func('e')
1138
1131
        self.flush()
1139
1132
 
1140
1133
    def _write_prefixed_body(self, bytes):
1141
 
        self._write_func(b'b')
 
1134
        self._write_func('b')
1142
1135
        self._write_func(struct.pack('!L', len(bytes)))
1143
1136
        self._write_func(bytes)
1144
1137
 
1145
1138
    def _write_chunked_body_start(self):
1146
 
        self._write_func(b'oC')
 
1139
        self._write_func('oC')
1147
1140
 
1148
1141
    def _write_error_status(self):
1149
 
        self._write_func(b'oE')
 
1142
        self._write_func('oE')
1150
1143
 
1151
1144
    def _write_success_status(self):
1152
 
        self._write_func(b'oS')
 
1145
        self._write_func('oS')
1153
1146
 
1154
1147
 
1155
1148
class ProtocolThreeResponder(_ProtocolThreeEncoder):
1157
1150
    def __init__(self, write_func):
1158
1151
        _ProtocolThreeEncoder.__init__(self, write_func)
1159
1152
        self.response_sent = False
1160
 
        self._headers = {'Software version': breezy.__version__}
 
1153
        self._headers = {'Software version': bzrlib.__version__}
1161
1154
        if 'hpss' in debug.debug_flags:
1162
 
            self._thread_id = _thread.get_ident()
 
1155
            self._thread_id = thread.get_ident()
1163
1156
            self._response_start_time = None
1164
1157
 
1165
1158
    def _trace(self, action, message, extra_bytes=None, include_time=False):
1279
1272
    iterator = iter(iterable)
1280
1273
    while True:
1281
1274
        try:
1282
 
            yield None, next(iterator)
 
1275
            yield None, iterator.next()
1283
1276
        except StopIteration:
1284
1277
            return
1285
1278
        except (KeyboardInterrupt, SystemExit):
1383
1376
                self._write_structure(('error',))
1384
1377
                self._write_end()
1385
1378
                self._medium_request.finished_writing()
1386
 
                try:
1387
 
                    reraise(*exc_info)
1388
 
                finally:
1389
 
                    del exc_info
 
1379
                raise exc_info[0], exc_info[1], exc_info[2]
1390
1380
            else:
1391
1381
                self._write_prefixed_body(part)
1392
1382
                self.flush()