~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/smart/request.py

  • Committer: Martin Pool
  • Date: 2009-03-03 03:01:49 UTC
  • mfrom: (4070 +trunk)
  • mto: This revision was merged to the branch mainline in revision 4073.
  • Revision ID: mbp@sourcefrog.net-20090303030149-8p8o8hszdtqa7w8f
merge trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
33
33
    errors,
34
34
    registry,
35
35
    revision,
 
36
    trace,
36
37
    urlutils,
37
38
    )
38
39
from bzrlib.lazy_import import lazy_import
43
44
 
44
45
class SmartServerRequest(object):
45
46
    """Base class for request handlers.
46
 
    
 
47
 
47
48
    To define a new request, subclass this class and override the `do` method
48
49
    (and if appropriate, `do_body` as well).  Request implementors should take
49
50
    care to call `translate_client_path` and `transport_from_client_path` as
78
79
 
79
80
    def do(self, *args):
80
81
        """Mandatory extension point for SmartServerRequest subclasses.
81
 
        
 
82
 
82
83
        Subclasses must implement this.
83
 
        
 
84
 
84
85
        This should return a SmartServerResponse if this command expects to
85
86
        receive no body.
86
87
        """
101
102
        """Called if the client sends a body with the request.
102
103
 
103
104
        The do() method is still called, and must have returned None.
104
 
        
 
105
 
105
106
        Must return a SmartServerResponse.
106
107
        """
107
108
        if body_bytes != '':
119
120
        body_bytes = ''.join(self._body_chunks)
120
121
        self._body_chunks = None
121
122
        return self.do_body(body_bytes)
122
 
    
 
123
 
123
124
    def translate_client_path(self, client_path):
124
125
        """Translate a path received from a network client into a local
125
126
        relpath.
158
159
 
159
160
class SmartServerResponse(object):
160
161
    """A response to a client request.
161
 
    
 
162
 
162
163
    This base class should not be used. Instead use
163
164
    SuccessfulSmartServerResponse and FailedSmartServerResponse as appropriate.
164
165
    """
208
209
 
209
210
class SmartServerRequestHandler(object):
210
211
    """Protocol logic for smart server.
211
 
    
 
212
 
212
213
    This doesn't handle serialization at all, it just processes requests and
213
214
    creates responses.
214
215
    """
240
241
    def accept_body(self, bytes):
241
242
        """Accept body data."""
242
243
        self._run_handler_code(self._command.do_chunk, (bytes,), {})
243
 
        
 
244
 
244
245
    def end_of_body(self):
245
246
        """No more body data will be received."""
246
247
        self._run_handler_code(self._command.do_end, (), {})
277
278
        # be in SmartServerVFSRequestHandler somewhere.
278
279
        try:
279
280
            return callable(*args, **kwargs)
280
 
        except errors.NoSuchFile, e:
281
 
            return FailedSmartServerResponse(('NoSuchFile', e.path))
282
 
        except errors.FileExists, e:
283
 
            return FailedSmartServerResponse(('FileExists', e.path))
284
 
        except errors.DirectoryNotEmpty, e:
285
 
            return FailedSmartServerResponse(('DirectoryNotEmpty', e.path))
286
 
        except errors.ShortReadvError, e:
287
 
            return FailedSmartServerResponse(('ShortReadvError',
288
 
                e.path, str(e.offset), str(e.length), str(e.actual)))
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',))
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):
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.
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
309
 
            return FailedSmartServerResponse((e.__class__.__name__,
310
 
                    e.encoding, val, str(e.start), str(e.end), e.reason))
311
 
        except errors.TransportNotPossible, e:
312
 
            if e.msg == "readonly transport":
313
 
                return FailedSmartServerResponse(('ReadOnlyError', ))
314
 
            else:
315
 
                raise
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))
 
281
        except (KeyboardInterrupt, SystemExit):
 
282
            raise
 
283
        except Exception, err:
 
284
            err_struct = _translate_error(err)
 
285
            return FailedSmartServerResponse(err_struct)
322
286
 
323
287
    def headers_received(self, headers):
324
288
        # Just a no-op at the moment.
342
306
        pass
343
307
 
344
308
 
 
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)
 
347
    # Unserialisable error.  Log it, and return a generic error
 
348
    trace.log_exception_quietly()
 
349
    return ('error', str(err))
 
350
 
 
351
 
345
352
class HelloRequest(SmartServerRequest):
346
353
    """Answer a version request with the highest protocol version this server
347
354
    supports.
401
408
request_handlers.register_lazy(
402
409
    'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
403
410
request_handlers.register_lazy(
 
411
    'BzrDir.create_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestCreateBranch')
 
412
request_handlers.register_lazy(
 
413
    'BzrDir.create_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestCreateRepository')
 
414
request_handlers.register_lazy(
404
415
    'BzrDir.find_repository', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV1')
405
416
request_handlers.register_lazy(
406
417
    'BzrDir.find_repositoryV2', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV2')
407
418
request_handlers.register_lazy(
 
419
    'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir', 'SmartServerRequestFindRepositoryV3')
 
420
request_handlers.register_lazy(
408
421
    'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir', 'SmartServerRequestInitializeBzrDir')
409
422
request_handlers.register_lazy(
410
423
    'BzrDir.open_branch', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBranch')
448
461
request_handlers.register_lazy(
449
462
    'Repository.has_revision', 'bzrlib.smart.repository', 'SmartServerRequestHasRevision')
450
463
request_handlers.register_lazy(
 
464
    'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
 
465
request_handlers.register_lazy(
451
466
    'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
452
467
request_handlers.register_lazy(
453
468
    'Repository.lock_write', 'bzrlib.smart.repository', 'SmartServerRepositoryLockWrite')
454
469
request_handlers.register_lazy(
 
470
    'Repository.set_make_working_trees', 'bzrlib.smart.repository',
 
471
    'SmartServerRepositorySetMakeWorkingTrees')
 
472
request_handlers.register_lazy(
455
473
    'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
456
474
request_handlers.register_lazy(
 
475
    'Repository.get_stream', 'bzrlib.smart.repository',
 
476
    'SmartServerRepositoryGetStream')
 
477
request_handlers.register_lazy(
457
478
    'Repository.tarball', 'bzrlib.smart.repository',
458
479
    'SmartServerRepositoryTarball')
459
480
request_handlers.register_lazy(