~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
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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,
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
36
    urlutils,
2402.1.2 by Andrew Bennetts
Deal with review comments.
37
    )
3224.5.6 by Andrew Bennetts
Don't import bzrlib.bundle in bzrlib.smart.request until it's needed.
38
from bzrlib.lazy_import import lazy_import
39
lazy_import(globals(), """
40
from bzrlib.bundle import serializer
41
""")
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
42
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.
43
44
class SmartServerRequest(object):
2692.1.10 by Andrew Bennetts
More docstring polish
45
    """Base class for request handlers.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
46
2692.1.10 by Andrew Bennetts
More docstring polish
47
    To define a new request, subclass this class and override the `do` method
48
    (and if appropriate, `do_body` as well).  Request implementors should take
49
    care to call `translate_client_path` and `transport_from_client_path` as
50
    appropriate when dealing with paths received from the client.
51
    """
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.
52
    # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
53
    # *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.
54
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
55
    def __init__(self, backing_transport, root_client_path='/'):
2402.1.2 by Andrew Bennetts
Deal with review comments.
56
        """Constructor.
57
58
        :param backing_transport: the base transport to be used when performing
59
            this request.
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
60
        :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.
61
            backing_transport.  This is used to interpret relpaths received
62
            from the client.  Clients will not be able to refer to paths above
2692.1.16 by Andrew Bennetts
Improve comments.
63
            this root.  If root_client_path is None, then no translation will
64
            be performed on client paths.  Default is '/'.
2402.1.2 by Andrew Bennetts
Deal with review comments.
65
        """
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.
66
        self._backing_transport = backing_transport
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
67
        if root_client_path is not None:
68
            if not root_client_path.startswith('/'):
69
                root_client_path = '/' + root_client_path
70
            if not root_client_path.endswith('/'):
71
                root_client_path += '/'
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
72
        self._root_client_path = root_client_path
3842.3.19 by Andrew Bennetts
Tweaks suggested by review.
73
        self._body_chunks = []
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
74
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)
75
    def _check_enabled(self):
76
        """Raises DisabledMethod if this method is disabled."""
77
        pass
78
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
79
    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)
80
        """Mandatory extension point for SmartServerRequest subclasses.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
81
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)
82
        Subclasses must implement this.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
83
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
84
        This should return a SmartServerResponse if this command expects to
85
        receive no body.
86
        """
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
87
        raise NotImplementedError(self.do)
88
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)
89
    def execute(self, *args):
90
        """Public entry point to execute this request.
91
92
        It will return a SmartServerResponse if the command does not expect a
93
        body.
94
95
        :param *args: the arguments of the request.
96
        """
97
        self._check_enabled()
98
        return self.do(*args)
99
2018.5.5 by Andrew Bennetts
Pass body_bytes directly to SmartServerRequest.do_body
100
    def do_body(self, body_bytes):
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
101
        """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.
102
103
        The do() method is still called, and must have returned None.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
104
2018.5.19 by Andrew Bennetts
Add docstrings to all the new modules, and a few other places.
105
        Must return a SmartServerResponse.
106
        """
3990.3.2 by Andrew Bennetts
Fix the do_body NotImplementedError log spam.
107
        if body_bytes != '':
3990.3.3 by Andrew Bennetts
Add a test that unexpected request bodies trigger a SmartProtocolError from request implementations.
108
            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.
109
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).
110
    def do_chunk(self, chunk_bytes):
111
        """Called with each body chunk if the request has a streamed body.
112
113
        The do() method is still called, and must have returned None.
114
        """
3842.3.19 by Andrew Bennetts
Tweaks suggested by review.
115
        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).
116
117
    def do_end(self):
118
        """Called when the end of the request has been received."""
3842.3.19 by Andrew Bennetts
Tweaks suggested by review.
119
        body_bytes = ''.join(self._body_chunks)
120
        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.
121
        return self.do_body(body_bytes)
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
122
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
123
    def translate_client_path(self, client_path):
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
124
        """Translate a path received from a network client into a local
125
        relpath.
126
127
        All paths received from the client *must* be translated.
128
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
129
        :param client_path: the path from the client.
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
130
        :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.
131
            (unlike the untranslated client_path, which must not be used with
132
            the backing transport).
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
133
        """
2692.1.14 by Andrew Bennetts
All WSGI tests passing, and manual testing works too.
134
        if self._root_client_path is None:
135
            # no translation necessary!
136
            return client_path
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
137
        if not client_path.startswith('/'):
138
            client_path = '/' + client_path
139
        if client_path.startswith(self._root_client_path):
140
            path = client_path[len(self._root_client_path):]
141
            relpath = urlutils.joinpath('/', path)
3376.2.4 by Martin Pool
Remove every assert statement from bzrlib!
142
            if not relpath.startswith('/'):
143
                raise ValueError(relpath)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
144
            return '.' + relpath
145
        else:
146
            raise errors.PathNotChild(client_path, self._root_client_path)
147
148
    def transport_from_client_path(self, client_path):
2692.1.9 by Andrew Bennetts
Docstrings for translate_client_path and transport_from_client_path.
149
        """Get a backing transport corresponding to the location referred to by
150
        a network client.
151
152
        :seealso: translate_client_path
153
        :returns: a transport cloned from self._backing_transport
154
        """
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
155
        relpath = self.translate_client_path(client_path)
2692.1.16 by Andrew Bennetts
Improve comments.
156
        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).
157
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
158
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
159
class SmartServerResponse(object):
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
160
    """A response to a client request.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
161
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
162
    This base class should not be used. Instead use
163
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
164
    """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
165
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
166
    def __init__(self, args, body=None, body_stream=None):
167
        """Constructor.
168
169
        :param args: tuple of response arguments.
170
        :param body: string of a response body.
171
        :param body_stream: iterable of bytestrings to be streamed to the
172
            client.
173
        """
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
174
        self.args = args
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
175
        if body is not None and body_stream is not None:
176
            raise errors.BzrError(
177
                "'body' and 'body_stream' are mutually exclusive.")
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
178
        self.body = body
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
179
        self.body_stream = body_stream
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
180
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
181
    def __eq__(self, other):
182
        if other is None:
183
            return False
2748.4.2 by Andrew Bennetts
Add protocol (version two) support for streaming bodies (using chunking) in responses.
184
        return (other.args == self.args and
185
                other.body == self.body and
186
                other.body_stream is self.body_stream)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
187
188
    def __repr__(self):
3691.2.6 by Martin Pool
Disable RemoteBranch stacking, but get get_stacked_on_url working, and passing back exceptions
189
        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.
190
            self.args, self.body)
2402.1.1 by Andrew Bennetts
Use the Command pattern for handling smart server commands.
191
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
192
2432.4.2 by Robert Collins
Add FailedSmartServerResponse.
193
class FailedSmartServerResponse(SmartServerResponse):
194
    """A SmartServerResponse for a request which failed."""
195
196
    def is_successful(self):
197
        """FailedSmartServerResponse are not successful."""
198
        return False
199
200
2432.4.1 by Robert Collins
Add SuccessfulSmartServerResponse.
201
class SuccessfulSmartServerResponse(SmartServerResponse):
202
    """A SmartServerResponse for a successfully completed request."""
203
204
    def is_successful(self):
205
        """SuccessfulSmartServerResponse are successful."""
206
        return True
207
2018.5.16 by Andrew Bennetts
Move SmartServerResponse to smart/request.py, untangling more import dependencies.
208
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
209
class SmartServerRequestHandler(object):
210
    """Protocol logic for smart server.
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
211
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
212
    This doesn't handle serialization at all, it just processes requests and
213
    creates responses.
214
    """
215
216
    # IMPORTANT FOR IMPLEMENTORS: It is important that SmartServerRequestHandler
217
    # not contain encoding or decoding logic to allow the wire protocol to vary
218
    # from the object protocol: we will want to tweak the wire protocol separate
219
    # from the object model, and ideally we will be able to do that without
220
    # having a SmartServerRequestHandler subclass for each wire protocol, rather
221
    # just a Protocol subclass.
222
223
    # TODO: Better way of representing the body for commands that take it,
224
    # and allow it to be streamed into the server.
225
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
226
    def __init__(self, backing_transport, commands, root_client_path):
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
227
        """Constructor.
228
229
        :param backing_transport: a Transport to handle requests for.
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
230
        :param commands: a registry mapping command names to SmartServerRequest
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
231
            subclasses. e.g. bzrlib.transport.smart.vfs.vfs_commands.
232
        """
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
233
        self._backing_transport = backing_transport
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
234
        self._root_client_path = root_client_path
2018.5.17 by Andrew Bennetts
Paramaterise the commands handled by SmartServerRequestHandler.
235
        self._commands = commands
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
236
        self.response = None
237
        self.finished_reading = False
238
        self._command = None
239
240
    def accept_body(self, bytes):
241
        """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.
242
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
3943.8.1 by Marius Kruger
remove all trailing whitespace from bzr source
243
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
244
    def end_of_body(self):
245
        """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.
246
        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.
247
        # cannot read after this.
248
        self.finished_reading = True
249
250
    def dispatch_command(self, cmd, args):
251
        """Deprecated compatibility method.""" # XXX XXX
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
252
        try:
253
            command = self._commands.get(cmd)
254
        except LookupError:
3245.4.29 by Andrew Bennetts
Add/tidy some comments, remove dud test_errors_are_logged test, add explicit UnknownSmartMethod to v3.
255
            raise errors.UnknownSmartMethod(cmd)
2692.1.1 by Andrew Bennetts
Add translate_client_path method to SmartServerRequest.
256
        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)
257
        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.
258
259
    def _run_handler_code(self, callable, args, kwargs):
260
        """Run some handler specific code 'callable'.
261
262
        If a result is returned, it is considered to be the commands response,
263
        and finished_reading is set true, and its assigned to self.response.
264
265
        Any exceptions caught are translated and a response object created
266
        from them.
267
        """
268
        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.
269
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
270
        if result is not None:
271
            self.response = result
272
            self.finished_reading = True
273
274
    def _call_converting_errors(self, callable, args, kwargs):
275
        """Call callable converting errors to Response objects."""
276
        # XXX: most of this error conversion is VFS-related, and thus ought to
277
        # be in SmartServerVFSRequestHandler somewhere.
278
        try:
279
            return callable(*args, **kwargs)
280
        except errors.NoSuchFile, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
281
            return FailedSmartServerResponse(('NoSuchFile', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
282
        except errors.FileExists, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
283
            return FailedSmartServerResponse(('FileExists', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
284
        except errors.DirectoryNotEmpty, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
285
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
286
        except errors.ShortReadvError, e:
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
287
            return FailedSmartServerResponse(('ShortReadvError',
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
288
                e.path, str(e.offset), str(e.length), str(e.actual)))
3691.2.6 by Martin Pool
Disable RemoteBranch stacking, but get get_stacked_on_url working, and passing back exceptions
289
        except errors.UnstackableRepositoryFormat, e:
290
            return FailedSmartServerResponse(('UnstackableRepositoryFormat',
291
                str(e.format), e.url))
292
        except errors.UnstackableBranchFormat, e:
293
            return FailedSmartServerResponse(('UnstackableBranchFormat',
294
                str(e.format), e.url))
295
        except errors.NotStacked, e:
296
            return FailedSmartServerResponse(('NotStacked',))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
297
        except UnicodeError, e:
298
            # If it is a DecodeError, than most likely we are starting
299
            # with a plain string
300
            str_or_unicode = e.object
301
            if isinstance(str_or_unicode, unicode):
3779.3.1 by Andrew Bennetts
Move encoding/decoding logic of PermissionDenied and ReadError so that it happens for all RPCs.
302
                # XXX: UTF-8 might have \x01 (our protocol v1 and v2 seperator
303
                # byte) in it, so this encoding could cause broken responses.
304
                # Newer clients use protocol v3, so will be fine.
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
305
                val = 'u:' + str_or_unicode.encode('utf-8')
306
            else:
307
                val = 's:' + str_or_unicode.encode('base64')
308
            # This handles UnicodeEncodeError or UnicodeDecodeError
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
309
            return FailedSmartServerResponse((e.__class__.__name__,
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
310
                    e.encoding, val, str(e.start), str(e.end), e.reason))
311
        except errors.TransportNotPossible, e:
312
            if e.msg == "readonly transport":
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
313
                return FailedSmartServerResponse(('ReadOnlyError', ))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
314
            else:
315
                raise
3779.3.1 by Andrew Bennetts
Move encoding/decoding logic of PermissionDenied and ReadError so that it happens for all RPCs.
316
        except errors.ReadError, e:
317
            # cannot read the file
318
            return FailedSmartServerResponse(('ReadError', e.path))
319
        except errors.PermissionDenied, e:
320
            return FailedSmartServerResponse(
321
                ('PermissionDenied', e.path, e.extra))
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
322
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.
323
    def headers_received(self, headers):
3245.4.33 by Andrew Bennetts
Remove unused no_body_received method on SmartServerRequestHandler.
324
        # 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.
325
        pass
326
327
    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).
328
        cmd = args[0]
329
        args = args[1:]
330
        try:
331
            command = self._commands.get(cmd)
332
        except LookupError:
3245.4.48 by Andrew Bennetts
raise UnknownSmartMethod from dispatch_command.
333
            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).
334
        self._command = command(self._backing_transport)
335
        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.
336
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).
337
    def end_received(self):
338
        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.
339
3923.5.4 by Andrew Bennetts
Allow a request's body part(s) to be followed by an error.
340
    def post_body_error_received(self, error_args):
341
        # Just a no-op at the moment.
342
        pass
343
2018.5.14 by Andrew Bennetts
Move SmartTCPServer to smart/server.py, and SmartServerRequestHandler to smart/request.py.
344
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
345
class HelloRequest(SmartServerRequest):
2432.2.6 by Andrew Bennetts
Improve HelloRequest's docstring.
346
    """Answer a version request with the highest protocol version this server
347
    supports.
348
    """
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
349
350
    def do(self):
3245.4.59 by Andrew Bennetts
Various tweaks in response to Martin's review.
351
        return SuccessfulSmartServerResponse(('ok', '2'))
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
352
353
354
class GetBundleRequest(SmartServerRequest):
2402.1.2 by Andrew Bennetts
Deal with review comments.
355
    """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.
356
357
    def do(self, path, revision_id):
358
        # open transport relative to our base
2692.1.7 by Andrew Bennetts
Translate path in GetBundleRequest too.
359
        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.
360
        control, extra_path = bzrdir.BzrDir.open_containing_from_transport(t)
361
        repo = control.open_repository()
362
        tmpf = tempfile.TemporaryFile()
363
        base_revision = revision.NULL_REVISION
3224.5.6 by Andrew Bennetts
Don't import bzrlib.bundle in bzrlib.smart.request until it's needed.
364
        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.
365
        tmpf.seek(0)
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
366
        return SuccessfulSmartServerResponse((), tmpf.read())
2018.5.6 by Andrew Bennetts
Tidy ups, and turn do_hello and do_get_bundle into command objects.
367
368
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.
369
class SmartServerIsReadonly(SmartServerRequest):
370
    # XXX: this request method belongs somewhere else.
371
372
    def do(self):
373
        if self._backing_transport.is_readonly():
374
            answer = 'yes'
375
        else:
376
            answer = 'no'
2432.4.5 by Robert Collins
Make using SuccessfulSmartServerResponse and FailedSmartServerResponse mandatory rather than optional in smart server logic.
377
        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.
378
379
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
380
request_handlers = registry.Registry()
381
request_handlers.register_lazy(
382
    'append', 'bzrlib.smart.vfs', 'AppendRequest')
383
request_handlers.register_lazy(
2018.5.59 by Robert Collins
Get BranchConfig working somewhat on RemoteBranches (Robert Collins, Vincent Ladeuil).
384
    'Branch.get_config_file', 'bzrlib.smart.branch', 'SmartServerBranchGetConfigFile')
385
request_handlers.register_lazy(
3691.2.5 by Martin Pool
Add Branch.get_stacked_on_url rpc and tests for same
386
    'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
387
request_handlers.register_lazy(
2018.5.51 by Wouter van Heyst
Test and implement RemoteBranch.last_revision_info()
388
    'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
389
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
390
    'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
391
request_handlers.register_lazy(
2018.5.38 by Robert Collins
Implement RemoteBranch.revision_history().
392
    'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
393
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
394
    '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.
395
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.
396
    'Branch.set_last_revision_info', 'bzrlib.smart.branch',
397
    'SmartServerBranchRequestSetLastRevisionInfo')
398
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.
399
    'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
400
    'SmartServerBranchRequestSetLastRevisionEx')
3441.5.6 by Andrew Bennetts
Greatly simplify RemoteBranch.update_revisions. Still needs more tests.
401
request_handlers.register_lazy(
2018.5.79 by Andrew Bennetts
Implement RemoteBranch.lock_write/unlock as smart operations.
402
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
403
request_handlers.register_lazy(
4032.3.2 by Robert Collins
Create and use a RPC call to create branches on bzr servers rather than using VFS calls.
404
    'BzrDir.create_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestCreateBranch')
405
request_handlers.register_lazy(
4017.3.2 by Robert Collins
Reduce the number of round trips required to create a repository over the network.
406
    'BzrDir.create_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestCreateRepository')
407
request_handlers.register_lazy(
3221.3.2 by Robert Collins
* New remote method ``RemoteBzrDir.find_repositoryV2`` adding support for
408
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')
409
request_handlers.register_lazy(
410
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
2018.5.34 by Robert Collins
Get test_remote.BasicRemoteObjectTests.test_open_remote_branch passing by implementing a remote method BzrDir.find_repository.
411
request_handlers.register_lazy(
2018.5.42 by Robert Collins
Various hopefully improvements, but wsgi is broken, handing over to spiv :).
412
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
413
request_handlers.register_lazy(
2018.6.1 by Robert Collins
Implement a BzrDir.open_branch smart server method for opening a branch without VFS.
414
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
415
request_handlers.register_lazy(
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
416
    'delete', 'bzrlib.smart.vfs', 'DeleteRequest')
417
request_handlers.register_lazy(
418
    'get', 'bzrlib.smart.vfs', 'GetRequest')
419
request_handlers.register_lazy(
420
    'get_bundle', 'bzrlib.smart.request', 'GetBundleRequest')
421
request_handlers.register_lazy(
422
    'has', 'bzrlib.smart.vfs', 'HasRequest')
423
request_handlers.register_lazy(
424
    'hello', 'bzrlib.smart.request', 'HelloRequest')
425
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
426
    'iter_files_recursive', 'bzrlib.smart.vfs', 'IterFilesRecursiveRequest')
2018.5.23 by Andrew Bennetts
Use a Registry for smart server command handlers.
427
request_handlers.register_lazy(
428
    'list_dir', 'bzrlib.smart.vfs', 'ListDirRequest')
429
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
430
    'mkdir', 'bzrlib.smart.vfs', 'MkdirRequest')
431
request_handlers.register_lazy(
432
    'move', 'bzrlib.smart.vfs', 'MoveRequest')
433
request_handlers.register_lazy(
434
    'put', 'bzrlib.smart.vfs', 'PutRequest')
435
request_handlers.register_lazy(
436
    'put_non_atomic', 'bzrlib.smart.vfs', 'PutNonAtomicRequest')
437
request_handlers.register_lazy(
438
    'readv', 'bzrlib.smart.vfs', 'ReadvRequest')
439
request_handlers.register_lazy(
440
    'rename', 'bzrlib.smart.vfs', 'RenameRequest')
3452.2.2 by Andrew Bennetts
Experimental PackRepository.{check_references,autopack} RPCs.
441
request_handlers.register_lazy(
442
    'PackRepository.autopack', 'bzrlib.smart.packrepository',
443
    'SmartServerPackRepositoryAutopack')
2018.10.2 by v.ladeuil+lp at free
gather_stats server side and request registration
444
request_handlers.register_lazy('Repository.gather_stats',
445
                               'bzrlib.smart.repository',
446
                               'SmartServerRepositoryGatherStats')
3842.3.3 by Andrew Bennetts
Remove RPC registration for VersionedFiles.get_parent_map, not Repository.get_parent_map.
447
request_handlers.register_lazy('Repository.get_parent_map',
448
                               'bzrlib.smart.repository',
449
                               'SmartServerRepositoryGetParentMap')
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
450
request_handlers.register_lazy(
2018.5.67 by Wouter van Heyst
Implement RemoteRepository.get_revision_graph (Wouter van Heyst, Robert Collins)
451
    'Repository.get_revision_graph', 'bzrlib.smart.repository', 'SmartServerRepositoryGetRevisionGraph')
452
request_handlers.register_lazy(
2018.5.40 by Robert Collins
Implement a remote Repository.has_revision method.
453
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
454
request_handlers.register_lazy(
4022.1.6 by Robert Collins
Cherrypick and polish the RemoteSink for streaming push.
455
    'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
456
request_handlers.register_lazy(
2018.5.57 by Robert Collins
Implement RemoteRepository.is_shared (Robert Collins, Vincent Ladeuil).
457
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
458
request_handlers.register_lazy(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
459
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
460
request_handlers.register_lazy(
4017.3.4 by Robert Collins
Create a verb for Repository.set_make_working_trees.
461
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
462
    'SmartServerRepositorySetMakeWorkingTrees')
463
request_handlers.register_lazy(
2018.5.78 by Andrew Bennetts
Implement RemoteRepository.lock_write/unlock to expect and send tokens over the
464
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
465
request_handlers.register_lazy(
2018.18.1 by Martin Pool
Add stub Repository.tarball smart method
466
    'Repository.tarball', 'bzrlib.smart.repository',
467
    'SmartServerRepositoryTarball')
468
request_handlers.register_lazy(
2018.5.37 by Andrew Bennetts
Make sure all the request handlers in bzrlib/smart/vfs.py have consistent names.
469
    'rmdir', 'bzrlib.smart.vfs', 'RmdirRequest')
470
request_handlers.register_lazy(
471
    '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.
472
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.
473
    'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
474
request_handlers.register_lazy(
2018.5.163 by Andrew Bennetts
Deal with various review comments from Robert.
475
    'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')