From 54fce5c06630b1b7fe47131b6ab104fda311521d Mon Sep 17 00:00:00 2001
From: Brian Warner <warner@allmydata.com>
Date: Wed, 24 Sep 2008 13:35:05 -0700
Subject: [PATCH] webapi: survive slashes in filenames better: make t=info and
 t=delete to work, and let t=rename fix the problem

---
 src/allmydata/test/test_web.py | 15 ---------------
 src/allmydata/web/directory.py | 21 ++++++++++++---------
 2 files changed, 12 insertions(+), 24 deletions(-)

diff --git a/src/allmydata/test/test_web.py b/src/allmydata/test/test_web.py
index 16da92e1..365b5de9 100644
--- a/src/allmydata/test/test_web.py
+++ b/src/allmydata/test/test_web.py
@@ -1836,21 +1836,6 @@ class Web(WebMixin, unittest.TestCase):
                   )
         d.addCallback(lambda res:
                       self.failUnlessNodeHasChild(self._foo_node, u"bar.txt"))
-        d.addCallback(lambda res: self.POST(self.public_url, t="rename",
-                      from_name="foo/bar.txt", to_name='george.txt'))
-        d.addBoth(self.shouldFail, error.Error,
-                  "test_POST_rename_file_slash_fail",
-                  "400 Bad Request",
-                  "from_name= may not contain a slash",
-                  )
-        d.addCallback(lambda res:
-                      self.failUnlessNodeHasChild(self.public_root, u"foo"))
-        d.addCallback(lambda res:
-                      self.failIfNodeHasChild(self.public_root, u"george.txt"))
-        d.addCallback(lambda res:
-                      self.failUnlessNodeHasChild(self._foo_node, u"bar.txt"))
-        d.addCallback(lambda res: self.GET(self.public_url + "/foo?t=json"))
-        d.addCallback(self.failUnlessIsFooJSON)
         return d
 
     def test_POST_rename_dir(self):
diff --git a/src/allmydata/web/directory.py b/src/allmydata/web/directory.py
index a2600773..5990570a 100644
--- a/src/allmydata/web/directory.py
+++ b/src/allmydata/web/directory.py
@@ -324,10 +324,12 @@ class DirectoryNodeHandler(RenderMixin, rend.Page, ReplaceMeMixin):
             assert isinstance(to_name, unicode)
         if not from_name or not to_name:
             raise WebError("rename requires from_name and to_name")
-        for k,v in [ ('from_name', from_name), ('to_name', to_name) ]:
-            if v and "/" in v:
-                raise WebError("%s= may not contain a slash" % k,
-                               http.BAD_REQUEST)
+
+        # allow from_name to contain slashes, so they can fix names that were
+        # accidentally created with them. But disallow them in to_name, to
+        # discourage the practice.
+        if "/" in to_name:
+            raise WebError("to_name= may not contain a slash", http.BAD_REQUEST)
 
         replace = boolean_of_arg(get_arg(req, "replace", "true"))
         d = self.node.move_child_to(from_name, self.node, to_name, replace)
@@ -444,6 +446,7 @@ class DirectoryAsHTML(rend.Page):
         name, (target, metadata) = data
         name = name.encode("utf-8")
         assert not isinstance(name, unicode)
+        nameurl = urllib.quote(name, safe="") # encode any slashes too
 
         root = self.get_root(ctx)
         here = "%s/uri/%s/" % (root, urllib.quote(self.node.get_uri()))
@@ -495,7 +498,7 @@ class DirectoryAsHTML(rend.Page):
             # to prevent javascript in displayed .html files from stealing a
             # secret directory URI from the URL, send the browser to a URI-based
             # page that doesn't know about the directory at all
-            dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, urllib.quote(name))
+            dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl)
 
             ctx.fillSlots("filename",
                           T.a(href=dlurl)[html.escape(name)])
@@ -504,10 +507,10 @@ class DirectoryAsHTML(rend.Page):
             ctx.fillSlots("size", "?")
 
             text_plain_url = "%s/file/%s/@@named=/foo.txt" % (root, quoted_uri)
-            info_link = "%s?t=info" % name
+            info_link = "%s?t=info" % nameurl
 
         elif IFileNode.providedBy(target):
-            dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, urllib.quote(name))
+            dlurl = "%s/file/%s/@@named=/%s" % (root, quoted_uri, nameurl)
 
             ctx.fillSlots("filename",
                           T.a(href=dlurl)[html.escape(name)])
@@ -516,7 +519,7 @@ class DirectoryAsHTML(rend.Page):
             ctx.fillSlots("size", target.get_size())
 
             text_plain_url = "%s/file/%s/@@named=/foo.txt" % (root, quoted_uri)
-            info_link = "%s?t=info" % name
+            info_link = "%s?t=info" % nameurl
 
         elif IDirectoryNode.providedBy(target):
             # directory
@@ -529,7 +532,7 @@ class DirectoryAsHTML(rend.Page):
                 dirtype = "DIR"
             ctx.fillSlots("type", dirtype)
             ctx.fillSlots("size", "-")
-            info_link = "%s/?t=info" % name
+            info_link = "%s/?t=info" % nameurl
 
         ctx.fillSlots("info", T.a(href=info_link)["More Info"])
 
-- 
2.45.2