/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 breezy/smart/protocol.py

  • Committer: Jelmer Vernooij
  • Date: 2017-06-08 23:30:31 UTC
  • mto: This revision was merged to the branch mainline in revision 6690.
  • Revision ID: jelmer@jelmer.uk-20170608233031-3qavls2o7a1pqllj
Update imports.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
client and server.
19
19
"""
20
20
 
21
 
try:
22
 
    from collections.abc import deque
23
 
except ImportError:  # python < 3.7
24
 
    from collections import deque
 
21
from __future__ import absolute_import
25
22
 
26
 
from io import BytesIO
 
23
import collections
27
24
import struct
28
25
import sys
29
 
import _thread
 
26
try:
 
27
    import _thread
 
28
except ImportError:
 
29
    import thread as _thread
30
30
import time
31
31
 
32
32
import breezy
33
 
from ... import (
 
33
from .. import (
34
34
    debug,
35
35
    errors,
36
36
    osutils,
37
37
    )
 
38
from ..sixish import (
 
39
    BytesIO,
 
40
    reraise,
 
41
)
38
42
from . import message, request
39
 
from ...trace import log_exception_quietly, mutter
40
 
from ...bencode import bdecode_as_tuple, bencode
 
43
from ..trace import log_exception_quietly, mutter
 
44
from ..bencode import bdecode_as_tuple, bencode
41
45
 
42
46
 
43
47
# Protocol version strings.  These are sent as prefixes of bzr requests and
44
48
# responses to identify the protocol version being used. (There are no version
45
49
# one strings because that version doesn't send any).
46
 
REQUEST_VERSION_TWO = b'bzr request 2\n'
47
 
RESPONSE_VERSION_TWO = b'bzr response 2\n'
 
50
REQUEST_VERSION_TWO = 'bzr request 2\n'
 
51
RESPONSE_VERSION_TWO = 'bzr response 2\n'
48
52
 
49
 
MESSAGE_VERSION_THREE = b'bzr message 3 (bzr 1.6)\n'
 
53
MESSAGE_VERSION_THREE = 'bzr message 3 (bzr 1.6)\n'
50
54
RESPONSE_VERSION_THREE = REQUEST_VERSION_THREE = MESSAGE_VERSION_THREE
51
55
 
52
56
 
56
60
 
57
61
 
58
62
def _decode_tuple(req_line):
59
 
    if req_line is None or req_line == b'':
 
63
    if req_line is None or req_line == '':
60
64
        return None
61
 
    if not req_line.endswith(b'\n'):
 
65
    if req_line[-1] != '\n':
62
66
        raise errors.SmartProtocolError("request %r not terminated" % req_line)
63
 
    return tuple(req_line[:-1].split(b'\x01'))
 
67
    return tuple(req_line[:-1].split('\x01'))
64
68
 
65
69
 
66
70
def _encode_tuple(args):
67
71
    """Encode the tuple args to a bytestream."""
68
 
    for arg in args:
69
 
        if isinstance(arg, str):
70
 
            raise TypeError(args)
71
 
    return b'\x01'.join(args) + b'\n'
 
72
    joined = '\x01'.join(args) + '\n'
 
73
    if isinstance(joined, unicode):
 
74
        # XXX: We should fix things so this never happens!  -AJB, 20100304
 
75
        mutter('response args contain unicode, should be only bytes: %r',
 
76
               joined)
 
77
        joined = joined.encode('ascii')
 
78
    return joined
72
79
 
73
80
 
74
81
class Requester(object):
112
119
    # support multiple chunks?
113
120
    def _encode_bulk_data(self, body):
114
121
        """Encode body as a bulk data chunk."""
115
 
        return b''.join((b'%d\n' % len(body), body, b'done\n'))
 
122
        return ''.join(('%d\n' % len(body), body, 'done\n'))
116
123
 
117
124
    def _serialise_offsets(self, offsets):
118
125
        """Serialise a readv offset list."""
119
126
        txt = []
120
127
        for start, length in offsets:
121
 
            txt.append(b'%d,%d' % (start, length))
122
 
        return b'\n'.join(txt)
 
128
            txt.append('%d,%d' % (start, length))
 
129
        return '\n'.join(txt)
123
130
 
124
131
 
125
132
class SmartServerRequestProtocolOne(SmartProtocolBase):
126
133
    """Server-side encoding and decoding logic for smart version 1."""
127
134
 
128
135
    def __init__(self, backing_transport, write_func, root_client_path='/',
129
 
                 jail_root=None):
 
136
            jail_root=None):
130
137
        self._backing_transport = backing_transport
131
138
        self._root_client_path = root_client_path
132
139
        self._jail_root = jail_root
133
 
        self.unused_data = b''
 
140
        self.unused_data = ''
134
141
        self._finished = False
135
 
        self.in_buffer = b''
 
142
        self.in_buffer = ''
136
143
        self._has_dispatched = False
137
144
        self.request = None
138
145
        self._body_decoder = None
139
146
        self._write_func = write_func
140
147
 
141
 
    def accept_bytes(self, data):
 
148
    def accept_bytes(self, bytes):
142
149
        """Take bytes, and advance the internal state machine appropriately.
143
150
 
144
 
        :param data: must be a byte string
 
151
        :param bytes: must be a byte string
145
152
        """
146
 
        if not isinstance(data, bytes):
147
 
            raise ValueError(data)
148
 
        self.in_buffer += data
 
153
        if not isinstance(bytes, str):
 
154
            raise ValueError(bytes)
 
155
        self.in_buffer += bytes
149
156
        if not self._has_dispatched:
150
 
            if b'\n' not in self.in_buffer:
 
157
            if '\n' not in self.in_buffer:
151
158
                # no command line yet
152
159
                return
153
160
            self._has_dispatched = True
154
161
            try:
155
 
                first_line, self.in_buffer = self.in_buffer.split(b'\n', 1)
156
 
                first_line += b'\n'
 
162
                first_line, self.in_buffer = self.in_buffer.split('\n', 1)
 
163
                first_line += '\n'
157
164
                req_args = _decode_tuple(first_line)
158
165
                self.request = request.SmartServerRequestHandler(
159
166
                    self._backing_transport, commands=request.request_handlers,
163
170
                if self.request.finished_reading:
164
171
                    # trivial request
165
172
                    self.unused_data = self.in_buffer
166
 
                    self.in_buffer = b''
 
173
                    self.in_buffer = ''
167
174
                    self._send_response(self.request.response)
168
175
            except KeyboardInterrupt:
169
176
                raise
170
177
            except errors.UnknownSmartMethod as err:
171
178
                protocol_error = errors.SmartProtocolError(
172
 
                    "bad request '%s'" % (err.verb.decode('ascii'),))
 
179
                    "bad request %r" % (err.verb,))
173
180
                failure = request.FailedSmartServerResponse(
174
 
                    (b'error', str(protocol_error).encode('utf-8')))
 
181
                    ('error', str(protocol_error)))
175
182
                self._send_response(failure)
176
183
                return
177
184
            except Exception as exception:
178
185
                # everything else: pass to client, flush, and quit
179
186
                log_exception_quietly()
180
187
                self._send_response(request.FailedSmartServerResponse(
181
 
                    (b'error', str(exception).encode('utf-8'))))
 
188
                    ('error', str(exception))))
182
189
                return
183
190
 
184
191
        if self._has_dispatched:
186
193
                # nothing to do.XXX: this routine should be a single state
187
194
                # machine too.
188
195
                self.unused_data += self.in_buffer
189
 
                self.in_buffer = b''
 
196
                self.in_buffer = ''
190
197
                return
191
198
            if self._body_decoder is None:
192
199
                self._body_decoder = LengthPrefixedBodyDecoder()
201
208
            if self.request.response is not None:
202
209
                self._send_response(self.request.response)
203
210
                self.unused_data = self.in_buffer
204
 
                self.in_buffer = b''
 
211
                self.in_buffer = ''
205
212
            else:
206
213
                if self.request.finished_reading:
207
214
                    raise AssertionError(
218
225
        self._write_success_or_failure_prefix(response)
219
226
        self._write_func(_encode_tuple(args))
220
227
        if body is not None:
221
 
            if not isinstance(body, bytes):
 
228
            if not isinstance(body, str):
222
229
                raise ValueError(body)
223
 
            data = self._encode_bulk_data(body)
224
 
            self._write_func(data)
 
230
            bytes = self._encode_bulk_data(body)
 
231
            self._write_func(bytes)
225
232
 
226
233
    def _write_protocol_version(self):
227
234
        """Write any prefixes this protocol requires.
258
265
    def _write_success_or_failure_prefix(self, response):
259
266
        """Write the protocol specific success/failure prefix."""
260
267
        if response.is_successful():
261
 
            self._write_func(b'success\n')
 
268
            self._write_func('success\n')
262
269
        else:
263
 
            self._write_func(b'failed\n')
 
270
            self._write_func('failed\n')
264
271
 
265
272
    def _write_protocol_version(self):
266
273
        r"""Write any prefixes this protocol requires.
278
285
        self._write_success_or_failure_prefix(response)
279
286
        self._write_func(_encode_tuple(response.args))
280
287
        if response.body is not None:
281
 
            if not isinstance(response.body, bytes):
282
 
                raise AssertionError('body must be bytes')
 
288
            if not isinstance(response.body, str):
 
289
                raise AssertionError('body must be a str')
283
290
            if not (response.body_stream is None):
284
291
                raise AssertionError(
285
292
                    'body_stream and body cannot both be set')
286
 
            data = self._encode_bulk_data(response.body)
287
 
            self._write_func(data)
 
293
            bytes = self._encode_bulk_data(response.body)
 
294
            self._write_func(bytes)
288
295
        elif response.body_stream is not None:
289
296
            _send_stream(response.body_stream, self._write_func)
290
297
 
291
298
 
292
299
def _send_stream(stream, write_func):
293
 
    write_func(b'chunked\n')
 
300
    write_func('chunked\n')
294
301
    _send_chunks(stream, write_func)
295
 
    write_func(b'END\n')
 
302
    write_func('END\n')
296
303
 
297
304
 
298
305
def _send_chunks(stream, write_func):
299
306
    for chunk in stream:
300
 
        if isinstance(chunk, bytes):
301
 
            data = ("%x\n" % len(chunk)).encode('ascii') + chunk
302
 
            write_func(data)
 
307
        if isinstance(chunk, str):
 
308
            bytes = "%x\n%s" % (len(chunk), chunk)
 
309
            write_func(bytes)
303
310
        elif isinstance(chunk, request.FailedSmartServerResponse):
304
 
            write_func(b'ERR\n')
 
311
            write_func('ERR\n')
305
312
            _send_chunks(chunk.args, write_func)
306
313
            return
307
314
        else:
339
346
        self.finished_reading = False
340
347
        self._in_buffer_list = []
341
348
        self._in_buffer_len = 0
342
 
        self.unused_data = b''
 
349
        self.unused_data = ''
343
350
        self.bytes_left = None
344
351
        self._number_needed_bytes = None
345
352
 
346
353
    def _get_in_buffer(self):
347
354
        if len(self._in_buffer_list) == 1:
348
355
            return self._in_buffer_list[0]
349
 
        in_buffer = b''.join(self._in_buffer_list)
 
356
        in_buffer = ''.join(self._in_buffer_list)
350
357
        if len(in_buffer) != self._in_buffer_len:
351
358
            raise AssertionError(
352
359
                "Length of buffer did not match expected value: %s != %s"
365
372
        # check if we can yield the bytes from just the first entry in our list
366
373
        if len(self._in_buffer_list) == 0:
367
374
            raise AssertionError('Callers must be sure we have buffered bytes'
368
 
                                 ' before calling _get_in_bytes')
 
375
                ' before calling _get_in_bytes')
369
376
        if len(self._in_buffer_list[0]) > count:
370
377
            return self._in_buffer_list[0][:count]
371
378
        # We can't yield it from the first buffer, so collapse all buffers, and
375
382
 
376
383
    def _set_in_buffer(self, new_buf):
377
384
        if new_buf is not None:
378
 
            if not isinstance(new_buf, bytes):
379
 
                raise TypeError(new_buf)
380
385
            self._in_buffer_list = [new_buf]
381
386
            self._in_buffer_len = len(new_buf)
382
387
        else:
383
388
            self._in_buffer_list = []
384
389
            self._in_buffer_len = 0
385
390
 
386
 
    def accept_bytes(self, new_buf):
 
391
    def accept_bytes(self, bytes):
387
392
        """Decode as much of bytes as possible.
388
393
 
389
 
        If 'new_buf' contains too much data it will be appended to
 
394
        If 'bytes' contains too much data it will be appended to
390
395
        self.unused_data.
391
396
 
392
397
        finished_reading will be set when no more data is required.  Further
393
398
        data will be appended to self.unused_data.
394
399
        """
395
 
        if not isinstance(new_buf, bytes):
396
 
            raise TypeError(new_buf)
397
400
        # accept_bytes is allowed to change the state
398
401
        self._number_needed_bytes = None
399
402
        # lsprof puts a very large amount of time on this specific call for
400
403
        # large readv arrays
401
 
        self._in_buffer_list.append(new_buf)
402
 
        self._in_buffer_len += len(new_buf)
 
404
        self._in_buffer_list.append(bytes)
 
405
        self._in_buffer_len += len(bytes)
403
406
        try:
404
407
            # Run the function for the current state.
405
408
            current_state = self.state_accept
427
430
        _StatefulDecoder.__init__(self)
428
431
        self.state_accept = self._state_accept_expecting_header
429
432
        self.chunk_in_progress = None
430
 
        self.chunks = deque()
 
433
        self.chunks = collections.deque()
431
434
        self.error = False
432
435
        self.error_in_progress = None
433
436
 
462
465
 
463
466
    def _extract_line(self):
464
467
        in_buf = self._get_in_buffer()
465
 
        pos = in_buf.find(b'\n')
 
468
        pos = in_buf.find('\n')
466
469
        if pos == -1:
467
470
            # We haven't read a complete line yet, so request more bytes before
468
471
            # we continue.
469
472
            raise _NeedMoreBytes(1)
470
473
        line = in_buf[:pos]
471
474
        # Trim the prefix (including '\n' delimiter) from the _in_buffer.
472
 
        self._set_in_buffer(in_buf[pos + 1:])
 
475
        self._set_in_buffer(in_buf[pos+1:])
473
476
        return line
474
477
 
475
478
    def _finished(self):
485
488
 
486
489
    def _state_accept_expecting_header(self):
487
490
        prefix = self._extract_line()
488
 
        if prefix == b'chunked':
 
491
        if prefix == 'chunked':
489
492
            self.state_accept = self._state_accept_expecting_length
490
493
        else:
491
494
            raise errors.SmartProtocolError(
493
496
 
494
497
    def _state_accept_expecting_length(self):
495
498
        prefix = self._extract_line()
496
 
        if prefix == b'ERR':
 
499
        if prefix == 'ERR':
497
500
            self.error = True
498
501
            self.error_in_progress = []
499
502
            self._state_accept_expecting_length()
500
503
            return
501
 
        elif prefix == b'END':
 
504
        elif prefix == 'END':
502
505
            # We've read the end-of-body marker.
503
506
            # Any further bytes are unused data, including the bytes left in
504
507
            # the _in_buffer.
506
509
            return
507
510
        else:
508
511
            self.bytes_left = int(prefix, 16)
509
 
            self.chunk_in_progress = b''
 
512
            self.chunk_in_progress = ''
510
513
            self.state_accept = self._state_accept_reading_chunk
511
514
 
512
515
    def _state_accept_reading_chunk(self):
537
540
        _StatefulDecoder.__init__(self)
538
541
        self.state_accept = self._state_accept_expecting_length
539
542
        self.state_read = self._state_read_no_data
540
 
        self._body = b''
541
 
        self._trailer_buffer = b''
 
543
        self._body = ''
 
544
        self._trailer_buffer = ''
542
545
 
543
546
    def next_read_size(self):
544
547
        if self.bytes_left is not None:
562
565
 
563
566
    def _state_accept_expecting_length(self):
564
567
        in_buf = self._get_in_buffer()
565
 
        pos = in_buf.find(b'\n')
 
568
        pos = in_buf.find('\n')
566
569
        if pos == -1:
567
570
            return
568
571
        self.bytes_left = int(in_buf[:pos])
569
 
        self._set_in_buffer(in_buf[pos + 1:])
 
572
        self._set_in_buffer(in_buf[pos+1:])
570
573
        self.state_accept = self._state_accept_reading_body
571
574
        self.state_read = self._state_read_body_buffer
572
575
 
588
591
        self._set_in_buffer(None)
589
592
        # TODO: what if the trailer does not match "done\n"?  Should this raise
590
593
        # a ProtocolViolation exception?
591
 
        if self._trailer_buffer.startswith(b'done\n'):
592
 
            self.unused_data = self._trailer_buffer[len(b'done\n'):]
 
594
        if self._trailer_buffer.startswith('done\n'):
 
595
            self.unused_data = self._trailer_buffer[len('done\n'):]
593
596
            self.state_accept = self._state_accept_reading_unused
594
597
            self.finished_reading = True
595
598
 
598
601
        self._set_in_buffer(None)
599
602
 
600
603
    def _state_read_no_data(self):
601
 
        return b''
 
604
        return ''
602
605
 
603
606
    def _state_read_body_buffer(self):
604
607
        result = self._body
605
 
        self._body = b''
 
608
        self._body = ''
606
609
        return result
607
610
 
608
611
 
630
633
            mutter('hpss call:   %s', repr(args)[1:-1])
631
634
            if getattr(self._request._medium, 'base', None) is not None:
632
635
                mutter('             (to %s)', self._request._medium.base)
633
 
            self._request_start_time = osutils.perf_counter()
 
636
            self._request_start_time = osutils.timer_func()
634
637
        self._write_args(args)
635
638
        self._request.finished_writing()
636
639
        self._last_verb = args[0]
643
646
        if 'hpss' in debug.debug_flags:
644
647
            mutter('hpss call w/body: %s (%r...)', repr(args)[1:-1], body[:20])
645
648
            if getattr(self._request._medium, '_path', None) is not None:
646
 
                mutter('                  (to %s)',
647
 
                       self._request._medium._path)
 
649
                mutter('                  (to %s)', self._request._medium._path)
648
650
            mutter('              %d bytes', len(body))
649
 
            self._request_start_time = osutils.perf_counter()
 
651
            self._request_start_time = osutils.timer_func()
650
652
            if 'hpssdetail' in debug.debug_flags:
651
653
                mutter('hpss body content: %s', body)
652
654
        self._write_args(args)
664
666
        if 'hpss' in debug.debug_flags:
665
667
            mutter('hpss call w/readv: %s', repr(args)[1:-1])
666
668
            if getattr(self._request._medium, '_path', None) is not None:
667
 
                mutter('                  (to %s)',
668
 
                       self._request._medium._path)
669
 
            self._request_start_time = osutils.perf_counter()
 
669
                mutter('                  (to %s)', self._request._medium._path)
 
670
            self._request_start_time = osutils.timer_func()
670
671
        self._write_args(args)
671
672
        readv_bytes = self._serialise_offsets(body)
672
673
        bytes = self._encode_bulk_data(readv_bytes)
698
699
        if 'hpss' in debug.debug_flags:
699
700
            if self._request_start_time is not None:
700
701
                mutter('   result:   %6.3fs  %s',
701
 
                       osutils.perf_counter() - self._request_start_time,
 
702
                       osutils.timer_func() - self._request_start_time,
702
703
                       repr(result)[1:-1])
703
704
                self._request_start_time = None
704
705
            else:
724
725
        # returned in response to existing version 1 smart requests.  Responses
725
726
        # starting with these codes are always "failed" responses.
726
727
        v1_error_codes = [
727
 
            b'norepository',
728
 
            b'NoSuchFile',
729
 
            b'FileExists',
730
 
            b'DirectoryNotEmpty',
731
 
            b'ShortReadvError',
732
 
            b'UnicodeEncodeError',
733
 
            b'UnicodeDecodeError',
734
 
            b'ReadOnlyError',
735
 
            b'nobranch',
736
 
            b'NoSuchRevision',
737
 
            b'nosuchrevision',
738
 
            b'LockContention',
739
 
            b'UnlockableTransport',
740
 
            b'LockFailed',
741
 
            b'TokenMismatch',
742
 
            b'ReadError',
743
 
            b'PermissionDenied',
 
728
            'norepository',
 
729
            'NoSuchFile',
 
730
            'FileExists',
 
731
            'DirectoryNotEmpty',
 
732
            'ShortReadvError',
 
733
            'UnicodeEncodeError',
 
734
            'UnicodeDecodeError',
 
735
            'ReadOnlyError',
 
736
            'nobranch',
 
737
            'NoSuchRevision',
 
738
            'nosuchrevision',
 
739
            'LockContention',
 
740
            'UnlockableTransport',
 
741
            'LockFailed',
 
742
            'TokenMismatch',
 
743
            'ReadError',
 
744
            'PermissionDenied',
744
745
            ]
745
746
        if result_tuple[0] in v1_error_codes:
746
747
            self._request.finished_reading()
755
756
        :param verb: The verb used in that call.
756
757
        :raises: UnexpectedSmartServerResponse
757
758
        """
758
 
        if (result_tuple == (b'error', b"Generic bzr smart protocol error: "
759
 
                             b"bad request '" + self._last_verb + b"'")
760
 
            or result_tuple == (b'error', b"Generic bzr smart protocol error: "
761
 
                                b"bad request u'%s'" % self._last_verb)):
 
759
        if (result_tuple == ('error', "Generic bzr smart protocol error: "
 
760
                "bad request '%s'" % self._last_verb) or
 
761
              result_tuple == ('error', "Generic bzr smart protocol error: "
 
762
                "bad request u'%s'" % self._last_verb)):
762
763
            # The response will have no body, so we've finished reading.
763
764
            self._request.finished_reading()
764
765
            raise errors.UnknownSmartMethod(self._last_verb)
775
776
 
776
777
        while not _body_decoder.finished_reading:
777
778
            bytes = self._request.read_bytes(_body_decoder.next_read_size())
778
 
            if bytes == b'':
 
779
            if bytes == '':
779
780
                # end of file encountered reading from server
780
781
                raise errors.ConnectionReset(
781
782
                    "Connection lost while reading response body.")
794
795
 
795
796
    def query_version(self):
796
797
        """Return protocol version number of the server."""
797
 
        self.call(b'hello')
 
798
        self.call('hello')
798
799
        resp = self.read_response_tuple()
799
 
        if resp == (b'ok', b'1'):
 
800
        if resp == ('ok', '1'):
800
801
            return 1
801
 
        elif resp == (b'ok', b'2'):
 
802
        elif resp == ('ok', '2'):
802
803
            return 2
803
804
        else:
804
805
            raise errors.SmartProtocolError("bad response %r" % (resp,))
836
837
        response_status = self._request.read_line()
837
838
        result = SmartClientRequestProtocolOne._read_response_tuple(self)
838
839
        self._response_is_unknown_method(result)
839
 
        if response_status == b'success\n':
 
840
        if response_status == 'success\n':
840
841
            self.response_status = True
841
842
            if not expect_body:
842
843
                self._request.finished_reading()
843
844
            return result
844
 
        elif response_status == b'failed\n':
 
845
        elif response_status == 'failed\n':
845
846
            self.response_status = False
846
847
            self._request.finished_reading()
847
848
            raise errors.ErrorFromSmartServer(result)
864
865
        _body_decoder = ChunkedBodyDecoder()
865
866
        while not _body_decoder.finished_reading:
866
867
            bytes = self._request.read_bytes(_body_decoder.next_read_size())
867
 
            if bytes == b'':
 
868
            if bytes == '':
868
869
                # end of file encountered reading from server
869
870
                raise errors.ConnectionReset(
870
871
                    "Connection lost while reading streamed body.")
883
884
        backing_transport, commands=request.request_handlers,
884
885
        root_client_path=root_client_path, jail_root=jail_root)
885
886
    responder = ProtocolThreeResponder(write_func)
886
 
    message_handler = message.ConventionalRequestHandler(
887
 
        request_handler, responder)
 
887
    message_handler = message.ConventionalRequestHandler(request_handler, responder)
888
888
    return ProtocolThreeDecoder(message_handler)
889
889
 
890
890
 
924
924
            # The state machine is ready to continue decoding, but the
925
925
            # exception has interrupted the loop that runs the state machine.
926
926
            # So we call accept_bytes again to restart it.
927
 
            self.accept_bytes(b'')
 
927
            self.accept_bytes('')
928
928
        except Exception as exception:
929
929
            # The decoder itself has raised an exception.  We cannot continue
930
930
            # decoding.
972
972
            # The buffer is empty
973
973
            raise _NeedMoreBytes(1)
974
974
        in_buf = self._get_in_buffer()
975
 
        one_byte = in_buf[0:1]
 
975
        one_byte = in_buf[0]
976
976
        self._set_in_buffer(in_buf[1:])
977
977
        return one_byte
978
978
 
1010
1010
 
1011
1011
    def _state_accept_expecting_message_part(self):
1012
1012
        message_part_kind = self._extract_single_byte()
1013
 
        if message_part_kind == b'o':
 
1013
        if message_part_kind == 'o':
1014
1014
            self.state_accept = self._state_accept_expecting_one_byte
1015
 
        elif message_part_kind == b's':
 
1015
        elif message_part_kind == 's':
1016
1016
            self.state_accept = self._state_accept_expecting_structure
1017
 
        elif message_part_kind == b'b':
 
1017
        elif message_part_kind == 'b':
1018
1018
            self.state_accept = self._state_accept_expecting_bytes
1019
 
        elif message_part_kind == b'e':
 
1019
        elif message_part_kind == 'e':
1020
1020
            self.done()
1021
1021
        else:
1022
1022
            raise errors.SmartProtocolError(
1080
1080
class _ProtocolThreeEncoder(object):
1081
1081
 
1082
1082
    response_marker = request_marker = MESSAGE_VERSION_THREE
1083
 
    BUFFER_SIZE = 1024 * 1024  # 1 MiB buffer before flushing
 
1083
    BUFFER_SIZE = 1024*1024 # 1 MiB buffer before flushing
1084
1084
 
1085
1085
    def __init__(self, write_func):
1086
1086
        self._buf = []
1100
1100
 
1101
1101
    def flush(self):
1102
1102
        if self._buf:
1103
 
            self._real_write_func(b''.join(self._buf))
 
1103
            self._real_write_func(''.join(self._buf))
1104
1104
            del self._buf[:]
1105
1105
            self._buf_len = 0
1106
1106
 
1108
1108
        """Serialise a readv offset list."""
1109
1109
        txt = []
1110
1110
        for start, length in offsets:
1111
 
            txt.append(b'%d,%d' % (start, length))
1112
 
        return b'\n'.join(txt)
 
1111
            txt.append('%d,%d' % (start, length))
 
1112
        return '\n'.join(txt)
1113
1113
 
1114
1114
    def _write_protocol_version(self):
1115
1115
        self._write_func(MESSAGE_VERSION_THREE)
1123
1123
        self._write_prefixed_bencode(headers)
1124
1124
 
1125
1125
    def _write_structure(self, args):
1126
 
        self._write_func(b's')
 
1126
        self._write_func('s')
1127
1127
        utf8_args = []
1128
1128
        for arg in args:
1129
 
            if isinstance(arg, str):
 
1129
            if isinstance(arg, unicode):
1130
1130
                utf8_args.append(arg.encode('utf8'))
1131
1131
            else:
1132
1132
                utf8_args.append(arg)
1133
1133
        self._write_prefixed_bencode(utf8_args)
1134
1134
 
1135
1135
    def _write_end(self):
1136
 
        self._write_func(b'e')
 
1136
        self._write_func('e')
1137
1137
        self.flush()
1138
1138
 
1139
1139
    def _write_prefixed_body(self, bytes):
1140
 
        self._write_func(b'b')
 
1140
        self._write_func('b')
1141
1141
        self._write_func(struct.pack('!L', len(bytes)))
1142
1142
        self._write_func(bytes)
1143
1143
 
1144
1144
    def _write_chunked_body_start(self):
1145
 
        self._write_func(b'oC')
 
1145
        self._write_func('oC')
1146
1146
 
1147
1147
    def _write_error_status(self):
1148
 
        self._write_func(b'oE')
 
1148
        self._write_func('oE')
1149
1149
 
1150
1150
    def _write_success_status(self):
1151
 
        self._write_func(b'oS')
 
1151
        self._write_func('oS')
1152
1152
 
1153
1153
 
1154
1154
class ProtocolThreeResponder(_ProtocolThreeEncoder):
1156
1156
    def __init__(self, write_func):
1157
1157
        _ProtocolThreeEncoder.__init__(self, write_func)
1158
1158
        self.response_sent = False
1159
 
        self._headers = {
1160
 
            b'Software version': breezy.__version__.encode('utf-8')}
 
1159
        self._headers = {'Software version': breezy.__version__}
1161
1160
        if 'hpss' in debug.debug_flags:
1162
1161
            self._thread_id = _thread.get_ident()
1163
1162
            self._response_start_time = None
1164
1163
 
1165
1164
    def _trace(self, action, message, extra_bytes=None, include_time=False):
1166
1165
        if self._response_start_time is None:
1167
 
            self._response_start_time = osutils.perf_counter()
 
1166
            self._response_start_time = osutils.timer_func()
1168
1167
        if include_time:
1169
 
            t = '%5.3fs ' % (osutils.perf_counter() - self._response_start_time)
 
1168
            t = '%5.3fs ' % (time.clock() - self._response_start_time)
1170
1169
        else:
1171
1170
            t = ''
1172
1171
        if extra_bytes is None:
1185
1184
                % (exception,))
1186
1185
        if isinstance(exception, errors.UnknownSmartMethod):
1187
1186
            failure = request.FailedSmartServerResponse(
1188
 
                (b'UnknownMethod', exception.verb))
 
1187
                ('UnknownMethod', exception.verb))
1189
1188
            self.send_response(failure)
1190
1189
            return
1191
1190
        if 'hpss' in debug.debug_flags:
1194
1193
        self._write_protocol_version()
1195
1194
        self._write_headers(self._headers)
1196
1195
        self._write_error_status()
1197
 
        self._write_structure(
1198
 
            (b'error', str(exception).encode('utf-8', 'replace')))
 
1196
        self._write_structure(('error', str(exception)))
1199
1197
        self._write_end()
1200
1198
 
1201
1199
    def send_response(self, response):
1309
1307
            base = getattr(self._medium_request._medium, 'base', None)
1310
1308
            if base is not None:
1311
1309
                mutter('             (to %s)', base)
1312
 
            self._request_start_time = osutils.perf_counter()
 
1310
            self._request_start_time = osutils.timer_func()
1313
1311
        self._write_protocol_version()
1314
1312
        self._write_headers(self._headers)
1315
1313
        self._write_structure(args)
1327
1325
            if path is not None:
1328
1326
                mutter('                  (to %s)', path)
1329
1327
            mutter('              %d bytes', len(body))
1330
 
            self._request_start_time = osutils.perf_counter()
 
1328
            self._request_start_time = osutils.timer_func()
1331
1329
        self._write_protocol_version()
1332
1330
        self._write_headers(self._headers)
1333
1331
        self._write_structure(args)
1346
1344
            path = getattr(self._medium_request._medium, '_path', None)
1347
1345
            if path is not None:
1348
1346
                mutter('                  (to %s)', path)
1349
 
            self._request_start_time = osutils.perf_counter()
 
1347
            self._request_start_time = osutils.timer_func()
1350
1348
        self._write_protocol_version()
1351
1349
        self._write_headers(self._headers)
1352
1350
        self._write_structure(args)
1363
1361
            path = getattr(self._medium_request._medium, '_path', None)
1364
1362
            if path is not None:
1365
1363
                mutter('                  (to %s)', path)
1366
 
            self._request_start_time = osutils.perf_counter()
 
1364
            self._request_start_time = osutils.timer_func()
1367
1365
        self.body_stream_started = False
1368
1366
        self._write_protocol_version()
1369
1367
        self._write_headers(self._headers)
1381
1379
                self._write_error_status()
1382
1380
                # Currently the client unconditionally sends ('error',) as the
1383
1381
                # error args.
1384
 
                self._write_structure((b'error',))
 
1382
                self._write_structure(('error',))
1385
1383
                self._write_end()
1386
1384
                self._medium_request.finished_writing()
1387
 
                (exc_type, exc_val, exc_tb) = exc_info
1388
1385
                try:
1389
 
                    raise exc_val
 
1386
                    reraise(*exc_info)
1390
1387
                finally:
1391
1388
                    del exc_info
1392
1389
            else:
1394
1391
                self.flush()
1395
1392
        self._write_end()
1396
1393
        self._medium_request.finished_writing()
 
1394