/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/request.py

  • Committer: Colin D Bennett
  • Date: 2009-02-12 16:57:39 UTC
  • mto: This revision was merged to the branch mainline in revision 4008.
  • Revision ID: colin@gibibit.com-20090212165739-02xv63odccfmxomw
Generate PDF version of the User Guide.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2006-2011 Canonical Ltd
 
1
# Copyright (C) 2006, 2007 Canonical Ltd
2
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
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
 
"""Infrastructure for server-side request handlers.
18
 
 
19
 
Interesting module attributes:
20
 
    * The request_handlers registry maps verb names to SmartServerRequest
21
 
      classes.
22
 
    * The jail_info threading.local() object is used to prevent accidental
23
 
      opening of BzrDirs outside of the backing transport, or any other
24
 
      transports placed in jail_info.transports.  The jail_info is reset on
25
 
      every call into a request handler (which can happen an arbitrary number
26
 
      of times during a request).
 
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
 
 
17
"""Basic server-side logic for dealing with requests.
 
18
 
 
19
**XXX**:
 
20
 
 
21
The class names are a little confusing: the protocol will instantiate a
 
22
SmartServerRequestHandler, whose dispatch_command method creates an instance of
 
23
a SmartServerRequest subclass.
 
24
 
 
25
The request_handlers registry tracks SmartServerRequest classes (rather than
 
26
SmartServerRequestHandler).
27
27
"""
28
28
 
29
 
from __future__ import absolute_import
30
 
 
31
 
# XXX: The class names are a little confusing: the protocol will instantiate a
32
 
# SmartServerRequestHandler, whose dispatch_command method creates an instance
33
 
# of a SmartServerRequest subclass.
34
 
 
35
 
 
36
 
import threading
37
 
try:
38
 
    from _thread import get_ident
39
 
except ImportError:  # Python < 3
40
 
    from thread import get_ident
41
 
 
42
 
from ... import (
43
 
    branch as _mod_branch,
44
 
    debug,
 
29
import tempfile
 
30
 
 
31
from bzrlib import (
 
32
    bzrdir,
45
33
    errors,
46
 
    osutils,
47
34
    registry,
48
35
    revision,
49
 
    trace,
50
36
    urlutils,
51
37
    )
52
 
from ...sixish import text_type
53
 
from ...lazy_import import lazy_import
 
38
from bzrlib.lazy_import import lazy_import
54
39
lazy_import(globals(), """
55
 
from breezy.bzr import bzrdir
56
 
from breezy.bundle import serializer
57
 
 
58
 
import tempfile
 
40
from bzrlib.bundle import serializer
59
41
""")
60
42
 
61
43
 
62
 
jail_info = threading.local()
63
 
jail_info.transports = None
64
 
 
65
 
 
66
 
class DisabledMethod(errors.InternalBzrError):
67
 
 
68
 
    _fmt = "The smart server method '%(class_name)s' is disabled."
69
 
 
70
 
    def __init__(self, class_name):
71
 
        errors.BzrError.__init__(self)
72
 
        self.class_name = class_name
73
 
 
74
 
 
75
 
def _install_hook():
76
 
    bzrdir.BzrDir.hooks.install_named_hook(
77
 
        'pre_open', _pre_open_hook, 'checking server jail')
78
 
 
79
 
 
80
 
def _pre_open_hook(transport):
81
 
    allowed_transports = getattr(jail_info, 'transports', None)
82
 
    if allowed_transports is None:
83
 
        return
84
 
    abspath = transport.base
85
 
    for allowed_transport in allowed_transports:
86
 
        try:
87
 
            allowed_transport.relpath(abspath)
88
 
        except errors.PathNotChild:
89
 
            continue
90
 
        else:
91
 
            return
92
 
    raise errors.JailBreak(abspath)
93
 
 
94
 
 
95
 
_install_hook()
96
 
 
97
 
 
98
44
class SmartServerRequest(object):
99
45
    """Base class for request handlers.
100
 
 
 
46
    
101
47
    To define a new request, subclass this class and override the `do` method
102
48
    (and if appropriate, `do_body` as well).  Request implementors should take
103
49
    care to call `translate_client_path` and `transport_from_client_path` as
106
52
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
107
53
    # *handler* is a different concept to the request.
108
54
 
109
 
    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
 
55
    def __init__(self, backing_transport, root_client_path='/'):
110
56
        """Constructor.
111
57
 
112
58
        :param backing_transport: the base transport to be used when performing
116
62
            from the client.  Clients will not be able to refer to paths above
117
63
            this root.  If root_client_path is None, then no translation will
118
64
            be performed on client paths.  Default is '/'.
119
 
        :param jail_root: if specified, the root of the BzrDir.open jail to use
120
 
            instead of backing_transport.
121
65
        """
122
66
        self._backing_transport = backing_transport
123
 
        if jail_root is None:
124
 
            jail_root = backing_transport
125
 
        self._jail_root = jail_root
126
67
        if root_client_path is not None:
127
68
            if not root_client_path.startswith('/'):
128
69
                root_client_path = '/' + root_client_path
137
78
 
138
79
    def do(self, *args):
139
80
        """Mandatory extension point for SmartServerRequest subclasses.
140
 
 
 
81
        
141
82
        Subclasses must implement this.
142
 
 
 
83
        
143
84
        This should return a SmartServerResponse if this command expects to
144
85
        receive no body.
145
86
        """
151
92
        It will return a SmartServerResponse if the command does not expect a
152
93
        body.
153
94
 
154
 
        :param args: the arguments of the request.
 
95
        :param *args: the arguments of the request.
155
96
        """
156
97
        self._check_enabled()
157
98
        return self.do(*args)
160
101
        """Called if the client sends a body with the request.
161
102
 
162
103
        The do() method is still called, and must have returned None.
163
 
 
 
104
        
164
105
        Must return a SmartServerResponse.
165
106
        """
166
 
        if body_bytes != b'':
167
 
            raise errors.SmartProtocolError('Request does not expect a body')
 
107
        raise NotImplementedError(self.do_body)
168
108
 
169
109
    def do_chunk(self, chunk_bytes):
170
110
        """Called with each body chunk if the request has a streamed body.
175
115
 
176
116
    def do_end(self):
177
117
        """Called when the end of the request has been received."""
178
 
        body_bytes = b''.join(self._body_chunks)
 
118
        body_bytes = ''.join(self._body_chunks)
179
119
        self._body_chunks = None
180
120
        return self.do_body(body_bytes)
181
 
 
182
 
    def setup_jail(self):
183
 
        jail_info.transports = [self._jail_root]
184
 
 
185
 
    def teardown_jail(self):
186
 
        jail_info.transports = None
187
 
 
 
121
    
188
122
    def translate_client_path(self, client_path):
189
123
        """Translate a path received from a network client into a local
190
124
        relpath.
196
130
            (unlike the untranslated client_path, which must not be used with
197
131
            the backing transport).
198
132
        """
199
 
        client_path = client_path.decode('utf-8')
200
133
        if self._root_client_path is None:
201
134
            # no translation necessary!
202
135
            return client_path
203
136
        if not client_path.startswith('/'):
204
137
            client_path = '/' + client_path
205
 
        if client_path + '/' == self._root_client_path:
206
 
            return '.'
207
138
        if client_path.startswith(self._root_client_path):
208
139
            path = client_path[len(self._root_client_path):]
209
140
            relpath = urlutils.joinpath('/', path)
210
141
            if not relpath.startswith('/'):
211
142
                raise ValueError(relpath)
212
 
            return urlutils.escape('.' + relpath)
 
143
            return '.' + relpath
213
144
        else:
214
145
            raise errors.PathNotChild(client_path, self._root_client_path)
215
146
 
226
157
 
227
158
class SmartServerResponse(object):
228
159
    """A response to a client request.
229
 
 
 
160
    
230
161
    This base class should not be used. Instead use
231
162
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
232
163
    """
249
180
    def __eq__(self, other):
250
181
        if other is None:
251
182
            return False
252
 
        return (other.args == self.args
253
 
                and other.body == self.body
254
 
                and other.body_stream is self.body_stream)
 
183
        return (other.args == self.args and
 
184
                other.body == self.body and
 
185
                other.body_stream is self.body_stream)
255
186
 
256
187
    def __repr__(self):
257
188
        return "<%s args=%r body=%r>" % (self.__class__.__name__,
258
 
                                         self.args, self.body)
 
189
            self.args, self.body)
259
190
 
260
191
 
261
192
class FailedSmartServerResponse(SmartServerResponse):
276
207
 
277
208
class SmartServerRequestHandler(object):
278
209
    """Protocol logic for smart server.
279
 
 
 
210
    
280
211
    This doesn't handle serialization at all, it just processes requests and
281
212
    creates responses.
282
213
    """
291
222
    # TODO: Better way of representing the body for commands that take it,
292
223
    # and allow it to be streamed into the server.
293
224
 
294
 
    def __init__(self, backing_transport, commands, root_client_path,
295
 
                 jail_root=None):
 
225
    def __init__(self, backing_transport, commands, root_client_path):
296
226
        """Constructor.
297
227
 
298
228
        :param backing_transport: a Transport to handle requests for.
299
229
        :param commands: a registry mapping command names to SmartServerRequest
300
 
            subclasses. e.g. breezy.transport.smart.vfs.vfs_commands.
 
230
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
301
231
        """
302
232
        self._backing_transport = backing_transport
303
233
        self._root_client_path = root_client_path
304
234
        self._commands = commands
305
 
        if jail_root is None:
306
 
            jail_root = backing_transport
307
 
        self._jail_root = jail_root
308
235
        self.response = None
309
236
        self.finished_reading = False
310
237
        self._command = None
311
 
        if 'hpss' in debug.debug_flags:
312
 
            self._request_start_time = osutils.timer_func()
313
 
            self._thread_id = get_ident()
314
 
 
315
 
    def _trace(self, action, message, extra_bytes=None, include_time=False):
316
 
        # It is a bit of a shame that this functionality overlaps with that of
317
 
        # ProtocolThreeRequester._trace. However, there is enough difference
318
 
        # that just putting it in a helper doesn't help a lot. And some state
319
 
        # is taken from the instance.
320
 
        if include_time:
321
 
            t = '%5.3fs ' % (osutils.timer_func() - self._request_start_time)
322
 
        else:
323
 
            t = ''
324
 
        if extra_bytes is None:
325
 
            extra = ''
326
 
        else:
327
 
            extra = ' ' + repr(extra_bytes[:40])
328
 
            if len(extra) > 33:
329
 
                extra = extra[:29] + extra[-1] + '...'
330
 
        trace.mutter('%12s: [%s] %s%s%s'
331
 
                     % (action, self._thread_id, t, message, extra))
332
238
 
333
239
    def accept_body(self, bytes):
334
240
        """Accept body data."""
335
 
        if self._command is None:
336
 
            # no active command object, so ignore the event.
337
 
            return
338
241
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
339
 
        if 'hpss' in debug.debug_flags:
340
 
            self._trace('accept body',
341
 
                        '%d bytes' % (len(bytes),), bytes)
342
 
 
 
242
        
343
243
    def end_of_body(self):
344
244
        """No more body data will be received."""
345
245
        self._run_handler_code(self._command.do_end, (), {})
346
246
        # cannot read after this.
347
247
        self.finished_reading = True
348
 
        if 'hpss' in debug.debug_flags:
349
 
            self._trace('end of body', '', include_time=True)
 
248
 
 
249
    def dispatch_command(self, cmd, args):
 
250
        """Deprecated compatibility method.""" # XXX XXX
 
251
        try:
 
252
            command = self._commands.get(cmd)
 
253
        except LookupError:
 
254
            raise errors.UnknownSmartMethod(cmd)
 
255
        self._command = command(self._backing_transport, self._root_client_path)
 
256
        self._run_handler_code(self._command.execute, args, {})
350
257
 
351
258
    def _run_handler_code(self, callable, args, kwargs):
352
259
        """Run some handler specific code 'callable'.
368
275
        # XXX: most of this error conversion is VFS-related, and thus ought to
369
276
        # be in SmartServerVFSRequestHandler somewhere.
370
277
        try:
371
 
            self._command.setup_jail()
372
 
            try:
373
 
                return callable(*args, **kwargs)
374
 
            finally:
375
 
                self._command.teardown_jail()
376
 
        except (KeyboardInterrupt, SystemExit):
377
 
            raise
378
 
        except Exception as err:
379
 
            err_struct = _translate_error(err)
380
 
            return FailedSmartServerResponse(err_struct)
 
278
            return callable(*args, **kwargs)
 
279
        except errors.NoSuchFile, e:
 
280
            return FailedSmartServerResponse(('NoSuchFile', e.path))
 
281
        except errors.FileExists, e:
 
282
            return FailedSmartServerResponse(('FileExists', e.path))
 
283
        except errors.DirectoryNotEmpty, e:
 
284
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
 
285
        except errors.ShortReadvError, e:
 
286
            return FailedSmartServerResponse(('ShortReadvError',
 
287
                e.path, str(e.offset), str(e.length), str(e.actual)))
 
288
        except errors.UnstackableRepositoryFormat, e:
 
289
            return FailedSmartServerResponse(('UnstackableRepositoryFormat',
 
290
                str(e.format), e.url))
 
291
        except errors.UnstackableBranchFormat, e:
 
292
            return FailedSmartServerResponse(('UnstackableBranchFormat',
 
293
                str(e.format), e.url))
 
294
        except errors.NotStacked, e:
 
295
            return FailedSmartServerResponse(('NotStacked',))
 
296
        except UnicodeError, e:
 
297
            # If it is a DecodeError, than most likely we are starting
 
298
            # with a plain string
 
299
            str_or_unicode = e.object
 
300
            if isinstance(str_or_unicode, unicode):
 
301
                # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
 
302
                # byte) in it, so this encoding could cause broken responses.
 
303
                # Newer clients use protocol v3, so will be fine.
 
304
                val = 'u:' + str_or_unicode.encode('utf-8')
 
305
            else:
 
306
                val = 's:' + str_or_unicode.encode('base64')
 
307
            # This handles UnicodeEncodeError or UnicodeDecodeError
 
308
            return FailedSmartServerResponse((e.__class__.__name__,
 
309
                    e.encoding, val, str(e.start), str(e.end), e.reason))
 
310
        except errors.TransportNotPossible, e:
 
311
            if e.msg == "readonly transport":
 
312
                return FailedSmartServerResponse(('ReadOnlyError', ))
 
313
            else:
 
314
                raise
 
315
        except errors.ReadError, e:
 
316
            # cannot read the file
 
317
            return FailedSmartServerResponse(('ReadError', e.path))
 
318
        except errors.PermissionDenied, e:
 
319
            return FailedSmartServerResponse(
 
320
                ('PermissionDenied', e.path, e.extra))
381
321
 
382
322
    def headers_received(self, headers):
383
323
        # Just a no-op at the moment.
384
 
        if 'hpss' in debug.debug_flags:
385
 
            self._trace('headers', repr(headers))
 
324
        pass
386
325
 
387
326
    def args_received(self, args):
388
327
        cmd = args[0]
390
329
        try:
391
330
            command = self._commands.get(cmd)
392
331
        except LookupError:
393
 
            if 'hpss' in debug.debug_flags:
394
 
                self._trace('hpss unknown request',
395
 
                            cmd, repr(args)[1:-1])
396
332
            raise errors.UnknownSmartMethod(cmd)
397
 
        if 'hpss' in debug.debug_flags:
398
 
            from . import vfs
399
 
            if issubclass(command, vfs.VfsRequest):
400
 
                action = 'hpss vfs req'
401
 
            else:
402
 
                action = 'hpss request'
403
 
            self._trace(action, '%s %s' % (cmd, repr(args)[1:-1]))
404
 
        self._command = command(
405
 
            self._backing_transport, self._root_client_path, self._jail_root)
 
333
        self._command = command(self._backing_transport)
406
334
        self._run_handler_code(self._command.execute, args, {})
407
335
 
408
336
    def end_received(self):
409
 
        if self._command is None:
410
 
            # no active command object, so ignore the event.
411
 
            return
412
337
        self._run_handler_code(self._command.do_end, (), {})
413
 
        if 'hpss' in debug.debug_flags:
414
 
            self._trace('end', '', include_time=True)
415
338
 
416
339
    def post_body_error_received(self, error_args):
417
340
        # Just a no-op at the moment.
418
341
        pass
419
342
 
420
343
 
421
 
def _translate_error(err):
422
 
    if isinstance(err, errors.NoSuchFile):
423
 
        return (b'NoSuchFile', err.path.encode('utf-8'))
424
 
    elif isinstance(err, errors.FileExists):
425
 
        return (b'FileExists', err.path.encode('utf-8'))
426
 
    elif isinstance(err, errors.DirectoryNotEmpty):
427
 
        return (b'DirectoryNotEmpty', err.path.encode('utf-8'))
428
 
    elif isinstance(err, errors.IncompatibleRepositories):
429
 
        return (b'IncompatibleRepositories', str(err.source), str(err.target),
430
 
                str(err.details))
431
 
    elif isinstance(err, errors.ShortReadvError):
432
 
        return (b'ShortReadvError', err.path.encode('utf-8'),
433
 
                str(err.offset).encode('ascii'),
434
 
                str(err.length).encode('ascii'),
435
 
                str(err.actual).encode('ascii'))
436
 
    elif isinstance(err, errors.RevisionNotPresent):
437
 
        return (b'RevisionNotPresent', err.revision_id, err.file_id)
438
 
    elif isinstance(err, errors.UnstackableRepositoryFormat):
439
 
        return ((b'UnstackableRepositoryFormat',
440
 
                 str(err.format).encode('utf-8'), err.url.encode('utf-8')))
441
 
    elif isinstance(err, _mod_branch.UnstackableBranchFormat):
442
 
        return (b'UnstackableBranchFormat', str(err.format).encode('utf-8'),
443
 
                err.url.encode('utf-8'))
444
 
    elif isinstance(err, errors.NotStacked):
445
 
        return (b'NotStacked',)
446
 
    elif isinstance(err, errors.BzrCheckError):
447
 
        return (b'BzrCheckError', err.msg.encode('utf-8'))
448
 
    elif isinstance(err, UnicodeError):
449
 
        # If it is a DecodeError, than most likely we are starting
450
 
        # with a plain string
451
 
        str_or_unicode = err.object
452
 
        if isinstance(str_or_unicode, text_type):
453
 
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
454
 
            # byte) in it, so this encoding could cause broken responses.
455
 
            # Newer clients use protocol v3, so will be fine.
456
 
            val = 'u:' + str_or_unicode.encode('utf-8')
457
 
        else:
458
 
            val = 's:' + str_or_unicode.encode('base64')
459
 
        # This handles UnicodeEncodeError or UnicodeDecodeError
460
 
        return (err.__class__.__name__, err.encoding, val, str(err.start),
461
 
                str(err.end), err.reason)
462
 
    elif isinstance(err, errors.TransportNotPossible):
463
 
        if err.msg == "readonly transport":
464
 
            return (b'ReadOnlyError', )
465
 
    elif isinstance(err, errors.ReadError):
466
 
        # cannot read the file
467
 
        return (b'ReadError', err.path)
468
 
    elif isinstance(err, errors.PermissionDenied):
469
 
        return (b'PermissionDenied', err.path.encode('utf-8'), err.extra.encode('utf-8'))
470
 
    elif isinstance(err, errors.TokenMismatch):
471
 
        return (b'TokenMismatch', err.given_token, err.lock_token)
472
 
    elif isinstance(err, errors.LockContention):
473
 
        return (b'LockContention',)
474
 
    elif isinstance(err, errors.GhostRevisionsHaveNoRevno):
475
 
        return (b'GhostRevisionsHaveNoRevno', err.revision_id, err.ghost_revision_id)
476
 
    elif isinstance(err, urlutils.InvalidURL):
477
 
        return (b'InvalidURL', err.path.encode('utf-8'), err.extra.encode('ascii'))
478
 
    elif isinstance(err, MemoryError):
479
 
        # GZ 2011-02-24: Copy breezy.trace -Dmem_dump functionality here?
480
 
        return (b'MemoryError',)
481
 
    # Unserialisable error.  Log it, and return a generic error
482
 
    trace.log_exception_quietly()
483
 
    return (b'error',
484
 
            trace._qualified_exception_name(
485
 
                err.__class__, True).encode('utf-8'),
486
 
            str(err).encode('utf-8'))
487
 
 
488
 
 
489
344
class HelloRequest(SmartServerRequest):
490
345
    """Answer a version request with the highest protocol version this server
491
346
    supports.
492
347
    """
493
348
 
494
349
    def do(self):
495
 
        return SuccessfulSmartServerResponse((b'ok', b'2'))
 
350
        return SuccessfulSmartServerResponse(('ok', '2'))
496
351
 
497
352
 
498
353
class GetBundleRequest(SmartServerRequest):
515
370
 
516
371
    def do(self):
517
372
        if self._backing_transport.is_readonly():
518
 
            answer = b'yes'
 
373
            answer = 'yes'
519
374
        else:
520
 
            answer = b'no'
 
375
            answer = 'no'
521
376
        return SuccessfulSmartServerResponse((answer,))
522
377
 
523
378
 
524
 
# In the 'info' attribute, we store whether this request is 'safe' to retry if
525
 
# we get a disconnect while reading the response. It can have the values:
526
 
#   read    This is purely a read request, so retrying it is perfectly ok.
527
 
#   idem    An idempotent write request. Something like 'put' where if you put
528
 
#           the same bytes twice you end up with the same final bytes.
529
 
#   semi    This is a request that isn't strictly idempotent, but doesn't
530
 
#           result in corruption if it is retried. This is for things like
531
 
#           'lock' and 'unlock'. If you call lock, it updates the disk
532
 
#           structure. If you fail to read the response, you won't be able to
533
 
#           use the lock, because you don't have the lock token. Calling lock
534
 
#           again will fail, because the lock is already taken. However, we
535
 
#           can't tell if the server received our request or not. If it didn't,
536
 
#           then retrying the request is fine, as it will actually do what we
537
 
#           want. If it did, we will interrupt the current operation, but we
538
 
#           are no worse off than interrupting the current operation because of
539
 
#           a ConnectionReset.
540
 
#   semivfs Similar to semi, but specific to a Virtual FileSystem request.
541
 
#   stream  This is a request that takes a stream that cannot be restarted if
542
 
#           consumed. This request is 'safe' in that if we determine the
543
 
#           connection is closed before we consume the stream, we can try
544
 
#           again.
545
 
#   mutate  State is updated in a way that replaying that request results in a
546
 
#           different state. For example 'append' writes more bytes to a given
547
 
#           file. If append succeeds, it moves the file pointer.
548
379
request_handlers = registry.Registry()
549
380
request_handlers.register_lazy(
550
 
    b'append', 'breezy.bzr.smart.vfs', 'AppendRequest', info='mutate')
551
 
request_handlers.register_lazy(
552
 
    b'Branch.break_lock', 'breezy.bzr.smart.branch',
553
 
    'SmartServerBranchBreakLock', info='idem')
554
 
request_handlers.register_lazy(
555
 
    b'Branch.get_config_file', 'breezy.bzr.smart.branch',
556
 
    'SmartServerBranchGetConfigFile', info='read')
557
 
request_handlers.register_lazy(
558
 
    b'Branch.get_parent', 'breezy.bzr.smart.branch', 'SmartServerBranchGetParent',
559
 
    info='read')
560
 
request_handlers.register_lazy(
561
 
    b'Branch.put_config_file', 'breezy.bzr.smart.branch',
562
 
    'SmartServerBranchPutConfigFile', info='idem')
563
 
request_handlers.register_lazy(
564
 
    b'Branch.get_tags_bytes', 'breezy.bzr.smart.branch',
565
 
    'SmartServerBranchGetTagsBytes', info='read')
566
 
request_handlers.register_lazy(
567
 
    b'Branch.set_tags_bytes', 'breezy.bzr.smart.branch',
568
 
    'SmartServerBranchSetTagsBytes', info='idem')
569
 
request_handlers.register_lazy(
570
 
    b'Branch.heads_to_fetch', 'breezy.bzr.smart.branch',
571
 
    'SmartServerBranchHeadsToFetch', info='read')
572
 
request_handlers.register_lazy(
573
 
    b'Branch.get_stacked_on_url', 'breezy.bzr.smart.branch',
574
 
    'SmartServerBranchRequestGetStackedOnURL', info='read')
575
 
request_handlers.register_lazy(
576
 
    b'Branch.get_physical_lock_status', 'breezy.bzr.smart.branch',
577
 
    'SmartServerBranchRequestGetPhysicalLockStatus', info='read')
578
 
request_handlers.register_lazy(
579
 
    b'Branch.last_revision_info', 'breezy.bzr.smart.branch',
580
 
    'SmartServerBranchRequestLastRevisionInfo', info='read')
581
 
request_handlers.register_lazy(
582
 
    b'Branch.lock_write', 'breezy.bzr.smart.branch',
583
 
    'SmartServerBranchRequestLockWrite', info='semi')
584
 
request_handlers.register_lazy(
585
 
    b'Branch.revision_history', 'breezy.bzr.smart.branch',
586
 
    'SmartServerRequestRevisionHistory', info='read')
587
 
request_handlers.register_lazy(
588
 
    b'Branch.set_config_option', 'breezy.bzr.smart.branch',
589
 
    'SmartServerBranchRequestSetConfigOption', info='idem')
590
 
request_handlers.register_lazy(
591
 
    b'Branch.set_config_option_dict', 'breezy.bzr.smart.branch',
592
 
    'SmartServerBranchRequestSetConfigOptionDict', info='idem')
593
 
request_handlers.register_lazy(
594
 
    b'Branch.set_last_revision', 'breezy.bzr.smart.branch',
595
 
    'SmartServerBranchRequestSetLastRevision', info='idem')
596
 
request_handlers.register_lazy(
597
 
    b'Branch.set_last_revision_info', 'breezy.bzr.smart.branch',
598
 
    'SmartServerBranchRequestSetLastRevisionInfo', info='idem')
599
 
request_handlers.register_lazy(
600
 
    b'Branch.set_last_revision_ex', 'breezy.bzr.smart.branch',
601
 
    'SmartServerBranchRequestSetLastRevisionEx', info='idem')
602
 
request_handlers.register_lazy(
603
 
    b'Branch.set_parent_location', 'breezy.bzr.smart.branch',
604
 
    'SmartServerBranchRequestSetParentLocation', info='idem')
605
 
request_handlers.register_lazy(
606
 
    b'Branch.unlock', 'breezy.bzr.smart.branch',
607
 
    'SmartServerBranchRequestUnlock', info='semi')
608
 
request_handlers.register_lazy(
609
 
    b'Branch.revision_id_to_revno', 'breezy.bzr.smart.branch',
610
 
    'SmartServerBranchRequestRevisionIdToRevno', info='read')
611
 
request_handlers.register_lazy(
612
 
    b'BzrDir.checkout_metadir', 'breezy.bzr.smart.bzrdir',
613
 
    'SmartServerBzrDirRequestCheckoutMetaDir', info='read')
614
 
request_handlers.register_lazy(
615
 
    b'BzrDir.cloning_metadir', 'breezy.bzr.smart.bzrdir',
616
 
    'SmartServerBzrDirRequestCloningMetaDir', info='read')
617
 
request_handlers.register_lazy(
618
 
    b'BzrDir.create_branch', 'breezy.bzr.smart.bzrdir',
619
 
    'SmartServerRequestCreateBranch', info='semi')
620
 
request_handlers.register_lazy(
621
 
    b'BzrDir.create_repository', 'breezy.bzr.smart.bzrdir',
622
 
    'SmartServerRequestCreateRepository', info='semi')
623
 
request_handlers.register_lazy(
624
 
    b'BzrDir.find_repository', 'breezy.bzr.smart.bzrdir',
625
 
    'SmartServerRequestFindRepositoryV1', info='read')
626
 
request_handlers.register_lazy(
627
 
    b'BzrDir.find_repositoryV2', 'breezy.bzr.smart.bzrdir',
628
 
    'SmartServerRequestFindRepositoryV2', info='read')
629
 
request_handlers.register_lazy(
630
 
    b'BzrDir.find_repositoryV3', 'breezy.bzr.smart.bzrdir',
631
 
    'SmartServerRequestFindRepositoryV3', info='read')
632
 
request_handlers.register_lazy(
633
 
    b'BzrDir.get_branches', 'breezy.bzr.smart.bzrdir',
634
 
    'SmartServerBzrDirRequestGetBranches', info='read')
635
 
request_handlers.register_lazy(
636
 
    b'BzrDir.get_config_file', 'breezy.bzr.smart.bzrdir',
637
 
    'SmartServerBzrDirRequestConfigFile', info='read')
638
 
request_handlers.register_lazy(
639
 
    b'BzrDir.destroy_branch', 'breezy.bzr.smart.bzrdir',
640
 
    'SmartServerBzrDirRequestDestroyBranch', info='semi')
641
 
request_handlers.register_lazy(
642
 
    b'BzrDir.destroy_repository', 'breezy.bzr.smart.bzrdir',
643
 
    'SmartServerBzrDirRequestDestroyRepository', info='semi')
644
 
request_handlers.register_lazy(
645
 
    b'BzrDir.has_workingtree', 'breezy.bzr.smart.bzrdir',
646
 
    'SmartServerBzrDirRequestHasWorkingTree', info='read')
647
 
request_handlers.register_lazy(
648
 
    b'BzrDirFormat.initialize', 'breezy.bzr.smart.bzrdir',
649
 
    'SmartServerRequestInitializeBzrDir', info='semi')
650
 
request_handlers.register_lazy(
651
 
    b'BzrDirFormat.initialize_ex_1.16', 'breezy.bzr.smart.bzrdir',
652
 
    'SmartServerRequestBzrDirInitializeEx', info='semi')
653
 
request_handlers.register_lazy(
654
 
    b'BzrDir.open', 'breezy.bzr.smart.bzrdir', 'SmartServerRequestOpenBzrDir',
655
 
    info='read')
656
 
request_handlers.register_lazy(
657
 
    b'BzrDir.open_2.1', 'breezy.bzr.smart.bzrdir',
658
 
    'SmartServerRequestOpenBzrDir_2_1', info='read')
659
 
request_handlers.register_lazy(
660
 
    b'BzrDir.open_branch', 'breezy.bzr.smart.bzrdir',
661
 
    'SmartServerRequestOpenBranch', info='read')
662
 
request_handlers.register_lazy(
663
 
    b'BzrDir.open_branchV2', 'breezy.bzr.smart.bzrdir',
664
 
    'SmartServerRequestOpenBranchV2', info='read')
665
 
request_handlers.register_lazy(
666
 
    b'BzrDir.open_branchV3', 'breezy.bzr.smart.bzrdir',
667
 
    'SmartServerRequestOpenBranchV3', info='read')
668
 
request_handlers.register_lazy(
669
 
    b'delete', 'breezy.bzr.smart.vfs', 'DeleteRequest', info='semivfs')
670
 
request_handlers.register_lazy(
671
 
    b'get', 'breezy.bzr.smart.vfs', 'GetRequest', info='read')
672
 
request_handlers.register_lazy(
673
 
    b'get_bundle', 'breezy.bzr.smart.request', 'GetBundleRequest', info='read')
674
 
request_handlers.register_lazy(
675
 
    b'has', 'breezy.bzr.smart.vfs', 'HasRequest', info='read')
676
 
request_handlers.register_lazy(
677
 
    b'hello', 'breezy.bzr.smart.request', 'HelloRequest', info='read')
678
 
request_handlers.register_lazy(
679
 
    b'iter_files_recursive', 'breezy.bzr.smart.vfs', 'IterFilesRecursiveRequest',
680
 
    info='read')
681
 
request_handlers.register_lazy(
682
 
    b'list_dir', 'breezy.bzr.smart.vfs', 'ListDirRequest', info='read')
683
 
request_handlers.register_lazy(
684
 
    b'mkdir', 'breezy.bzr.smart.vfs', 'MkdirRequest', info='semivfs')
685
 
request_handlers.register_lazy(
686
 
    b'move', 'breezy.bzr.smart.vfs', 'MoveRequest', info='semivfs')
687
 
request_handlers.register_lazy(
688
 
    b'put', 'breezy.bzr.smart.vfs', 'PutRequest', info='idem')
689
 
request_handlers.register_lazy(
690
 
    b'put_non_atomic', 'breezy.bzr.smart.vfs', 'PutNonAtomicRequest', info='idem')
691
 
request_handlers.register_lazy(
692
 
    b'readv', 'breezy.bzr.smart.vfs', 'ReadvRequest', info='read')
693
 
request_handlers.register_lazy(
694
 
    b'rename', 'breezy.bzr.smart.vfs', 'RenameRequest', info='semivfs')
695
 
request_handlers.register_lazy(
696
 
    b'Repository.add_signature_text', 'breezy.bzr.smart.repository',
697
 
    'SmartServerRepositoryAddSignatureText', info='idem')
698
 
request_handlers.register_lazy(
699
 
    b'Repository.annotate_file_revision', 'breezy.bzr.smart.repository',
700
 
    'SmartServerRepositoryAnnotateFileRevision', info='read')
701
 
request_handlers.register_lazy(
702
 
    b'Repository.all_revision_ids', 'breezy.bzr.smart.repository',
703
 
    'SmartServerRepositoryAllRevisionIds', info='read')
704
 
request_handlers.register_lazy(
705
 
    b'PackRepository.autopack', 'breezy.bzr.smart.packrepository',
706
 
    'SmartServerPackRepositoryAutopack', info='idem')
707
 
request_handlers.register_lazy(
708
 
    b'Repository.break_lock', 'breezy.bzr.smart.repository',
709
 
    'SmartServerRepositoryBreakLock', info='idem')
710
 
request_handlers.register_lazy(
711
 
    b'Repository.gather_stats', 'breezy.bzr.smart.repository',
712
 
    'SmartServerRepositoryGatherStats', info='read')
713
 
request_handlers.register_lazy(
714
 
    b'Repository.get_parent_map', 'breezy.bzr.smart.repository',
715
 
    'SmartServerRepositoryGetParentMap', info='read')
716
 
request_handlers.register_lazy(
717
 
    b'Repository.get_revision_graph', 'breezy.bzr.smart.repository',
718
 
    'SmartServerRepositoryGetRevisionGraph', info='read')
719
 
request_handlers.register_lazy(
720
 
    b'Repository.get_revision_signature_text', 'breezy.bzr.smart.repository',
721
 
    'SmartServerRepositoryGetRevisionSignatureText', info='read')
722
 
request_handlers.register_lazy(
723
 
    b'Repository.has_revision', 'breezy.bzr.smart.repository',
724
 
    'SmartServerRequestHasRevision', info='read')
725
 
request_handlers.register_lazy(
726
 
    b'Repository.has_signature_for_revision_id', 'breezy.bzr.smart.repository',
727
 
    'SmartServerRequestHasSignatureForRevisionId', info='read')
728
 
request_handlers.register_lazy(
729
 
    b'Repository.insert_stream', 'breezy.bzr.smart.repository',
730
 
    'SmartServerRepositoryInsertStream', info='stream')
731
 
request_handlers.register_lazy(
732
 
    b'Repository.insert_stream_1.19', 'breezy.bzr.smart.repository',
733
 
    'SmartServerRepositoryInsertStream_1_19', info='stream')
734
 
request_handlers.register_lazy(
735
 
    b'Repository.insert_stream_locked', 'breezy.bzr.smart.repository',
736
 
    'SmartServerRepositoryInsertStreamLocked', info='stream')
737
 
request_handlers.register_lazy(
738
 
    b'Repository.is_shared', 'breezy.bzr.smart.repository',
739
 
    'SmartServerRepositoryIsShared', info='read')
740
 
request_handlers.register_lazy(
741
 
    b'Repository.iter_files_bytes', 'breezy.bzr.smart.repository',
742
 
    'SmartServerRepositoryIterFilesBytes', info='read')
743
 
request_handlers.register_lazy(
744
 
    b'Repository.lock_write', 'breezy.bzr.smart.repository',
745
 
    'SmartServerRepositoryLockWrite', info='semi')
746
 
request_handlers.register_lazy(
747
 
    b'Repository.make_working_trees', 'breezy.bzr.smart.repository',
748
 
    'SmartServerRepositoryMakeWorkingTrees', info='read')
749
 
request_handlers.register_lazy(
750
 
    b'Repository.set_make_working_trees', 'breezy.bzr.smart.repository',
751
 
    'SmartServerRepositorySetMakeWorkingTrees', info='idem')
752
 
request_handlers.register_lazy(
753
 
    b'Repository.unlock', 'breezy.bzr.smart.repository',
754
 
    'SmartServerRepositoryUnlock', info='semi')
755
 
request_handlers.register_lazy(
756
 
    b'Repository.get_physical_lock_status', 'breezy.bzr.smart.repository',
757
 
    'SmartServerRepositoryGetPhysicalLockStatus', info='read')
758
 
request_handlers.register_lazy(
759
 
    b'Repository.get_rev_id_for_revno', 'breezy.bzr.smart.repository',
760
 
    'SmartServerRepositoryGetRevIdForRevno', info='read')
761
 
request_handlers.register_lazy(
762
 
    b'Repository.get_stream', 'breezy.bzr.smart.repository',
763
 
    'SmartServerRepositoryGetStream', info='read')
764
 
request_handlers.register_lazy(
765
 
    b'Repository.get_stream_1.19', 'breezy.bzr.smart.repository',
766
 
    'SmartServerRepositoryGetStream_1_19', info='read')
767
 
request_handlers.register_lazy(
768
 
    b'Repository.get_stream_for_missing_keys', 'breezy.bzr.smart.repository',
769
 
    'SmartServerRepositoryGetStreamForMissingKeys', info='read')
770
 
request_handlers.register_lazy(
771
 
    b'Repository.iter_revisions', 'breezy.bzr.smart.repository',
772
 
    'SmartServerRepositoryIterRevisions', info='read')
773
 
request_handlers.register_lazy(
774
 
    b'Repository.pack', 'breezy.bzr.smart.repository',
775
 
    'SmartServerRepositoryPack', info='idem')
776
 
request_handlers.register_lazy(
777
 
    b'Repository.start_write_group', 'breezy.bzr.smart.repository',
778
 
    'SmartServerRepositoryStartWriteGroup', info='semi')
779
 
request_handlers.register_lazy(
780
 
    b'Repository.commit_write_group', 'breezy.bzr.smart.repository',
781
 
    'SmartServerRepositoryCommitWriteGroup', info='semi')
782
 
request_handlers.register_lazy(
783
 
    b'Repository.abort_write_group', 'breezy.bzr.smart.repository',
784
 
    'SmartServerRepositoryAbortWriteGroup', info='semi')
785
 
request_handlers.register_lazy(
786
 
    b'Repository.check_write_group', 'breezy.bzr.smart.repository',
787
 
    'SmartServerRepositoryCheckWriteGroup', info='read')
788
 
request_handlers.register_lazy(
789
 
    b'Repository.reconcile', 'breezy.bzr.smart.repository',
790
 
    'SmartServerRepositoryReconcile', info='idem')
791
 
request_handlers.register_lazy(
792
 
    b'Repository.revision_archive', 'breezy.bzr.smart.repository',
793
 
    'SmartServerRepositoryRevisionArchive', info='read')
794
 
request_handlers.register_lazy(
795
 
    b'Repository.tarball', 'breezy.bzr.smart.repository',
796
 
    'SmartServerRepositoryTarball', info='read')
797
 
request_handlers.register_lazy(
798
 
    b'VersionedFileRepository.get_serializer_format', 'breezy.bzr.smart.repository',
799
 
    'SmartServerRepositoryGetSerializerFormat', info='read')
800
 
request_handlers.register_lazy(
801
 
    b'VersionedFileRepository.get_inventories', 'breezy.bzr.smart.repository',
802
 
    'SmartServerRepositoryGetInventories', info='read')
803
 
request_handlers.register_lazy(
804
 
    b'rmdir', 'breezy.bzr.smart.vfs', 'RmdirRequest', info='semivfs')
805
 
request_handlers.register_lazy(
806
 
    b'stat', 'breezy.bzr.smart.vfs', 'StatRequest', info='read')
807
 
request_handlers.register_lazy(
808
 
    b'Transport.is_readonly', 'breezy.bzr.smart.request',
809
 
    'SmartServerIsReadonly', info='read')
 
381
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
 
382
request_handlers.register_lazy(
 
383
    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
 
384
request_handlers.register_lazy(
 
385
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
 
386
request_handlers.register_lazy(
 
387
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
 
388
request_handlers.register_lazy(
 
389
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
 
390
request_handlers.register_lazy(
 
391
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
 
392
request_handlers.register_lazy(
 
393
    'Branch.set_last_revision', 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
 
394
request_handlers.register_lazy(
 
395
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
 
396
    'SmartServerBranchRequestSetLastRevisionInfo')
 
397
request_handlers.register_lazy(
 
398
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
 
399
    'SmartServerBranchRequestSetLastRevisionEx')
 
400
request_handlers.register_lazy(
 
401
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
 
402
request_handlers.register_lazy(
 
403
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')
 
404
request_handlers.register_lazy(
 
405
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
 
406
request_handlers.register_lazy(
 
407
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
 
408
request_handlers.register_lazy(
 
409
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
 
410
request_handlers.register_lazy(
 
411
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
 
412
request_handlers.register_lazy(
 
413
    'get', 'bzrlib.smart.vfs', 'GetRequest')
 
414
request_handlers.register_lazy(
 
415
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
 
416
request_handlers.register_lazy(
 
417
    'has', 'bzrlib.smart.vfs', 'HasRequest')
 
418
request_handlers.register_lazy(
 
419
    'hello', 'bzrlib.smart.request', 'HelloRequest')
 
420
request_handlers.register_lazy(
 
421
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
 
422
request_handlers.register_lazy(
 
423
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
 
424
request_handlers.register_lazy(
 
425
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
 
426
request_handlers.register_lazy(
 
427
    'move', 'bzrlib.smart.vfs', 'MoveRequest')
 
428
request_handlers.register_lazy(
 
429
    'put', 'bzrlib.smart.vfs', 'PutRequest')
 
430
request_handlers.register_lazy(
 
431
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
 
432
request_handlers.register_lazy(
 
433
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
 
434
request_handlers.register_lazy(
 
435
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
 
436
request_handlers.register_lazy(
 
437
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
 
438
    'SmartServerPackRepositoryAutopack')
 
439
request_handlers.register_lazy('Repository.gather_stats',
 
440
                               'bzrlib.smart.repository',
 
441
                               'SmartServerRepositoryGatherStats')
 
442
request_handlers.register_lazy('Repository.get_parent_map',
 
443
                               'bzrlib.smart.repository',
 
444
                               'SmartServerRepositoryGetParentMap')
 
445
request_handlers.register_lazy(
 
446
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
 
447
request_handlers.register_lazy(
 
448
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
 
449
request_handlers.register_lazy(
 
450
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
 
451
request_handlers.register_lazy(
 
452
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
 
453
request_handlers.register_lazy(
 
454
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
 
455
request_handlers.register_lazy(
 
456
    'Repository.tarball', 'bzrlib.smart.repository',
 
457
    'SmartServerRepositoryTarball')
 
458
request_handlers.register_lazy(
 
459
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
 
460
request_handlers.register_lazy(
 
461
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
 
462
request_handlers.register_lazy(
 
463
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
 
464
request_handlers.register_lazy(
 
465
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')