Rev 4762: (andrew) Fix jail break errors in bzr+http servers. (#348308) in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Thu Oct 22 02:07:27 BST 2009


At file:///home/pqm/archives/thelove/bzr/%2Btrunk/

------------------------------------------------------------
revno: 4762 [merge]
revision-id: pqm at pqm.ubuntu.com-20091022010725-lzpmhctqph34xcol
parent: pqm at pqm.ubuntu.com-20091021163017-itbys2a178vt5605
parent: andrew.bennetts at canonical.com-20091021231524-w0uu60fgyb8s2zta
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Thu 2009-10-22 02:07:25 +0100
message:
  (andrew) Fix jail break errors in bzr+http servers. (#348308)
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/smart/branch.py         branch.py-20061124031907-mzh3pla28r83r97f-1
  bzrlib/smart/protocol.py       protocol.py-20061108035435-ot0lstk2590yqhzr-1
  bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
  bzrlib/tests/test_wsgi.py      test_wsgi.py-20061005091552-rz8pva0olkxv0sd8-1
  bzrlib/transport/http/wsgi.py  wsgi.py-20061005091552-rz8pva0olkxv0sd8-2
=== modified file 'NEWS'
--- a/NEWS	2009-10-21 14:32:16 +0000
+++ b/NEWS	2009-10-22 01:07:25 +0000
@@ -22,6 +22,9 @@
 Bug Fixes
 *********
 
+* ``bzr+http`` servers no longer give spurious jail break errors when
+  serving branches inside a shared repository.  (Andrew Bennetts, #348308)
+
 * TreeTransform.adjust_path updates the limbo paths of descendants of adjusted
   files.  (Aaron Bentley)
 

=== modified file 'bzrlib/smart/branch.py'
--- a/bzrlib/smart/branch.py	2009-07-27 04:32:56 +0000
+++ b/bzrlib/smart/branch.py	2009-10-21 06:05:49 +0000
@@ -105,9 +105,9 @@
 
 class SmartServerBranchSetTagsBytes(SmartServerLockedBranchRequest):
 
-    def __init__(self, backing_transport, root_client_path='/'):
+    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
         SmartServerLockedBranchRequest.__init__(
-            self, backing_transport, root_client_path)
+            self, backing_transport, root_client_path, jail_root)
         self.locked = False
         
     def do_with_locked_branch(self, branch):

=== modified file 'bzrlib/smart/protocol.py'
--- a/bzrlib/smart/protocol.py	2009-09-11 06:07:05 +0000
+++ b/bzrlib/smart/protocol.py	2009-10-21 06:05:49 +0000
@@ -114,9 +114,11 @@
 class SmartServerRequestProtocolOne(SmartProtocolBase):
     """Server-side encoding and decoding logic for smart version 1."""
 
-    def __init__(self, backing_transport, write_func, root_client_path='/'):
+    def __init__(self, backing_transport, write_func, root_client_path='/',
+            jail_root=None):
         self._backing_transport = backing_transport
         self._root_client_path = root_client_path
+        self._jail_root = jail_root
         self.unused_data = ''
         self._finished = False
         self.in_buffer = ''
@@ -144,7 +146,8 @@
                 req_args = _decode_tuple(first_line)
                 self.request = request.SmartServerRequestHandler(
                     self._backing_transport, commands=request.request_handlers,
-                    root_client_path=self._root_client_path)
+                    root_client_path=self._root_client_path,
+                    jail_root=self._jail_root)
                 self.request.args_received(req_args)
                 if self.request.finished_reading:
                     # trivial request
@@ -858,10 +861,10 @@
 
 
 def build_server_protocol_three(backing_transport, write_func,
-                                root_client_path):
+                                root_client_path, jail_root=None):
     request_handler = request.SmartServerRequestHandler(
         backing_transport, commands=request.request_handlers,
-        root_client_path=root_client_path)
+        root_client_path=root_client_path, jail_root=jail_root)
     responder = ProtocolThreeResponder(write_func)
     message_handler = message.ConventionalRequestHandler(request_handler, responder)
     return ProtocolThreeDecoder(message_handler)

=== modified file 'bzrlib/smart/request.py'
--- a/bzrlib/smart/request.py	2009-09-24 05:31:23 +0000
+++ b/bzrlib/smart/request.py	2009-10-21 06:05:49 +0000
@@ -86,7 +86,7 @@
     # XXX: rename this class to BaseSmartServerRequestHandler ?  A request
     # *handler* is a different concept to the request.
 
-    def __init__(self, backing_transport, root_client_path='/'):
+    def __init__(self, backing_transport, root_client_path='/', jail_root=None):
         """Constructor.
 
         :param backing_transport: the base transport to be used when performing
@@ -96,8 +96,13 @@
             from the client.  Clients will not be able to refer to paths above
             this root.  If root_client_path is None, then no translation will
             be performed on client paths.  Default is '/'.
+        :param jail_root: if specified, the root of the BzrDir.open jail to use
+            instead of backing_transport.
         """
         self._backing_transport = backing_transport
+        if jail_root is None:
+            jail_root = backing_transport
+        self._jail_root = jail_root
         if root_client_path is not None:
             if not root_client_path.startswith('/'):
                 root_client_path = '/' + root_client_path
@@ -155,7 +160,7 @@
         return self.do_body(body_bytes)
 
     def setup_jail(self):
-        jail_info.transports = [self._backing_transport]
+        jail_info.transports = [self._jail_root]
 
     def teardown_jail(self):
         jail_info.transports = None
@@ -265,7 +270,8 @@
     # TODO: Better way of representing the body for commands that take it,
     # and allow it to be streamed into the server.
 
-    def __init__(self, backing_transport, commands, root_client_path):
+    def __init__(self, backing_transport, commands, root_client_path,
+        jail_root):
         """Constructor.
 
         :param backing_transport: a Transport to handle requests for.
@@ -275,6 +281,7 @@
         self._backing_transport = backing_transport
         self._root_client_path = root_client_path
         self._commands = commands
+        self._jail_root = jail_root
         self.response = None
         self.finished_reading = False
         self._command = None
@@ -335,7 +342,7 @@
         except LookupError:
             raise errors.UnknownSmartMethod(cmd)
         self._command = command(
-            self._backing_transport, self._root_client_path)
+            self._backing_transport, self._root_client_path, self._jail_root)
         self._run_handler_code(self._command.execute, args, {})
 
     def end_received(self):

=== modified file 'bzrlib/tests/test_wsgi.py'
--- a/bzrlib/tests/test_wsgi.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/test_wsgi.py	2009-10-21 11:13:40 +0000
@@ -19,17 +19,12 @@
 from cStringIO import StringIO
 
 from bzrlib import tests
-from bzrlib.smart import protocol
+from bzrlib.smart import medium, message, protocol
 from bzrlib.transport.http import wsgi
 from bzrlib.transport import chroot, memory
 
 
-class TestWSGI(tests.TestCase):
-
-    def setUp(self):
-        tests.TestCase.setUp(self)
-        self.status = None
-        self.headers = None
+class WSGITestMixin(object):
 
     def build_environ(self, updates=None):
         """Builds an environ dict with all fields required by PEP 333.
@@ -69,6 +64,14 @@
         self.status = status
         self.headers = headers
 
+
+class TestWSGI(tests.TestCase, WSGITestMixin):
+
+    def setUp(self):
+        tests.TestCase.setUp(self)
+        self.status = None
+        self.headers = None
+
     def test_construct(self):
         app = wsgi.SmartWSGIApp(FakeTransport())
         self.assertIsInstance(
@@ -242,6 +245,51 @@
             protocol.RESPONSE_VERSION_TWO + 'success\nok\x012\n', response)
 
 
+class TestWSGIJail(tests.TestCaseWithMemoryTransport, WSGITestMixin):
+
+    def make_hpss_wsgi_request(self, wsgi_relpath, *args):
+        write_buf = StringIO()
+        request_medium = medium.SmartSimplePipesClientMedium(
+            None, write_buf, 'fake:' + wsgi_relpath)
+        request_encoder = protocol.ProtocolThreeRequester(
+            request_medium.get_request())
+        request_encoder.call(*args)
+        write_buf.seek(0)
+        environ = self.build_environ({
+            'REQUEST_METHOD': 'POST',
+            'CONTENT_LENGTH': len(write_buf.getvalue()),
+            'wsgi.input': write_buf,
+            'bzrlib.relpath': wsgi_relpath,
+        })
+        return environ
+
+    def test_jail_root(self):
+        """The WSGI HPSS glue allows access to the whole WSGI backing
+        transport, regardless of which HTTP path the request was delivered
+        to.
+        """
+        # make a branch in a shared repo
+        self.make_repository('repo', shared=True)
+        branch = self.make_bzrdir('repo/branch').create_branch()
+        # serve the repo via bzr+http WSGI
+        wsgi_app = wsgi.SmartWSGIApp(self.get_transport())
+        # send a request to /repo/branch that will have to access /repo.
+        environ = self.make_hpss_wsgi_request(
+            '/repo/branch', 'BzrDir.open_branchV2', '.')
+        iterable = wsgi_app(environ, self.start_response)
+        response_bytes = self.read_response(iterable)
+        self.assertEqual('200 OK', self.status)
+        # expect a successful response, rather than a jail break error
+        from bzrlib.tests.test_smart_transport import LoggingMessageHandler
+        message_handler = LoggingMessageHandler()
+        decoder = protocol.ProtocolThreeDecoder(
+            message_handler, expect_version_marker=True)
+        decoder.accept_bytes(response_bytes)
+        self.assertTrue(
+            ('structure', ('branch', branch._format.network_name()))
+            in message_handler.event_log)
+
+
 class FakeRequest(object):
 
     def __init__(self, transport, write_func):

=== modified file 'bzrlib/transport/http/wsgi.py'
--- a/bzrlib/transport/http/wsgi.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/transport/http/wsgi.py	2009-10-21 06:05:49 +0000
@@ -176,6 +176,7 @@
     def make_request(self, transport, write_func, request_bytes, rcp):
         protocol_factory, unused_bytes = medium._get_protocol_factory_for_bytes(
             request_bytes)
-        server_protocol = protocol_factory(transport, write_func, rcp)
+        server_protocol = protocol_factory(
+            transport, write_func, rcp, self.backing_transport)
         server_protocol.accept_bytes(unused_bytes)
         return server_protocol




More information about the bazaar-commits mailing list