[tahoe-dev] uricap.diff.txt

zooko zooko at zooko.com
Fri May 16 11:51:42 PDT 2008


Brian:

Here is a diff of a change that I made that might interact with the  
webish.py refactoring that you are doing.

The idea is: start accepting "cap" instead of "uri" in all of the  
various places where it matters (while still generating "uri" for  
backwards compatibility).  This patch also generalizes and fixes the  
regex for URL caps per Ben Laurie's suggestion [1].

This patch also refactors uri.py to have separate notions of  
encodings of caps "for humans" and encodings of caps "for  
computers".  The latter may in the future be more highly compressed.

This patch is fairly complete, but I think I didn't get it passing  
all of its unit tests because I couldn't figure out something about  
control flow in webish.py.

This patch is one of those "forward compatibility" things that makes  
me want to put it into the next Tahoe release.

Regards,

Zooko

[1] http://allmydata.org/pipermail/tahoe-dev/2008-April/000511.html

-------
diff -rN -u old-trunk-uri_cap/src/allmydata/test/test_uri.py new- 
trunk-uri_cap/src/allmydata/test/test_uri.py
--- old-trunk-uri_cap/src/allmydata/test/test_uri.py	2008-05-16  
12:40:05.000000000 -0600
+++ new-trunk-uri_cap/src/allmydata/test/test_uri.py	2008-05-16  
12:40:06.000000000 -0600
@@ -29,17 +29,46 @@
          self.failUnlessIdentical(u, u3)
          self.failUnlessEqual(u.get_verifier(), None)

+    def _help_test_humanencoding(self, data):
+        u0 = uri.LiteralFileURI(data)
+        lcap  = u0.to_human_encoding()
+
+        def _t(u):
+            self.failUnless(IURI.providedBy(u))
+            self.failUnless(IFileURI.providedBy(u))
+            self.failIf(IDirnodeURI.providedBy(u))
+            self.failUnlessEqual(u.data, data)
+            self.failUnlessEqual(u.get_size(), len(data))
+            self.failUnless(u.is_readonly())
+            self.failIf(u.is_mutable())
+
+        u = uri.LiteralFileURI.init_from_human_encoding(lcap)
+        _t(u)
+
+        u2 = uri.from_human_encoding(u.to_string())
+        _t(u2)
+
+        u3 = uri.from_human_encoding(u.to_human_encoding())
+        _t(u3)
+
+        u4 = u.get_readonly()
+        self.failUnlessIdentical(u, u4)
+        self.failUnlessEqual(u.get_verifier(), None)
+
      def test_empty(self):
          data = "" # This data is some *very* small data!
-        return self._help_test(data)
+        self._help_test(data)
+        self._help_test_humanencoding(data)

      def test_pack(self):
          data = "This is some small data"
-        return self._help_test(data)
+        self._help_test(data)
+        self._help_test_humanencoding(data)

      def test_nonascii(self):
          data = "This contains \x00 and URI:LIT: and \n, oh my."
-        return self._help_test(data)
+        self._help_test(data)
+        self._help_test_humanencoding(data)

  class Compare(unittest.TestCase):
      def test_compare(self):
@@ -86,21 +115,30 @@
          u1a = IFileURI(u.to_string())
          self.failUnlessEqual(u1a, u)

+        def _t(u):
+            self.failUnlessEqual(u.storage_index, storage_index)
+            self.failUnlessEqual(u.key, key)
+            self.failUnlessEqual(u.uri_extension_hash,  
uri_extension_hash)
+            self.failUnlessEqual(u.needed_shares, needed_shares)
+            self.failUnlessEqual(u.total_shares, total_shares)
+            self.failUnlessEqual(u.size, size)
+            self.failUnless(u.is_readonly())
+            self.failIf(u.is_mutable())
+            self.failUnless(IURI.providedBy(u))
+            self.failUnless(IFileURI.providedBy(u))
+            self.failIf(IDirnodeURI.providedBy(u))
+            self.failUnlessEqual(u.get_size(), 1234)
+            self.failUnless(u.is_readonly())
+            self.failIf(u.is_mutable())
+
          u2 = uri.from_string(u.to_string())
-        self.failUnlessEqual(u2.storage_index, storage_index)
-        self.failUnlessEqual(u2.key, key)
-        self.failUnlessEqual(u2.uri_extension_hash, uri_extension_hash)
-        self.failUnlessEqual(u2.needed_shares, needed_shares)
-        self.failUnlessEqual(u2.total_shares, total_shares)
-        self.failUnlessEqual(u2.size, size)
-        self.failUnless(u2.is_readonly())
-        self.failIf(u2.is_mutable())
-        self.failUnless(IURI.providedBy(u2))
-        self.failUnless(IFileURI.providedBy(u2))
-        self.failIf(IDirnodeURI.providedBy(u2))
-        self.failUnlessEqual(u2.get_size(), 1234)
-        self.failUnless(u2.is_readonly())
-        self.failIf(u2.is_mutable())
+        _t(u2)
+
+        u3 = uri.from_human_encoding(u.to_human_encoding())
+        _t(u3)
+
+        u4 = uri.from_human_encoding(u.to_string())
+        _t(u4)

          v = u.get_verifier()
          self.failUnless(isinstance(v.to_string(), str))
@@ -163,13 +201,17 @@
      def test_create_invalid(self):
          not_uri = "I am not a URI"
          self.failUnlessRaises(TypeError, uri.from_string, not_uri)
+        self.failUnlessRaises(TypeError, uri.from_human_encoding,  
not_uri)


  class Constraint(unittest.TestCase):
      def test_constraint(self):
         good="http://127.0.0.1:8123/uri/URI%3ADIR2% 
3Agh3l5rbvnv2333mrfvalmjfr4i% 
3Alz6l7u3z3b7g37s4zkdmfpx5ly4ib4m6thrpbusi6ys62qtc6mma/"
+       good2="http://127.0.0.1:8123/cap/CAP%3ADIR2% 
3Agh3l5rbvnv2333mrfvalmjfr4i% 
3Alz6l7u3z3b7g37s4zkdmfpx5ly4ib4m6thrpbusi6ys62qtc6mma/"
         uri.NewDirectoryURI.init_from_human_encoding(good)
+       uri.NewDirectoryURI.init_from_human_encoding(good2)
         self.failUnlessRaises(AssertionError,  
uri.NewDirectoryURI.init_from_string, good)
+       self.failUnlessRaises(AssertionError,  
uri.NewDirectoryURI.init_from_string, good2)
         bad = good + '==='
         self.failUnlessRaises(AssertionError,  
uri.NewDirectoryURI.init_from_human_encoding, bad)
         self.failUnlessRaises(AssertionError,  
uri.NewDirectoryURI.init_from_string, bad)
@@ -193,45 +235,64 @@
          u1a = IMutableFileURI(u.to_string())
          self.failUnlessEqual(u1a, u)

+        def _t(u):
+            self.failUnlessEqual(u.writekey, writekey)
+            self.failUnlessEqual(u.fingerprint, fingerprint)
+            self.failIf(u.is_readonly())
+            self.failUnless(u.is_mutable())
+            self.failUnless(IURI.providedBy(u))
+            self.failUnless(IMutableFileURI.providedBy(u))
+            self.failIf(IDirnodeURI.providedBy(u))
+
          u2 = uri.from_string(u.to_string())
-        self.failUnlessEqual(u2.writekey, writekey)
-        self.failUnlessEqual(u2.fingerprint, fingerprint)
-        self.failIf(u2.is_readonly())
-        self.failUnless(u2.is_mutable())
-        self.failUnless(IURI.providedBy(u2))
-        self.failUnless(IMutableFileURI.providedBy(u2))
-        self.failIf(IDirnodeURI.providedBy(u2))
+        _t(u2)
+
+        u2h = uri.from_human_encoding(u.to_human_encoding())
+        _t(u2h)
+
+        u2hs = uri.from_human_encoding(u.to_string())
+        _t(u2hs)

-        u3 = u2.get_readonly()
          readkey = hashutil.ssk_readkey_hash(writekey)
-        self.failUnlessEqual(u3.fingerprint, fingerprint)
-        self.failUnlessEqual(u3.readkey, readkey)
-        self.failUnless(u3.is_readonly())
-        self.failUnless(u3.is_mutable())
-        self.failUnless(IURI.providedBy(u3))
-        self.failUnless(IMutableFileURI.providedBy(u3))
-        self.failIf(IDirnodeURI.providedBy(u3))
+        def _tr(u):
+            self.failUnlessEqual(u.fingerprint, fingerprint)
+            self.failUnlessEqual(u.readkey, readkey)
+            self.failUnless(u.is_readonly())
+            self.failUnless(u.is_mutable())
+            self.failUnless(IURI.providedBy(u))
+            self.failUnless(IMutableFileURI.providedBy(u))
+            self.failIf(IDirnodeURI.providedBy(u))
+
+        u3 = u2.get_readonly()
+        _tr(u3)

          u4 = uri.ReadonlySSKFileURI(readkey, fingerprint)
-        self.failUnlessEqual(u4.fingerprint, fingerprint)
-        self.failUnlessEqual(u4.readkey, readkey)
-        self.failUnless(u4.is_readonly())
-        self.failUnless(u4.is_mutable())
-        self.failUnless(IURI.providedBy(u4))
-        self.failUnless(IMutableFileURI.providedBy(u4))
-        self.failIf(IDirnodeURI.providedBy(u4))
+        _tr(u4)

          u4a = uri.from_string(u4.to_string())
          self.failUnlessEqual(u4a, u4)
          self.failUnless("ReadonlySSKFileURI" in str(u4a))
          self.failUnlessIdentical(u4a.get_readonly(), u4a)

+        u4h = uri.from_human_encoding(u4.to_human_encoding())
+        self.failUnlessEqual(u4h, u4)
+        self.failUnless("ReadonlySSKFileURI" in str(u4h))
+        self.failUnlessIdentical(u4h.get_readonly(), u4h)
+
+        u4hs = uri.from_human_encoding(u4.to_string())
+        self.failUnlessEqual(u4hs, u4)
+        self.failUnless("ReadonlySSKFileURI" in str(u4hs))
+        self.failUnlessIdentical(u4hs.get_readonly(), u4hs)
+
          u5 = u4.get_verifier()
          self.failUnless(IVerifierURI.providedBy(u5))
          self.failUnlessEqual(u5.storage_index, u.storage_index)
          u6 = IVerifierURI(u5.to_string())
          self.failUnless(IVerifierURI.providedBy(u6))
          self.failUnlessEqual(u6.storage_index, u.storage_index)
+        u6h = uri.from_human_encoding(u5.to_human_encoding())
+        self.failUnless(IVerifierURI.providedBy(u6h))
+        self.failUnlessEqual(u6h.storage_index, u.storage_index)
          u7 = u.get_verifier()
          self.failUnless(IVerifierURI.providedBy(u7))
          self.failUnlessEqual(u7.storage_index, u.storage_index)
@@ -256,13 +317,19 @@
          u1a = IDirnodeURI(u1.to_string())
          self.failUnlessEqual(u1a, u1)

+        def _t(u):
+            self.failUnlessEqual(u1.to_string(), u.to_string())
+            self.failIf(u.is_readonly())
+            self.failUnless(u.is_mutable())
+            self.failUnless(IURI.providedBy(u))
+            self.failIf(IFileURI.providedBy(u))
+            self.failUnless(IDirnodeURI.providedBy(u))
+
          u2 = uri.from_string(u1.to_string())
-        self.failUnlessEqual(u1.to_string(), u2.to_string())
-        self.failIf(u2.is_readonly())
-        self.failUnless(u2.is_mutable())
-        self.failUnless(IURI.providedBy(u2))
-        self.failIf(IFileURI.providedBy(u2))
-        self.failUnless(IDirnodeURI.providedBy(u2))
+        _t(u2)
+
+        u2h = uri.from_human_encoding(u1.to_human_encoding())
+        _t(u2h)

          u3 = u2.get_readonly()
          self.failUnless(u3.is_readonly())
@@ -280,8 +347,15 @@
          u3a = uri.from_string(u3.to_string())
          self.failUnlessIdentical(u3a, u3a.get_readonly())

+        u3h = uri.from_human_encoding(u3.to_human_encoding())
+        self.failUnlessIdentical(u3h, u3h.get_readonly())
+
+        u3hs = uri.from_human_encoding(u3.to_string())
+        self.failUnlessIdentical(u3hs, u3hs.get_readonly())
+
          u4 = uri.ReadonlyNewDirectoryURI 
(u2._filenode_uri.get_readonly())
          self.failUnlessEqual(u4.to_string(), u3.to_string())
+        self.failUnlessEqual(u4.to_human_encoding(),  
u3.to_human_encoding())
          self.failUnless(u4.is_readonly())
          self.failUnless(u4.is_mutable())
          self.failUnless(IURI.providedBy(u4))
diff -rN -u old-trunk-uri_cap/src/allmydata/uri.py new-trunk-uri_cap/ 
src/allmydata/uri.py
--- old-trunk-uri_cap/src/allmydata/uri.py	2008-05-16  
12:40:05.000000000 -0600
+++ new-trunk-uri_cap/src/allmydata/uri.py	2008-05-16  
12:40:06.000000000 -0600
@@ -14,12 +14,13 @@
  BASE32STR_128bits = '(%s{25}%s)' % (base32.BASE32CHAR,  
base32.BASE32CHAR_3bits)
  BASE32STR_256bits = '(%s{51}%s)' % (base32.BASE32CHAR,  
base32.BASE32CHAR_1bits)

+URI='(?:URI|CAP)'
  SEP='(?::|%3A)'
  NUMBER='([0-9]+)'

  # URIs (soon to be renamed "caps") are always allowed to come with  
a leading
  # 'http://127.0.0.1:8123/uri/' that will be ignored.
-OPTIONALHTTPLEAD=r'(?:https?://(127.0.0.1|localhost):8123/uri/)?'
+OPTIONALHTTPLEAD=r'(?:https?://(?:127.0.0.1|localhost):8123/(?:uri| 
cap)/)?'


  class _BaseURI:
@@ -33,14 +34,18 @@
          return cmp(self.to_string(), them.to_string())
      def to_human_encoding(self):
          return 'http://127.0.0.1:8123/uri/'+self.to_string()
+    # def __repr__(self):
+    #     return "%s(%s)" % (self.__class__.__name__,  
self.to_human_encoding())
+    # def __str__(self):
+    #     return self.to_human_encoding()

  class CHKFileURI(_BaseURI):
      implements(IURI, IFileURI)

-    STRING_RE=re.compile('^URI:CHK:'+BASE32STR_128bits+':'+
+    STRING_RE=re.compile('^'+URI+':CHK:'+BASE32STR_128bits+':'+
                           BASE32STR_256bits+':'+NUMBER+':'+NUMBER 
+':'+NUMBER+
                           '$')
-    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'CHK'+SEP+
+    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'CHK'+SEP+
                       BASE32STR_128bits+SEP+BASE32STR_256bits+SEP 
+NUMBER+
                       SEP+NUMBER+SEP+NUMBER+'$')

@@ -56,12 +61,19 @@
          self.storage_index = hashutil.storage_index_hash(key)
          assert len(self.storage_index) == 16 # sha256 hash  
truncated to 128

+    def abbrev(self):
+        return base32.b2a(self.storage_index)
+
      @classmethod
      def init_from_human_encoding(cls, uri):
          mo = cls.HUMAN_RE.search(uri)
          assert mo, uri
-        return cls(base32.a2b(mo.group(1)), base32.a2b(mo.group(2)),
-                   int(mo.group(3)), int(mo.group(4)), int(mo.group 
(5)))
+        k = mo.group(1)
+        assert k
+        h = mo.group(2)
+        assert h
+        return cls(base32.a2b(k), base32.a2b(h), int(mo.group(3)),
+                   int(mo.group(4)), int(mo.group(5)))

      @classmethod
      def init_from_string(cls, uri):
@@ -102,9 +114,9 @@
  class CHKFileVerifierURI(_BaseURI):
      implements(IVerifierURI)

-    STRING_RE=re.compile('^URI:CHK-Verifier:'+BASE32STR_128bits+':'+
+    STRING_RE=re.compile('^'+URI+':CHK-Verifier:'+BASE32STR_128bits 
+':'+
                           BASE32STR_256bits+':'+NUMBER+':'+NUMBER 
+':'+NUMBER)
-    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'CHK- 
Verifier'+SEP+
+    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'CHK- 
Verifier'+SEP+
                          BASE32STR_128bits+SEP+BASE32STR_256bits+SEP 
+NUMBER+
                          SEP+NUMBER+SEP+NUMBER)

@@ -147,8 +159,8 @@
  class LiteralFileURI(_BaseURI):
      implements(IURI, IFileURI)

-    STRING_RE=re.compile('^URI:LIT:'+base32.BASE32STR_anybytes+'$')
-    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'LIT'+SEP 
+base32.BASE32STR_anybytes+'$')
+    STRING_RE=re.compile('^'+URI+':LIT:'+base32.BASE32STR_anybytes+'$')
+    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'LIT'+SEP 
+base32.BASE32STR_anybytes+'$')

      def __init__(self, data=None):
          if data is not None:
@@ -186,10 +198,11 @@
  class WriteableSSKFileURI(_BaseURI):
      implements(IURI, IMutableFileURI)

-    BASE_STRING='URI:SSK:'
-    STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits+':'+
+    BASE_STR='URI:SSK:' # produce this string
+    BASE_STR_OPT=URI+':SSK:' # accept this regex
+    STRING_RE=re.compile('^'+BASE_STR_OPT+BASE32STR_128bits+':'+
                           BASE32STR_256bits+'$')
-    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'SSK'+SEP+
+    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'SSK'+SEP+
                          BASE32STR_128bits+SEP+BASE32STR_256bits+'$')

      def __init__(self, writekey, fingerprint):
@@ -217,9 +230,6 @@
          return 'URI:SSK:%s:%s' % (base32.b2a(self.writekey),
                                    base32.b2a(self.fingerprint))

-    def __repr__(self):
-        return "<%s %s>" % (self.__class__.__name__, self.abbrev())
-
      def abbrev(self):
          return base32.b2a(self.writekey[:5])

@@ -235,9 +245,10 @@
  class ReadonlySSKFileURI(_BaseURI):
      implements(IURI, IMutableFileURI)

-    BASE_STRING='URI:SSK-RO:'
-    STRING_RE=re.compile('^URI:SSK-RO:'+BASE32STR_128bits 
+':'+BASE32STR_256bits+'$')
-    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'SSK-RO'+SEP 
+BASE32STR_128bits+SEP+BASE32STR_256bits+'$')
+    BASE_STR='URI:SSK-RO:' # produce this str
+    BASE_STR_OPT=URI+':SSK-RO:' # accept this regex
+    STRING_RE=re.compile('^'+BASE_STR_OPT+BASE32STR_128bits 
+':'+BASE32STR_256bits+'$')
+    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'SSK-RO'+SEP 
+BASE32STR_128bits+SEP+BASE32STR_256bits+'$')

      def __init__(self, readkey, fingerprint):
          self.readkey = readkey
@@ -263,9 +274,6 @@
          return 'URI:SSK-RO:%s:%s' % (base32.b2a(self.readkey),
                                       base32.b2a(self.fingerprint))

-    def __repr__(self):
-        return "<%s %s>" % (self.__class__.__name__, self.abbrev())
-
      def abbrev(self):
          return base32.b2a(self.readkey[:5])

@@ -281,9 +289,10 @@
  class SSKVerifierURI(_BaseURI):
      implements(IVerifierURI)

-    BASE_STRING='URI:SSK-Verifier:'
-    STRING_RE=re.compile('^'+BASE_STRING+BASE32STR_128bits 
+':'+BASE32STR_256bits+'$')
-    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'SSK-RO'+SEP 
+BASE32STR_128bits+SEP+BASE32STR_256bits+'$')
+    BASE_STR='URI:SSK-Verifier:' # produce this str
+    BASE_STR_OPT=URI+':SSK-Verifier:' # accept this regex
+    STRING_RE=re.compile('^'+BASE_STR_OPT+BASE32STR_128bits 
+':'+BASE32STR_256bits+'$')
+    HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'SSK- 
Verifier'+SEP+BASE32STR_128bits+SEP+BASE32STR_256bits+'$')

      def __init__(self, storage_index, fingerprint):
          assert len(storage_index) == 16
@@ -313,16 +322,13 @@
      def __init__(self, filenode_uri=None):
          self._filenode_uri = filenode_uri

-    def __repr__(self):
-        return "<%s %s>" % (self.__class__.__name__, self.abbrev())
-
      @classmethod
      def init_from_string(cls, uri):
-        mo = cls.BASE_STRING_RE.search(uri)
+        mo = re.search(cls.BASE_STR_OPT, uri)
          assert mo, (uri, cls)
          bits = uri[mo.end():]
          fn = cls.INNER_URI_CLASS.init_from_string(
-            cls.INNER_URI_CLASS.BASE_STRING+bits)
+            cls.INNER_URI_CLASS.BASE_STR+bits)
          return cls(fn)

      @classmethod
@@ -333,15 +339,15 @@
          while bits and bits[-1] == '/':
              bits = bits[:-1]
          fn = cls.INNER_URI_CLASS.init_from_string(
-            cls.INNER_URI_CLASS.BASE_STRING+urllib.unquote(bits))
+            cls.INNER_URI_CLASS.BASE_STR+urllib.unquote(bits))
          return cls(fn)

      def to_string(self):
          fnuri = self._filenode_uri.to_string()
-        mo = re.match(self.INNER_URI_CLASS.BASE_STRING, fnuri)
+        mo = re.match(self.INNER_URI_CLASS.BASE_STR_OPT, fnuri)
          assert mo, fnuri
          bits = fnuri[mo.end():]
-        return self.BASE_STRING+bits
+        return self.BASE_STR+bits

      def abbrev(self):
          return self._filenode_uri.to_string().split(':')[2][:5]
@@ -358,9 +364,10 @@
  class NewDirectoryURI(_NewDirectoryBaseURI):
      implements(INewDirectoryURI)

-    BASE_STRING='URI:DIR2:'
-    BASE_STRING_RE=re.compile('^'+BASE_STRING)
-    BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2'+SEP)
+    BASE_STR='URI:DIR2:' # produce this str
+    BASE_STR_OPT=URI+':DIR2:' # accept this regex
+    BASE_STRING_RE=re.compile('^'+BASE_STR_OPT)
+    BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'DIR2'+SEP)
      INNER_URI_CLASS=WriteableSSKFileURI

      def __init__(self, filenode_uri=None):
@@ -377,9 +384,10 @@
  class ReadonlyNewDirectoryURI(_NewDirectoryBaseURI):
      implements(IReadonlyNewDirectoryURI)

-    BASE_STRING='URI:DIR2-RO:'
-    BASE_STRING_RE=re.compile('^'+BASE_STRING)
-    BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2- 
RO'+SEP)
+    BASE_STR='URI:DIR2-RO:' # produce this str
+    BASE_STR_OPT=URI+':DIR2-RO:' # accept this regex
+    BASE_STRING_RE=re.compile('^'+BASE_STR_OPT)
+    BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'DIR2- 
RO'+SEP)
      INNER_URI_CLASS=ReadonlySSKFileURI

      def __init__(self, filenode_uri=None):
@@ -396,9 +404,10 @@
  class NewDirectoryURIVerifier(_NewDirectoryBaseURI):
      implements(IVerifierURI)

-    BASE_STRING='URI:DIR2-Verifier:'
-    BASE_STRING_RE=re.compile('^'+BASE_STRING)
-    BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+'URI'+SEP+'DIR2- 
Verifier'+SEP)
+    BASE_STR='URI:DIR2-Verifier:' # produce this str
+    BASE_STR_OPT=URI+':DIR2-Verifier:' # accept this regex
+    BASE_STRING_RE=re.compile('^'+BASE_STR_OPT)
+    BASE_HUMAN_RE=re.compile('^'+OPTIONALHTTPLEAD+URI+SEP+'DIR2- 
Verifier'+SEP)
      INNER_URI_CLASS=SSKVerifierURI

      def __init__(self, filenode_uri=None):
@@ -412,29 +421,65 @@


  def from_string(s):
-    if s.startswith('URI:CHK:'):
+    mo = re.match(URI, s)
+    if not mo:
+        raise TypeError("badly formed capability: %s" % s)
+    if s[mo.end(0)] != ':':
+        raise TypeError("badly formed capability: %s" % s)
+    typespec = s[mo.end(0)+1:]
+    if typespec.startswith('CHK:'):
          return CHKFileURI.init_from_string(s)
-    elif s.startswith('URI:CHK-Verifier:'):
+    elif typespec.startswith('CHK-Verifier:'):
          return CHKFileVerifierURI.init_from_string(s)
-    elif s.startswith('URI:LIT:'):
+    elif typespec.startswith('LIT:'):
          return LiteralFileURI.init_from_string(s)
-    elif s.startswith('URI:SSK:'):
+    elif typespec.startswith('SSK:'):
          return WriteableSSKFileURI.init_from_string(s)
-    elif s.startswith('URI:SSK-RO:'):
+    elif typespec.startswith('SSK-RO:'):
          return ReadonlySSKFileURI.init_from_string(s)
-    elif s.startswith('URI:SSK-Verifier:'):
+    elif typespec.startswith('SSK-Verifier:'):
          return SSKVerifierURI.init_from_string(s)
-    elif s.startswith('URI:DIR2:'):
+    elif typespec.startswith('DIR2:'):
          return NewDirectoryURI.init_from_string(s)
-    elif s.startswith('URI:DIR2-RO:'):
+    elif typespec.startswith('DIR2-RO:'):
          return ReadonlyNewDirectoryURI.init_from_string(s)
-    elif s.startswith('URI:DIR2-Verifier:'):
+    elif typespec.startswith('DIR2-Verifier:'):
          return NewDirectoryURIVerifier.init_from_string(s)
      else:
-        raise TypeError("unknown URI type: %s.." % s[:12])
+        raise TypeError("unknown capability type: %s" % s)

  registerAdapter(from_string, str, IURI)

+def from_human_encoding(s):
+    assert isinstance(s, basestring), "precondition: s is required  
to be a string, but it was %s :: %s" % (s, type(s))
+    mo = re.match(OPTIONALHTTPLEAD, s)
+    if mo:
+        s = s[mo.end(0):]
+    mo = re.match(URI+SEP, s)
+    if not mo:
+        raise TypeError("ill-formed capability %r" % s)
+    typespec = s[mo.end(0):]
+    if typespec.startswith('CHK:'):
+        return CHKFileURI.init_from_human_encoding(s)
+    elif typespec.startswith('CHK-Verifier:'):
+        return CHKFileVerifierURI.init_from_human_encoding(s)
+    elif typespec.startswith('LIT:'):
+        return LiteralFileURI.init_from_human_encoding(s)
+    elif typespec.startswith('SSK:'):
+        return WriteableSSKFileURI.init_from_human_encoding(s)
+    elif typespec.startswith('SSK-RO:'):
+        return ReadonlySSKFileURI.init_from_human_encoding(s)
+    elif typespec.startswith('SSK-Verifier:'):
+        return SSKVerifierURI.init_from_human_encoding(s)
+    elif typespec.startswith('DIR2:'):
+        return NewDirectoryURI.init_from_human_encoding(s)
+    elif typespec.startswith('DIR2-RO:'):
+        return ReadonlyNewDirectoryURI.init_from_human_encoding(s)
+    elif typespec.startswith('DIR2-Verifier:'):
+        return NewDirectoryURIVerifier.init_from_human_encoding(s)
+    else:
+        raise TypeError("unknown capability type: %s" % s)
+
  def is_uri(s):
      try:
          uri = from_string(s)
@@ -442,6 +487,13 @@
      except (TypeError, AssertionError):
          return False

+def is_human_encoding(s):
+    try:
+        uri = from_human_encoding(s)
+        return True
+    except (TypeError, AssertionError):
+        return False
+
  def from_string_dirnode(s):
      u = from_string(s)
      assert IDirnodeURI.providedBy(u)
diff -rN -u old-trunk-uri_cap/src/allmydata/webish.py new-trunk- 
uri_cap/src/allmydata/webish.py
--- old-trunk-uri_cap/src/allmydata/webish.py	2008-05-16  
12:40:05.000000000 -0600
+++ new-trunk-uri_cap/src/allmydata/webish.py	2008-05-16  
12:40:06.000000000 -0600
@@ -12,6 +12,7 @@
       IMutableFileNode
  import allmydata # to display import path
  from allmydata import download
+from allmydata import uri as urimodule
  from allmydata.upload import FileHandle, FileName
  from allmydata import provisioning
  from allmydata import get_package_versions_string
@@ -143,15 +144,19 @@
              # sure we censor these too.
              if queryargs.startswith("uri="):
                  queryargs = "[uri=CENSORED]"
+            if queryargs.startswith("cap="):
+                queryargs = "[cap=CENSORED]"
              queryargs = "?" + queryargs
          if path.startswith("/uri"):
              path = "/uri/[CENSORED].."
-        uri = path + queryargs
+        if path.startswith("/cap"):
+            path = "/cap/[CENSORED].."
+        theuri = path + queryargs

          log.msg(format="web: %(clientip)s %(method)s %(uri)s %(code) 
s %(length)s",
                  clientip=self.getClientIP(),
                  method=self.method,
-                uri=uri,
+                uri=theuri,
                  code=self.code,
                  length=(self.sentLength or "-"),
                  facility="tahoe.webish",
@@ -827,11 +832,16 @@
              d = self._check_replacement(name)
              d.addCallback(lambda res:  
self._node.create_empty_directory(name))
              d.addCallback(lambda res: "directory created")
-        elif t == "uri":
+        elif t == "uri" or t == "cap":
              if not name:
                  raise RuntimeError("set-uri requires a name")
-            newuri = get_arg(req, "uri")
-            assert newuri is not None
+            newuristr = get_arg(req, "uri")
+            assert isinstance(newuristr, basestring), (repr 
(newuristr), type(newuristr))
+            assert urimodule.is_human_encoding(newuristr), (repr 
(newuristr), type(newuristr))
+            if newuristr is None:
+                newuristr = get_arg(req, "cap")
+            newuri = urimodule.from_human_encoding(newuristr)
+
              d = self._check_replacement(name)
              d.addCallback(lambda res: self._node.set_uri(name,  
newuri))
              d.addCallback(lambda res: newuri)
@@ -1018,7 +1028,7 @@
                  # take the last step
                  d.addCallback(self._get_or_create_directories,  
self._path[-1:])
                  d.addCallback(self._upload_localdir, localdir)
-        elif t == "uri":
+        elif t == "uri" or t == "cap":
              d.addCallback(self._attach_uri, req.content, name)
          elif t == "mkdir":
              d.addCallback(self._mkdir, name)
@@ -1240,9 +1250,9 @@
                          return FileDownloader(node, filename), ()
                      elif t == "json":
                          return FileJSONMetadata(node), ()
-                    elif t == "uri":
+                    elif t == "uri" or t == "cap":
                          return FileURI(node), ()
-                    elif t == "readonly-uri":
+                    elif t == "readonly-uri" or t == "readonly-cap":
                          return FileReadOnlyURI(node), ()
                      else:
                          return child_error("bad t=%s" % t)
@@ -1257,9 +1267,9 @@
                          return Directory(self.name, node, path), ()
                      elif t == "json":
                          return DirectoryJSONMetadata(node), ()
-                    elif t == "uri":
+                    elif t == "uri" or t == "cap":
                          return DirectoryURI(node), ()
-                    elif t == "readonly-uri":
+                    elif t == "readonly-uri" or t == "readonly-cap":
                          return DirectoryReadonlyURI(node), ()
                      elif t == "manifest":
                          return Manifest(node, path), ()
@@ -1623,13 +1633,19 @@
              segments.append('')
          segments = tuple(segments)
          if segments:
-            if segments[0] == "uri":
+            if (segments[0] == "uri") or (segments[0] == "cap"):
                  if len(segments) == 1 or segments[1] == '':
-                    uri = get_arg(req, "uri", None)
-                    if uri is not None:
+                    uristr = get_arg(req, "uri", None)
+                    if uristr is not None:
                          there = url.URL.fromContext(ctx)
                          there = there.clear("uri")
-                        there = there.child("uri").child(uri)
+                        there = there.child("uri").child(uristr)
+                        return there, ()
+                    uristr = get_arg(req, "cap", None)
+                    if uristr is not None:
+                        there = url.URL.fromContext(ctx)
+                        there = there.clear("cap")
+                        there = there.child("cap").child(uristr)
                          return there, ()
                  if len(segments) == 1:
                      # /uri
@@ -1665,9 +1681,10 @@
                          return WebError(http.BAD_REQUEST, errmsg), ()
                  if len(segments) < 2:
                      return rend.NotFound
-                uri = segments[1]
-                d = defer.maybeDeferred(client.create_node_from_uri,  
uri)
-                d.addCallback(lambda node: VDrive(node, uri))
+                uristr = segments[1]
+                uriobj = urimodule.from_human_encoding(uristr)
+                d = defer.maybeDeferred(client.create_node_from_uri,  
uristr)
+                d.addCallback(lambda node: VDrive(node, uristr))
                  d.addCallback(lambda vd: vd.locateChild(ctx,  
segments[2:]))
                  def _trap_KeyError(f):
                      f.trap(KeyError)


-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: uricap.diff.txt
Url: http://allmydata.org/pipermail/tahoe-dev/attachments/20080516/10f6407d/attachment-0001.txt 


More information about the tahoe-dev mailing list