From 05163ec8e1353ada943b67fda75ed6e5ed0fcbf7 Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Wed, 23 May 2007 11:18:49 -0700
Subject: [PATCH] change uri-packer-unpacker to deal with dictionaries, not
 fragile tuples

---
 src/allmydata/download.py         | 24 ++++++++++++++----------
 src/allmydata/test/test_system.py |  9 ++++-----
 src/allmydata/test/test_upload.py | 16 ++++++++--------
 src/allmydata/uri.py              | 23 +++++++++++++----------
 src/allmydata/webish.py           |  3 +--
 5 files changed, 40 insertions(+), 35 deletions(-)

diff --git a/src/allmydata/download.py b/src/allmydata/download.py
index 656c8ecb..02b79547 100644
--- a/src/allmydata/download.py
+++ b/src/allmydata/download.py
@@ -214,17 +214,21 @@ class FileDownloader:
     def __init__(self, client, uri, downloadable):
         self._client = client
         self._downloadable = downloadable
-        (codec_name, codec_params, tail_codec_params, verifierid, fileid, key, roothash, needed_shares, total_shares, size, segment_size) = unpack_uri(uri)
+
+        d = unpack_uri(uri)
+        verifierid = d['verifierid']
+        size = d['size']
+        segment_size = d['segment_size']
         assert isinstance(verifierid, str)
         assert len(verifierid) == 20
         self._verifierid = verifierid
-        self._fileid = fileid
-        self._roothash = roothash
+        self._fileid = d['fileid']
+        self._roothash = d['roothash']
 
-        self._codec = codec.get_decoder_by_name(codec_name)
-        self._codec.set_serialized_params(codec_params)
-        self._tail_codec = codec.get_decoder_by_name(codec_name)
-        self._tail_codec.set_serialized_params(tail_codec_params)
+        self._codec = codec.get_decoder_by_name(d['codec_name'])
+        self._codec.set_serialized_params(d['codec_params'])
+        self._tail_codec = codec.get_decoder_by_name(d['codec_name'])
+        self._tail_codec.set_serialized_params(d['tail_codec_params'])
 
 
         self._total_segments = mathutil.div_ceil(size, segment_size)
@@ -233,10 +237,10 @@ class FileDownloader:
         self._size = size
         self._num_needed_shares = self._codec.get_needed_shares()
 
-        self._output = Output(downloadable, key)
+        self._output = Output(downloadable, d['key'])
 
-        self._share_hashtree = hashtree.IncompleteHashTree(total_shares)
-        self._share_hashtree.set_hashes({0: roothash})
+        self._share_hashtree = hashtree.IncompleteHashTree(d['total_shares'])
+        self._share_hashtree.set_hashes({0: self._roothash})
 
         self.active_buckets = {} # k: shnum, v: bucket
         self._share_buckets = {} # k: shnum, v: set of buckets
diff --git a/src/allmydata/test/test_system.py b/src/allmydata/test/test_system.py
index e692c771..81aa91bc 100644
--- a/src/allmydata/test/test_system.py
+++ b/src/allmydata/test/test_system.py
@@ -212,11 +212,10 @@ class SystemTest(testutil.SignalMixin, unittest.TestCase):
     def mangle_uri(self, gooduri):
         # change the verifierid, which means we'll be asking about the wrong
         # file, so nobody will have any shares
-        pieces = list(uri.unpack_uri(gooduri))
-        # [3] is the verifierid
-        assert len(pieces[3]) == 20
-        pieces[3] = self.flip_bit(pieces[3])
-        return uri.pack_uri(*pieces)
+        d = uri.unpack_uri(gooduri)
+        assert len(d['verifierid']) == 20
+        d['verifierid'] = self.flip_bit(d['verifierid'])
+        return uri.pack_uri(**d)
 
     # TODO: add a test which mangles the fileid instead, and should fail in
     # the post-download phase when the file's integrity check fails. Do the
diff --git a/src/allmydata/test/test_upload.py b/src/allmydata/test/test_upload.py
index 383462ae..efae86d4 100644
--- a/src/allmydata/test/test_upload.py
+++ b/src/allmydata/test/test_upload.py
@@ -24,14 +24,14 @@ class GoodServer(unittest.TestCase):
     def _check(self, uri):
         self.failUnless(isinstance(uri, str))
         self.failUnless(uri.startswith("URI:"))
-        codec_name, codec_params, tail_codec_params, verifierid, fileid, key, roothash, needed_shares, total_shares, size, segment_size = unpack_uri(uri)
-        self.failUnless(isinstance(verifierid, str))
-        self.failUnlessEqual(len(verifierid), 20)
-        self.failUnless(isinstance(fileid, str))
-        self.failUnlessEqual(len(fileid), 20)
-        self.failUnless(isinstance(key, str))
-        self.failUnlessEqual(len(key), 16)
-        self.failUnless(isinstance(codec_params, str))
+        d = unpack_uri(uri)
+        self.failUnless(isinstance(d['verifierid'], str))
+        self.failUnlessEqual(len(d['verifierid']), 20)
+        self.failUnless(isinstance(d['fileid'], str))
+        self.failUnlessEqual(len(d['fileid']), 20)
+        self.failUnless(isinstance(d['key'], str))
+        self.failUnlessEqual(len(d['key']), 16)
+        self.failUnless(isinstance(d['codec_params'], str))
 
     def testData(self):
         data = "This is some data to upload"
diff --git a/src/allmydata/uri.py b/src/allmydata/uri.py
index 356e409b..96fca1da 100644
--- a/src/allmydata/uri.py
+++ b/src/allmydata/uri.py
@@ -8,6 +8,7 @@ from allmydata.util import idlib
 def pack_uri(codec_name, codec_params, tail_codec_params,
              verifierid, fileid, key,
              roothash, needed_shares, total_shares, size, segment_size):
+    # applications should pass keyword parameters into this
     assert isinstance(codec_name, str)
     assert len(codec_name) < 10
     assert ":" not in codec_name
@@ -26,15 +27,17 @@ def pack_uri(codec_name, codec_params, tail_codec_params,
 
 def unpack_uri(uri):
     assert uri.startswith("URI:")
-    header, codec_name, codec_params, tail_codec_params, verifierid_s, fileid_s, key_s, roothash_s, needed_shares_s, total_shares_s, size_s, segment_size_s = uri.split(":")
-    verifierid = idlib.a2b(verifierid_s)
-    fileid = idlib.a2b(fileid_s)
-    key = idlib.a2b(key_s)
-    roothash = idlib.a2b(roothash_s)
-    needed_shares = int(needed_shares_s)
-    total_shares = int(total_shares_s)
-    size = int(size_s)
-    segment_size = int(segment_size_s)
-    return codec_name, codec_params, tail_codec_params, verifierid, fileid, key, roothash, needed_shares, total_shares, size, segment_size
+    d = {}
+    header, d['codec_name'], d['codec_params'], d['tail_codec_params'], verifierid_s, fileid_s, key_s, roothash_s, needed_shares_s, total_shares_s, size_s, segment_size_s = uri.split(":")
+    assert header == "URI"
+    d['verifierid'] = idlib.a2b(verifierid_s)
+    d['fileid'] = idlib.a2b(fileid_s)
+    d['key'] = idlib.a2b(key_s)
+    d['roothash'] = idlib.a2b(roothash_s)
+    d['needed_shares'] = int(needed_shares_s)
+    d['total_shares'] = int(total_shares_s)
+    d['size'] = int(size_s)
+    d['segment_size'] = int(segment_size_s)
+    return d
 
 
diff --git a/src/allmydata/webish.py b/src/allmydata/webish.py
index 5275b0de..687d63bf 100644
--- a/src/allmydata/webish.py
+++ b/src/allmydata/webish.py
@@ -128,8 +128,7 @@ class Directory(rend.Page):
             ctx.fillSlots("uri", T.a(href=dl_uri_url)[html.escape(uri)])
 
             #extract and display file size
-            unpacked = unpack_uri(uri)
-            ctx.fillSlots("size", unpacked[9])
+            ctx.fillSlots("size", unpack_uri(uri)['size'])
 
             # this creates a button which will cause our child__delete method
             # to be invoked, which deletes the file and then redirects the
-- 
2.45.2