write-cap as the HTTP response body. The new directory is not attached to
any other directory: the returned write-cap is the only reference to it.
- Initial children are provided in the "children" field of the POST form. 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:
+ Initial children are provided as the body of the POST form (this is more
+ efficient than doing separate mkdir and set_children operations). If the
+ body is empty, the new directory will be empty. If not empty, the body 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", {
} } } ]
}
+ Note that the webapi-using client application must not provide the
+ "Content-Type: multipart/form-data" header that usually accompanies HTML
+ form submissions, since the body is not formatted this way. Doing so will
+ cause a server error as the lower-level code misparses the request body.
+
+POST /uri?t=mkdir-immutable
+
+ Like t=mkdir-with-children above, but the new directory will be
+ deep-immutable. This means that the directory itself is immutable, and that
+ it can only contain deep-immutable objects, like immutable files, literal
+ files, and deep-immutable directories. A non-empty request body is
+ mandatory, since after the directory is created, it will not be possible to
+ add more children to it.
+
POST /uri/$DIRCAP/[SUBDIRS../]SUBDIR?t=mkdir
PUT /uri/$DIRCAP/[SUBDIRS../]SUBDIR?t=mkdir
POST /uri/$DIRCAP/[SUBDIRS../]SUBDIR?t=mkdir-with-children
Like above, but if the final directory is created, it will be populated with
- initial children via the POST 'children' form field, as described above in
- the /uri?t=mkdir-with-children operation.
+ initial children from the POST request body, as described above in the
+ /uri?t=mkdir-with-children operation.
+
+POST /uri/$DIRCAP/[SUBDIRS../]SUBDIR?t=mkdir-immutable
+
+ Like above, but the final directory will be deep-immutable, with the
+ children specified as a JSON dictionary in the POST request body.
POST /uri/$DIRCAP/[SUBDIRS../]?t=mkdir&name=NAME
POST /uri/$DIRCAP/[SUBDIRS../]?t=mkdir-with-children&name=NAME
As above, but the new directory will be populated with initial children via
- the POST 'children' form field, as described in /uri?t=mkdir-with-children
- above.
+ the POST request body, as described in /uri?t=mkdir-with-children above.
+ Note that the name= argument must be passed as a queryarg, because the POST
+ request body is used for the initial children JSON.
+
+POST /uri/$DIRCAP/[SUBDIRS../]?t=mkdir-immutable&name=NAME
+
+ As above, but the new directory will be deep-immutable, with the children
+ specified as a JSON dictionary in the POST request body. Again, the name=
+ argument must be passed as a queryarg.
=== Get Information About A File Or Directory (as JSON) ===
def create_dirnode(self, initial_children={}):
d = self.nodemaker.create_new_mutable_directory(initial_children)
return d
- def create_immutable_dirnode(self, children):
- return self.nodemaker.create_immutable_directory(children,
- self.convergence)
+ def create_immutable_dirnode(self, children, convergence=None):
+ return self.nodemaker.create_immutable_directory(children, convergence)
def create_mutable_file(self, contents=None, keysize=None):
return self.nodemaker.create_mutable_file(contents, keysize)
filenode_class = MutableFileNode
def __init__(self, filenode, nodemaker, uploader):
+ assert IFileNode.providedBy(filenode), filenode
+ assert not IDirectoryNode.providedBy(filenode), filenode
self._node = filenode
filenode_cap = filenode.get_cap()
self._uri = wrap_dirnode_cap(filenode_cap)
d.addCallback(lambda res: deleter.old_child)
return d
- def create_subdirectory(self, name, initial_children={}, overwrite=True):
+ def create_subdirectory(self, name, initial_children={}, overwrite=True,
+ mutable=True):
assert isinstance(name, unicode)
if self.is_readonly():
return defer.fail(NotMutableError())
- d = self._nodemaker.create_new_mutable_directory(initial_children)
+ if mutable:
+ d = self._nodemaker.create_new_mutable_directory(initial_children)
+ else:
+ d = self._nodemaker.create_immutable_directory(initial_children)
def _created(child):
entries = {name: (child, None)}
a = Adder(self, entries, overwrite=overwrite)
"""I recognize the cap/URI, but I cannot create an IFilesystemNode for
it."""
+class NotDeepImmutableError(Exception):
+ """Deep-immutable directories can only contain deep-immutable children"""
+
class IFilesystemNode(Interface):
def get_cap():
"""Return the strongest 'cap instance' associated with this node.
import weakref
from zope.interface import implements
from allmydata.util.assertutil import precondition
-from allmydata.interfaces import INodeMaker
+from allmydata.interfaces import INodeMaker, NotDeepImmutableError
from allmydata.immutable.filenode import FileNode, LiteralFileNode
from allmydata.immutable.upload import Data
from allmydata.mutable.filenode import MutableFileNode
d.addCallback(self._create_dirnode)
return d
- def create_immutable_directory(self, children, convergence):
+ def create_immutable_directory(self, children, convergence=None):
+ if convergence is None:
+ convergence = self.secret_holder.get_convergence_secret()
for (name, (node, metadata)) in children.iteritems():
precondition(not isinstance(node, UnknownNode),
"create_immutable_directory does not accept UnknownNode", node)
precondition(isinstance(metadata, dict),
"create_immutable_directory requires metadata to be a dict, not None", metadata)
- precondition(not node.is_mutable(),
- "create_immutable_directory requires immutable children", node)
+ if node.is_mutable():
+ raise NotDeepImmutableError("%s is not immutable" % (node,))
n = DummyImmutableFileNode() # writekey=None
packed = pack_children(n, children)
uploadable = Data(packed, convergence)
return self.my_uri.to_string()
def get_readonly_uri(self):
return self.my_uri.to_string()
+ def get_cap(self):
+ return self.my_uri
def get_verify_cap(self):
return self.my_uri.get_verify_cap()
def get_repair_cap(self):
import time
+from zope.interface import implements
from twisted.trial import unittest
from twisted.internet import defer
from allmydata import uri, dirnode
from allmydata.client import Client
from allmydata.immutable import upload
-from allmydata.interfaces import IFileNode, \
- ExistingChildError, NoSuchChildError, \
+from allmydata.interfaces import IFileNode, IMutableFileNode, \
+ ExistingChildError, NoSuchChildError, NotDeepImmutableError, \
IDeepCheckResults, IDeepCheckAndRepairResults, CannotPackUnknownNodeError
from allmydata.mutable.filenode import MutableFileNode
from allmydata.mutable.common import UncoordinatedWriteError
bad_kids2))
bad_kids3 = {u"one": (nm.create_from_cap(mut_writecap), {})}
d.addCallback(lambda ign:
- self.shouldFail(AssertionError, "bad_kids3",
- "create_immutable_directory requires immutable children",
+ self.shouldFail(NotDeepImmutableError, "bad_kids3",
+ "is not immutable",
c.create_immutable_dirnode,
bad_kids3))
bad_kids4 = {u"one": (nm.create_from_cap(mut_readcap), {})}
d.addCallback(lambda ign:
- self.shouldFail(AssertionError, "bad_kids4",
- "create_immutable_directory requires immutable children",
+ self.shouldFail(NotDeepImmutableError, "bad_kids4",
+ "is not immutable",
c.create_immutable_dirnode,
bad_kids4))
d.addCallback(lambda ign: c.create_immutable_dirnode({}))
return dn.list()
d.addCallback(_created_small)
d.addCallback(lambda kids: self.failUnlessEqual(kids.keys(), [u"o"]))
+
+ # now test n.create_subdirectory(mutable=False)
+ d.addCallback(lambda ign: c.create_dirnode())
+ def _made_parent(n):
+ d = n.create_subdirectory(u"subdir", kids, mutable=False)
+ d.addCallback(lambda sd: sd.list())
+ d.addCallback(_check_kids)
+ d.addCallback(lambda ign: n.list())
+ d.addCallback(lambda children:
+ self.failUnlessEqual(children.keys(), [u"subdir"]))
+ d.addCallback(lambda ign: n.get(u"subdir"))
+ d.addCallback(lambda sd: sd.list())
+ d.addCallback(_check_kids)
+ d.addCallback(lambda ign: n.get(u"subdir"))
+ d.addCallback(lambda sd: self.failIf(sd.is_mutable()))
+ bad_kids = {u"one": (nm.create_from_cap(mut_writecap), {})}
+ d.addCallback(lambda ign:
+ self.shouldFail(NotDeepImmutableError, "YZ",
+ "is not immutable",
+ n.create_subdirectory,
+ u"sub2", bad_kids, mutable=False))
+ return d
+ d.addCallback(_made_parent)
return d
+
def test_check(self):
self.basedir = "dirnode/Dirnode/test_check"
self.set_up_grid()
fn, kids, deep_immutable=True)
class FakeMutableFile:
+ implements(IMutableFileNode)
counter = 0
def __init__(self, initial_contents=""):
self.data = self._get_initial_contents(initial_contents)
d.addCallback(lambda junk: self.clients[3].create_dirnode())
d.addCallback(check_kg_poolsize, -2)
# use_helper induces use of clients[3], which is the using-key_gen client
- d.addCallback(lambda junk: self.POST("uri", use_helper=True, t="mkdir", name='george'))
+ d.addCallback(lambda junk:
+ self.POST("uri?t=mkdir&name=george", use_helper=True))
d.addCallback(check_kg_poolsize, -3)
return d
return getPage(url, method="GET", followRedirect=followRedirect)
def POST(self, urlpath, followRedirect=False, use_helper=False, **fields):
- if use_helper:
- url = self.helper_webish_url + urlpath
- else:
- url = self.webish_url + urlpath
sepbase = "boogabooga"
sep = "--" + sepbase
form = []
form.append(str(value))
form.append(sep)
form[-1] += "--"
- body = "\r\n".join(form) + "\r\n"
- headers = {"content-type": "multipart/form-data; boundary=%s" % sepbase,
- }
- return getPage(url, method="POST", postdata=body,
- headers=headers, followRedirect=followRedirect)
+ body = ""
+ headers = {}
+ if fields:
+ body = "\r\n".join(form) + "\r\n"
+ headers["content-type"] = "multipart/form-data; boundary=%s" % sepbase
+ return self.POST2(urlpath, body, headers, followRedirect, use_helper)
+
+ def POST2(self, urlpath, body="", headers={}, followRedirect=False,
+ use_helper=False):
+ if use_helper:
+ url = self.helper_webish_url + urlpath
+ else:
+ url = self.webish_url + urlpath
+ return getPage(url, method="POST", postdata=body, headers=headers,
+ followRedirect=followRedirect)
def _test_web(self, res):
base = self.webish_url
return client.getPage(url, method="DELETE")
def POST(self, urlpath, followRedirect=False, **fields):
- url = self.webish_url + urlpath
sepbase = "boogabooga"
sep = "--" + sepbase
form = []
form.append(value)
form.append(sep)
form[-1] += "--"
- body = "\r\n".join(form) + "\r\n"
- headers = {"content-type": "multipart/form-data; boundary=%s" % sepbase,
- }
+ body = ""
+ headers = {}
+ if fields:
+ body = "\r\n".join(form) + "\r\n"
+ headers["content-type"] = "multipart/form-data; boundary=%s" % sepbase
+ return self.POST2(urlpath, body, headers, followRedirect)
+
+ def POST2(self, urlpath, body="", headers={}, followRedirect=False):
+ url = self.webish_url + urlpath
return client.getPage(url, method="POST", postdata=body,
headers=headers, followRedirect=followRedirect)
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-with-children",
- children=simplejson.dumps(newkids))
+ d = self.POST2(self.public_url + "/foo/newdir?t=mkdir-with-children",
+ simplejson.dumps(newkids))
def _check(uri):
n = self.s.create_node_from_uri(uri.strip())
d2 = self.failUnlessNodeKeysAre(n, newkids.keys())
d.addCallback(self.failUnlessChildURIIs, u"child-imm", filecap1)
return d
+ def test_POST_NEWDIRURL_immutable(self):
+ (newkids, filecap1, immdircap) = self._create_immutable_children()
+ d = self.POST2(self.public_url + "/foo/newdir?t=mkdir-immutable",
+ 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"dirchild-imm",
+ immdircap))
+ 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)
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessChildURIIs, u"dirchild-imm", immdircap)
+ d.addErrback(self.explain_web_error)
+ return d
+
+ def test_POST_NEWDIRURL_immutable_bad(self):
+ (newkids, filecap1, filecap2, filecap3,
+ dircap) = self._create_initial_children()
+ d = self.shouldFail2(error.Error, "test_POST_NEWDIRURL_immutable_bad",
+ "400 Bad Request",
+ "a mkdir-immutable operation was given a child that was not itself immutable",
+ self.POST2,
+ self.public_url + "/foo/newdir?t=mkdir-immutable",
+ simplejson.dumps(newkids))
+ return d
+
def test_PUT_NEWDIRURL_exists(self):
d = self.PUT(self.public_url + "/foo/sub?t=mkdir", "")
d.addCallback(lambda res:
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-with-children",
- name="newdir", children=simplejson.dumps(newkids))
+ d = self.POST2(self.public_url +
+ "/foo?t=mkdir-with-children&name=newdir",
+ 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.failUnlessChildURIIs, u"child-imm", filecap1)
return d
+ def test_POST_mkdir_immutable(self):
+ (newkids, filecap1, immdircap) = self._create_immutable_children()
+ d = self.POST2(self.public_url +
+ "/foo?t=mkdir-immutable&name=newdir",
+ 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)
+ d.addCallback(lambda res: self._foo_node.get(u"newdir"))
+ d.addCallback(self.failUnlessChildURIIs, u"dirchild-imm", immdircap)
+ return d
+
+ def test_POST_mkdir_immutable_bad(self):
+ (newkids, filecap1, filecap2, filecap3,
+ dircap) = self._create_initial_children()
+ d = self.shouldFail2(error.Error, "test_POST_mkdir_immutable_bad",
+ "400 Bad Request",
+ "a mkdir-immutable operation was given a child that was not itself immutable",
+ self.POST2,
+ self.public_url +
+ "/foo?t=mkdir-immutable&name=newdir",
+ simplejson.dumps(newkids))
+ return d
+
def test_POST_mkdir_2(self):
d = self.POST(self.public_url + "/foo/newdir?t=mkdir", "")
d.addCallback(lambda res:
}
return newkids, filecap1, filecap2, filecap3, dircap
+ def _create_immutable_children(self):
+ contents, n, filecap1 = self.makefile(12)
+ md1 = {"metakey1": "metavalue1"}
+ tnode = create_chk_filenode("immutable directory contents\n"*10)
+ dnode = DirectoryNode(tnode, None, None)
+ assert not dnode.is_mutable()
+ immdircap = dnode.get_uri()
+ newkids = {u"child-imm": ["filenode", {"ro_uri": filecap1,
+ "metadata": md1, }],
+ u"dirchild-imm": ["dirnode", {"ro_uri": immdircap}],
+ }
+ return newkids, filecap1, immdircap
+
def test_POST_mkdir_no_parentdir_initial_children(self):
(newkids, filecap1, filecap2, filecap3,
dircap) = self._create_initial_children()
- d = self.POST("/uri?t=mkdir-with-children",
- children=simplejson.dumps(newkids))
+ d = self.POST2("/uri?t=mkdir-with-children", simplejson.dumps(newkids))
def _after_mkdir(res):
self.failUnless(res.startswith("URI:DIR"), res)
n = self.s.create_node_from_uri(res)
400, "Bad Request",
"t=mkdir does not accept children=, "
"try t=mkdir-with-children instead",
- self.POST, "/uri?t=mkdir", # without children
- children=simplejson.dumps(newkids))
+ self.POST2, "/uri?t=mkdir", # without children
+ simplejson.dumps(newkids))
return d
def test_POST_noparent_bad(self):
self.POST, "/uri?t=bogus")
return d
+ def test_POST_mkdir_no_parentdir_immutable(self):
+ (newkids, filecap1, immdircap) = self._create_immutable_children()
+ d = self.POST2("/uri?t=mkdir-immutable", 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"dirchild-imm",
+ immdircap))
+ return d2
+ d.addCallback(_after_mkdir)
+ return d
+
+ def test_POST_mkdir_no_parentdir_immutable_bad(self):
+ (newkids, filecap1, filecap2, filecap3,
+ dircap) = self._create_initial_children()
+ d = self.shouldFail2(error.Error,
+ "test_POST_mkdir_no_parentdir_immutable_bad",
+ "400 Bad Request",
+ "a mkdir-immutable operation was given a child that was not itself immutable",
+ self.POST2,
+ "/uri?t=mkdir-immutable",
+ simplejson.dumps(newkids))
+ return d
+
def test_welcome_page_mkdir_button(self):
# Fetch the welcome page.
d = self.GET("/")
from nevow.inevow import IRequest
from nevow.util import resource_filename
from allmydata.interfaces import ExistingChildError, NoSuchChildError, \
- FileTooLargeError, NotEnoughSharesError, NoSharesError
+ FileTooLargeError, NotEnoughSharesError, NoSharesError, \
+ NotDeepImmutableError
from allmydata.mutable.common import UnrecoverableFileError
from allmydata.util import abbreviate # TODO: consolidate
def convert_children_json(nodemaker, children_json):
"""I convert the JSON output of GET?t=json into the dict-of-nodes input
to both dirnode.create_subdirectory() and
- client.create_directory(initial_children=)."""
- initial_children = {}
+ client.create_directory(initial_children=). This is used by
+ t=mkdir-with-children and t=mkdir-immutable"""
+ children = {}
if children_json:
data = simplejson.loads(children_json)
for (name, (ctype, propdict)) in data.iteritems():
readcap = str(readcap)
metadata = propdict.get("metadata", {})
childnode = nodemaker.create_from_cap(writecap, readcap)
- initial_children[name] = (childnode, metadata)
- return initial_children
+ children[name] = (childnode, metadata)
+ return children
def abbreviate_time(data):
# 1.23s, 790ms, 132us
"failure, or disk corruption. You should perform a filecheck on "
"this object to learn more.")
return (t, http.GONE)
+ if f.check(NotDeepImmutableError):
+ t = ("NotDeepImmutableError: a mkdir-immutable operation was given "
+ "a child that was not itself immutable: %s" % (f.value,))
+ return (t, http.BAD_REQUEST)
if f.check(WebError):
return (f.value.text, f.value.code)
if f.check(FileTooLargeError):
if DEBUG: print " terminal"
# terminal node
if (method,t) in [ ("POST","mkdir"), ("PUT","mkdir"),
- ("POST", "mkdir-with-children") ]:
+ ("POST", "mkdir-with-children"),
+ ("POST", "mkdir-immutable") ]:
if DEBUG: print " making final directory"
# final directory
kids = {}
- if (method,t) == ("POST", "mkdir-with-children"):
- kids_json = get_arg(req, "children", "")
+ if t in ("mkdir-with-children", "mkdir-immutable"):
+ req.content.seek(0)
+ kids_json = req.content.read()
kids = convert_children_json(self.client.nodemaker,
kids_json)
- d = self.node.create_subdirectory(name, kids)
+ mutable = True
+ if t == "mkdir-immutable":
+ mutable = False
+ d = self.node.create_subdirectory(name, kids,
+ mutable=mutable)
d.addCallback(make_handler_for,
self.client, self.node, name)
return d
d = self._POST_mkdir(req)
elif t == "mkdir-with-children":
d = self._POST_mkdir_with_children(req)
+ elif t == "mkdir-immutable":
+ d = self._POST_mkdir_immutable(req)
elif t == "mkdir-p":
# TODO: docs, tests
d = self._POST_mkdir_p(req)
return defer.succeed(self.node.get_uri()) # TODO: urlencode
name = name.decode("utf-8")
replace = boolean_of_arg(get_arg(req, "replace", "true"))
- kids_json = get_arg(req, "children", "")
+ req.content.seek(0)
+ kids_json = req.content.read()
kids = convert_children_json(self.client.nodemaker, kids_json)
d = self.node.create_subdirectory(name, kids, overwrite=replace)
d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
return d
+ def _POST_mkdir_immutable(self, req):
+ name = get_arg(req, "name", "")
+ if not name:
+ # our job is done, it was handled by the code in got_child
+ # which created the final directory (i.e. us)
+ return defer.succeed(self.node.get_uri()) # TODO: urlencode
+ name = name.decode("utf-8")
+ replace = boolean_of_arg(get_arg(req, "replace", "true"))
+ req.content.seek(0)
+ kids_json = req.content.read()
+ kids = convert_children_json(self.client.nodemaker, kids_json)
+ d = self.node.create_subdirectory(name, kids, mutable=False)
+ d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
+ return d
+
def _POST_mkdir_p(self, req):
path = get_arg(req, "path")
if not path:
elif t == "mkdir-with-children":
return unlinked.POSTUnlinkedCreateDirectoryWithChildren(req,
self.client)
+ elif t == "mkdir-immutable":
+ return unlinked.POSTUnlinkedCreateImmutableDirectory(req,
+ self.client)
errmsg = ("/uri accepts only PUT, PUT?t=mkdir, POST?t=upload, "
"and POST?t=mkdir")
raise WebError(errmsg, http.BAD_REQUEST)
def POSTUnlinkedCreateDirectory(req, client):
# "POST /uri?t=mkdir", to create an unlinked directory.
- kids_json = get_arg(req, "children", None)
- if kids_json is not None:
+ req.content.seek(0)
+ kids_json = req.content.read()
+ if kids_json:
raise WebError("t=mkdir does not accept children=, "
"try t=mkdir-with-children instead",
http.BAD_REQUEST)
def POSTUnlinkedCreateDirectoryWithChildren(req, client):
# "POST /uri?t=mkdir", to create an unlinked directory.
- kids_json = get_arg(req, "children", "")
+ req.content.seek(0)
+ kids_json = req.content.read()
kids = convert_children_json(client.nodemaker, kids_json)
d = client.create_dirnode(initial_children=kids)
redirect = get_arg(req, "redirect_to_result", "false")
d.addCallback(lambda dirnode: dirnode.get_uri())
return d
+def POSTUnlinkedCreateImmutableDirectory(req, client):
+ # "POST /uri?t=mkdir", to create an unlinked directory.
+ req.content.seek(0)
+ kids_json = req.content.read()
+ kids = convert_children_json(client.nodemaker, kids_json)
+ d = client.create_immutable_dirnode(kids)
+ redirect = get_arg(req, "redirect_to_result", "false")
+ if boolean_of_arg(redirect):
+ def _then_redir(res):
+ new_url = "uri/" + urllib.quote(res.get_uri())
+ req.setResponseCode(http.SEE_OTHER) # 303
+ req.setHeader('location', new_url)
+ req.finish()
+ return ''
+ d.addCallback(_then_redir)
+ else:
+ d.addCallback(lambda dirnode: dirnode.get_uri())
+ return d