Ticket #1526: no-extensions.diff

File no-extensions.diff, 42.0 KB (added by warner, at 2011-09-26T02:30:12Z)

tolerate-but-ignore extensions in MDMF filecaps: remove extension-handling code and tests

  • src/allmydata/mutable/filenode.py

    diff --git a/src/allmydata/mutable/filenode.py b/src/allmydata/mutable/filenode.py
    index 02f99b6..cafe20f 100644
    a b class MutableFileNode: 
    118118        self._privkey = None
    119119        self._encprivkey = None
    120120
    121         # Starting with MDMF caps, we allowed arbitrary extensions in
    122         # caps. If we were initialized with a cap that had extensions,
    123         # we want to remember them so we can tell MutableFileVersions
    124         # about them.
    125         extensions = self._uri.get_extension_params()
    126         if extensions:
    127             extensions = map(int, extensions)
    128             suspected_k, suspected_segsize = extensions
    129             self._downloader_hints['k'] = suspected_k
    130             self._downloader_hints['segsize'] = suspected_segsize
    131 
    132121        return self
    133122
    134123    def create_with_keys(self, (pubkey, privkey), contents,
    class MutableFileNode: 
    701690
    702691    def set_downloader_hints(self, hints):
    703692        self._downloader_hints = hints
    704         extensions = [ hints["k"], hints["segsize"] ]
    705         self._uri.set_extension_params(extensions)
    706 
    707693
    708694    def _did_upload(self, res, size):
    709695        self._most_recent_size = size
  • src/allmydata/scripts/debug.py

    diff --git a/src/allmydata/scripts/debug.py b/src/allmydata/scripts/debug.py
    index 16e57b3..b482fb9 100644
    a b def dump_MDMF_share(m, length, options): 
    369369        if base32.could_be_base32_encoded(piece):
    370370            storage_index = base32.a2b(piece)
    371371            fingerprint = hashutil.ssk_pubkey_fingerprint_hash(pubkey)
    372             hints = [str(k), str(segsize)]
    373             u = MDMFVerifierURI(storage_index, fingerprint, hints)
     372            u = MDMFVerifierURI(storage_index, fingerprint)
    374373            verify_cap = u.to_string()
    375374            print >>out, "  verify-cap:", quote_output(verify_cap, quotemarks=False)
    376375
  • src/allmydata/test/common.py

    diff --git a/src/allmydata/test/common.py b/src/allmydata/test/common.py
    index 1e29f0d..42890d8 100644
    a b class FakeMutableFileNode: 
    208208        data = initial_contents.read(initial_contents.get_size())
    209209        data = "".join(data)
    210210        self.all_contents[self.storage_index] = data
    211         self.my_uri.set_extension_params([self._k, self._segsize])
    212211        return defer.succeed(self)
    213212    def _get_initial_contents(self, contents):
    214213        if contents is None:
    class FakeMutableFileNode: 
    358357        new_data = new_contents.read(new_contents.get_size())
    359358        new_data = "".join(new_data)
    360359        self.all_contents[self.storage_index] = new_data
    361         self.my_uri.set_extension_params([self._k, self._segsize])
    362360        return defer.succeed(None)
    363361    def modify(self, modifier):
    364362        # this does not implement FileTooLargeError, but the real one does
    class FakeMutableFileNode: 
    368366        old_contents = self.all_contents[self.storage_index]
    369367        new_data = modifier(old_contents, None, True)
    370368        self.all_contents[self.storage_index] = new_data
    371         self.my_uri.set_extension_params([self._k, self._segsize])
    372369        return None
    373370
    374371    # As actually implemented, MutableFilenode and MutableFileVersion
  • src/allmydata/test/test_cli.py

    diff --git a/src/allmydata/test/test_cli.py b/src/allmydata/test/test_cli.py
    index 5d6b728..fb6f143 100644
    a b class Put(GridTestMixin, CLITestMixin, unittest.TestCase): 
    12291229        d = self.do_cli("put", "--mutable", "--mutable-type=mdmf", fn1)
    12301230        def _got_cap((rc, out, err)):
    12311231            self.failUnlessEqual(rc, 0)
    1232             self.cap = out
     1232            self.cap = out.strip()
    12331233        d.addCallback(_got_cap)
    12341234        # Now try to write something to the cap using put.
    12351235        data2 = "data2" * 100000
    class Put(GridTestMixin, CLITestMixin, unittest.TestCase): 
    12481248            self.failUnlessEqual(rc, 0)
    12491249            self.failUnlessEqual(out, data2)
    12501250        d.addCallback(_got_data)
    1251         # Now strip the extension information off of the cap and try
    1252         # to put something to it.
    1253         def _make_bare_cap(ignored):
    1254             cap = self.cap.split(":")
    1255             cap = ":".join(cap[:len(cap) - 2])
    1256             self.cap = cap
    1257         d.addCallback(_make_bare_cap)
     1251        # add some extension information to the cap and try to put something
     1252        # to it.
     1253        def _make_extended_cap(ignored):
     1254            self.cap = self.cap + ":Extension-Stuff"
     1255        d.addCallback(_make_extended_cap)
    12581256        data3 = "data3" * 100000
    12591257        fn3 = os.path.join(self.basedir, "data3")
    12601258        fileutil.write(fn3, data3)
    class Put(GridTestMixin, CLITestMixin, unittest.TestCase): 
    12771275        d = self.do_cli("put", "--mutable", "--mutable-type=sdmf", fn1)
    12781276        def _got_cap((rc, out, err)):
    12791277            self.failUnlessEqual(rc, 0)
    1280             self.cap = out
     1278            self.cap = out.strip()
    12811279        d.addCallback(_got_cap)
    12821280        # Now try to write something to the cap using put.
    12831281        data2 = "data2" * 100000
  • src/allmydata/test/test_dirnode.py

    diff --git a/src/allmydata/test/test_dirnode.py b/src/allmydata/test/test_dirnode.py
    index 9f9a5ad..145419b 100644
    a b class MemAccum: 
    4141setup_py_uri = "URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861"
    4242one_uri = "URI:LIT:n5xgk" # LIT for "one"
    4343mut_write_uri = "URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq"
    44 mdmf_write_uri = "URI:MDMF:x533rhbm6kiehzl5kj3s44n5ie:4gif5rhneyd763ouo5qjrgnsoa3bg43xycy4robj2rf3tvmhdl3a:1:131072"
     44mdmf_write_uri = "URI:MDMF:x533rhbm6kiehzl5kj3s44n5ie:4gif5rhneyd763ouo5qjrgnsoa3bg43xycy4robj2rf3tvmhdl3a"
    4545empty_litdir_uri = "URI:DIR2-LIT:"
    4646tiny_litdir_uri = "URI:DIR2-LIT:gqytunj2onug64tufqzdcosvkjetutcjkq5gw4tvm5vwszdgnz5hgyzufqydulbshj5x2lbm" # contains one child which is itself also LIT
    4747mut_read_uri = "URI:SSK-RO:jf6wkflosyvntwxqcdo7a54jvm:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq"
    48 mdmf_read_uri = "URI:MDMF-RO:d4cydxselputycfzkw6qgz4zv4:4gif5rhneyd763ouo5qjrgnsoa3bg43xycy4robj2rf3tvmhdl3a:1:131072"
     48mdmf_read_uri = "URI:MDMF-RO:d4cydxselputycfzkw6qgz4zv4:4gif5rhneyd763ouo5qjrgnsoa3bg43xycy4robj2rf3tvmhdl3a"
    4949future_write_uri = "x-tahoe-crazy://I_am_from_the_future."
    5050future_read_uri = "x-tahoe-crazy-readonly://I_am_from_the_future."
    5151future_nonascii_write_uri = u"x-tahoe-even-more-crazy://I_am_from_the_future_rw_\u263A".encode('utf-8')
  • src/allmydata/test/test_mutable.py

    diff --git a/src/allmydata/test/test_mutable.py b/src/allmydata/test/test_mutable.py
    index f88cb90..d42a9ab 100644
    a b class Filenode(unittest.TestCase, testutil.ShouldFailMixin): 
    375375        return d
    376376
    377377
    378     def test_create_from_mdmf_writecap_with_extensions(self):
    379         # Test that the nodemaker is capable of creating an MDMF
    380         # filenode when given a writecap with extension parameters in
    381         # them.
    382         d = self.nodemaker.create_mutable_file(version=MDMF_VERSION)
    383         def _created(n):
    384             self.failUnless(isinstance(n, MutableFileNode))
    385             s = n.get_uri()
    386             # We need to cheat a little and delete the nodemaker's
    387             # cache, otherwise we'll get the same node instance back.
    388             self.failUnlessIn(":3:131073", s)
    389             n2 = self.nodemaker.create_from_cap(s)
    390 
    391             self.failUnlessEqual(n2.get_storage_index(), n.get_storage_index())
    392             self.failUnlessEqual(n.get_writekey(), n2.get_writekey())
    393             hints = n2._downloader_hints
    394             self.failUnlessEqual(hints['k'], 3)
    395             self.failUnlessEqual(hints['segsize'], 131073)
    396         d.addCallback(_created)
    397         return d
    398 
    399 
    400378    def test_create_from_mdmf_readcap(self):
    401379        d = self.nodemaker.create_mutable_file(version=MDMF_VERSION)
    402380        def _created(n):
    class Filenode(unittest.TestCase, testutil.ShouldFailMixin): 
    411389        return d
    412390
    413391
    414     def test_create_from_mdmf_readcap_with_extensions(self):
    415         # We should be able to create an MDMF filenode with the
    416         # extension parameters without it breaking.
    417         d = self.nodemaker.create_mutable_file(version=MDMF_VERSION)
    418         def _created(n):
    419             self.failUnless(isinstance(n, MutableFileNode))
    420             s = n.get_readonly_uri()
    421             self.failUnlessIn(":3:131073", s)
    422 
    423             n2 = self.nodemaker.create_from_cap(s)
    424             self.failUnless(isinstance(n2, MutableFileNode))
    425             self.failUnless(n2.is_readonly())
    426             self.failUnlessEqual(n.get_storage_index(), n2.get_storage_index())
    427             hints = n2._downloader_hints
    428             self.failUnlessEqual(hints["k"], 3)
    429             self.failUnlessEqual(hints["segsize"], 131073)
    430         d.addCallback(_created)
    431         return d
    432 
    433 
    434392    def test_internal_version_from_cap(self):
    435393        # MutableFileNodes and MutableFileVersions have an internal
    436394        # switch that tells them whether they're dealing with an SDMF or
    class Filenode(unittest.TestCase, testutil.ShouldFailMixin): 
    606564        d = self.nodemaker.create_mutable_file(version=MDMF_VERSION)
    607565        def _created(node):
    608566            self.uri = node.get_uri()
     567            # also confirm that the cap has no extension fields
     568            pieces = self.uri.split(":")
     569            self.failUnlessEqual(len(pieces), 4)
    609570
    610571            return node.overwrite(MutableData("contents1" * 100000))
    611572        def _then(ignored):
    class Filenode(unittest.TestCase, testutil.ShouldFailMixin): 
    619580        return d
    620581
    621582
    622     def test_create_and_download_from_bare_mdmf_cap(self):
    623         # MDMF caps have extension parameters on them by default. We
    624         # need to make sure that they work without extension parameters.
    625         contents = MutableData("contents" * 100000)
    626         d = self.nodemaker.create_mutable_file(version=MDMF_VERSION,
    627                                                contents=contents)
    628         def _created(node):
    629             uri = node.get_uri()
    630             self._created = node
    631             self.failUnlessIn(":3:131073", uri)
    632             # Now strip that off the end of the uri, then try creating
    633             # and downloading the node again.
    634             bare_uri = uri.replace(":3:131073", "")
    635             assert ":3:131073" not in bare_uri
    636 
    637             return self.nodemaker.create_from_cap(bare_uri)
    638         d.addCallback(_created)
    639         def _created_bare(node):
    640             self.failUnlessEqual(node.get_writekey(),
    641                                  self._created.get_writekey())
    642             self.failUnlessEqual(node.get_readkey(),
    643                                  self._created.get_readkey())
    644             self.failUnlessEqual(node.get_storage_index(),
    645                                  self._created.get_storage_index())
    646             return node.download_best_version()
    647         d.addCallback(_created_bare)
    648         d.addCallback(lambda data:
    649             self.failUnlessEqual(data, "contents" * 100000))
    650         return d
    651 
    652 
    653583    def test_mdmf_write_count(self):
    654584        # Publishing an MDMF file should only cause one write for each
    655585        # share that is to be published. Otherwise, we introduce
    class Version(GridTestMixin, unittest.TestCase, testutil.ShouldFailMixin, \ 
    30682998        return d
    30692999
    30703000
    3071     def test_version_extension_api(self):
    3072         # We need to define an API by which an uploader can set the
    3073         # extension parameters, and by which a downloader can retrieve
    3074         # extensions.
    3075         d = self.do_upload_mdmf()
    3076         d.addCallback(lambda ign: self.mdmf_node.get_best_mutable_version())
    3077         def _got_version(version):
    3078             hints = version.get_downloader_hints()
    3079             # Should be empty at this point.
    3080             self.failUnlessIn("k", hints)
    3081             self.failUnlessEqual(hints['k'], 3)
    3082             self.failUnlessIn('segsize', hints)
    3083             self.failUnlessEqual(hints['segsize'], 131073)
    3084         d.addCallback(_got_version)
    3085         return d
    3086 
    3087 
    3088     def test_extensions_from_cap(self):
    3089         # If we initialize a mutable file with a cap that has extension
    3090         # parameters in it and then grab the extension parameters using
    3091         # our API, we should see that they're set correctly.
    3092         d = self.do_upload_mdmf()
    3093         def _then(ign):
    3094             mdmf_uri = self.mdmf_node.get_uri()
    3095             new_node = self.nm.create_from_cap(mdmf_uri)
    3096             return new_node.get_best_mutable_version()
    3097         d.addCallback(_then)
    3098         def _got_version(version):
    3099             hints = version.get_downloader_hints()
    3100             self.failUnlessIn("k", hints)
    3101             self.failUnlessEqual(hints["k"], 3)
    3102             self.failUnlessIn("segsize", hints)
    3103             self.failUnlessEqual(hints["segsize"], 131073)
    3104         d.addCallback(_got_version)
    3105         return d
    3106 
    3107 
    3108     def test_extensions_from_upload(self):
    3109         # If we create a new mutable file with some contents, we should
    3110         # get back an MDMF cap with the right hints in place.
    3111         contents = "foo bar baz" * 100000
    3112         d = self.nm.create_mutable_file(contents, version=MDMF_VERSION)
    3113         def _got_mutable_file(n):
    3114             rw_uri = n.get_uri()
    3115             expected_k = str(self.c.DEFAULT_ENCODING_PARAMETERS['k'])
    3116             self.failUnlessIn(expected_k, rw_uri)
    3117             # XXX: Get this more intelligently.
    3118             self.failUnlessIn("131073", rw_uri)
    3119 
    3120             ro_uri = n.get_readonly_uri()
    3121             self.failUnlessIn(expected_k, ro_uri)
    3122             self.failUnlessIn("131073", ro_uri)
    3123         d.addCallback(_got_mutable_file)
    3124         return d
    3125 
    3126 
    31273001    def test_cap_after_upload(self):
    31283002        # If we create a new mutable file and upload things to it, and
    31293003        # it's an MDMF file, we should get an MDMF cap back from that
  • src/allmydata/test/test_uri.py

    diff --git a/src/allmydata/test/test_uri.py b/src/allmydata/test/test_uri.py
    index 7662c7f..c6fb5bc 100644
    a b  
    11
    2 import re
     2import os, re
    33from twisted.trial import unittest
    44from allmydata import uri
    55from allmydata.util import hashutil, base32
    class Mutable(testutil.ReallyEqualMixin, unittest.TestCase): 
    430430        u4 = u2.get_verify_cap()
    431431        self.failUnlessReallyEqual(u4, u2)
    432432
    433     def test_mdmf_cap_extra_information(self):
    434         # MDMF caps can be arbitrarily extended after the fingerprint
    435         # and key/storage index fields.
     433    def test_mdmf_cap_ignore_extensions(self):
     434        # MDMF caps can be arbitrarily extended after the fingerprint and
     435        # key/storage index fields. tahoe-1.9 is supposed to ignore any
     436        # extensions, and not add any itself.
    436437        u1 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint)
    437         self.failUnlessEqual([], u1.get_extension_params())
    438 
    439         cap = u1.to_string()
    440         # Now let's append some fields. Say, 131073 (the segment size)
    441         # and 3 (the "k" encoding parameter).
    442         expected_extensions = []
    443         for e in ('131073', '3'):
    444             cap += (":%s" % e)
    445             expected_extensions.append(e)
    446 
    447             u2 = uri.WriteableMDMFFileURI.init_from_string(cap)
    448             self.failUnlessReallyEqual(self.writekey, u2.writekey)
    449             self.failUnlessReallyEqual(self.fingerprint, u2.fingerprint)
    450             self.failIf(u2.is_readonly())
    451             self.failUnless(u2.is_mutable())
    452 
    453             c2 = u2.to_string()
    454             u2n = uri.WriteableMDMFFileURI.init_from_string(c2)
    455             self.failUnlessReallyEqual(u2, u2n)
    456 
    457             # We should get the extra back when we ask for it.
    458             self.failUnlessEqual(expected_extensions, u2.get_extension_params())
    459 
    460             # These should be preserved through cap attenuation, too.
    461             u3 = u2.get_readonly()
    462             self.failUnlessReallyEqual(self.readkey, u3.readkey)
    463             self.failUnlessReallyEqual(self.fingerprint, u3.fingerprint)
    464             self.failUnless(u3.is_readonly())
    465             self.failUnless(u3.is_mutable())
    466             self.failUnlessEqual(expected_extensions, u3.get_extension_params())
    467 
    468             c3 = u3.to_string()
    469             u3n = uri.ReadonlyMDMFFileURI.init_from_string(c3)
    470             self.failUnlessReallyEqual(u3, u3n)
    471 
    472             u4 = u3.get_verify_cap()
    473             self.failUnlessReallyEqual(self.storage_index, u4.storage_index)
    474             self.failUnlessReallyEqual(self.fingerprint, u4.fingerprint)
    475             self.failUnless(u4.is_readonly())
    476             self.failIf(u4.is_mutable())
    477 
    478             c4 = u4.to_string()
    479             u4n = uri.MDMFVerifierURI.init_from_string(c4)
    480             self.failUnlessReallyEqual(u4n, u4)
    481 
    482             self.failUnlessEqual(expected_extensions, u4.get_extension_params())
    483 
    484 
    485     def test_sdmf_cap_extra_information(self):
    486         # For interface consistency, we define a method to get
    487         # extensions for SDMF files as well. This method must always
    488         # return no extensions, since SDMF files were not created with
    489         # extensions and cannot be modified to include extensions
    490         # without breaking older clients.
    491         u1 = uri.WriteableSSKFileURI(self.writekey, self.fingerprint)
    492438        cap = u1.to_string()
    493         u2 = uri.WriteableSSKFileURI.init_from_string(cap)
    494         self.failUnlessEqual([], u2.get_extension_params())
    495 
    496     def test_extension_character_range(self):
    497         # As written now, we shouldn't put things other than numbers in
    498         # the extension fields.
    499         writecap = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint).to_string()
    500         readcap  = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint).to_string()
    501         vcap     = uri.MDMFVerifierURI(self.storage_index, self.fingerprint).to_string()
    502         self.failUnlessRaises(uri.BadURIError,
    503                               uri.WriteableMDMFFileURI.init_from_string,
    504                               ("%s:invalid" % writecap))
    505         self.failUnlessRaises(uri.BadURIError,
    506                               uri.ReadonlyMDMFFileURI.init_from_string,
    507                               ("%s:invalid" % readcap))
    508         self.failUnlessRaises(uri.BadURIError,
    509                               uri.MDMFVerifierURI.init_from_string,
    510                               ("%s:invalid" % vcap))
     439
     440        cap2 = cap+":I COME FROM THE FUTURE"
     441        u2 = uri.WriteableMDMFFileURI.init_from_string(cap2)
     442        self.failUnlessReallyEqual(self.writekey, u2.writekey)
     443        self.failUnlessReallyEqual(self.fingerprint, u2.fingerprint)
     444        self.failIf(u2.is_readonly())
     445        self.failUnless(u2.is_mutable())
     446
     447        cap3 = cap+":"+os.urandom(40) # parse *that*!
     448        u3 = uri.WriteableMDMFFileURI.init_from_string(cap3)
     449        self.failUnlessReallyEqual(self.writekey, u3.writekey)
     450        self.failUnlessReallyEqual(self.fingerprint, u3.fingerprint)
     451        self.failIf(u3.is_readonly())
     452        self.failUnless(u3.is_mutable())
     453
     454        cap4 = u1.get_readonly().to_string()+":ooh scary future stuff"
     455        u4 = uri.from_string_mutable_filenode(cap4)
     456        self.failUnlessReallyEqual(self.readkey, u4.readkey)
     457        self.failUnlessReallyEqual(self.fingerprint, u4.fingerprint)
     458        self.failUnless(u4.is_readonly())
     459        self.failUnless(u4.is_mutable())
     460
     461        cap5 = u1.get_verify_cap().to_string()+":spoilers!"
     462        u5 = uri.from_string(cap5)
     463        self.failUnlessReallyEqual(self.storage_index, u5.storage_index)
     464        self.failUnlessReallyEqual(self.fingerprint, u5.fingerprint)
     465        self.failUnless(u5.is_readonly())
     466        self.failIf(u5.is_mutable())
    511467
    512468
    513469    def test_mdmf_valid_human_encoding(self):
    class Mutable(testutil.ReallyEqualMixin, unittest.TestCase): 
    517473        # test that a valid cap (with and without the traditional
    518474        # separators) is recognized and accepted by the classes.
    519475        w1 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint)
    520         w2 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint,
    521                                      ['131073', '3'])
    522476        r1 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint)
    523         r2 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint,
    524                                      ['131073', '3'])
    525477        v1 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint)
    526         v2 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint,
    527                                  ['131073', '3'])
    528478
    529         # These will yield six different caps.
    530         for o in (w1, w2, r1 , r2, v1, v2):
     479        # These will yield three different caps.
     480        for o in (w1, r1, v1):
    531481            url = base + o.to_string()
    532482            o1 = o.__class__.init_from_human_encoding(url)
    533483            self.failUnlessReallyEqual(o1, o)
    534484
    535             # Note that our cap will, by default, have : as separators. 
     485            # Note that our cap will, by default, have : as separators.
    536486            # But it's expected that users from, e.g., the WUI, will
    537487            # have %3A as a separator. We need to make sure that the
    538488            # initialization routine handles that, too.
    class Mutable(testutil.ReallyEqualMixin, unittest.TestCase): 
    550500        # test that a valid cap (with and without the traditional
    551501        # separators) is recognized and accepted by the classes.
    552502        w1 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint)
    553         w2 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint,
    554                                      ['131073', '3'])
    555503        r1 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint)
    556         r2 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint,
    557                                      ['131073', '3'])
    558504        v1 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint)
    559         v2 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint,
    560                                  ['131073', '3'])
    561505
    562         # These will yield six different caps.
    563         for o in (w1, w2, r1 , r2, v1, v2):
     506        # These will yield three different caps.
     507        for o in (w1, r1, v1):
    564508            url = base + o.to_string()
    565509            self.failUnlessRaises(uri.BadURIError,
    566510                                  o.__class__.init_from_human_encoding,
    class Mutable(testutil.ReallyEqualMixin, unittest.TestCase): 
    572516        # test that a valid cap (with and without the traditional
    573517        # separators) is recognized and accepted by the classes.
    574518        w1 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint)
    575         w2 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint,
    576                                      ['131073', '3'])
    577519        r1 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint)
    578         r2 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint,
    579                                      ['131073', '3'])
    580520        v1 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint)
    581         v2 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint,
    582                                  ['131073', '3'])
    583521
    584         # These will yield six different caps.
    585         for o in (w1, w2, r1 , r2, v1, v2):
     522        # These will yield three different caps.
     523        for o in (w1, r1, v1):
    586524            # not exhaustive, obviously...
    587525            url = base + o.to_string() + "foobarbaz"
    588526            url2 = base + "foobarbaz" + o.to_string()
    class Mutable(testutil.ReallyEqualMixin, unittest.TestCase): 
    603541        u3 = uri.from_string_mutable_filenode(cap)
    604542        self.failUnlessEqual(u3, u1)
    605543
    606         # XXX: We should refactor the extension field into setUp
    607         u1 = uri.WriteableMDMFFileURI(self.writekey, self.fingerprint,
    608                                      ['131073', '3'])
    609         cap = u1.to_string()
    610         self.failUnless(uri.is_uri(cap))
    611         u2 = uri.from_string(cap)
    612         self.failUnlessReallyEqual(u1, u2)
    613         u3 = uri.from_string_mutable_filenode(cap)
    614         self.failUnlessEqual(u3, u1)
    615 
    616544        u1 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint)
    617545        cap = u1.to_string()
    618546        self.failUnless(uri.is_uri(cap))
    class Mutable(testutil.ReallyEqualMixin, unittest.TestCase): 
    621549        u3 = uri.from_string_mutable_filenode(cap)
    622550        self.failUnlessEqual(u3, u1)
    623551
    624         u1 = uri.ReadonlyMDMFFileURI(self.readkey, self.fingerprint,
    625                                      ['131073', '3'])
    626         cap = u1.to_string()
    627         self.failUnless(uri.is_uri(cap))
    628         u2 = uri.from_string(cap)
    629         self.failUnlessReallyEqual(u1, u2)
    630         u3 = uri.from_string_mutable_filenode(cap)
    631         self.failUnlessEqual(u3, u1)
    632 
    633552        u1 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint)
    634553        cap = u1.to_string()
    635554        self.failUnless(uri.is_uri(cap))
    class Mutable(testutil.ReallyEqualMixin, unittest.TestCase): 
    638557        u3 = uri.from_string_verifier(cap)
    639558        self.failUnlessEqual(u3, u1)
    640559
    641         u1 = uri.MDMFVerifierURI(self.storage_index, self.fingerprint,
    642                                  ['131073', '3'])
    643         cap = u1.to_string()
    644         self.failUnless(uri.is_uri(cap))
    645         u2 = uri.from_string(cap)
    646         self.failUnlessReallyEqual(u1, u2)
    647         u3 = uri.from_string_verifier(cap)
    648         self.failUnlessEqual(u3, u1)
    649 
    650560
    651561class Dirnode(testutil.ReallyEqualMixin, unittest.TestCase):
    652562    def test_pack(self):
    class Dirnode(testutil.ReallyEqualMixin, unittest.TestCase): 
    816726        d3 = uri.from_string(d2.to_string(), deep_immutable=True)
    817727        self.failUnlessIsInstance(d3, uri.UnknownURI)
    818728
    819     def test_mdmf_with_extensions(self):
    820         writekey = "\x01" * 16
    821         fingerprint = "\x02" * 32
    822         uri1 = uri.WriteableMDMFFileURI(writekey, fingerprint)
    823         d1 = uri.MDMFDirectoryURI(uri1)
    824         d1_uri = d1.to_string()
    825         # Add some extensions, verify that the URI is interpreted
    826         # correctly.
    827         d1_uri += ":3:131073"
    828         uri2 = uri.from_string(d1_uri)
    829         self.failUnlessIsInstance(uri2, uri.MDMFDirectoryURI)
    830         self.failUnless(IURI.providedBy(uri2))
    831         self.failUnless(IDirnodeURI.providedBy(uri2))
    832         self.failUnless(uri1.is_mutable())
    833         self.failIf(uri1.is_readonly())
    834 
    835         d2_uri = uri2.to_string()
    836         self.failUnlessIn(":3:131073", d2_uri)
    837 
    838         # Now attenuate, verify that the extensions persist
    839         ro_uri = uri2.get_readonly()
    840         self.failUnlessIsInstance(ro_uri, uri.ReadonlyMDMFDirectoryURI)
    841         self.failUnless(ro_uri.is_mutable())
    842         self.failUnless(ro_uri.is_readonly())
    843         self.failUnless(IURI.providedBy(ro_uri))
    844         self.failUnless(IDirnodeURI.providedBy(ro_uri))
    845         ro_uri_str = ro_uri.to_string()
    846         self.failUnlessIn(":3:131073", ro_uri_str)
    847 
    848729    def test_mdmf_attenuation(self):
    849730        writekey = "\x01" * 16
    850731        fingerprint = "\x02" * 32
  • src/allmydata/test/test_web.py

    diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
    index 370f09a..adf4f71 100644
    a b class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi 
    892892        return d
    893893
    894894    def test_GET_FILE_URI_mdmf_extensions(self):
    895         base = "/uri/%s" % urllib.quote("%s:3:131073" % self._quux_txt_uri)
    896         d = self.GET(base)
    897         d.addCallback(self.failUnlessIsQuuxDotTxt)
    898         return d
    899 
    900     def test_GET_FILE_URI_mdmf_bare_cap(self):
    901         cap_elements = self._quux_txt_uri.split(":")
    902         # 6 == expected cap length with two extensions.
    903         self.failUnlessEqual(len(cap_elements), 6)
    904 
    905         # Now lop off the extension parameters and stitch everything
    906         # back together
    907         quux_uri = ":".join(cap_elements[:len(cap_elements) - 2])
    908 
    909         # Now GET that. We should get back quux.
    910         base = "/uri/%s" % urllib.quote(quux_uri)
     895        base = "/uri/%s" % urllib.quote("%s:RANDOMSTUFF" % self._quux_txt_uri)
    911896        d = self.GET(base)
    912897        d.addCallback(self.failUnlessIsQuuxDotTxt)
    913898        return d
    class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi 
    949934        return d
    950935
    951936    def test_PUT_FILE_URI_mdmf_extensions(self):
    952         base = "/uri/%s" % urllib.quote("%s:3:131073" % self._quux_txt_uri)
     937        base = "/uri/%s" % urllib.quote("%s:EXTENSIONSTUFF" % self._quux_txt_uri)
    953938        self._quux_new_contents = "new_contents"
    954939        d = self.GET(base)
    955940        d.addCallback(lambda res: self.failUnlessIsQuuxDotTxt(res))
    class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi 
    959944                                                       res))
    960945        return d
    961946
    962     def test_PUT_FILE_URI_mdmf_bare_cap(self):
    963         elements = self._quux_txt_uri.split(":")
    964         self.failUnlessEqual(len(elements), 6)
    965 
    966         quux_uri = ":".join(elements[:len(elements) - 2])
    967         base = "/uri/%s" % urllib.quote(quux_uri)
    968         self._quux_new_contents = "new_contents" * 50000
    969 
    970         d = self.GET(base)
    971         d.addCallback(self.failUnlessIsQuuxDotTxt)
    972         d.addCallback(lambda ignored: self.PUT(base, self._quux_new_contents))
    973         d.addCallback(lambda ignored: self.GET(base))
    974         d.addCallback(lambda res:
    975             self.failUnlessEqual(res, self._quux_new_contents))
    976         return d
    977 
    978947    def test_PUT_FILE_URI_mdmf_readonly(self):
    979948        # We're not allowed to PUT things to a readonly cap.
    980949        base = "/uri/%s" % self._quux_txt_readonly_uri
    class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi 
    10431012        return d
    10441013
    10451014    def test_GET_FILEURL_info_mdmf_extensions(self):
    1046         d = self.GET("/uri/%s:3:131073?t=info" % self._quux_txt_uri)
     1015        d = self.GET("/uri/%s:STUFF?t=info" % self._quux_txt_uri)
    10471016        def _got(res):
    10481017            self.failUnlessIn("mutable file (mdmf)", res)
    10491018            self.failUnlessIn(self._quux_txt_uri, res)
    class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi 
    10511020        d.addCallback(_got)
    10521021        return d
    10531022
    1054     def test_GET_FILEURL_info_mdmf_bare_cap(self):
    1055         elements = self._quux_txt_uri.split(":")
    1056         self.failUnlessEqual(len(elements), 6)
    1057 
    1058         quux_uri = ":".join(elements[:len(elements) - 2])
    1059         base = "/uri/%s?t=info" % urllib.quote(quux_uri)
    1060         d = self.GET(base)
    1061         def _got(res):
    1062             self.failUnlessIn("mutable file (mdmf)", res)
    1063             self.failUnlessIn(quux_uri, res)
    1064         d.addCallback(_got)
    1065         return d
    1066 
    10671023    def test_PUT_overwrite_only_files(self):
    10681024        # create a directory, put a file in that directory.
    10691025        contents, n, filecap = self.makefile(8)
    class Web(WebMixin, WebErrorMixin, testutil.StallMixin, testutil.ReallyEqualMixi 
    12881244        d.addCallback(_got_json, "sdmf")
    12891245        return d
    12901246
    1291     def test_GET_FILEURL_json_mdmf_extensions(self):
    1292         # A GET invoked against a URL that includes an MDMF cap with
    1293         # extensions should fetch the same JSON information as a GET
    1294         # invoked against a bare cap.
    1295         self._quux_txt_uri = "%s:3:131073" % self._quux_txt_uri
    1296         self._quux_txt_readonly_uri = "%s:3:131073" % self._quux_txt_readonly_uri
    1297         d = self.GET("/uri/%s?t=json" % urllib.quote(self._quux_txt_uri))
    1298         d.addCallback(self.failUnlessIsQuuxJSON)
    1299         return d
    1300 
    1301     def test_GET_FILEURL_json_mdmf_bare_cap(self):
    1302         elements = self._quux_txt_uri.split(":")
    1303         self.failUnlessEqual(len(elements), 6)
    1304 
    1305         quux_uri = ":".join(elements[:len(elements) - 2])
    1306         # so failUnlessIsQuuxJSON will work.
    1307         self._quux_txt_uri = quux_uri
    1308 
    1309         # we need to alter the readonly URI in the same way, again so
    1310         # failUnlessIsQuuxJSON will work
    1311         elements = self._quux_txt_readonly_uri.split(":")
    1312         self.failUnlessEqual(len(elements), 6)
    1313         quux_ro_uri = ":".join(elements[:len(elements) - 2])
    1314         self._quux_txt_readonly_uri = quux_ro_uri
    1315 
    1316         base = "/uri/%s?t=json" % urllib.quote(quux_uri)
    1317         d = self.GET(base)
    1318         d.addCallback(self.failUnlessIsQuuxJSON)
    1319         return d
    1320 
    1321     def test_GET_FILEURL_json_mdmf_bare_readonly_cap(self):
    1322         elements = self._quux_txt_readonly_uri.split(":")
    1323         self.failUnlessEqual(len(elements), 6)
    1324 
    1325         quux_readonly_uri = ":".join(elements[:len(elements) - 2])
    1326         # so failUnlessIsQuuxJSON will work
    1327         self._quux_txt_readonly_uri = quux_readonly_uri
    1328         base = "/uri/%s?t=json" % quux_readonly_uri
    1329         d = self.GET(base)
    1330         # XXX: We may need to make a method that knows how to check for
    1331         # readonly JSON, or else alter that one so that it knows how to
    1332         # do that.
    1333         d.addCallback(self.failUnlessIsQuuxJSON, readonly=True)
    1334         return d
    1335 
    13361247    def test_GET_FILEURL_json_mdmf(self):
    13371248        d = self.GET("/uri/%s?t=json" % urllib.quote(self._quux_txt_uri))
    13381249        d.addCallback(self.failUnlessIsQuuxJSON)
  • src/allmydata/uri.py

    diff --git a/src/allmydata/uri.py b/src/allmydata/uri.py
    index 62bf9b9..c500c7b 100644
    a b BASE32STR_256bits = '(%s{51}%s)' % (base32.BASE32CHAR, base32.BASE32CHAR_1bits) 
    2828SEP='(?::|%3A)'
    2929NUMBER='([0-9]+)'
    3030NUMBER_IGNORE='(?:[0-9]+)'
    31 OPTIONAL_EXTENSION_FIELD = '(' + SEP + '[0-9' + SEP + ']+|)'
    3231
    3332# "human-encoded" URIs are allowed to come with a leading
    3433# 'http://127.0.0.1:(8123|3456)/uri/' that will be ignored.
    class WriteableSSKFileURI(_BaseURI): 
    294293    def get_verify_cap(self):
    295294        return SSKVerifierURI(self.storage_index, self.fingerprint)
    296295
    297     def get_extension_params(self):
    298         return []
    299 
    300     def set_extension_params(self, params):
    301         pass
    302 
    303296class ReadonlySSKFileURI(_BaseURI):
    304297    implements(IURI, IMutableFileURI)
    305298
    class ReadonlySSKFileURI(_BaseURI): 
    354347    def get_verify_cap(self):
    355348        return SSKVerifierURI(self.storage_index, self.fingerprint)
    356349
    357     def get_extension_params(self):
    358         return []
    359 
    360     def set_extension_params(self, params):
    361         pass
    362 
    363350class SSKVerifierURI(_BaseURI):
    364351    implements(IVerifierURI)
    365352
    class SSKVerifierURI(_BaseURI): 
    404391    def get_verify_cap(self):
    405392        return self
    406393
    407     def get_extension_params(self):
    408         return []
    409 
    410     def set_extension_params(self, params):
    411         pass
    412 
    413394class WriteableMDMFFileURI(_BaseURI):
    414395    implements(IURI, IMutableFileURI)
    415396
    416397    BASE_STRING='URI:MDMF:'
    417     STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
    418     HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
     398    STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+'(:|$)')
     399    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+'(:|$)')
    419400
    420     def __init__(self, writekey, fingerprint, params=[]):
     401    def __init__(self, writekey, fingerprint):
    421402        self.writekey = writekey
    422403        self.readkey = hashutil.ssk_readkey_hash(writekey)
    423404        self.storage_index = hashutil.ssk_storage_index_hash(self.readkey)
    424405        assert len(self.storage_index) == 16
    425406        self.fingerprint = fingerprint
    426         self.extension = params
    427407
    428408    @classmethod
    429409    def init_from_human_encoding(cls, uri):
    430410        mo = cls.HUMAN_RE.search(uri)
    431411        if not mo:
    432412            raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
    433         params = filter(lambda x: x != '', re.split(SEP, mo.group(3)))
    434         return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
     413        return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
    435414
    436415    @classmethod
    437416    def init_from_string(cls, uri):
    438417        mo = cls.STRING_RE.search(uri)
    439418        if not mo:
    440419            raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
    441         params = mo.group(3)
    442         params = filter(lambda x: x != '', params.split(":"))
    443         return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
     420        return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
    444421
    445422    def to_string(self):
    446423        assert isinstance(self.writekey, str)
    447424        assert isinstance(self.fingerprint, str)
    448425        ret = 'URI:MDMF:%s:%s' % (base32.b2a(self.writekey),
    449426                                  base32.b2a(self.fingerprint))
    450         if self.extension:
    451             ret += ":"
    452             ret += ":".join(self.extension)
    453 
    454427        return ret
    455428
    456429    def __repr__(self):
    class WriteableMDMFFileURI(_BaseURI): 
    469442        return True
    470443
    471444    def get_readonly(self):
    472         return ReadonlyMDMFFileURI(self.readkey, self.fingerprint, self.extension)
     445        return ReadonlyMDMFFileURI(self.readkey, self.fingerprint)
    473446
    474447    def get_verify_cap(self):
    475         return MDMFVerifierURI(self.storage_index, self.fingerprint, self.extension)
    476 
    477     def get_extension_params(self):
    478         return self.extension
    479 
    480     def set_extension_params(self, params):
    481         params = map(str, params)
    482         self.extension = params
     448        return MDMFVerifierURI(self.storage_index, self.fingerprint)
    483449
    484450class ReadonlyMDMFFileURI(_BaseURI):
    485451    implements(IURI, IMutableFileURI)
    486452
    487453    BASE_STRING='URI:MDMF-RO:'
    488     STRING_RE=re.compile('^' +BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
    489     HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF-RO'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
     454    STRING_RE=re.compile('^' +BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+'(:|$)')
     455    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF-RO'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+'(:|$)')
    490456
    491     def __init__(self, readkey, fingerprint, params=[]):
     457    def __init__(self, readkey, fingerprint):
    492458        self.readkey = readkey
    493459        self.storage_index = hashutil.ssk_storage_index_hash(self.readkey)
    494460        assert len(self.storage_index) == 16
    495461        self.fingerprint = fingerprint
    496         self.extension = params
    497462
    498463    @classmethod
    499464    def init_from_human_encoding(cls, uri):
    500465        mo = cls.HUMAN_RE.search(uri)
    501466        if not mo:
    502467            raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
    503         params = mo.group(3)
    504         params = filter(lambda x: x!= '', re.split(SEP, params))
    505         return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
     468        return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
    506469
    507470    @classmethod
    508471    def init_from_string(cls, uri):
    class ReadonlyMDMFFileURI(_BaseURI): 
    510473        if not mo:
    511474            raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
    512475
    513         params = mo.group(3)
    514         params = filter(lambda x: x != '', params.split(":"))
    515         return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
     476        return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)))
    516477
    517478    def to_string(self):
    518479        assert isinstance(self.readkey, str)
    519480        assert isinstance(self.fingerprint, str)
    520481        ret = 'URI:MDMF-RO:%s:%s' % (base32.b2a(self.readkey),
    521482                                     base32.b2a(self.fingerprint))
    522         if self.extension:
    523             ret += ":"
    524             ret += ":".join(self.extension)
    525 
    526483        return ret
    527484
    528485    def __repr__(self):
    class ReadonlyMDMFFileURI(_BaseURI): 
    544501        return self
    545502
    546503    def get_verify_cap(self):
    547         return MDMFVerifierURI(self.storage_index, self.fingerprint, self.extension)
    548 
    549     def get_extension_params(self):
    550         return self.extension
    551 
    552     def set_extension_params(self, params):
    553         params = map(str, params)
    554         self.extension = params
     504        return MDMFVerifierURI(self.storage_index, self.fingerprint)
    555505
    556506class MDMFVerifierURI(_BaseURI):
    557507    implements(IVerifierURI)
    558508
    559509    BASE_STRING='URI:MDMF-Verifier:'
    560     STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
    561     HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF-Verifier'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+OPTIONAL_EXTENSION_FIELD+'$')
     510    STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+BASE32STR_256bits+'(:|$)')
     511    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'MDMF-Verifier'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+'(:|$)')
    562512
    563     def __init__(self, storage_index, fingerprint, params=[]):
     513    def __init__(self, storage_index, fingerprint):
    564514        assert len(storage_index) == 16
    565515        self.storage_index = storage_index
    566516        self.fingerprint = fingerprint
    567         self.extension = params
    568517
    569518    @classmethod
    570519    def init_from_human_encoding(cls, uri):
    571520        mo = cls.HUMAN_RE.search(uri)
    572521        if not mo:
    573522            raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
    574         params = mo.group(3)
    575         params = filter(lambda x: x != '', re.split(SEP, params))
    576         return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
     523        return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)))
    577524
    578525    @classmethod
    579526    def init_from_string(cls, uri):
    580527        mo = cls.STRING_RE.search(uri)
    581528        if not mo:
    582529            raise BadURIError("'%s' doesn't look like a %s cap" % (uri, cls))
    583         params = mo.group(3)
    584         params = filter(lambda x: x != '', params.split(":"))
    585         return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)), params)
     530        return cls(si_a2b(mo.group(1)), base32.a2b(mo.group(2)))
    586531
    587532    def to_string(self):
    588533        assert isinstance(self.storage_index, str)
    589534        assert isinstance(self.fingerprint, str)
    590535        ret = 'URI:MDMF-Verifier:%s:%s' % (si_b2a(self.storage_index),
    591536                                           base32.b2a(self.fingerprint))
    592         if self.extension:
    593             ret += ':'
    594             ret += ":".join(self.extension)
    595 
    596537        return ret
    597538
    598539    def is_readonly(self):
    class MDMFVerifierURI(_BaseURI): 
    607548    def get_verify_cap(self):
    608549        return self
    609550
    610     def get_extension_params(self):
    611         return self.extension
    612 
    613551class _DirectoryBaseURI(_BaseURI):
    614552    implements(IURI, IDirnodeURI)
    615553    def __init__(self, filenode_uri=None):