1 | diff -rN -u old-tahoe/docs/frontends/webapi.txt new-tahoe/docs/frontends/webapi.txt |
---|
2 | --- old-tahoe/docs/frontends/webapi.txt 2010-01-27 23:20:14.922000000 +0000 |
---|
3 | +++ new-tahoe/docs/frontends/webapi.txt 2010-01-27 23:20:18.929000000 +0000 |
---|
4 | @@ -743,8 +743,14 @@ |
---|
5 | |
---|
6 | Note that this operation does not take its child cap in the form of |
---|
7 | separate "rw_uri" and "ro_uri" fields. Therefore, it cannot accept a |
---|
8 | - child cap in a format unknown to the webapi server, because the server |
---|
9 | - is not able to attenuate an unknown write cap to a read cap. |
---|
10 | + child cap in a format unknown to the webapi server, unless its URI |
---|
11 | + starts with "ro." or "imm.". This restriction is necessary because the |
---|
12 | + server is not able to attenuate an unknown write cap to a read cap. |
---|
13 | + Unknown URIs starting with "ro." or "imm.", on the other hand, are |
---|
14 | + assumed to represent read caps. The client should not prefix a write |
---|
15 | + cap with "ro." or "imm." and pass it to this operation, since that |
---|
16 | + would result in granting the cap's write authority to holders of the |
---|
17 | + directory read cap. |
---|
18 | |
---|
19 | === Adding multiple files or directories to a parent directory at once === |
---|
20 | |
---|
21 | @@ -1028,7 +1034,9 @@ |
---|
22 | |
---|
23 | This attaches a given read- or write- cap "CHILDCAP" to the designated |
---|
24 | directory, with a specified child name. This behaves much like the PUT t=uri |
---|
25 | - operation, and is a lot like a UNIX hardlink. |
---|
26 | + operation, and is a lot like a UNIX hardlink. It is subject to the same |
---|
27 | + restrictions as that operation on the use of cap formats unknown to the |
---|
28 | + webapi server. |
---|
29 | |
---|
30 | This will create additional intermediate directories as necessary, although |
---|
31 | since it is expected to be triggered by a form that was retrieved by "GET |
---|
32 | diff -rN -u old-tahoe/src/allmydata/dirnode.py new-tahoe/src/allmydata/dirnode.py |
---|
33 | --- old-tahoe/src/allmydata/dirnode.py 2010-01-27 23:20:16.828000000 +0000 |
---|
34 | +++ new-tahoe/src/allmydata/dirnode.py 2010-01-27 23:20:20.898000000 +0000 |
---|
35 | @@ -265,23 +265,23 @@ |
---|
36 | while position < len(data): |
---|
37 | entries, position = split_netstring(data, 1, position) |
---|
38 | entry = entries[0] |
---|
39 | - (name, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4) |
---|
40 | + (name_utf8, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4) |
---|
41 | if not mutable and len(rwcapdata) > 0: |
---|
42 | raise ValueError("the rwcapdata field of a dirnode in an immutable directory was not empty") |
---|
43 | - name = name.decode("utf-8") |
---|
44 | + name = name_utf8.decode("utf-8") |
---|
45 | rw_uri = "" |
---|
46 | if writeable: |
---|
47 | rw_uri = self._decrypt_rwcapdata(rwcapdata) |
---|
48 | |
---|
49 | # Since the encryption uses CTR mode, it currently leaks the length of the |
---|
50 | # plaintext rw_uri -- and therefore whether it is present, i.e. whether the |
---|
51 | - # dirnode is writeable (ticket #925). By stripping spaces in Tahoe >= 1.6.0, |
---|
52 | - # we may make it easier for future versions to plug this leak. |
---|
53 | + # dirnode is writeable (ticket #925). By stripping trailing spaces in |
---|
54 | + # Tahoe >= 1.6.0, we may make it easier for future versions to plug this leak. |
---|
55 | # ro_uri is treated in the same way for consistency. |
---|
56 | # rw_uri and ro_uri will be either None or a non-empty string. |
---|
57 | |
---|
58 | - rw_uri = rw_uri.strip(' ') or None |
---|
59 | - ro_uri = ro_uri.strip(' ') or None |
---|
60 | + rw_uri = rw_uri.rstrip(' ') or None |
---|
61 | + ro_uri = ro_uri.rstrip(' ') or None |
---|
62 | |
---|
63 | try: |
---|
64 | child = self._create_and_validate_node(rw_uri, ro_uri, name) |
---|
65 | @@ -292,11 +292,11 @@ |
---|
66 | children.set_with_aux(name, (child, metadata), auxilliary=entry) |
---|
67 | else: |
---|
68 | log.msg(format="mutable cap for child '%(name)s' unpacked from an immutable directory", |
---|
69 | - name=name.encode("utf-8"), |
---|
70 | + name=name_utf8, |
---|
71 | facility="tahoe.webish", level=log.UNUSUAL) |
---|
72 | except CapConstraintError, e: |
---|
73 | log.msg(format="unmet constraint on cap for child '%(name)s' unpacked from a directory:\n" |
---|
74 | - "%(message)s", message=e.args[0], name=name.encode("utf-8"), |
---|
75 | + "%(message)s", message=e.args[0], name=name_utf8, |
---|
76 | facility="tahoe.webish", level=log.UNUSUAL) |
---|
77 | |
---|
78 | return children |
---|
79 | diff -rN -u old-tahoe/src/allmydata/test/test_dirnode.py new-tahoe/src/allmydata/test/test_dirnode.py |
---|
80 | --- old-tahoe/src/allmydata/test/test_dirnode.py 2010-01-27 23:20:17.690000000 +0000 |
---|
81 | +++ new-tahoe/src/allmydata/test/test_dirnode.py 2010-01-27 23:20:21.660000000 +0000 |
---|
82 | @@ -13,6 +13,7 @@ |
---|
83 | from allmydata.mutable.filenode import MutableFileNode |
---|
84 | from allmydata.mutable.common import UncoordinatedWriteError |
---|
85 | from allmydata.util import hashutil, base32 |
---|
86 | +from allmydata.util.netstring import split_netstring |
---|
87 | from allmydata.monitor import Monitor |
---|
88 | from allmydata.test.common import make_chk_file_uri, make_mutable_file_uri, \ |
---|
89 | ErrorMixin |
---|
90 | @@ -48,6 +49,7 @@ |
---|
91 | self.set_up_grid() |
---|
92 | c = self.g.clients[0] |
---|
93 | nm = c.nodemaker |
---|
94 | + |
---|
95 | setup_py_uri = "URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861" |
---|
96 | one_uri = "URI:LIT:n5xgk" # LIT for "one" |
---|
97 | mut_write_uri = "URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq" |
---|
98 | @@ -115,6 +117,8 @@ |
---|
99 | |
---|
100 | bad_future_node = UnknownNode(future_write_uri, None) |
---|
101 | bad_kids1 = {u"one": (bad_future_node, {})} |
---|
102 | + # This should fail because we don't know how to diminish the future_write_uri |
---|
103 | + # cap (given in a write slot and not prefixed with "ro." or "imm.") to a readcap. |
---|
104 | d.addCallback(lambda ign: |
---|
105 | self.shouldFail(MustNotBeUnknownRWError, "bad_kids1", |
---|
106 | "cannot attach unknown", |
---|
107 | @@ -133,6 +137,7 @@ |
---|
108 | self.set_up_grid() |
---|
109 | c = self.g.clients[0] |
---|
110 | nm = c.nodemaker |
---|
111 | + |
---|
112 | setup_py_uri = "URI:CHK:n7r3m6wmomelk4sep3kw5cvduq:os7ijw5c3maek7pg65e5254k2fzjflavtpejjyhshpsxuqzhcwwq:3:20:14861" |
---|
113 | one_uri = "URI:LIT:n5xgk" # LIT for "one" |
---|
114 | mut_write_uri = "URI:SSK:vfvcbdfbszyrsaxchgevhmmlii:euw4iw7bbnkrrwpzuburbhppuxhc3gwxv26f6imekhz7zyw2ojnq" |
---|
115 | @@ -280,6 +285,75 @@ |
---|
116 | d.addCallback(_made_parent) |
---|
117 | return d |
---|
118 | |
---|
119 | + def test_spaces_are_stripped_on_the_way_out(self): |
---|
120 | + self.basedir = "dirnode/Dirnode/test_spaces_are_stripped_on_the_way_out" |
---|
121 | + self.set_up_grid() |
---|
122 | + c = self.g.clients[0] |
---|
123 | + nm = c.nodemaker |
---|
124 | + |
---|
125 | + # This test checks that any trailing spaces in URIs are retained in the |
---|
126 | + # encoded directory, but stripped when we get them out of the directory. |
---|
127 | + # See ticket #925 for why we want that. |
---|
128 | + |
---|
129 | + stripped_write_uri = "lafs://from_the_future\t" |
---|
130 | + stripped_read_uri = "lafs://readonly_from_the_future\t" |
---|
131 | + spacedout_write_uri = stripped_write_uri + " " |
---|
132 | + spacedout_read_uri = stripped_read_uri + " " |
---|
133 | + |
---|
134 | + child = nm.create_from_cap(spacedout_write_uri, spacedout_read_uri) |
---|
135 | + self.failUnlessEqual(child.get_write_uri(), spacedout_write_uri) |
---|
136 | + self.failUnlessEqual(child.get_readonly_uri(), "ro." + spacedout_read_uri) |
---|
137 | + |
---|
138 | + kids = {u"child": (child, {})} |
---|
139 | + d = c.create_dirnode(kids) |
---|
140 | + |
---|
141 | + def _created(dn): |
---|
142 | + self.failUnless(isinstance(dn, dirnode.DirectoryNode)) |
---|
143 | + self.failUnless(dn.is_mutable()) |
---|
144 | + self.failIf(dn.is_readonly()) |
---|
145 | + dn.raise_error() |
---|
146 | + self.cap = dn.get_cap() |
---|
147 | + self.rootnode = dn |
---|
148 | + return dn._node.download_best_version() |
---|
149 | + d.addCallback(_created) |
---|
150 | + |
---|
151 | + def _check_data(data): |
---|
152 | + # Decode the netstring representation of the directory to check that the |
---|
153 | + # spaces are retained when the URIs are stored. |
---|
154 | + position = 0 |
---|
155 | + numkids = 0 |
---|
156 | + while position < len(data): |
---|
157 | + entries, position = split_netstring(data, 1, position) |
---|
158 | + entry = entries[0] |
---|
159 | + (name_utf8, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4) |
---|
160 | + name = name_utf8.decode("utf-8") |
---|
161 | + rw_uri = self.rootnode._decrypt_rwcapdata(rwcapdata) |
---|
162 | + self.failUnless(name in kids) |
---|
163 | + (expected_child, ign) = kids[name] |
---|
164 | + self.failUnlessEqual(rw_uri, expected_child.get_write_uri()) |
---|
165 | + self.failUnlessEqual("ro." + ro_uri, expected_child.get_readonly_uri()) |
---|
166 | + numkids += 1 |
---|
167 | + |
---|
168 | + self.failUnlessEqual(numkids, 1) |
---|
169 | + return self.rootnode.list() |
---|
170 | + d.addCallback(_check_data) |
---|
171 | + |
---|
172 | + # Now when we use the real directory listing code, the trailing spaces |
---|
173 | + # should have been stripped (and "ro." should have been prepended to the |
---|
174 | + # ro_uri, since it's unknown). |
---|
175 | + def _check_kids(children): |
---|
176 | + self.failUnlessEqual(sorted(children.keys()), [u"child"]) |
---|
177 | + child_node, child_metadata = children[u"child"] |
---|
178 | + |
---|
179 | + self.failUnlessEqual(child_node.get_write_uri(), stripped_write_uri) |
---|
180 | + self.failUnlessEqual(child_node.get_readonly_uri(), "ro." + stripped_read_uri) |
---|
181 | + d.addCallback(_check_kids) |
---|
182 | + |
---|
183 | + d.addCallback(lambda ign: nm.create_from_cap(self.cap.to_string())) |
---|
184 | + d.addCallback(lambda n: n.list()) |
---|
185 | + d.addCallback(_check_kids) # again with dirnode recreated from cap |
---|
186 | + return d |
---|
187 | + |
---|
188 | def test_check(self): |
---|
189 | self.basedir = "dirnode/Dirnode/test_check" |
---|
190 | self.set_up_grid() |
---|
191 | @@ -1121,6 +1195,9 @@ |
---|
192 | def is_allowed_in_immutable_directory(self): |
---|
193 | return False |
---|
194 | |
---|
195 | + def raise_error(self): |
---|
196 | + pass |
---|
197 | + |
---|
198 | def modify(self, modifier): |
---|
199 | self.data = modifier(self.data, None, True) |
---|
200 | return defer.succeed(None) |
---|
201 | diff -rN -u old-tahoe/src/allmydata/test/test_filenode.py new-tahoe/src/allmydata/test/test_filenode.py |
---|
202 | --- old-tahoe/src/allmydata/test/test_filenode.py 2010-01-27 23:20:17.705000000 +0000 |
---|
203 | +++ new-tahoe/src/allmydata/test/test_filenode.py 2010-01-27 23:20:21.672000000 +0000 |
---|
204 | @@ -39,10 +39,10 @@ |
---|
205 | self.failUnlessEqual(fn1.get_uri(), u.to_string()) |
---|
206 | self.failUnlessEqual(fn1.get_cap(), u) |
---|
207 | self.failUnlessEqual(fn1.get_readcap(), u) |
---|
208 | - self.failUnlessEqual(fn1.is_readonly(), True) |
---|
209 | - self.failUnlessEqual(fn1.is_mutable(), False) |
---|
210 | - self.failUnlessEqual(fn1.is_unknown(), False) |
---|
211 | - self.failUnlessEqual(fn1.is_allowed_in_immutable_directory(), True) |
---|
212 | + self.failUnless(fn1.is_readonly()) |
---|
213 | + self.failIf(fn1.is_mutable()) |
---|
214 | + self.failIf(fn1.is_unknown()) |
---|
215 | + self.failUnless(fn1.is_allowed_in_immutable_directory()) |
---|
216 | self.failUnlessEqual(fn1.get_write_uri(), None) |
---|
217 | self.failUnlessEqual(fn1.get_readonly_uri(), u.to_string()) |
---|
218 | self.failUnlessEqual(fn1.get_size(), 1000) |
---|
219 | @@ -54,8 +54,8 @@ |
---|
220 | v = fn1.get_verify_cap() |
---|
221 | self.failUnless(isinstance(v, uri.CHKFileVerifierURI)) |
---|
222 | self.failUnlessEqual(fn1.get_repair_cap(), v) |
---|
223 | - self.failUnlessEqual(v.is_readonly(), True) |
---|
224 | - self.failUnlessEqual(v.is_mutable(), False) |
---|
225 | + self.failUnless(v.is_readonly()) |
---|
226 | + self.failIf(v.is_mutable()) |
---|
227 | |
---|
228 | |
---|
229 | def test_literal_filenode(self): |
---|
230 | @@ -69,10 +69,10 @@ |
---|
231 | self.failUnlessEqual(fn1.get_uri(), u.to_string()) |
---|
232 | self.failUnlessEqual(fn1.get_cap(), u) |
---|
233 | self.failUnlessEqual(fn1.get_readcap(), u) |
---|
234 | - self.failUnlessEqual(fn1.is_readonly(), True) |
---|
235 | - self.failUnlessEqual(fn1.is_mutable(), False) |
---|
236 | - self.failUnlessEqual(fn1.is_unknown(), False) |
---|
237 | - self.failUnlessEqual(fn1.is_allowed_in_immutable_directory(), True) |
---|
238 | + self.failUnless(fn1.is_readonly()) |
---|
239 | + self.failIf(fn1.is_mutable()) |
---|
240 | + self.failIf(fn1.is_unknown()) |
---|
241 | + self.failUnless(fn1.is_allowed_in_immutable_directory()) |
---|
242 | self.failUnlessEqual(fn1.get_write_uri(), None) |
---|
243 | self.failUnlessEqual(fn1.get_readonly_uri(), u.to_string()) |
---|
244 | self.failUnlessEqual(fn1.get_size(), len(DATA)) |
---|
245 | @@ -122,10 +122,10 @@ |
---|
246 | self.failUnlessEqual(n.get_readonly_uri(), u.get_readonly().to_string()) |
---|
247 | self.failUnlessEqual(n.get_cap(), u) |
---|
248 | self.failUnlessEqual(n.get_readcap(), u.get_readonly()) |
---|
249 | - self.failUnlessEqual(n.is_mutable(), True) |
---|
250 | - self.failUnlessEqual(n.is_readonly(), False) |
---|
251 | - self.failUnlessEqual(n.is_unknown(), False) |
---|
252 | - self.failUnlessEqual(n.is_allowed_in_immutable_directory(), False) |
---|
253 | + self.failUnless(n.is_mutable()) |
---|
254 | + self.failIf(n.is_readonly()) |
---|
255 | + self.failIf(n.is_unknown()) |
---|
256 | + self.failIf(n.is_allowed_in_immutable_directory()) |
---|
257 | n.raise_error() |
---|
258 | |
---|
259 | n2 = MutableFileNode(None, None, client.get_encoding_parameters(), |
---|
260 | @@ -144,10 +144,10 @@ |
---|
261 | self.failUnlessEqual(nro.get_readonly(), nro) |
---|
262 | self.failUnlessEqual(nro.get_cap(), u.get_readonly()) |
---|
263 | self.failUnlessEqual(nro.get_readcap(), u.get_readonly()) |
---|
264 | - self.failUnlessEqual(nro.is_mutable(), True) |
---|
265 | - self.failUnlessEqual(nro.is_readonly(), True) |
---|
266 | - self.failUnlessEqual(nro.is_unknown(), False) |
---|
267 | - self.failUnlessEqual(nro.is_allowed_in_immutable_directory(), False) |
---|
268 | + self.failUnless(nro.is_mutable()) |
---|
269 | + self.failUnless(nro.is_readonly()) |
---|
270 | + self.failIf(nro.is_unknown()) |
---|
271 | + self.failIf(nro.is_allowed_in_immutable_directory()) |
---|
272 | nro_u = nro.get_uri() |
---|
273 | self.failUnlessEqual(nro_u, nro.get_readonly_uri()) |
---|
274 | self.failUnlessEqual(nro_u, u.get_readonly().to_string()) |
---|
275 | diff -rN -u old-tahoe/src/allmydata/test/test_web.py new-tahoe/src/allmydata/test/test_web.py |
---|
276 | --- old-tahoe/src/allmydata/test/test_web.py 2010-01-27 23:20:17.913000000 +0000 |
---|
277 | +++ new-tahoe/src/allmydata/test/test_web.py 2010-01-27 23:20:21.879000000 +0000 |
---|
278 | @@ -2376,7 +2376,7 @@ |
---|
279 | def test_POST_set_children_with_hyphen(self): |
---|
280 | return self.test_POST_set_children(command_name="set-children") |
---|
281 | |
---|
282 | - def test_POST_put_uri(self): |
---|
283 | + def test_POST_link_uri(self): |
---|
284 | contents, n, newuri = self.makefile(8) |
---|
285 | d = self.POST(self.public_url + "/foo", t="uri", name="new.txt", uri=newuri) |
---|
286 | d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, u"new.txt") |
---|
287 | @@ -2385,7 +2385,7 @@ |
---|
288 | contents)) |
---|
289 | return d |
---|
290 | |
---|
291 | - def test_POST_put_uri_replace(self): |
---|
292 | + def test_POST_link_uri_replace(self): |
---|
293 | contents, n, newuri = self.makefile(8) |
---|
294 | d = self.POST(self.public_url + "/foo", t="uri", name="bar.txt", uri=newuri) |
---|
295 | d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, u"bar.txt") |
---|
296 | @@ -2394,12 +2394,33 @@ |
---|
297 | contents)) |
---|
298 | return d |
---|
299 | |
---|
300 | - def test_POST_put_uri_no_replace_queryarg(self): |
---|
301 | + def test_POST_link_uri_unknown_bad(self): |
---|
302 | + newuri = "lafs://from_the_future" |
---|
303 | + d = self.POST(self.public_url + "/foo", t="uri", name="future.txt", uri=newuri) |
---|
304 | + d.addBoth(self.shouldFail, error.Error, |
---|
305 | + "POST_link_uri_unknown_bad", |
---|
306 | + "400 Bad Request", |
---|
307 | + "unknown cap in a write slot") |
---|
308 | + return d |
---|
309 | + |
---|
310 | + def test_POST_link_uri_unknown_ro_good(self): |
---|
311 | + newuri = "ro.lafs://readonly_from_the_future" |
---|
312 | + d = self.POST(self.public_url + "/foo", t="uri", name="future-ro.txt", uri=newuri) |
---|
313 | + d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, u"future-ro.txt") |
---|
314 | + return d |
---|
315 | + |
---|
316 | + def test_POST_link_uri_unknown_imm_good(self): |
---|
317 | + newuri = "imm.lafs://immutable_from_the_future" |
---|
318 | + d = self.POST(self.public_url + "/foo", t="uri", name="future-imm.txt", uri=newuri) |
---|
319 | + d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, u"future-imm.txt") |
---|
320 | + return d |
---|
321 | + |
---|
322 | + def test_POST_link_uri_no_replace_queryarg(self): |
---|
323 | contents, n, newuri = self.makefile(8) |
---|
324 | d = self.POST(self.public_url + "/foo?replace=false", t="uri", |
---|
325 | name="bar.txt", uri=newuri) |
---|
326 | d.addBoth(self.shouldFail, error.Error, |
---|
327 | - "POST_put_uri_no_replace_queryarg", |
---|
328 | + "POST_link_uri_no_replace_queryarg", |
---|
329 | "409 Conflict", |
---|
330 | "There was already a child by that name, and you asked me " |
---|
331 | "to not replace it") |
---|
332 | @@ -2407,12 +2428,12 @@ |
---|
333 | d.addCallback(self.failUnlessIsBarDotTxt) |
---|
334 | return d |
---|
335 | |
---|
336 | - def test_POST_put_uri_no_replace_field(self): |
---|
337 | + def test_POST_link_uri_no_replace_field(self): |
---|
338 | contents, n, newuri = self.makefile(8) |
---|
339 | d = self.POST(self.public_url + "/foo", t="uri", replace="false", |
---|
340 | name="bar.txt", uri=newuri) |
---|
341 | d.addBoth(self.shouldFail, error.Error, |
---|
342 | - "POST_put_uri_no_replace_field", |
---|
343 | + "POST_link_uri_no_replace_field", |
---|
344 | "409 Conflict", |
---|
345 | "There was already a child by that name, and you asked me " |
---|
346 | "to not replace it") |
---|
347 | @@ -2680,6 +2701,29 @@ |
---|
348 | "to not replace it") |
---|
349 | return d |
---|
350 | |
---|
351 | + def test_PUT_NEWFILEURL_uri_unknown_bad(self): |
---|
352 | + new_uri = "lafs://from_the_future" |
---|
353 | + d = self.PUT(self.public_url + "/foo/put-future.txt?t=uri", new_uri) |
---|
354 | + d.addBoth(self.shouldFail, error.Error, |
---|
355 | + "POST_put_uri_unknown_bad", |
---|
356 | + "400 Bad Request", |
---|
357 | + "unknown cap in a write slot") |
---|
358 | + return d |
---|
359 | + |
---|
360 | + def test_PUT_NEWFILEURL_uri_unknown_ro_good(self): |
---|
361 | + new_uri = "ro.lafs://readonly_from_the_future" |
---|
362 | + d = self.PUT(self.public_url + "/foo/put-future-ro.txt?t=uri", new_uri) |
---|
363 | + d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, |
---|
364 | + u"put-future-ro.txt") |
---|
365 | + return d |
---|
366 | + |
---|
367 | + def test_PUT_NEWFILEURL_uri_unknown_imm_good(self): |
---|
368 | + new_uri = "imm.lafs://immutable_from_the_future" |
---|
369 | + d = self.PUT(self.public_url + "/foo/put-future-imm.txt?t=uri", new_uri) |
---|
370 | + d.addCallback(self.failUnlessURIMatchesROChild, self._foo_node, |
---|
371 | + u"put-future-imm.txt") |
---|
372 | + return d |
---|
373 | + |
---|
374 | def test_PUT_NEWFILE_URI(self): |
---|
375 | file_contents = "New file contents here\n" |
---|
376 | d = self.PUT("/uri", file_contents) |
---|
377 | @@ -3360,15 +3404,13 @@ |
---|
378 | while position < len(data): |
---|
379 | entries, position = split_netstring(data, 1, position) |
---|
380 | entry = entries[0] |
---|
381 | - (name, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4) |
---|
382 | - name = name.decode("utf-8") |
---|
383 | + (name_utf8, ro_uri, rwcapdata, metadata_s), subpos = split_netstring(entry, 4) |
---|
384 | + name = name_utf8.decode("utf-8") |
---|
385 | self.failUnless(rwcapdata == "") |
---|
386 | - ro_uri = ro_uri.strip() |
---|
387 | - if name in kids: |
---|
388 | - self.failIfEqual(ro_uri, "") |
---|
389 | - (expected_child, ign) = kids[name] |
---|
390 | - self.failUnlessEqual(ro_uri, expected_child.get_readonly_uri()) |
---|
391 | - numkids += 1 |
---|
392 | + self.failUnless(name in kids) |
---|
393 | + (expected_child, ign) = kids[name] |
---|
394 | + self.failUnlessEqual(ro_uri, expected_child.get_readonly_uri()) |
---|
395 | + numkids += 1 |
---|
396 | |
---|
397 | self.failUnlessEqual(numkids, 3) |
---|
398 | return self.rootnode.list() |
---|