~bzr-pqm/bzr/bzr.dev

3224.5.8 by Andrew Bennetts
Fix failing tests.
1
# Copyright (C) 2006, 2007 Canonical Ltd
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
2
#
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
7
#
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
12
#
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
4183.7.1 by Sabin Iacob
update FSF mailing address
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
16
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
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
"""
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
28
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
29
import tempfile
30
2402.1.2 by Andrew Bennetts
Deal with review comments.
31
from bzrlib import (
32
    bzrdir,
33
    errors,
34
    registry,
35
    revision,
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
36
    trace,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
37
    urlutils,
2402.1.2 by Andrew Bennetts
Deal with review comments.
38
    )
3224.5.6 by Andrew Bennetts
Don't import bzrlib.bundle in bzrlib.smart.request until it's needed.
39
from bzrlib.lazy_import import lazy_import
40
lazy_import(globals(), """
41
from bzrlib.bundle import serializer
42
""")
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
43
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
44
45
class SmartServerRequest(object):
2692.1.10 by Andrew Bennetts
More docstring polish
46
    """Base class for request handlers.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
47
2692.1.10 by Andrew Bennetts
More docstring polish
48
    To define a new request, subclass this class and override the `do` method
49
    (and if appropriate, `do_body` as well).  Request implementors should take
50
    care to call `translate_client_path` and `transport_from_client_path` as
51
    appropriate when dealing with paths received from the client.
52
    """
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
53
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
54
    # *handler* is a different concept to the request.
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
55
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
56
    def __init__(self, backing_transport, root_client_path='/'):
2402.1.2 by Andrew Bennetts
Deal with review comments.
57
        """Constructor.
58
59
        :param backing_transport: the base transport to be used when performing
60
            this request.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
61
        :param root_client_path: the client path that maps to the root of
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
62
            backing_transport.  This is used to interpret relpaths received
63
            from the client.  Clients will not be able to refer to paths above
2692.1.16 by Andrew Bennetts
Improve comments.
64
            this root.  If root_client_path is None, then no translation will
65
            be performed on client paths.  Default is '/'.
2402.1.2 by Andrew Bennetts
Deal with review comments.
66
        """
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
67
        self._backing_transport = backing_transport
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
68
        if root_client_path is not None:
69
            if not root_client_path.startswith('/'):
70
                root_client_path = '/' + root_client_path
71
            if not root_client_path.endswith('/'):
72
                root_client_path += '/'
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
73
        self._root_client_path = root_client_path
3842.3.19 by Andrew Bennetts
Tweaks suggested by review.
74
        self._body_chunks = []
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
75
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
76
    def _check_enabled(self):
77
        """Raises DisabledMethod if this method is disabled."""
78
        pass
79
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
80
    def do(self, *args):
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
81
        """Mandatory extension point for SmartServerRequest subclasses.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
82
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
83
        Subclasses must implement this.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
84
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
85
        This should return a SmartServerResponse if this command expects to
86
        receive no body.
87
        """
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
88
        raise NotImplementedError(self.do)
89
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
90
    def execute(self, *args):
91
        """Public entry point to execute this request.
92
93
        It will return a SmartServerResponse if the command does not expect a
94
        body.
95
96
        :param *args: the arguments of the request.
97
        """
98
        self._check_enabled()
99
        return self.do(*args)
100
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
101
    def do_body(self, body_bytes):
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
102
        """Called if the client sends a body with the request.
3184.1.10 by Robert Collins
Change the smart server verb for Repository.stream_revisions_chunked to use SearchResults as the request mechanism for downloads.
103
104
        The do() method is still called, and must have returned None.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
105
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
106
        Must return a SmartServerResponse.
107
        """
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
108
        if body_bytes != '':
3990.3.3 by Andrew Bennetts
Add a test that unexpected request bodies trigger a SmartProtocolError from request implementations.
109
            raise errors.SmartProtocolError('Request does not expect a body')
2018.5.4 by Andrew Bennetts
Split smart server VFS logic out into a new file, and start using the command pattern in the SmartServerRequestHandler.
110
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
111
    def do_chunk(self, chunk_bytes):
112
        """Called with each body chunk if the request has a streamed body.
113
114
        The do() method is still called, and must have returned None.
115
        """
3842.3.19 by Andrew Bennetts
Tweaks suggested by review.
116
        self._body_chunks.append(chunk_bytes)
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
117
118
    def do_end(self):
119
        """Called when the end of the request has been received."""
3842.3.19 by Andrew Bennetts
Tweaks suggested by review.
120
        body_bytes = ''.join(self._body_chunks)
121
        self._body_chunks = None
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
122
        return self.do_body(body_bytes)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
123
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
124
    def translate_client_path(self, client_path):
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
125
        """Translate a path received from a network client into a local
126
        relpath.
127
128
        All paths received from the client *must* be translated.
129
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
130
        :param client_path: the path from the client.
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
131
        :returns: a relpath that may be used with self._backing_transport
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
132
            (unlike the untranslated client_path, which must not be used with
133
            the backing transport).
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
134
        """
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
135
        if self._root_client_path is None:
136
            # no translation necessary!
137
            return client_path
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
138
        if not client_path.startswith('/'):
139
            client_path = '/' + client_path
140
        if client_path.startswith(self._root_client_path):
141
            path = client_path[len(self._root_client_path):]
142
            relpath = urlutils.joinpath('/', path)
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
143
            if not relpath.startswith('/'):
144
                raise ValueError(relpath)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
145
            return '.' + relpath
146
        else:
147
            raise errors.PathNotChild(client_path, self._root_client_path)
148
149
    def transport_from_client_path(self, client_path):
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
150
        """Get a backing transport corresponding to the location referred to by
151
        a network client.
152
153
        :seealso: translate_client_path
154
        :returns: a transport cloned from self._backing_transport
155
        """
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
156
        relpath = self.translate_client_path(client_path)
2692.1.16 by Andrew Bennetts
Improve comments.
157
        return self._backing_transport.clone(relpath)
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
158
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
159
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
160
class SmartServerResponse(object):
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
161
    """A response to a client request.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
162
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
163
    This base class should not be used. Instead use
164
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
165
    """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
166
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
167
    def __init__(self, args, body=None, body_stream=None):
168
        """Constructor.
169
170
        :param args: tuple of response arguments.
171
        :param body: string of a response body.
172
        :param body_stream: iterable of bytestrings to be streamed to the
173
            client.
174
        """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
175
        self.args = args
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
176
        if body is not None and body_stream is not None:
177
            raise errors.BzrError(
178
                "'body' and 'body_stream' are mutually exclusive.")
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
179
        self.body = body
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
180
        self.body_stream = body_stream
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
181
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
182
    def __eq__(self, other):
183
        if other is None:
184
            return False
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
185
        return (other.args == self.args and
186
                other.body == self.body and
187
                other.body_stream is self.body_stream)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
188
189
    def __repr__(self):
3691.2.6 by Martin Pool
Disable RemoteBranch stacking, but get get_stacked_on_url working, and passing back exceptions
190
        return "<%s args=%r body=%r>" % (self.__class__.__name__,
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
191
            self.args, self.body)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
192
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
193
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
194
class FailedSmartServerResponse(SmartServerResponse):
195
    """A SmartServerResponse for a request which failed."""
196
197
    def is_successful(self):
198
        """FailedSmartServerResponse are not successful."""
199
        return False
200
201
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
202
class SuccessfulSmartServerResponse(SmartServerResponse):
203
    """A SmartServerResponse for a successfully completed request."""
204
205
    def is_successful(self):
206
        """SuccessfulSmartServerResponse are successful."""
207
        return True
208
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
209
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
210
class SmartServerRequestHandler(object):
211
    """Protocol logic for smart server.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
212
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
213
    This doesn't handle serialization at all, it just processes requests and
214
    creates responses.
215
    """
216
217
    # IMPORTANT FOR IMPLEMENTORS: It is important that SmartServerRequestHandler
218
    # not contain encoding or decoding logic to allow the wire protocol to vary
219
    # from the object protocol: we will want to tweak the wire protocol separate
220
    # from the object model, and ideally we will be able to do that without
221
    # having a SmartServerRequestHandler subclass for each wire protocol, rather
222
    # just a Protocol subclass.
223
224
    # TODO: Better way of representing the body for commands that take it,
225
    # and allow it to be streamed into the server.
226
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
227
    def __init__(self, backing_transport, commands, root_client_path):
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
228
        """Constructor.
229
230
        :param backing_transport: a Transport to handle requests for.
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
231
        :param commands: a registry mapping command names to SmartServerRequest
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
232
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
233
        """
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
234
        self._backing_transport = backing_transport
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
235
        self._root_client_path = root_client_path
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
236
        self._commands = commands
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
237
        self.response = None
238
        self.finished_reading = False
239
        self._command = None
240
241
    def accept_body(self, bytes):
242
        """Accept body data."""
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
243
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
244
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
245
    def end_of_body(self):
246
        """No more body data will be received."""
3923.5.2 by Andrew Bennetts
Completely delegate handling of request body chunks to the command object. The default implementation accumulates, like the existing behaviour.
247
        self._run_handler_code(self._command.do_end, (), {})
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
248
        # cannot read after this.
249
        self.finished_reading = True
250
251
    def dispatch_command(self, cmd, args):
252
        """Deprecated compatibility method.""" # XXX XXX
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
253
        try:
254
            command = self._commands.get(cmd)
255
        except LookupError:
3245.4.29 by Andrew Bennetts
Add/tidy some comments, remove dud test_errors_are_logged test, add explicit UnknownSmartMethod to v3.
256
            raise errors.UnknownSmartMethod(cmd)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
257
        self._command = command(self._backing_transport, self._root_client_path)
2018.5.24 by Andrew Bennetts
Setting NO_SMART_VFS in environment will disable VFS methods in the smart server. (Robert Collins, John Arbash Meinel, Andrew Bennetts)
258
        self._run_handler_code(self._command.execute, args, {})
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
259
260
    def _run_handler_code(self, callable, args, kwargs):
261
        """Run some handler specific code 'callable'.
262
263
        If a result is returned, it is considered to be the commands response,
264
        and finished_reading is set true, and its assigned to self.response.
265
266
        Any exceptions caught are translated and a response object created
267
        from them.
268
        """
269
        result = self._call_converting_errors(callable, args, kwargs)
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
270
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
271
        if result is not None:
272
            self.response = result
273
            self.finished_reading = True
274
275
    def _call_converting_errors(self, callable, args, kwargs):
276
        """Call callable converting errors to Response objects."""
277
        # XXX: most of this error conversion is VFS-related, and thus ought to
278
        # be in SmartServerVFSRequestHandler somewhere.
279
        try:
280
            return callable(*args, **kwargs)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
281
        except (KeyboardInterrupt, SystemExit):
282
            raise
283
        except Exception, err:
284
            err_struct = _translate_error(err)
285
            return FailedSmartServerResponse(err_struct)
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
286
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
287
    def headers_received(self, headers):
3245.4.33 by Andrew Bennetts
Remove unused no_body_received method on SmartServerRequestHandler.
288
        # Just a no-op at the moment.
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
289
        pass
290
291
    def args_received(self, args):
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
292
        cmd = args[0]
293
        args = args[1:]
294
        try:
295
            command = self._commands.get(cmd)
296
        except LookupError:
3245.4.48 by Andrew Bennetts
raise UnknownSmartMethod from dispatch_command.
297
            raise errors.UnknownSmartMethod(cmd)
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
298
        self._command = command(self._backing_transport)
299
        self._run_handler_code(self._command.execute, args, {})
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
300
3195.3.4 by Andrew Bennetts
Make the general request handler dispatch version 3 events to the specific request handler (i.e. to the SmartServerRequest instance).
301
    def end_received(self):
302
        self._run_handler_code(self._command.do_end, (), {})
3195.3.2 by Andrew Bennetts
Checkpoint first rough cut of SmartServerRequestProtocolThree, this implementation reuses the _StatefulDecoder class. Plus some attempts to start tidying the smart protocol tests.
303
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
304
    def post_body_error_received(self, error_args):
305
        # Just a no-op at the moment.
306
        pass
307
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
308
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
309
def _translate_error(err):
310
    if isinstance(err, errors.NoSuchFile):
311
        return ('NoSuchFile', err.path)
312
    elif isinstance(err, errors.FileExists):
313
        return ('FileExists', err.path)
314
    elif isinstance(err, errors.DirectoryNotEmpty):
315
        return ('DirectoryNotEmpty', err.path)
316
    elif isinstance(err, errors.ShortReadvError):
317
        return ('ShortReadvError', err.path, str(err.offset), str(err.length),
318
                str(err.actual))
319
    elif isinstance(err, errors.UnstackableRepositoryFormat):
320
        return (('UnstackableRepositoryFormat', str(err.format), err.url))
321
    elif isinstance(err, errors.UnstackableBranchFormat):
322
        return ('UnstackableBranchFormat', str(err.format), err.url)
323
    elif isinstance(err, errors.NotStacked):
324
        return ('NotStacked',)
325
    elif isinstance(err, UnicodeError):
326
        # If it is a DecodeError, than most likely we are starting
327
        # with a plain string
328
        str_or_unicode = err.object
329
        if isinstance(str_or_unicode, unicode):
330
            # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
331
            # byte) in it, so this encoding could cause broken responses.
332
            # Newer clients use protocol v3, so will be fine.
333
            val = 'u:' + str_or_unicode.encode('utf-8')
334
        else:
335
            val = 's:' + str_or_unicode.encode('base64')
336
        # This handles UnicodeEncodeError or UnicodeDecodeError
337
        return (err.__class__.__name__, err.encoding, val, str(err.start),
338
                str(err.end), err.reason)
339
    elif isinstance(err, errors.TransportNotPossible):
340
        if err.msg == "readonly transport":
341
            return ('ReadOnlyError', )
342
    elif isinstance(err, errors.ReadError):
343
        # cannot read the file
344
        return ('ReadError', err.path)
345
    elif isinstance(err, errors.PermissionDenied):
346
        return ('PermissionDenied', err.path, err.extra)
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
347
    elif isinstance(err, errors.TokenMismatch):
348
        return ('TokenMismatch', err.given_token, err.lock_token)
349
    elif isinstance(err, errors.LockContention):
350
        return ('LockContention', err.lock, err.msg)
4064.1.2 by Andrew Bennetts
Refactor server-side error translation, improve tests.
351
    # Unserialisable error.  Log it, and return a generic error
352
    trace.log_exception_quietly()
353
    return ('error', str(err))
354
355
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
356
class HelloRequest(SmartServerRequest):
2432.2.6 by Andrew Bennetts
Improve HelloRequest's docstring.
357
    """Answer a version request with the highest protocol version this server
358
    supports.
359
    """
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
360
361
    def do(self):
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
362
        return SuccessfulSmartServerResponse(('ok', '2'))
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
363
364
365
class GetBundleRequest(SmartServerRequest):
2402.1.2 by Andrew Bennetts
Deal with review comments.
366
    """Get a bundle of from the null revision to the specified revision."""
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
367
368
    def do(self, path, revision_id):
369
        # open transport relative to our base
2692.1.7 by Andrew Bennetts
Translate path in GetBundleRequest too.
370
        t = self.transport_from_client_path(path)
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
371
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
372
        repo = control.open_repository()
373
        tmpf = tempfile.TemporaryFile()
374
        base_revision = revision.NULL_REVISION
3224.5.6 by Andrew Bennetts
Don't import bzrlib.bundle in bzrlib.smart.request until it's needed.
375
        serializer.write_bundle(repo, revision_id, base_revision, tmpf)
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
376
        tmpf.seek(0)
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
377
        return SuccessfulSmartServerResponse((), tmpf.read())
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
378
379
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
380
class SmartServerIsReadonly(SmartServerRequest):
381
    # XXX: this request method belongs somewhere else.
382
383
    def do(self):
384
        if self._backing_transport.is_readonly():
385
            answer = 'yes'
386
        else:
387
            answer = 'no'
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
388
        return SuccessfulSmartServerResponse((answer,))
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
389
390
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
391
request_handlers = registry.Registry()
392
request_handlers.register_lazy(
393
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
394
request_handlers.register_lazy(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
395
    'Branch.get_config_file', 'bzrlib.smart.branch',
396
    'SmartServerBranchGetConfigFile')
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
397
request_handlers.register_lazy(
4078.2.1 by Robert Collins
Add a Branch.get_parent remote call for RemoteBranch.
398
    'Branch.get_parent', 'bzrlib.smart.branch', 'SmartServerBranchGetParent')
399
request_handlers.register_lazy(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
400
    'Branch.get_tags_bytes', 'bzrlib.smart.branch',
401
    'SmartServerBranchGetTagsBytes')
402
request_handlers.register_lazy(
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
403
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
404
request_handlers.register_lazy(
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
405
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
406
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
407
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
408
request_handlers.register_lazy(
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
409
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
410
request_handlers.register_lazy(
2018.5.77 by Wouter van Heyst
Fix typo in request_handlers registration of Branch.set_last_revision, and test that registration
411
    'Branch.set_last_revision', 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
2018.12.3 by Andrew Bennetts
Add a Branch.set_last_revision smart method, and make RemoteBranch.set_revision_history use it.
412
request_handlers.register_lazy(
2892.2.1 by Andrew Bennetts
Add Branch.set_last_revision_info smart method, and make the RemoteBranch client use it.
413
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
414
    'SmartServerBranchRequestSetLastRevisionInfo')
415
request_handlers.register_lazy(
3441.5.25 by Andrew Bennetts
Rename Branch.set_last_revision_descendant verb to Branch.set_last_revision_ex. It's a cop out, but at least it's not misleading.
416
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
417
    'SmartServerBranchRequestSetLastRevisionEx')
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
418
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
419
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
420
request_handlers.register_lazy(
4070.2.3 by Robert Collins
Get BzrDir.cloning_metadir working.
421
    'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
422
    'SmartServerBzrDirRequestCloningMetaDir')
423
request_handlers.register_lazy(
4084.2.1 by Robert Collins
Make accessing a branch.tags.get_tag_dict use a smart[er] method rather than VFS calls and real objects.
424
    'BzrDir.create_branch', 'bzrlib.smart.bzrdir',
425
    'SmartServerRequestCreateBranch')
426
request_handlers.register_lazy(
427
    'BzrDir.create_repository', 'bzrlib.smart.bzrdir',
428
    'SmartServerRequestCreateRepository')
429
request_handlers.register_lazy(
430
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir',
431
    'SmartServerRequestFindRepositoryV1')
432
request_handlers.register_lazy(
433
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir',
434
    'SmartServerRequestFindRepositoryV2')
435
request_handlers.register_lazy(
436
    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
437
    'SmartServerRequestFindRepositoryV3')
438
request_handlers.register_lazy(
439
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
440
    'SmartServerRequestInitializeBzrDir')
441
request_handlers.register_lazy(
442
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
443
    'SmartServerRequestOpenBranch')
444
request_handlers.register_lazy(
445
    'BzrDir.open_branchV2', 'bzrlib.smart.bzrdir',
446
    'SmartServerRequestOpenBranchV2')
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
447
request_handlers.register_lazy(
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
448
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
449
request_handlers.register_lazy(
450
    'get', 'bzrlib.smart.vfs', 'GetRequest')
451
request_handlers.register_lazy(
452
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
453
request_handlers.register_lazy(
454
    'has', 'bzrlib.smart.vfs', 'HasRequest')
455
request_handlers.register_lazy(
456
    'hello', 'bzrlib.smart.request', 'HelloRequest')
457
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
458
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
459
request_handlers.register_lazy(
460
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
461
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
462
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
463
request_handlers.register_lazy(
464
    'move', 'bzrlib.smart.vfs', 'MoveRequest')
465
request_handlers.register_lazy(
466
    'put', 'bzrlib.smart.vfs', 'PutRequest')
467
request_handlers.register_lazy(
468
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
469
request_handlers.register_lazy(
470
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
471
request_handlers.register_lazy(
472
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
3452.2.2 by Andrew Bennetts
Experimental PackRepository.{check_references,autopack} RPCs.
473
request_handlers.register_lazy(
474
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
475
    'SmartServerPackRepositoryAutopack')
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
476
request_handlers.register_lazy('Repository.gather_stats',
477
                               'bzrlib.smart.repository',
478
                               'SmartServerRepositoryGatherStats')
3842.3.3 by Andrew Bennetts
Remove RPC registration for VersionedFiles.get_parent_map, not Repository.get_parent_map.
479
request_handlers.register_lazy('Repository.get_parent_map',
480
                               'bzrlib.smart.repository',
481
                               'SmartServerRepositoryGetParentMap')
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
482
request_handlers.register_lazy(
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
483
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
484
request_handlers.register_lazy(
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
485
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
486
request_handlers.register_lazy(
4022.1.6 by Robert Collins
Cherrypick and polish the RemoteSink for streaming push.
487
    'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
488
request_handlers.register_lazy(
4144.3.1 by Andrew Bennetts
Add Repository.insert_stream_locked server-side implementation, plus tests for server-side _translate_error.
489
    'Repository.insert_stream_locked', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStreamLocked')
490
request_handlers.register_lazy(
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
491
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
492
request_handlers.register_lazy(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
493
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
494
request_handlers.register_lazy(
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
495
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
496
    'SmartServerRepositorySetMakeWorkingTrees')
497
request_handlers.register_lazy(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
498
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
499
request_handlers.register_lazy(
4060.1.5 by Robert Collins
Verb change name requested by Andrew.
500
    'Repository.get_stream', 'bzrlib.smart.repository',
501
    'SmartServerRepositoryGetStream')
4060.1.4 by Robert Collins
Streaming fetch from remote servers.
502
request_handlers.register_lazy(
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
503
    'Repository.tarball', 'bzrlib.smart.repository',
504
    'SmartServerRepositoryTarball')
505
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
506
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
507
request_handlers.register_lazy(
508
    'stat', 'bzrlib.smart.vfs', 'StatRequest')
2018.5.26 by Andrew Bennetts
Extract a simple SmartClient class from RemoteTransport, and a hack to avoid VFS operations when probing for a bzrdir over a smart transport.
509
request_handlers.register_lazy(
2018.5.95 by Andrew Bennetts
Add a Transport.is_readonly remote call, let {Branch,Repository}.lock_write remote call return UnlockableTransport, and miscellaneous test fixes.
510
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
511
request_handlers.register_lazy(
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
512
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')