POST /uri?t=mkdir
PUT /uri?t=mkdir
- Create a new empty directory and return its write-cap as the HTTP response
- body. This does not make the newly created directory visible from the
- virtual drive. The "PUT" operation is provided for backwards compatibility:
- new code should use POST.
+ Create a new directory (either empty or with some initial children) and
+ return its write-cap as the HTTP response body. This does not make the newly
+ created directory visible from the virtual drive. The "PUT" operation is
+ provided for backwards compatibility: new code should use POST.
+
+ Initial children are provided in the "children" field of the POST form, or
+ as the request body of the PUT request. This is more efficient than doing
+ separate mkdir and add-children operations. If this value is empty, the new
+ directory will be empty.
+
+ If not empty, it will be interpreted as a JSON-encoded dictionary of
+ children with which the new directory should be populated, using the same
+ format as would be returned in the 'children' value of the t=json GET
+ request, described below. Each dictionary key should be a child name, and
+ each value should be a list of [TYPE, PROPDICT], where PROPDICT contains
+ "rw_uri", "ro_uri", and "metadata" keys (all others are ignored). For
+ example, the PUT request body could be:
+
+ {
+ "Fran\u00e7ais": [ "filenode", {
+ "ro_uri": "URI:CHK:...",
+ "size": bytes,
+ "metadata": {
+ "ctime": 1202777696.7564139,
+ "mtime": 1202777696.7564139,
+ "tahoe": {
+ "linkcrtime": 1202777696.7564139,
+ "linkmotime": 1202777696.7564139,
+ } } } ],
+ "subdir": [ "dirnode", {
+ "rw_uri": "URI:DIR2:...",
+ "ro_uri": "URI:DIR2-RO:...",
+ "metadata": {
+ "ctime": 1202778102.7589991,
+ "mtime": 1202778111.2160511,
+ "tahoe": {
+ "linkcrtime": 1202777696.7564139,
+ "linkmotime": 1202777696.7564139,
+ } } } ]
+ }
POST /uri/$DIRCAP/[SUBDIRS../]SUBDIR?t=mkdir
PUT /uri/$DIRCAP/[SUBDIRS../]SUBDIR?t=mkdir
intermediate directories as necessary. If the named target directory already
exists, this will make no changes to it.
+ If a directory is created, it will be populated with initial children via
+ the PUT request body or POST 'children' form field, as described above.
+
This will return an error if a blocking file is present at any of the parent
names, preventing the server from creating the necessary parent directory.
POST /uri/$DIRCAP/[SUBDIRS../]?t=mkdir&name=NAME
Create a new empty directory and attach it to the given existing directory.
- This will create additional intermediate directories as necessary.
+ This will create additional intermediate directories as necessary. The new
+ directory will be populated with initial children via the PUT request body
+ or POST 'children' form field, as described above.
The URL of this form points to the parent of the bottom-most new directory,
whereas the previous form has a URL that points directly to the bottom-most
"false"), then the HTTP response body will simply be the write-cap of the
new directory.
+ It accepts the same initial-children arguments as described in earlier
+ t=mkdir sections, but these are unlikely to be useful from a browser form.
+
POST /uri/$DIRCAP/[SUBDIRS../]?t=mkdir&name=CHILDNAME
This creates a new directory as a child of the designated SUBDIR. This will
when_done= argument, the HTTP response will simply contain the write-cap of
the directory that was just created.
+ It accepts the same initial-children arguments as described in earlier
+ t=mkdir sections, but these are unlikely to be useful from a browser form.
+
=== Uploading a File ===
from allmydata.storage.shares import get_share_file
from allmydata.storage_client import StorageFarmBroker
from allmydata.immutable import upload, download
+from allmydata.dirnode import DirectoryNode
from allmydata.nodemaker import NodeMaker
from allmydata.unknown import UnknownNode
from allmydata.web import status, common
from allmydata.scripts.debug import CorruptShareOptions, corrupt_share
from allmydata.util import fileutil, base32
from allmydata.test.common import FakeCHKFileNode, FakeMutableFileNode, \
- create_chk_filenode, WebErrorMixin, ShouldFailMixin
+ create_chk_filenode, WebErrorMixin, ShouldFailMixin, make_mutable_file_uri
from allmydata.interfaces import IMutableFileNode
from allmydata.mutable import servermap, publish, retrieve
import common_util as testutil
d.addCallback(self.failUnlessNodeKeysAre, [])
return d
+ def test_PUT_NEWDIRURL_initial_children(self):
+ (newkids, filecap1, filecap2, filecap3,
+ dircap) = self._create_initial_children()
+ d = self.PUT(self.public_url + "/foo/newdir?t=mkdir",
+ simplejson.dumps(newkids))
+ def _check(uri):
+ n = self.s.create_node_from_uri(uri.strip())
+ d2 = self.failUnlessNodeKeysAre(n, newkids.keys())
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-imm", filecap1))
+ d2.addCallback(lambda ign:
+ n.get_child_and_metadata_at_path(u"child-imm"))
+ d2.addCallback(lambda (c1, md1):
+ self.failUnlessEqual(md1["metakey1"], "metavalue1"))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable",
+ filecap2))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable-ro",
+ filecap3))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"dirchild", dircap))
+ return d2
+ d.addCallback(_check)
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessNodeKeysAre, newkids.keys())
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessChildURIIs, u"child-imm", filecap1)
+ return d
+
+ def test_POST_NEWDIRURL_initial_children(self):
+ (newkids, filecap1, filecap2, filecap3,
+ dircap) = self._create_initial_children()
+ d = self.POST(self.public_url + "/foo/newdir?t=mkdir",
+ children=simplejson.dumps(newkids))
+ def _check(uri):
+ n = self.s.create_node_from_uri(uri.strip())
+ d2 = self.failUnlessNodeKeysAre(n, newkids.keys())
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-imm", filecap1))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable",
+ filecap2))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable-ro",
+ filecap3))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"dirchild", dircap))
+ return d2
+ d.addCallback(_check)
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessNodeKeysAre, newkids.keys())
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessChildURIIs, u"child-imm", filecap1)
+ return d
+
def test_PUT_NEWDIRURL_exists(self):
d = self.PUT(self.public_url + "/foo/sub?t=mkdir", "")
d.addCallback(lambda res:
d.addCallback(self.failUnlessNodeKeysAre, [])
return d
+ def test_POST_mkdir_initial_children(self):
+ newkids, filecap1, ign, ign, ign = self._create_initial_children()
+ d = self.POST(self.public_url + "/foo", t="mkdir", name="newdir",
+ children=simplejson.dumps(newkids))
+ d.addCallback(lambda res:
+ self.failUnlessNodeHasChild(self._foo_node, u"newdir"))
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessNodeKeysAre, newkids.keys())
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessChildURIIs, u"child-imm", filecap1)
+ return d
+
def test_POST_mkdir_2(self):
d = self.POST(self.public_url + "/foo/newdir?t=mkdir", "")
d.addCallback(lambda res:
d.addCallback(_check_target)
return d
+ def _create_initial_children(self):
+ contents, n, filecap1 = self.makefile(12)
+ md1 = {"metakey1": "metavalue1"}
+ filecap2 = make_mutable_file_uri()
+ node3 = self.s.create_node_from_uri(make_mutable_file_uri())
+ filecap3 = node3.get_readonly_uri()
+ node4 = self.s.create_node_from_uri(make_mutable_file_uri())
+ dircap = DirectoryNode(node4, None, None).get_uri()
+ newkids = {u"child-imm": ["filenode", {"ro_uri": filecap1,
+ "metadata": md1, }],
+ u"child-mutable": ["filenode", {"rw_uri": filecap2}],
+ u"child-mutable-ro": ["filenode", {"ro_uri": filecap3}],
+ u"dirchild": ["dirnode", {"rw_uri": dircap}],
+ }
+ return newkids, filecap1, filecap2, filecap3, dircap
+
+ def test_POST_mkdir_no_parentdir_initial_children(self):
+ (newkids, filecap1, filecap2, filecap3,
+ dircap) = self._create_initial_children()
+ d = self.POST("/uri?t=mkdir", children=simplejson.dumps(newkids))
+ def _after_mkdir(res):
+ self.failUnless(res.startswith("URI:DIR"), res)
+ n = self.s.create_node_from_uri(res)
+ d2 = self.failUnlessNodeKeysAre(n, newkids.keys())
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-imm", filecap1))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable",
+ filecap2))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable-ro",
+ filecap3))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"dirchild", dircap))
+ return d2
+ d.addCallback(_after_mkdir)
+ return d
+
def test_POST_noparent_bad(self):
d = self.shouldHTTPError("POST /uri?t=bogus", 400, "Bad Request",
"/uri accepts only PUT, PUT?t=mkdir, "
d.addCallback(self.failUnlessIsEmptyJSON)
return d
+ def test_PUT_mkdir_initial_children(self):
+ (newkids, filecap1, filecap2, filecap3,
+ dircap) = self._create_initial_children()
+ d = self.PUT("/uri?t=mkdir", simplejson.dumps(newkids))
+ def _check(uri):
+ n = self.s.create_node_from_uri(uri.strip())
+ d2 = self.failUnlessNodeKeysAre(n, newkids.keys())
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-imm", filecap1))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable",
+ filecap2))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"child-mutable-ro",
+ filecap3))
+ d2.addCallback(lambda ign:
+ self.failUnlessChildURIIs(n, u"dirchild", dircap))
+ return d2
+ d.addCallback(_check)
+ return d
+
def test_POST_check(self):
d = self.POST(self.public_url + "/foo", t="check", name="bar.txt")
def _done(res):
IOpHandleTable, NeedOperationHandleError, \
boolean_of_arg, get_arg, get_root, parse_replace_arg, \
should_create_intermediate_directories, \
- getxmlfile, RenderMixin, humanize_failure
+ getxmlfile, RenderMixin, humanize_failure, convert_initial_children_json
from allmydata.web.filenode import ReplaceMeMixin, \
FileNodeHandler, PlaceHolderNodeHandler
from allmydata.web.check_results import CheckResults, \
if (method,t) in [ ("POST","mkdir"), ("PUT","mkdir") ]:
if DEBUG: print " making final directory"
# final directory
- d = self.node.create_subdirectory(name)
+ if method == "POST":
+ kids_json = get_arg(req, "children", "")
+ else:
+ req.content.seek(0)
+ kids_json = req.content.read()
+ initial_children = convert_initial_children_json(kids_json)
+ d = self.node.create_subdirectory(name, initial_children)
d.addCallback(make_handler_for,
self.client, self.node, name)
return d
return defer.succeed(self.node.get_uri()) # TODO: urlencode
name = name.decode("utf-8")
replace = boolean_of_arg(get_arg(req, "replace", "true"))
- d = self.node.create_subdirectory(name, overwrite=replace)
+ children_json = get_arg(req, "children", "")
+ initial_children = convert_initial_children_json(children_json)
+ d = self.node.create_subdirectory(name, initial_children,
+ overwrite=replace)
d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
return d