Rev 4194: (andrew) Strengthen the smart server's jail, in file:///home/pqm/archives/thelove/bzr/%2Btrunk/

Canonical.com Patch Queue Manager pqm at pqm.ubuntu.com
Tue Mar 24 06:40:33 GMT 2009


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

------------------------------------------------------------
revno: 4194
revision-id: pqm at pqm.ubuntu.com-20090324064026-a5a7mmoiaev5mpc9
parent: pqm at pqm.ubuntu.com-20090324051224-rneg6bkbzjyd85rl
parent: andrew.bennetts at canonical.com-20090324053815-3tcoyeuejfp4jud5
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Tue 2009-03-24 06:40:26 +0000
message:
  (andrew) Strengthen the smart server's jail,
  	and add ignore_fallbacks parameter to BzrDir.open_branch.
modified:
  NEWS                           NEWS-20050323055033-4e00b5db738777ff
  bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
  bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
  bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
  bzrlib/smart/branch.py         branch.py-20061124031907-mzh3pla28r83r97f-1
  bzrlib/smart/bzrdir.py         bzrdir.py-20061122024551-ol0l0o0oofsu9b3t-1
  bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
  bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
  bzrlib/tests/blackbox/test_branch.py test_branch.py-20060524161337-noms9gmcwqqrfi8y-1
  bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
  bzrlib/tests/test_branch.py    test_branch.py-20060116013032-97819aa07b8ab3b5
  bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
  bzrlib/tests/test_smart.py     test_smart.py-20061122024551-ol0l0o0oofsu9b3t-2
  bzrlib/tests/test_smart_request.py test_smart_request.p-20090211070731-o38wayv3asm25d6a-1
    ------------------------------------------------------------
    revno: 4160.2.16
    revision-id: andrew.bennetts at canonical.com-20090324053815-3tcoyeuejfp4jud5
    parent: andrew.bennetts at canonical.com-20090324043838-3nhf0syvkz5iqdsz
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Tue 2009-03-24 16:38:15 +1100
    message:
      Update SampleBranchFormat in test_branch for ignore_fallbacks parameter.
    modified:
      bzrlib/tests/test_branch.py    test_branch.py-20060116013032-97819aa07b8ab3b5
    ------------------------------------------------------------
    revno: 4160.2.15
    revision-id: andrew.bennetts at canonical.com-20090324043838-3nhf0syvkz5iqdsz
    parent: andrew.bennetts at canonical.com-20090324042634-cf4y15a5y24fw2n0
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Tue 2009-03-24 15:38:38 +1100
    message:
      Restore lines accidentally removed in bad NEWS merge.
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 4160.2.14
    revision-id: andrew.bennetts at canonical.com-20090324042634-cf4y15a5y24fw2n0
    parent: andrew.bennetts at canonical.com-20090324040153-7kjc38xuliwkymuo
    parent: pqm at pqm.ubuntu.com-20090324015928-a4eisbr51odi0due
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Tue 2009-03-24 15:26:34 +1100
    message:
      Merge bzr.dev, improve NEWS entry and bzrlib.smart.request docs.
    added:
      bzrlib/filters/                filters-20080416080515-mkxl29amuwrf6uir-1
      bzrlib/filters/__init__.py     __init__.py-20080416080515-mkxl29amuwrf6uir-2
      bzrlib/help_topics/en/content-filters.txt contentfilters.txt-20080516145112-7x1meuoci5w41isv-1
      bzrlib/tests/ftp_server/       ftp_server-20090227112800-4r9jkezw2hw9tij7-1
      bzrlib/tests/ftp_server/__init__.py __init__.py-20090227130107-4gcpgvr00l7v3fsw-1
      bzrlib/tests/ftp_server/pyftpdlib_based.py pyftpdlib_based.py-20090227151014-882k9q34m1gwnhvi-1
      bzrlib/tests/test_filters.py   test_filters.py-20080417120614-tc3zok0vvvprsc99-1
      bzrlib/tests/workingtree_implementations/test_content_filters.py test_content_filters-20080424071441-8navsrmrfdxpn90a-1
    renamed:
      bzrlib/tests/ftp_server.py => bzrlib/tests/ftp_server/medusa_based.py ftpserver.py-20071019102346-61jbvdkrr70igauv-1
      doc/developers/ec2-windows.txt => doc/developers/ec2.txt ec2windows.txt-20090219062112-2ga0nqpcm7n02njf-1
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/btree_index.py          index.py-20080624222253-p0x5f92uyh5hw734-7
      bzrlib/builtins.py             builtins.py-20050830033751-fc01482b9ca23183
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/commit.py               commit.py-20050511101309-79ec1a0168e0e825
      bzrlib/diff.py                 diff.py-20050309040759-26944fbbf2ebbf36
      bzrlib/errors.py               errors.py-20050309040759-20512168c4e14fbd
      bzrlib/export/__init__.py      __init__.py-20051114235828-1ba62cb4062304e6
      bzrlib/export/dir_exporter.py  dir_exporter.py-20051114235828-b51397f56bc7b117
      bzrlib/export/tar_exporter.py  tar_exporter.py-20051114235828-1f6349a2f090a5d0
      bzrlib/export/zip_exporter.py  zip_exporter.py-20051114235828-8f57f954fba6497e
      bzrlib/graph.py                graph_walker.py-20070525030359-y852guab65d4wtn0-1
      bzrlib/hashcache.py            hashcache.py-20050706091756-fe3a8cc1143ff24f
      bzrlib/help_topics/__init__.py help_topics.py-20060920210027-rnim90q9e0bwxvy4-1
      bzrlib/help_topics/en/debug-flags.txt debugflags.txt-20090312050229-rdspqbqq4fzbjtpe-1
      bzrlib/hooks.py                hooks.py-20070325015548-ix4np2q0kd8452au-1
      bzrlib/index.py                index.py-20070712131115-lolkarso50vjr64s-1
      bzrlib/inventory.py            inventory.py-20050309040759-6648b84ca2005b37
      bzrlib/log.py                  log.py-20050505065812-c40ce11702fe5fb1
      bzrlib/osutils.py              osutils.py-20050309040759-eeaff12fbf77ac86
      bzrlib/plugin.py               plugin.py-20050622060424-829b654519533d69
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/repofmt/knitrepo.py     knitrepo.py-20070206081537-pyy4a00xdas0j4pf-1
      bzrlib/repofmt/pack_repo.py    pack_repo.py-20070813041115-gjv5ma7ktfqwsjgn-1
      bzrlib/repofmt/weaverepo.py    presplitout.py-20070125045333-wfav3tsh73oxu3zk-1
      bzrlib/repository.py           rev_storage.py-20051111201905-119e9401e46257e3
      bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
      bzrlib/symbol_versioning.py    symbol_versioning.py-20060105104851-9ecf8af605d15a80
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/blackbox/test_add.py test_add.py-20060518072250-857e4f86f54a30b2
      bzrlib/tests/blackbox/test_breakin.py test_breakin.py-20070424043903-qyy6zm4pj3h4sbp3-1
      bzrlib/tests/blackbox/test_cat.py test_cat.py-20051201162916-f0937e4e19ea24b3
      bzrlib/tests/blackbox/test_push.py test_push.py-20060329002750-929af230d5d22663
      bzrlib/tests/blackbox/test_selftest.py test_selftest.py-20060123024542-01c5f1bbcb596d78
      bzrlib/tests/interrepository_implementations/test_interrepository.py test_interrepository.py-20060220061411-1ec13fa99e5e3eee
      bzrlib/tests/inventory_implementations/basics.py basics.py-20070903044446-kdjwbiu1p1zi9phs-1
      bzrlib/tests/per_repository/test_commit_builder.py test_commit_builder.py-20060606110838-76e3ra5slucqus81-1
      bzrlib/tests/per_repository/test_repository.py test_repository.py-20060131092128-ad07f494f5c9d26c
      bzrlib/tests/test_btree_index.py test_index.py-20080624222253-p0x5f92uyh5hw734-13
      bzrlib/tests/test_ftp_transport.py test_aftp_transport.-20060823221619-98mwjzxtwtkt527k-1
      bzrlib/tests/test_hashcache.py testhashcache.py-20050706091800-0288ab2659338981
      bzrlib/tests/test_hooks.py     test_hooks.py-20070628030849-89rtsbe5dmer5npz-1
      bzrlib/tests/test_log.py       testlog.py-20050728115707-1a514809d7d49309
      bzrlib/tests/test_merge.py     testmerge.py-20050905070950-c1b5aa49ff911024
      bzrlib/tests/test_osutils.py   test_osutils.py-20051201224856-e48ee24c12182989
      bzrlib/tests/test_plugins.py   plugins.py-20050622075746-32002b55e5e943e9
      bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
      bzrlib/tests/test_revision.py  testrevision.py-20050804210559-46f5e1eb67b01289
      bzrlib/tests/test_selftest.py  test_selftest.py-20051202044319-c110a115d8c0456a
      bzrlib/tests/test_symbol_versioning.py test_symbol_versioning.py-20060105104851-51d7722c2018d42b
      bzrlib/tests/test_transport_implementations.py test_transport_implementations.py-20051227111451-f97c5c7d5c49fce7
      bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
      bzrlib/tests/workingtree_implementations/__init__.py __init__.py-20060203003124-b2aa5aca21a8bfad
      bzrlib/tests/workingtree_implementations/test_smart_add.py test_smart_add.py-20070215175752-9s5mxoz8aqpd80fm-1
      bzrlib/trace.py                trace.py-20050309040759-c8ed824bdcd4748a
      bzrlib/transform.py            transform.py-20060105172343-dd99e54394d91687
      bzrlib/transport/__init__.py   transport.py-20050711165921-4978aa7ce1285ad5
      bzrlib/transport/ftp/__init__.py ftp.py-20051116161804-58dc9506548c2a53
      bzrlib/transport/ftp/_gssapi.py _gssapi.py-20080611190840-7ejrtp884bk5eu72-2
      bzrlib/transport/log.py        log.py-20080902041816-vh8x5yt5nvdzvew3-5
      bzrlib/transport/readonly.py   readonly.py-20060120032407-66d3166c39ffdc79
      bzrlib/transport/remote.py     ssh.py-20060608202016-c25gvf1ob7ypbus6-1
      bzrlib/tree.py                 tree.py-20050309040759-9d5f2496be663e77
      bzrlib/ui/text.py              text.py-20051130153916-2e438cffc8afc478
      bzrlib/version_info_formats/__init__.py generate_version_info.py-20051228204928-8358edabcddcd97e
      bzrlib/weave.py                knit.py-20050627021749-759c29984154256b
      bzrlib/win32utils.py           win32console.py-20051021033308-123c6c929d04973d
      bzrlib/workingtree.py          workingtree.py-20050511021032-29b6ec0a681e02e3
      bzrlib/workingtree_4.py        workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
      doc/developers/HACKING.txt     HACKING-20050805200004-2a5dc975d870f78c
      doc/developers/index.txt       index.txt-20070508041241-qznziunkg0nffhiw-1
      doc/developers/overview.txt    overview.txt-20080904022501-ww2ggomrs5elxfm0-1
      doc/developers/performance-contributing.txt performancecontribut-20070621063612-ac4zhhagjzkr21qp-1
      doc/developers/releasing.txt   releasing.txt-20080502015919-fnrcav8fwy8ccibu-1
      doc/en/user-guide/web_browsing.txt web_browsing.txt-20080509065016-cjc90f46407vi9a0-3
      bzrlib/tests/ftp_server/medusa_based.py ftpserver.py-20071019102346-61jbvdkrr70igauv-1
      doc/developers/ec2.txt         ec2windows.txt-20090219062112-2ga0nqpcm7n02njf-1
    ------------------------------------------------------------
    revno: 4160.2.13
    revision-id: andrew.bennetts at canonical.com-20090324040153-7kjc38xuliwkymuo
    parent: andrew.bennetts at canonical.com-20090323053049-mrknn26g68c69t61
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Tue 2009-03-24 15:01:53 +1100
    message:
      Add some tests for ignore_fallbacks.
    modified:
      bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
    ------------------------------------------------------------
    revno: 4160.2.12
    revision-id: andrew.bennetts at canonical.com-20090323053049-mrknn26g68c69t61
    parent: andrew.bennetts at canonical.com-20090323033129-ci8b7zthtjt1036o
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Mon 2009-03-23 16:30:49 +1100
    message:
      Improve docstrings and remove a line of cruft.
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/smart/bzrdir.py         bzrdir.py-20061122024551-ol0l0o0oofsu9b3t-1
    ------------------------------------------------------------
    revno: 4160.2.11
    revision-id: andrew.bennetts at canonical.com-20090323033129-ci8b7zthtjt1036o
    parent: andrew.bennetts at canonical.com-20090323033124-273x2h5ut41ycx0p
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Mon 2009-03-23 14:31:29 +1100
    message:
      Add NEWS entry.
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
    ------------------------------------------------------------
    revno: 4160.2.10
    revision-id: andrew.bennetts at canonical.com-20090323033124-273x2h5ut41ycx0p
    parent: andrew.bennetts at canonical.com-20090323032002-q2rbmpp5ne255d46
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Mon 2009-03-23 14:31:24 +1100
    message:
      Improve documentation of BzrDir.cloning_metadir RPC
    modified:
      bzrlib/smart/bzrdir.py         bzrdir.py-20061122024551-ol0l0o0oofsu9b3t-1
    ------------------------------------------------------------
    revno: 4160.2.9
    revision-id: andrew.bennetts at canonical.com-20090323032002-q2rbmpp5ne255d46
    parent: andrew.bennetts at canonical.com-20090319215751-4kypi4vo0vkp1nci
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Mon 2009-03-23 14:20:02 +1100
    message:
      Fix BzrDir.cloning_metadir RPC to fail on branch references, and make
      RemoteBzrDir cope with that by opening the referenced branch and asking it for
      the cloning_metadir.  This can cause extra round trips, but only for callers
      that haven't already resolved branch references, which only occurs in our test
      suite, not UI code.
      
      This theoretically breaks 1.13 clients that depend on the cloning_metadir RPC
      resolving the reference for them, but again that never happens via any builtin
      commands, and the new branch-open jail has already broken those clients.
    modified:
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/smart/bzrdir.py         bzrdir.py-20061122024551-ol0l0o0oofsu9b3t-1
      bzrlib/tests/test_remote.py    test_remote.py-20060720103555-yeeg2x51vn0rbtdp-2
      bzrlib/tests/test_smart.py     test_smart.py-20061122024551-ol0l0o0oofsu9b3t-2
    ------------------------------------------------------------
    revno: 4160.2.8
    revision-id: andrew.bennetts at canonical.com-20090319215751-4kypi4vo0vkp1nci
    parent: andrew.bennetts at canonical.com-20090318094500-froh981qf37u5z57
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Fri 2009-03-20 08:57:51 +1100
    message:
      Slightly less messy BzrBranch7.__init__.
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
    ------------------------------------------------------------
    revno: 4160.2.7
    revision-id: andrew.bennetts at canonical.com-20090318094500-froh981qf37u5z57
    parent: andrew.bennetts at canonical.com-20090318072814-chvt67ssr9jyz259
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Wed 2009-03-18 20:45:00 +1100
    message:
      Branch-from-stacked ratchet down to 23.
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/tests/blackbox/test_branch.py test_branch.py-20060524161337-noms9gmcwqqrfi8y-1
    ------------------------------------------------------------
    revno: 4160.2.6
    revision-id: andrew.bennetts at canonical.com-20090318072814-chvt67ssr9jyz259
    parent: andrew.bennetts at canonical.com-20090318053325-w5xdsr0fjwcpatj2
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Wed 2009-03-18 18:28:14 +1100
    message:
      Add ignore_fallbacks flag.
    modified:
      bzrlib/branch.py               branch.py-20050309040759-e4baf4e0d046576e
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/remote.py               remote.py-20060720103555-yeeg2x51vn0rbtdp-1
      bzrlib/smart/branch.py         branch.py-20061124031907-mzh3pla28r83r97f-1
      bzrlib/smart/bzrdir.py         bzrdir.py-20061122024551-ol0l0o0oofsu9b3t-1
    ------------------------------------------------------------
    revno: 4160.2.5
    revision-id: andrew.bennetts at canonical.com-20090318053325-w5xdsr0fjwcpatj2
    parent: andrew.bennetts at canonical.com-20090318051733-l5rxgj31et1dkm6s
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Wed 2009-03-18 16:33:25 +1100
    message:
      Add test_jail_hook.
    modified:
      bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
      bzrlib/tests/test_smart_request.py test_smart_request.p-20090211070731-o38wayv3asm25d6a-1
    ------------------------------------------------------------
    revno: 4160.2.4
    revision-id: andrew.bennetts at canonical.com-20090318051733-l5rxgj31et1dkm6s
    parent: andrew.bennetts at canonical.com-20090318050656-ae2t1m7um2djp2pg
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Wed 2009-03-18 16:17:33 +1100
    message:
      Use BzrDir pre_open hook to jail request code from accessing transports other than the backing transport.
    modified:
      bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
      bzrlib/tests/__init__.py       selftest.py-20050531073622-8d0e3c8845c97a64
      bzrlib/tests/test_smart.py     test_smart.py-20061122024551-ol0l0o0oofsu9b3t-2
    ------------------------------------------------------------
    revno: 4160.2.3
    revision-id: andrew.bennetts at canonical.com-20090318050656-ae2t1m7um2djp2pg
    parent: andrew.bennetts at canonical.com-20090318044931-uqq32ujozbz0csuv
    parent: pqm at pqm.ubuntu.com-20090318043730-vt9fcxb6ndb8toxa
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Wed 2009-03-18 16:06:56 +1100
    message:
      Merge bzr.dev.
    modified:
      NEWS                           NEWS-20050323055033-4e00b5db738777ff
      bzrlib/_dirstate_helpers_c.pyx dirstate_helpers.pyx-20070503201057-u425eni465q4idwn-3
      bzrlib/bzrdir.py               bzrdir.py-20060131065624-156dfea39c4387cb
      bzrlib/dirstate.py             dirstate.py-20060728012006-d6mvoihjb3je9peu-1
      bzrlib/hooks.py                hooks.py-20070325015548-ix4np2q0kd8452au-1
      bzrlib/tests/test__dirstate_helpers.py test_dirstate_helper-20070504035751-jsbn00xodv0y1eve-2
      bzrlib/tests/test_bzrdir.py    test_bzrdir.py-20060131065654-deba40eef51cf220
      bzrlib/tests/test_dirstate.py  test_dirstate.py-20060728012006-d6mvoihjb3je9peu-2
    ------------------------------------------------------------
    revno: 4160.2.2
    revision-id: andrew.bennetts at canonical.com-20090318044931-uqq32ujozbz0csuv
    parent: andrew.bennetts at canonical.com-20090318032448-f93pjfrhwmv4hwhl
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Wed 2009-03-18 15:49:31 +1100
    message:
      Add setup_jail and teardown_jail to SmartServerRequest.
    modified:
      bzrlib/smart/request.py        request.py-20061108095550-gunadhxmzkdjfeek-1
      bzrlib/tests/test_smart_request.py test_smart_request.p-20090211070731-o38wayv3asm25d6a-1
    ------------------------------------------------------------
    revno: 4160.2.1
    revision-id: andrew.bennetts at canonical.com-20090318032448-f93pjfrhwmv4hwhl
    parent: pqm at pqm.ubuntu.com-20090318021431-md1n8o3542wwsvai
    committer: Andrew Bennetts <andrew.bennetts at canonical.com>
    branch nick: bzrdir-open-gaol
    timestamp: Wed 2009-03-18 14:24:48 +1100
    message:
      Failing test for BzrDir.open_branchV2 RPC not opening stacked-on branch.
    modified:
      bzrlib/tests/test_smart.py     test_smart.py-20061122024551-ol0l0o0oofsu9b3t-2
=== modified file 'NEWS'
--- a/NEWS	2009-03-24 04:24:57 +0000
+++ b/NEWS	2009-03-24 06:40:26 +0000
@@ -151,6 +151,11 @@
 * The ``pb`` argument to ``fetch()`` is deprecated.
   (Martin Pool)
 
+* The smart server jail now hooks into BzrDir.open to prevent any BzrDir
+  that is not inside the backing transport from being opened.  See the
+  module documentation for ``bzrlib.smart.request`` for details.
+  (Andrew Bennetts, Robert Collins)
+
 Testing
 *******
 
@@ -172,14 +177,18 @@
 Internals
 *********
 
+* ``BtreeIndex._spill_mem_keys_to_disk()`` now generates disk index with
+  optmizations turned off. This only has effect when processing > 100,000
+  keys during something like ``bzr pack``. (John Arbash Meinel)
+
 * ``bzr selftest`` now accepts ``--subunit`` to run in subunit output
   mode. Requires ``lp:subunit`` installed to work, but is not a hard
   dependency. (Robert Collins)
 
-* ``BtreeIndex._spill_mem_keys_to_disk()`` now generates disk index with
-  optmizations turned off. This only has effect when processing > 100,000
-  keys during something like ``bzr pack``. (John Arbash Meinel)
-
+* ``BzrDir.open_branch`` now takes an optional ``ignore_fallbacks``
+  parameter for controlling opening of stacked branches.
+  (Andrew Bennetts, Robert Collins)
+  
 * ``CommitBuilder`` has a new method, ``record_iter_changes`` which works
   in terms of an iter_changes iterator rather than full tree scanning.
   (Robert Collins)

=== modified file 'bzrlib/branch.py'
--- a/bzrlib/branch.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/branch.py	2009-03-24 06:40:26 +0000
@@ -1318,11 +1318,14 @@
         """
         raise NotImplementedError(self.network_name)
 
-    def open(self, a_bzrdir, _found=False):
+    def open(self, a_bzrdir, _found=False, ignore_fallbacks=False):
         """Return the branch object for a_bzrdir
 
-        _found is a private parameter, do not use it. It is used to indicate
-               if format probing has already be done.
+        :param a_bzrdir: A BzrDir that contains a branch.
+        :param _found: a private parameter, do not use it. It is used to
+            indicate if format probing has already be done.
+        :param ignore_fallbacks: when set, no fallback branches will be opened
+            (if there are any).  Default is to open fallbacks.
         """
         raise NotImplementedError(self.open)
 
@@ -1500,12 +1503,8 @@
         """The network name for this format is the control dirs disk label."""
         return self._matchingbzrdir.get_format_string()
 
-    def open(self, a_bzrdir, _found=False):
-        """Return the branch object for a_bzrdir
-
-        _found is a private parameter, do not use it. It is used to indicate
-               if format probing has already be done.
-        """
+    def open(self, a_bzrdir, _found=False, ignore_fallbacks=False):
+        """See BranchFormat.open()."""
         if not _found:
             # we are being called directly and must probe.
             raise NotImplementedError
@@ -1532,12 +1531,8 @@
         """
         return self.get_format_string()
 
-    def open(self, a_bzrdir, _found=False):
-        """Return the branch object for a_bzrdir.
-
-        _found is a private parameter, do not use it. It is used to indicate
-               if format probing has already be done.
-        """
+    def open(self, a_bzrdir, _found=False, ignore_fallbacks=False):
+        """See BranchFormat.open()."""
         if not _found:
             format = BranchFormat.find_format(a_bzrdir)
             if format.__class__ != self.__class__:
@@ -1550,7 +1545,8 @@
             return self._branch_class()(_format=self,
                               _control_files=control_files,
                               a_bzrdir=a_bzrdir,
-                              _repository=a_bzrdir.find_repository())
+                              _repository=a_bzrdir.find_repository(),
+                              ignore_fallbacks=ignore_fallbacks)
         except errors.NoSuchFile:
             raise errors.NotBranchError(path=transport.base)
 
@@ -1736,11 +1732,18 @@
         return clone
 
     def open(self, a_bzrdir, _found=False, location=None,
-             possible_transports=None):
+             possible_transports=None, ignore_fallbacks=False):
         """Return the branch that the branch reference in a_bzrdir points at.
 
-        _found is a private parameter, do not use it. It is used to indicate
-               if format probing has already be done.
+        :param a_bzrdir: A BzrDir that contains a branch.
+        :param _found: a private parameter, do not use it. It is used to
+            indicate if format probing has already be done.
+        :param ignore_fallbacks: when set, no fallback branches will be opened
+            (if there are any).  Default is to open fallbacks.
+        :param location: The location of the referenced branch.  If
+            unspecified, this will be determined from the branch reference in
+            a_bzrdir.
+        :param possible_transports: An optional reusable transports list.
         """
         if not _found:
             format = BranchFormat.find_format(a_bzrdir)
@@ -1751,7 +1754,7 @@
             location = self.get_reference(a_bzrdir)
         real_bzrdir = bzrdir.BzrDir.open(
             location, possible_transports=possible_transports)
-        result = real_bzrdir.open_branch()
+        result = real_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
         # this changes the behaviour of result.clone to create a new reference
         # rather than a copy of the content of the branch.
         # I did not use a proxy object because that needs much more extensive
@@ -1804,7 +1807,8 @@
     """
 
     def __init__(self, _format=None,
-                 _control_files=None, a_bzrdir=None, _repository=None):
+                 _control_files=None, a_bzrdir=None, _repository=None,
+                 ignore_fallbacks=False):
         """Create new branch object at a particular location."""
         if a_bzrdir is None:
             raise ValueError('a_bzrdir must be supplied')
@@ -2304,6 +2308,8 @@
             self._get_fallback_repository(url))
 
     def _open_hook(self):
+        if self._ignore_fallbacks:
+            return
         try:
             url = self.get_stacked_on_url()
         except (errors.UnstackableRepositoryFormat, errors.NotStacked,
@@ -2325,6 +2331,7 @@
                 self.repository.base)
 
     def __init__(self, *args, **kwargs):
+        self._ignore_fallbacks = kwargs.get('ignore_fallbacks', False)
         super(BzrBranch7, self).__init__(*args, **kwargs)
         self._last_revision_info_cache = None
         self._partial_revision_history_cache = []

=== modified file 'bzrlib/bzrdir.py'
--- a/bzrlib/bzrdir.py	2009-03-24 01:53:42 +0000
+++ b/bzrlib/bzrdir.py	2009-03-24 06:40:26 +0000
@@ -838,7 +838,7 @@
         BzrDir._check_supported(format, _unsupported)
         return format.open(transport, _found=True)
 
-    def open_branch(self, unsupported=False):
+    def open_branch(self, unsupported=False, ignore_fallbacks=False):
         """Open the branch object at this BzrDir if one is present.
 
         If unsupported is True, then no longer supported branch formats can
@@ -1019,7 +1019,7 @@
         result_format = self._format.__class__()
         try:
             try:
-                branch = self.open_branch()
+                branch = self.open_branch(ignore_fallbacks=True)
                 source_repository = branch.repository
                 result_format._branch_format = branch._format
             except errors.NotBranchError:
@@ -1358,7 +1358,7 @@
             format = BzrDirFormat.get_default_format()
         return not isinstance(self._format, format.__class__)
 
-    def open_branch(self, unsupported=False):
+    def open_branch(self, unsupported=False, ignore_fallbacks=False):
         """See BzrDir.open_branch."""
         from bzrlib.branch import BzrBranchFormat4
         format = BzrBranchFormat4()
@@ -1609,11 +1609,11 @@
             pass
         return False
 
-    def open_branch(self, unsupported=False):
+    def open_branch(self, unsupported=False, ignore_fallbacks=False):
         """See BzrDir.open_branch."""
         format = self.find_branch_format()
         self._check_supported(format, unsupported)
-        return format.open(self, _found=True)
+        return format.open(self, _found=True, ignore_fallbacks=ignore_fallbacks)
 
     def open_repository(self, unsupported=False):
         """See BzrDir.open_repository."""

=== modified file 'bzrlib/remote.py'
--- a/bzrlib/remote.py	2009-03-24 01:53:42 +0000
+++ b/bzrlib/remote.py	2009-03-24 06:40:26 +0000
@@ -153,6 +153,15 @@
         except errors.UnknownSmartMethod:
             medium._remember_remote_is_before((1, 13))
             return self._vfs_cloning_metadir(require_stacking=require_stacking)
+        except errors.UnknownErrorFromSmartServer, err:
+            if err.error_tuple != ('BranchReference',):
+                raise
+            # We need to resolve the branch reference to determine the
+            # cloning_metadir.  This causes unnecessary RPCs to open the
+            # referenced branch (and bzrdir, etc) but only when the caller
+            # didn't already resolve the branch reference.
+            referenced_branch = self.open_branch()
+            return referenced_branch.bzrdir.cloning_metadir()
         if len(response) != 3:
             raise errors.UnexpectedSmartServerResponse(response)
         control_name, repo_name, branch_info = response
@@ -256,7 +265,7 @@
         """See BzrDir._get_tree_branch()."""
         return None, self.open_branch()
 
-    def open_branch(self, _unsupported=False):
+    def open_branch(self, _unsupported=False, ignore_fallbacks=False):
         if _unsupported:
             raise NotImplementedError('unsupported flag support not implemented yet.')
         if self._next_open_branch_result is not None:
@@ -268,12 +277,14 @@
         if response[0] == 'ref':
             # a branch reference, use the existing BranchReference logic.
             format = BranchReferenceFormat()
-            return format.open(self, _found=True, location=response[1])
+            return format.open(self, _found=True, location=response[1],
+                ignore_fallbacks=ignore_fallbacks)
         branch_format_name = response[1]
         if not branch_format_name:
             branch_format_name = None
         format = RemoteBranchFormat(network_name=branch_format_name)
-        return RemoteBranch(self, self.find_repository(), format=format)
+        return RemoteBranch(self, self.find_repository(), format=format,
+            setup_stacking=not ignore_fallbacks)
 
     def _open_repo_v1(self, path):
         verb = 'BzrDir.find_repository'
@@ -1733,8 +1744,8 @@
     def network_name(self):
         return self._network_name
 
-    def open(self, a_bzrdir):
-        return a_bzrdir.open_branch()
+    def open(self, a_bzrdir, ignore_fallbacks=False):
+        return a_bzrdir.open_branch(ignore_fallbacks=ignore_fallbacks)
 
     def _vfs_initialize(self, a_bzrdir):
         # Initialisation when using a local bzrdir object, or a non-vfs init

=== modified file 'bzrlib/smart/branch.py'
--- a/bzrlib/smart/branch.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/smart/branch.py	2009-03-24 06:40:26 +0000
@@ -45,7 +45,7 @@
         bzrdir = BzrDir.open_from_transport(transport)
         if bzrdir.get_branch_reference() is not None:
             raise errors.NotBranchError(transport.base)
-        branch = bzrdir.open_branch()
+        branch = bzrdir.open_branch(ignore_fallbacks=True)
         return self.do_with_branch(branch, *args)
 
 

=== modified file 'bzrlib/smart/bzrdir.py'
--- a/bzrlib/smart/bzrdir.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/smart/bzrdir.py	2009-03-24 06:40:26 +0000
@@ -92,11 +92,25 @@
 class SmartServerBzrDirRequestCloningMetaDir(SmartServerRequestBzrDir):
 
     def do_bzrdir_request(self, require_stacking):
-        """Get the format that should be used when cloning from this dir."""
+        """Get the format that should be used when cloning from this dir.
+
+        New in 1.13.
+        
+        :return: on success, a 3-tuple of network names for (control,
+            repository, branch) directories, where '' signifies "not present".
+            If this BzrDir contains a branch reference then this will fail with
+            BranchReference; clients should resolve branch references before
+            calling this RPC.
+        """
         try:
             branch_ref = self._bzrdir.get_branch_reference()
         except errors.NotBranchError:
             branch_ref = None
+        if branch_ref is not None:
+            # The server shouldn't try to resolve references, and it quite
+            # possibly can't reach them anyway.  The client needs to resolve
+            # the branch reference to determine the cloning_metadir.
+            return FailedSmartServerResponse(('BranchReference',))
         if require_stacking == "True":
             require_stacking = True
         else:
@@ -104,16 +118,11 @@
         control_format = self._bzrdir.cloning_metadir(
             require_stacking=require_stacking)
         control_name = control_format.network_name()
-        # XXX: There should be a method that tells us that the format does/does not
-        # have subformats.
+        # XXX: There should be a method that tells us that the format does/does
+        # not have subformats.
         if isinstance(control_format, BzrDirMetaFormat1):
-            if branch_ref is not None:
-                # If there's a branch reference, the client will have to resolve
-                # the branch reference to figure out the cloning metadir
-                branch_name = ('ref', branch_ref)
-            else:
-                branch_name = ('branch',
-                    control_format.get_branch_format().network_name())
+            branch_name = ('branch',
+                control_format.get_branch_format().network_name())
             repository_name = control_format.repository_format.network_name()
         else:
             # Only MetaDir has delegated formats today.
@@ -322,7 +331,8 @@
         try:
             reference_url = self._bzrdir.get_branch_reference()
             if reference_url is None:
-                format = self._bzrdir.open_branch()._format.network_name()
+                br = self._bzrdir.open_branch(ignore_fallbacks=True)
+                format = br._format.network_name()
                 return SuccessfulSmartServerResponse(('branch', format))
             else:
                 return SuccessfulSmartServerResponse(('ref', reference_url))

=== modified file 'bzrlib/smart/request.py'
--- a/bzrlib/smart/request.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/smart/request.py	2009-03-24 06:40:26 +0000
@@ -14,19 +14,25 @@
 # along with this program; if not, write to the Free Software
 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
-"""Basic server-side logic for dealing with requests.
-
-**XXX**:
-
-The class names are a little confusing: the protocol will instantiate a
-SmartServerRequestHandler, whose dispatch_command method creates an instance of
-a SmartServerRequest subclass.
-
-The request_handlers registry tracks SmartServerRequest classes (rather than
-SmartServerRequestHandler).
+"""Infrastructure for server-side request handlers.
+
+Interesting module attributes:
+    * The request_handlers registry maps verb names to SmartServerRequest
+      classes.
+    * The jail_info threading.local() object is used to prevent accidental
+      opening of BzrDirs outside of the backing transport, or any other
+      transports placed in jail_info.transports.  The jail_info is reset on
+      every call into a request handler (which can happen an arbitrary number
+      of times during a request).
 """
 
+# XXX: The class names are a little confusing: the protocol will instantiate a
+# SmartServerRequestHandler, whose dispatch_command method creates an instance
+# of a SmartServerRequest subclass.
+
+
 import tempfile
+import threading
 
 from bzrlib import (
     bzrdir,
@@ -42,6 +48,33 @@
 """)
 
 
+jail_info = threading.local()
+jail_info.transports = None
+
+
+def _install_hook():
+    bzrdir.BzrDir.hooks.install_named_hook(
+        'pre_open', _pre_open_hook, 'checking server jail')
+
+
+def _pre_open_hook(transport):
+    allowed_transports = jail_info.transports
+    if allowed_transports is None:
+        return
+    abspath = transport.base
+    for allowed_transport in allowed_transports:
+        try:
+            allowed_transport.relpath(abspath)
+        except errors.PathNotChild:
+            continue
+        else:
+            return
+    raise errors.BzrError('jail break: %r' % (abspath,))
+
+
+_install_hook()
+
+
 class SmartServerRequest(object):
     """Base class for request handlers.
 
@@ -121,6 +154,12 @@
         self._body_chunks = None
         return self.do_body(body_bytes)
 
+    def setup_jail(self):
+        jail_info.transports = [self._backing_transport]
+
+    def teardown_jail(self):
+        jail_info.transports = None
+
     def translate_client_path(self, client_path):
         """Translate a path received from a network client into a local
         relpath.
@@ -277,7 +316,11 @@
         # XXX: most of this error conversion is VFS-related, and thus ought to
         # be in SmartServerVFSRequestHandler somewhere.
         try:
-            return callable(*args, **kwargs)
+            self._command.setup_jail()
+            try:
+                return callable(*args, **kwargs)
+            finally:
+                self._command.teardown_jail()
         except (KeyboardInterrupt, SystemExit):
             raise
         except Exception, err:

=== modified file 'bzrlib/tests/__init__.py'
--- a/bzrlib/tests/__init__.py	2009-03-24 05:12:24 +0000
+++ b/bzrlib/tests/__init__.py	2009-03-24 06:40:26 +0000
@@ -77,7 +77,7 @@
 from bzrlib.merge import merge_inner
 import bzrlib.merge3
 import bzrlib.plugin
-from bzrlib.smart import client, server
+from bzrlib.smart import client, request, server
 import bzrlib.store
 from bzrlib import symbol_versioning
 from bzrlib.symbol_versioning import (
@@ -827,6 +827,8 @@
         for key, factory in hooks.known_hooks.items():
             parent, name = hooks.known_hooks_key_to_parent_and_attribute(key)
             setattr(parent, name, factory())
+        # this hook should always be installed
+        request._install_hook()
 
     def _silenceUI(self):
         """Turn off UI for duration of test"""

=== modified file 'bzrlib/tests/blackbox/test_branch.py'
--- a/bzrlib/tests/blackbox/test_branch.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/blackbox/test_branch.py	2009-03-24 06:40:26 +0000
@@ -302,13 +302,12 @@
         self.reset_smart_call_log()
         out, err = self.run_bzr(['branch', self.get_url('feature'),
             'local-target'])
-        rpc_count = len(self.hpss_calls)
         # This figure represent the amount of work to perform this use case. It
         # is entirely ok to reduce this number if a test fails due to rpc_count
         # being too low. If rpc_count increases, more network roundtrips have
         # become necessary for this use case. Please do not adjust this number
         # upwards without agreement from bzr's network support maintainers.
-        self.assertEqual(74, rpc_count)
+        self.assertLength(23, self.hpss_calls)
 
 
 class TestRemoteBranch(TestCaseWithSFTPServer):

=== modified file 'bzrlib/tests/branch_implementations/test_branch.py'
--- a/bzrlib/tests/branch_implementations/test_branch.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/branch_implementations/test_branch.py	2009-03-24 06:40:26 +0000
@@ -752,3 +752,25 @@
         tree3.merge_from_branch(tree2.branch)
         tree3.commit('empty commit 6')
         tree2.pull(tree3.branch)
+
+
+class TestIgnoreFallbacksParameter(TestCaseWithBranch):
+
+    def make_branch_with_fallback(self):
+        fallback = self.make_branch('fallback')
+        if not fallback._format.supports_stacking():
+            raise tests.TestNotApplicable("format does not support stacking")
+        stacked = self.make_branch('stacked')
+        stacked.set_stacked_on_url(fallback.base)
+        return stacked
+
+    def test_fallbacks_not_opened(self):
+        stacked = self.make_branch_with_fallback()
+        self.get_transport('').rename('fallback', 'moved')
+        reopened = stacked.bzrdir.open_branch(ignore_fallbacks=True)
+        self.assertEqual([], reopened.repository._fallback_repositories)
+        
+    def test_fallbacks_are_opened(self):
+        stacked = self.make_branch_with_fallback()
+        reopened = stacked.bzrdir.open_branch(ignore_fallbacks=False)
+        self.assertLength(1, reopened.repository._fallback_repositories)

=== modified file 'bzrlib/tests/test_branch.py'
--- a/bzrlib/tests/test_branch.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/test_branch.py	2009-03-24 06:40:26 +0000
@@ -151,7 +151,7 @@
     def is_supported(self):
         return False
 
-    def open(self, transport, _found=False):
+    def open(self, transport, _found=False, ignore_fallbacks=False):
         return "opened branch."
 
 

=== modified file 'bzrlib/tests/test_remote.py'
--- a/bzrlib/tests/test_remote.py	2009-03-24 01:53:42 +0000
+++ b/bzrlib/tests/test_remote.py	2009-03-24 06:40:26 +0000
@@ -408,6 +408,26 @@
             call.call.method == verb])
         self.assertEqual(1, call_count)
 
+    def test_branch_reference(self):
+        transport = self.get_transport('quack')
+        referenced = self.make_branch('referenced')
+        expected = referenced.bzrdir.cloning_metadir()
+        client = FakeClient(transport.base)
+        client.add_expected_call(
+            'BzrDir.cloning_metadir', ('quack/', 'False'),
+            'error', ('BranchReference',)),
+        client.add_expected_call(
+            'BzrDir.open_branchV2', ('quack/',),
+            'success', ('ref', self.get_url('referenced'))),
+        a_bzrdir = RemoteBzrDir(transport, remote.RemoteBzrDirFormat(),
+            _client=client)
+        result = a_bzrdir.cloning_metadir()
+        # We should have got a control dir matching the referenced branch.
+        self.assertEqual(bzrdir.BzrDirMetaFormat1, type(result))
+        self.assertEqual(expected._repository_format, result._repository_format)
+        self.assertEqual(expected._branch_format, result._branch_format)
+        client.finished_test()
+
     def test_current_server(self):
         transport = self.get_transport('.')
         transport = transport.clone('quack')

=== modified file 'bzrlib/tests/test_smart.py'
--- a/bzrlib/tests/test_smart.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/test_smart.py	2009-03-24 06:40:26 +0000
@@ -177,7 +177,7 @@
         self.assertEqual(expected, request.execute('', 'False'))
 
     def test_cloning_metadir_reference(self):
-        """The request works when bzrdir contains a branch reference."""
+        """The request fails when bzrdir contains a branch reference."""
         backing = self.get_transport()
         referenced_branch = self.make_branch('referenced')
         dir = self.make_bzrdir('.')
@@ -189,10 +189,7 @@
         backing.rename('referenced', 'moved')
         request_class = smart_dir.SmartServerBzrDirRequestCloningMetaDir
         request = request_class(backing)
-        expected = SuccessfulSmartServerResponse(
-            (local_result.network_name(),
-            local_result.repository_format.network_name(),
-            ('ref', reference_url)))
+        expected = FailedSmartServerResponse(('BranchReference',))
         self.assertEqual(expected, request.execute('', 'False'))
 
 
@@ -389,6 +386,26 @@
         self.assertEqual(SuccessfulSmartServerResponse(('ref', reference_url)),
             request.execute('reference'))
 
+    def test_stacked_branch(self):
+        """Opening a stacked branch does not open the stacked-on branch."""
+        trunk = self.make_branch('trunk')
+        feature = self.make_branch('feature', format='1.9')
+        feature.set_stacked_on_url(trunk.base)
+        opened_branches = []
+        Branch.hooks.install_named_hook('open', opened_branches.append, None)
+        backing = self.get_transport()
+        request = smart.bzrdir.SmartServerRequestOpenBranchV2(backing)
+        request.setup_jail()
+        try:
+            response = request.execute('feature')
+        finally:
+            request.teardown_jail()
+        expected_format = feature._format.network_name()
+        self.assertEqual(
+            SuccessfulSmartServerResponse(('branch', expected_format)),
+            response)
+        self.assertLength(1, opened_branches)
+
 
 class TestSmartServerRequestRevisionHistory(tests.TestCaseWithMemoryTransport):
 

=== modified file 'bzrlib/tests/test_smart_request.py'
--- a/bzrlib/tests/test_smart_request.py	2009-03-23 14:59:43 +0000
+++ b/bzrlib/tests/test_smart_request.py	2009-03-24 06:40:26 +0000
@@ -16,9 +16,12 @@
 
 """Tests for smart server request infrastructure (bzrlib.smart.request)."""
 
+import threading
+
 from bzrlib import errors
 from bzrlib.smart import request
-from bzrlib.tests import TestCase
+from bzrlib.tests import TestCase, TestCaseWithMemoryTransport
+from bzrlib.transport import get_transport
 
 
 class NoBodyRequest(request.SmartServerRequest):
@@ -61,6 +64,22 @@
         raise errors.NoSuchFile('xyzzy')
 
 
+class CheckJailRequest(request.SmartServerRequest):
+
+    def __init__(self, *args):
+        request.SmartServerRequest.__init__(self, *args)
+        self.jail_transports_log = []
+
+    def do(self):
+        self.jail_transports_log.append(request.jail_info.transports)
+
+    def do_chunk(self, bytes):
+        self.jail_transports_log.append(request.jail_info.transports)
+
+    def do_end(self):
+        self.jail_transports_log.append(request.jail_info.transports)
+
+
 class TestSmartRequest(TestCase):
 
     def test_request_class_without_do_body(self):
@@ -76,6 +95,20 @@
         handler.end_received()
         # Request done, no exception was raised.
 
+    def test_only_request_code_is_jailed(self):
+        transport = 'dummy transport'
+        handler = request.SmartServerRequestHandler(
+            transport, {'foo': CheckJailRequest}, '/')
+        handler.args_received(('foo',))
+        self.assertEqual(None, request.jail_info.transports)
+        handler.accept_body('bytes')
+        self.assertEqual(None, request.jail_info.transports)
+        handler.end_received()
+        self.assertEqual(None, request.jail_info.transports)
+        self.assertEqual(
+            [[transport]] * 3, handler._command.jail_transports_log)
+
+
 
 class TestSmartRequestHandlerErrorTranslation(TestCase):
     """Tests that SmartServerRequestHandler will translate exceptions raised by
@@ -134,3 +167,39 @@
             ('TokenMismatch', 'some-token', 'actual-token'),
             errors.TokenMismatch('some-token', 'actual-token'))
 
+
+class TestRequestJail(TestCaseWithMemoryTransport):
+    
+    def test_jail(self):
+        transport = self.get_transport('blah')
+        req = request.SmartServerRequest(transport)
+        self.assertEqual(None, request.jail_info.transports)
+        req.setup_jail()
+        self.assertEqual([transport], request.jail_info.transports)
+        req.teardown_jail()
+        self.assertEqual(None, request.jail_info.transports)
+
+
+class TestJailHook(TestCaseWithMemoryTransport):
+
+    def tearDown(self):
+        request.jail_info.transports = None
+        TestCaseWithMemoryTransport.tearDown(self)
+
+    def test_jail_hook(self):
+        request.jail_info.transports = None
+        _pre_open_hook = request._pre_open_hook
+        # Any transport is fine if jail_info.transports is None
+        t = self.get_transport('foo')
+        _pre_open_hook(t)
+        # A transport in jail_info.transports is allowed
+        request.jail_info.transports = [t]
+        _pre_open_hook(t)
+        # A child of a transport in jail_info is allowed
+        _pre_open_hook(t.clone('child'))
+        # A parent is not allowed
+        self.assertRaises(errors.BzrError, _pre_open_hook, t.clone('..'))
+        # A completely unrelated transport is not allowed
+        self.assertRaises(
+            errors.BzrError, _pre_open_hook, get_transport('http://host/'))
+




More information about the bazaar-commits mailing list