14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
"""Infrastructure for server-side request handlers.
19
Interesting module attributes:
20
* The request_handlers registry maps verb names to SmartServerRequest
22
* The jail_info threading.local() object is used to prevent accidental
23
opening of BzrDirs outside of the backing transport, or any other
24
transports placed in jail_info.transports. The jail_info is reset on
25
every call into a request handler (which can happen an arbitrary number
26
of times during a request).
17
"""Basic server-side logic for dealing with requests.
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.
25
The request_handlers registry tracks SmartServerRequest classes (rather than
26
SmartServerRequestHandler).
29
# XXX: The class names are a little confusing: the protocol will instantiate a
30
# SmartServerRequestHandler, whose dispatch_command method creates an instance
31
# of a SmartServerRequest subclass.
37
31
from bzrlib import (
51
jail_info = threading.local()
52
jail_info.transports = None
56
bzrdir.BzrDir.hooks.install_named_hook(
57
'pre_open', _pre_open_hook, 'checking server jail')
60
def _pre_open_hook(transport):
61
allowed_transports = getattr(jail_info, 'transports', None)
62
if allowed_transports is None:
64
abspath = transport.base
65
for allowed_transport in allowed_transports:
67
allowed_transport.relpath(abspath)
68
except errors.PathNotChild:
72
raise errors.JailBreak(abspath)
78
45
class SmartServerRequest(object):
79
46
"""Base class for request handlers.
154
121
self._body_chunks = None
155
122
return self.do_body(body_bytes)
157
def setup_jail(self):
158
jail_info.transports = [self._backing_transport]
160
def teardown_jail(self):
161
jail_info.transports = None
163
124
def translate_client_path(self, client_path):
164
125
"""Translate a path received from a network client into a local
176
137
return client_path
177
138
if not client_path.startswith('/'):
178
139
client_path = '/' + client_path
179
if client_path + '/' == self._root_client_path:
181
140
if client_path.startswith(self._root_client_path):
182
141
path = client_path[len(self._root_client_path):]
183
142
relpath = urlutils.joinpath('/', path)
282
241
def accept_body(self, bytes):
283
242
"""Accept body data."""
284
if self._command is None:
285
# no active command object, so ignore the event.
287
243
self._run_handler_code(self._command.do_chunk, (bytes,), {})
289
245
def end_of_body(self):
321
277
# XXX: most of this error conversion is VFS-related, and thus ought to
322
278
# be in SmartServerVFSRequestHandler somewhere.
324
self._command.setup_jail()
326
return callable(*args, **kwargs)
328
self._command.teardown_jail()
280
return callable(*args, **kwargs)
329
281
except (KeyboardInterrupt, SystemExit):
331
283
except Exception, err:
347
299
self._run_handler_code(self._command.execute, args, {})
349
301
def end_received(self):
350
if self._command is None:
351
# no active command object, so ignore the event.
353
302
self._run_handler_code(self._command.do_end, (), {})
355
304
def post_body_error_received(self, error_args):
364
313
return ('FileExists', err.path)
365
314
elif isinstance(err, errors.DirectoryNotEmpty):
366
315
return ('DirectoryNotEmpty', err.path)
367
elif isinstance(err, errors.IncompatibleRepositories):
368
return ('IncompatibleRepositories', str(err.source), str(err.target),
370
316
elif isinstance(err, errors.ShortReadvError):
371
317
return ('ShortReadvError', err.path, str(err.offset), str(err.length),
401
347
elif isinstance(err, errors.TokenMismatch):
402
348
return ('TokenMismatch', err.given_token, err.lock_token)
403
349
elif isinstance(err, errors.LockContention):
404
return ('LockContention',)
350
return ('LockContention', err.lock, err.msg)
405
351
# Unserialisable error. Log it, and return a generic error
406
352
trace.log_exception_quietly()
407
353
return ('error', str(err))
454
400
'Branch.get_tags_bytes', 'bzrlib.smart.branch',
455
401
'SmartServerBranchGetTagsBytes')
456
402
request_handlers.register_lazy(
457
'Branch.set_tags_bytes', 'bzrlib.smart.branch',
458
'SmartServerBranchSetTagsBytes')
459
request_handlers.register_lazy(
460
403
'Branch.get_stacked_on_url', 'bzrlib.smart.branch', 'SmartServerBranchRequestGetStackedOnURL')
461
404
request_handlers.register_lazy(
462
405
'Branch.last_revision_info', 'bzrlib.smart.branch', 'SmartServerBranchRequestLastRevisionInfo')
463
406
request_handlers.register_lazy(
464
407
'Branch.lock_write', 'bzrlib.smart.branch', 'SmartServerBranchRequestLockWrite')
465
request_handlers.register_lazy( 'Branch.revision_history',
466
'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
467
request_handlers.register_lazy( 'Branch.set_config_option',
468
'bzrlib.smart.branch', 'SmartServerBranchRequestSetConfigOption')
469
request_handlers.register_lazy( 'Branch.set_last_revision',
470
'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
408
request_handlers.register_lazy(
409
'Branch.revision_history', 'bzrlib.smart.branch', 'SmartServerRequestRevisionHistory')
410
request_handlers.register_lazy(
411
'Branch.set_last_revision', 'bzrlib.smart.branch', 'SmartServerBranchRequestSetLastRevision')
471
412
request_handlers.register_lazy(
472
413
'Branch.set_last_revision_info', 'bzrlib.smart.branch',
473
414
'SmartServerBranchRequestSetLastRevisionInfo')
475
416
'Branch.set_last_revision_ex', 'bzrlib.smart.branch',
476
417
'SmartServerBranchRequestSetLastRevisionEx')
477
418
request_handlers.register_lazy(
478
'Branch.set_parent_location', 'bzrlib.smart.branch',
479
'SmartServerBranchRequestSetParentLocation')
480
request_handlers.register_lazy(
481
419
'Branch.unlock', 'bzrlib.smart.branch', 'SmartServerBranchRequestUnlock')
482
420
request_handlers.register_lazy(
483
421
'BzrDir.cloning_metadir', 'bzrlib.smart.bzrdir',
498
436
'BzrDir.find_repositoryV3', 'bzrlib.smart.bzrdir',
499
437
'SmartServerRequestFindRepositoryV3')
500
438
request_handlers.register_lazy(
501
'BzrDir.get_config_file', 'bzrlib.smart.bzrdir',
502
'SmartServerBzrDirRequestConfigFile')
503
request_handlers.register_lazy(
504
439
'BzrDirFormat.initialize', 'bzrlib.smart.bzrdir',
505
440
'SmartServerRequestInitializeBzrDir')
506
441
request_handlers.register_lazy(
507
'BzrDirFormat.initialize_ex_1.16', 'bzrlib.smart.bzrdir',
508
'SmartServerRequestBzrDirInitializeEx')
509
request_handlers.register_lazy(
510
'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')
511
request_handlers.register_lazy(
512
442
'BzrDir.open_branch', 'bzrlib.smart.bzrdir',
513
443
'SmartServerRequestOpenBranch')
514
444
request_handlers.register_lazy(
556
486
request_handlers.register_lazy(
557
487
'Repository.insert_stream', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream')
558
488
request_handlers.register_lazy(
559
'Repository.insert_stream_1.19', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStream_1_19')
560
request_handlers.register_lazy(
561
489
'Repository.insert_stream_locked', 'bzrlib.smart.repository', 'SmartServerRepositoryInsertStreamLocked')
562
490
request_handlers.register_lazy(
563
491
'Repository.is_shared', 'bzrlib.smart.repository', 'SmartServerRepositoryIsShared')
569
497
request_handlers.register_lazy(
570
498
'Repository.unlock', 'bzrlib.smart.repository', 'SmartServerRepositoryUnlock')
571
499
request_handlers.register_lazy(
572
'Repository.get_rev_id_for_revno', 'bzrlib.smart.repository',
573
'SmartServerRepositoryGetRevIdForRevno')
574
request_handlers.register_lazy(
575
500
'Repository.get_stream', 'bzrlib.smart.repository',
576
501
'SmartServerRepositoryGetStream')
577
502
request_handlers.register_lazy(
578
'Repository.get_stream_1.19', 'bzrlib.smart.repository',
579
'SmartServerRepositoryGetStream_1_19')
580
request_handlers.register_lazy(
581
503
'Repository.tarball', 'bzrlib.smart.repository',
582
504
'SmartServerRepositoryTarball')
583
505
request_handlers.register_lazy(
586
508
'stat', 'bzrlib.smart.vfs', 'StatRequest')
587
509
request_handlers.register_lazy(
588
510
'Transport.is_readonly', 'bzrlib.smart.request', 'SmartServerIsReadonly')
511
request_handlers.register_lazy(
512
'BzrDir.open', 'bzrlib.smart.bzrdir', 'SmartServerRequestOpenBzrDir')