Example #1
0
    def replace_me_with_a_formpost(self, req, client, replace):
        # create a new file, maybe mutable, maybe immutable
        mutable = boolean_of_arg(get_arg(req, "mutable", "false"))

        # create an immutable file
        contents = req.fields["file"]
        if mutable:
            arg = get_arg(req, "mutable-type", None)
            mutable_type = parse_mutable_type_arg(arg)
            if mutable_type is "invalid":
                raise WebError("Unknown type: %s" % arg, http.BAD_REQUEST)
            uploadable = MutableFileHandle(contents.file)
            d = client.create_mutable_file(uploadable, version=mutable_type)
            def _uploaded(newnode):
                d2 = self.parentnode.set_node(self.name, newnode,
                                              overwrite=replace)
                d2.addCallback(lambda res: newnode.get_uri())
                return d2
            d.addCallback(_uploaded)
            return d

        uploadable = FileHandle(contents.file, convergence=client.convergence)
        d = self.parentnode.add_file(self.name, uploadable, overwrite=replace)
        d.addCallback(lambda newnode: newnode.get_uri())
        return d
Example #2
0
 def render_POST(self, ctx):
     # "POST /uri?t=upload&file=newfile" to upload an
     # unlinked file or "POST /uri?t=mkdir" to create a
     # new directory
     req = IRequest(ctx)
     t = get_arg(req, "t", "").strip()
     if t in ("", "upload"):
         mutable = bool(get_arg(req, "mutable", "").strip())
         if mutable:
             arg = get_arg(req, "mutable-type", None)
             version = parse_mutable_type_arg(arg)
             if version is "invalid":
                 raise WebError("Unknown type: %s" % arg, http.BAD_REQUEST)
             return unlinked.POSTUnlinkedSSK(req, self.client, version)
         else:
             return unlinked.POSTUnlinkedCHK(req, self.client)
     if t == "mkdir":
         return unlinked.POSTUnlinkedCreateDirectory(req, self.client)
     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)
Example #3
0
    def replace_me_with_a_child(self, req, client, replace):
        # a new file is being uploaded in our place.
        mutable = boolean_of_arg(get_arg(req, "mutable", "false"))
        if mutable:
            arg = get_arg(req, "mutable-type", None)
            mutable_type = parse_mutable_type_arg(arg)
            if mutable_type is "invalid":
                raise WebError("Unknown type: %s" % arg, http.BAD_REQUEST)

            data = MutableFileHandle(req.content)
            d = client.create_mutable_file(data, version=mutable_type)
            def _uploaded(newnode):
                d2 = self.parentnode.set_node(self.name, newnode,
                                              overwrite=replace)
                d2.addCallback(lambda res: newnode)
                return d2
            d.addCallback(_uploaded)
        else:
            uploadable = FileHandle(req.content, convergence=client.convergence)
            d = self.parentnode.add_file(self.name, uploadable,
                                         overwrite=replace)
        def _done(filenode):
            log.msg("webish upload complete",
                    facility="tahoe.webish", level=log.NOISY, umid="TCjBGQ")
            if self.node:
                # we've replaced an existing file (or modified a mutable
                # file), so the response code is 200
                req.setResponseCode(http.OK)
            else:
                # we've created a new file, so the code is 201
                req.setResponseCode(http.CREATED)
            return filenode.get_uri()
        d.addCallback(_done)
        return d
Example #4
0
    def _POST_rename(self, req):
        charset = get_arg(req, "_charset", "utf-8")
        from_name = get_arg(req, "from_name")
        if from_name is not None:
            from_name = from_name.strip()
            from_name = from_name.decode(charset)
            assert isinstance(from_name, unicode)
        to_name = get_arg(req, "to_name")
        if to_name is not None:
            to_name = to_name.strip()
            to_name = to_name.decode(charset)
            assert isinstance(to_name, unicode)
        if not from_name or not to_name:
            raise WebError("rename requires from_name and to_name")
        if from_name == to_name:
            return defer.succeed("redundant rename")

        # 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)
        d.addCallback(lambda res: "thing renamed")
        return d
Example #5
0
    def childFactory(self, ctx, name):
        ophandle = name
        if ophandle not in self.handles:
            raise WebError("unknown/expired handle '%s'" % escape(ophandle),
                           NOT_FOUND)
        (monitor, renderer, when_added) = self.handles[ophandle]

        request = IRequest(ctx)
        t = get_arg(ctx, "t", "status")
        if t == "cancel" and request.method == "POST":
            monitor.cancel()
            # return the status anyways, but release the handle
            self._release_ophandle(ophandle)

        else:
            retain_for = get_arg(ctx, "retain-for", None)
            if retain_for is not None:
                self._set_timer(ophandle, int(retain_for))

            if monitor.is_finished():
                if boolean_of_arg(get_arg(ctx, "release-after-complete", "false")):
                    self._release_ophandle(ophandle)
                if retain_for is None:
                    # this GET is collecting the ophandle, so change its timer
                    self._set_timer(ophandle, self.COLLECTED_HANDLE_LIFETIME)

        status = monitor.get_status()
        if isinstance(status, Failure):
            return defer.fail(status)

        return renderer
Example #6
0
    def render_POST(self, ctx):
        req = IRequest(ctx)
        t = get_arg(req, "t", "").strip()
        replace = boolean_of_arg(get_arg(req, "replace", "true"))
        if t == "check":
            d = self._POST_check(req)
        elif t == "upload":
            # like PUT, but get the file data from an HTML form's input field
            # We could get here from POST /uri/mutablefilecap?t=upload,
            # or POST /uri/path/file?t=upload, or
            # POST /uri/path/dir?t=upload&name=foo . All have the same
            # behavior, we just ignore any name= argument
            if self.node.is_mutable():
                d = self.replace_my_contents_with_a_formpost(req)
            else:
                if not replace:
                    raise ExistingChildError()
                assert self.parentnode and self.name
                d = self.replace_me_with_a_formpost(req, self.client, replace)
        else:
            raise WebError("POST to file: bad t=%s" % t)

        when_done = get_arg(req, "when_done", None)
        if when_done:
            d.addCallback(lambda res: url.URL.fromString(when_done))
        return d
Example #7
0
    def render_POST(self, ctx):
        req = IRequest(ctx)
        t = get_arg(req, "t", "").strip()
        replace = boolean_of_arg(get_arg(req, "replace", "true"))
        if t == "check":
            d = self._POST_check(req)
        elif t == "upload":
            # like PUT, but get the file data from an HTML form's input field
            # We could get here from POST /uri/mutablefilecap?t=upload,
            # or POST /uri/path/file?t=upload, or
            # POST /uri/path/dir?t=upload&name=foo . All have the same
            # behavior, we just ignore any name= argument
            if self.node.is_mutable():
                d = self.replace_my_contents_with_a_formpost(req)
            else:
                if not replace:
                    raise ExistingChildError()
                assert self.parentnode and self.name
                d = self.replace_me_with_a_formpost(req, self.client, replace)
        else:
            raise WebError("POST to file: bad t=%s" % t)

        when_done = get_arg(req, "when_done", None)
        if when_done:
            d.addCallback(lambda res: url.URL.fromString(when_done))
        return d
Example #8
0
 def _POST_stream_deep_check(self, ctx):
     verify = boolean_of_arg(get_arg(ctx, "verify", "false"))
     repair = boolean_of_arg(get_arg(ctx, "repair", "false"))
     add_lease = boolean_of_arg(get_arg(ctx, "add-lease", "false"))
     walker = DeepCheckStreamer(ctx, self.node, verify, repair, add_lease)
     monitor = self.node.deep_traverse(walker)
     walker.setMonitor(monitor)
     # register to hear stopProducing. The walker ignores pauseProducing.
     IRequest(ctx).registerProducer(walker, True)
     d = monitor.when_done()
     def _done(res):
         IRequest(ctx).unregisterProducer()
         return res
     d.addBoth(_done)
     def _cancelled(f):
         f.trap(OperationCancelledError)
         return "Operation Cancelled"
     d.addErrback(_cancelled)
     def _error(f):
         # signal the error as a non-JSON "ERROR:" line, plus exception
         msg = "ERROR: %s(%s)\n" % (f.value.__class__.__name__,
                                    ", ".join([str(a) for a in f.value.args]))
         msg += str(f)
         return msg
     d.addErrback(_error)
     return d
Example #9
0
    def childFactory(self, ctx, name):
        ophandle = name
        if ophandle not in self.handles:
            raise WebError("unknown/expired handle '%s'" % escape(ophandle),
                           NOT_FOUND)
        (monitor, renderer, when_added) = self.handles[ophandle]

        request = IRequest(ctx)
        t = get_arg(ctx, "t", "status")
        if t == "cancel" and request.method == "POST":
            monitor.cancel()
            # return the status anyways, but release the handle
            self._release_ophandle(ophandle)

        else:
            retain_for = get_arg(ctx, "retain-for", None)
            if retain_for is not None:
                self._set_timer(ophandle, int(retain_for))

            if monitor.is_finished():
                if boolean_of_arg(
                        get_arg(ctx, "release-after-complete", "false")):
                    self._release_ophandle(ophandle)
                if retain_for is None:
                    # this GET is collecting the ophandle, so change its timer
                    self._set_timer(ophandle, self.COLLECTED_HANDLE_LIFETIME)

        status = monitor.get_status()
        if isinstance(status, Failure):
            return defer.fail(status)

        return renderer
Example #10
0
    def _POST_rename(self, req):
        charset = get_arg(req, "_charset", "utf-8")
        from_name = get_arg(req, "from_name")
        if from_name is not None:
            from_name = from_name.strip()
            from_name = from_name.decode(charset)
            assert isinstance(from_name, unicode)
        to_name = get_arg(req, "to_name")
        if to_name is not None:
            to_name = to_name.strip()
            to_name = to_name.decode(charset)
            assert isinstance(to_name, unicode)
        if not from_name or not to_name:
            raise WebError("rename requires from_name and to_name")
        if from_name == to_name:
            return defer.succeed("redundant rename")

        # 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)
        d.addCallback(lambda res: "thing renamed")
        return d
Example #11
0
 def _POST_stream_deep_check(self, ctx):
     verify = boolean_of_arg(get_arg(ctx, "verify", "false"))
     repair = boolean_of_arg(get_arg(ctx, "repair", "false"))
     add_lease = boolean_of_arg(get_arg(ctx, "add-lease", "false"))
     walker = DeepCheckStreamer(ctx, self.node, verify, repair, add_lease)
     monitor = self.node.deep_traverse(walker)
     walker.setMonitor(monitor)
     # register to hear stopProducing. The walker ignores pauseProducing.
     IRequest(ctx).registerProducer(walker, True)
     d = monitor.when_done()
     def _done(res):
         IRequest(ctx).unregisterProducer()
         return res
     d.addBoth(_done)
     def _cancelled(f):
         f.trap(OperationCancelledError)
         return "Operation Cancelled"
     d.addErrback(_cancelled)
     def _error(f):
         # signal the error as a non-JSON "ERROR:" line, plus exception
         msg = "ERROR: %s(%s)\n" % (f.value.__class__.__name__,
                                    ", ".join([str(a) for a in f.value.args]))
         msg += str(f)
         return msg
     d.addErrback(_error)
     return d
Example #12
0
 def _POST_rename(self, req):
     # rename is identical to relink, but to_dir is not allowed
     # and to_name is required.
     if get_arg(req, "to_dir") is not None:
         raise WebError("to_dir= is not valid for rename")
     if get_arg(req, "to_name") is None:
         raise WebError("to_name= is required for rename")
     return self._POST_relink(req)
Example #13
0
 def redirect_to(self, ctx):
     ophandle = get_arg(ctx, "ophandle")
     assert ophandle
     target = get_root(ctx) + "/operations/" + ophandle
     output = get_arg(ctx, "output")
     if output:
         target = target + "?output=%s" % output
     return url.URL.fromString(target)
Example #14
0
 def _POST_rename(self, req):
     # rename is identical to relink, but to_dir is not allowed
     # and to_name is required.
     if get_arg(req, "to_dir") is not None:
         raise WebError("to_dir= is not valid for rename")
     if get_arg(req, "to_name") is None:
         raise WebError("to_name= is required for rename")
     return self._POST_relink(req)
Example #15
0
 def render_HEAD(self, req):
     t = get_arg(req, "t", "").strip()
     if t:
         raise WebError("HEAD file: bad t=%s" % t)
     filename = get_arg(req, "filename", self.name) or "unknown"
     d = self.node.get_best_readable_version()
     d.addCallback(lambda dn: FileDownloader(dn, filename))
     return d
Example #16
0
 def redirect_to(self, ctx):
     ophandle = get_arg(ctx, "ophandle")
     assert ophandle
     target = get_root(ctx) + "/operations/" + ophandle
     output = get_arg(ctx, "output")
     if output:
         target = target + "?output=%s" % output
     return url.URL.fromString(target)
Example #17
0
 def add_monitor(self, ctx, monitor, renderer):
     ophandle = get_arg(ctx, "ophandle")
     assert ophandle
     now = time.time()
     self.handles[ophandle] = (monitor, renderer, now)
     retain_for = get_arg(ctx, "retain-for", None)
     if retain_for is not None:
         self._set_timer(ophandle, int(retain_for))
     monitor.when_done().addBoth(self._operation_complete, ophandle)
Example #18
0
    def render_GET(self, ctx):
        req = IRequest(ctx)
        t = get_arg(req, "t", "").strip()

        # t=info contains variable ophandles, so is not allowed an ETag.
        FIXED_OUTPUT_TYPES = ["", "json", "uri", "readonly-uri"]
        if not self.node.is_mutable() and t in FIXED_OUTPUT_TYPES:
            # if the client already has the ETag then we can
            # short-circuit the whole process.
            si = self.node.get_storage_index()
            if si and req.setETag('%s-%s' % (base32.b2a(si), t or "")):
                return ""

        if not t:
            # just get the contents
            # the filename arrives as part of the URL or in a form input
            # element, and will be sent back in a Content-Disposition header.
            # Different browsers use various character sets for this name,
            # sometimes depending upon how language environment is
            # configured. Firefox sends the equivalent of
            # urllib.quote(name.encode("utf-8")), while IE7 sometimes does
            # latin-1. Browsers cannot agree on how to interpret the name
            # they see in the Content-Disposition header either, despite some
            # 11-year old standards (RFC2231) that explain how to do it
            # properly. So we assume that at least the browser will agree
            # with itself, and echo back the same bytes that we were given.
            filename = get_arg(req, "filename", self.name) or "unknown"
            d = self.node.get_best_readable_version()
            d.addCallback(lambda dn: FileDownloader(dn, filename))
            return d
        if t == "json":
            # We do this to make sure that fields like size and
            # mutable-type (which depend on the file on the grid and not
            # just on the cap) are filled in. The latter gets used in
            # tests, in particular.
            #
            # TODO: Make it so that the servermap knows how to update in
            # a mode specifically designed to fill in these fields, and
            # then update it in that mode.
            if self.node.is_mutable():
                d = self.node.get_servermap(MODE_READ)
            else:
                d = defer.succeed(None)
            if self.parentnode and self.name:
                d.addCallback(lambda ignored: self.parentnode.get_metadata_for(
                    self.name))
            else:
                d.addCallback(lambda ignored: None)
            d.addCallback(lambda md: FileJSONMetadata(ctx, self.node, md))
            return d
        if t == "info":
            return MoreInfo(self.node)
        if t == "uri":
            return FileURI(ctx, self.node)
        if t == "readonly-uri":
            return FileReadOnlyURI(ctx, self.node)
        raise WebError("GET file: bad t=%s" % t)
Example #19
0
    def render_GET(self, ctx):
        req = IRequest(ctx)
        t = get_arg(req, "t", "").strip()

        # t=info contains variable ophandles, so is not allowed an ETag.
        FIXED_OUTPUT_TYPES = ["", "json", "uri", "readonly-uri"]
        if not self.node.is_mutable() and t in FIXED_OUTPUT_TYPES:
            # if the client already has the ETag then we can
            # short-circuit the whole process.
            si = self.node.get_storage_index()
            if si and req.setETag('%s-%s' % (base32.b2a(si), t or "")):
                return ""

        if not t:
            # just get the contents
            # the filename arrives as part of the URL or in a form input
            # element, and will be sent back in a Content-Disposition header.
            # Different browsers use various character sets for this name,
            # sometimes depending upon how language environment is
            # configured. Firefox sends the equivalent of
            # urllib.quote(name.encode("utf-8")), while IE7 sometimes does
            # latin-1. Browsers cannot agree on how to interpret the name
            # they see in the Content-Disposition header either, despite some
            # 11-year old standards (RFC2231) that explain how to do it
            # properly. So we assume that at least the browser will agree
            # with itself, and echo back the same bytes that we were given.
            filename = get_arg(req, "filename", self.name) or "unknown"
            d = self.node.get_best_readable_version()
            d.addCallback(lambda dn: FileDownloader(dn, filename))
            return d
        if t == "json":
            # We do this to make sure that fields like size and
            # mutable-type (which depend on the file on the grid and not
            # just on the cap) are filled in. The latter gets used in
            # tests, in particular.
            #
            # TODO: Make it so that the servermap knows how to update in
            # a mode specifically designed to fill in these fields, and
            # then update it in that mode.
            if self.node.is_mutable():
                d = self.node.get_servermap(MODE_READ)
            else:
                d = defer.succeed(None)
            if self.parentnode and self.name:
                d.addCallback(lambda ignored:
                    self.parentnode.get_metadata_for(self.name))
            else:
                d.addCallback(lambda ignored: None)
            d.addCallback(lambda md: FileJSONMetadata(ctx, self.node, md))
            return d
        if t == "info":
            return MoreInfo(self.node)
        if t == "uri":
            return FileURI(ctx, self.node)
        if t == "readonly-uri":
            return FileReadOnlyURI(ctx, self.node)
        raise WebError("GET file: bad t=%s" % t)
Example #20
0
 def render_HEAD(self, ctx):
     req = IRequest(ctx)
     t = get_arg(req, "t", "").strip()
     if t:
         raise WebError("HEAD file: bad t=%s" % t)
     filename = get_arg(req, "filename", self.name) or "unknown"
     d = self.node.get_best_readable_version()
     d.addCallback(lambda dn: FileDownloader(dn, filename))
     return d
Example #21
0
 def add_monitor(self, ctx, monitor, renderer):
     ophandle = get_arg(ctx, "ophandle")
     assert ophandle
     now = time.time()
     self.handles[ophandle] = (monitor, renderer, now)
     retain_for = get_arg(ctx, "retain-for", None)
     if retain_for is not None:
         self._set_timer(ophandle, int(retain_for))
     monitor.when_done().addBoth(self._operation_complete, ophandle)
Example #22
0
 def _POST_check(self, req):
     verify = boolean_of_arg(get_arg(req, "verify", "false"))
     repair = boolean_of_arg(get_arg(req, "repair", "false"))
     add_lease = boolean_of_arg(get_arg(req, "add-lease", "false"))
     if repair:
         d = self.node.check_and_repair(Monitor(), verify, add_lease)
         d.addCallback(self._maybe_literal, CheckAndRepairResultsRenderer)
     else:
         d = self.node.check(Monitor(), verify, add_lease)
         d.addCallback(self._maybe_literal, CheckResultsRenderer)
     return d
Example #23
0
 def _POST_check(self, req):
     verify = boolean_of_arg(get_arg(req, "verify", "false"))
     repair = boolean_of_arg(get_arg(req, "repair", "false"))
     add_lease = boolean_of_arg(get_arg(req, "add-lease", "false"))
     if repair:
         d = self.node.check_and_repair(Monitor(), verify, add_lease)
         d.addCallback(self._maybe_literal, CheckAndRepairResultsRenderer)
     else:
         d = self.node.check(Monitor(), verify, add_lease)
         d.addCallback(self._maybe_literal, CheckResultsRenderer)
     return d
Example #24
0
 def _POST_mkdir(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"))
     kids = {}
     d = self.node.create_subdirectory(name, kids, overwrite=replace)
     d.addCallback(lambda child: child.get_uri())  # TODO: urlencode
     return d
Example #25
0
 def redirect_to(self, req):
     """
     :param allmydata.webish.MyRequest req:
     """
     ophandle = get_arg(req, "ophandle").decode("utf-8")
     assert ophandle
     here = DecodedURL.from_text(str(URLPath.fromRequest(req)))
     target = here.click(u"/").child(u"operations", ophandle)
     output = get_arg(req, "output")
     if output:
         target = target.add(u"output", output.decode("utf-8"))
     return target
Example #26
0
 def _POST_mkdir(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"))
     kids = {}
     d = self.node.create_subdirectory(name, kids, overwrite=replace)
     d.addCallback(lambda child: child.get_uri()) # TODO: urlencode
     return d
Example #27
0
    def _POST_relink(self, req):
        charset = get_arg(req, "_charset", "utf-8")
        replace = parse_replace_arg(get_arg(req, "replace", "true"))

        from_name = get_arg(req, "from_name")
        if from_name is not None:
            from_name = from_name.strip()
            from_name = from_name.decode(charset)
            assert isinstance(from_name, unicode)
        else:
            raise WebError("from_name= is required")

        to_name = get_arg(req, "to_name")
        if to_name is not None:
            to_name = to_name.strip()
            to_name = to_name.decode(charset)
            assert isinstance(to_name, unicode)
        else:
            to_name = from_name

        # Disallow slashes in both from_name and to_name, that would only
        # cause confusion.
        if "/" in from_name:
            raise WebError("from_name= may not contain a slash",
                           http.BAD_REQUEST)
        if "/" in to_name:
            raise WebError("to_name= may not contain a slash",
                           http.BAD_REQUEST)

        to_dir = get_arg(req, "to_dir")
        if to_dir is not None and to_dir != self.node.get_write_uri():
            to_dir = to_dir.strip()
            to_dir = to_dir.decode(charset)
            assert isinstance(to_dir, unicode)
            to_path = to_dir.split(u"/")
            to_root = self.client.nodemaker.create_from_cap(to_str(to_path[0]))
            if not IDirectoryNode.providedBy(to_root):
                raise WebError("to_dir is not a directory", http.BAD_REQUEST)
            d = to_root.get_child_at_path(to_path[1:])
        else:
            d = defer.succeed(self.node)

        def _got_new_parent(new_parent):
            if not IDirectoryNode.providedBy(new_parent):
                raise WebError("to_dir is not a directory", http.BAD_REQUEST)

            return self.node.move_child_to(from_name, new_parent, to_name,
                                           replace)

        d.addCallback(_got_new_parent)
        d.addCallback(lambda res: "thing moved")
        return d
Example #28
0
 def render_HEAD(self, ctx):
     req = IRequest(ctx)
     t = get_arg(req, "t", "").strip()
     if t:
         raise WebError("GET file: bad t=%s" % t)
     filename = get_arg(req, "filename", self.name) or "unknown"
     if self.node.is_mutable():
         # some day: d = self.node.get_best_version()
         d = makeMutableDownloadable(self.node)
     else:
         d = defer.succeed(self.node)
     d.addCallback(lambda dn: FileDownloader(dn, filename))
     return d
Example #29
0
 def render_HEAD(self, ctx):
     req = IRequest(ctx)
     t = get_arg(req, "t", "").strip()
     if t:
         raise WebError("GET file: bad t=%s" % t)
     filename = get_arg(req, "filename", self.name) or "unknown"
     if self.node.is_mutable():
         # some day: d = self.node.get_best_version()
         d = makeMutableDownloadable(self.node)
     else:
         d = defer.succeed(self.node)
     d.addCallback(lambda dn: FileDownloader(dn, filename))
     return d
Example #30
0
    def _POST_relink(self, req):
        charset = get_arg(req, "_charset", "utf-8")
        replace = parse_replace_arg(get_arg(req, "replace", "true"))

        from_name = get_arg(req, "from_name")
        if from_name is not None:
            from_name = from_name.strip()
            from_name = from_name.decode(charset)
            assert isinstance(from_name, unicode)
        else:
            raise WebError("from_name= is required")

        to_name = get_arg(req, "to_name")
        if to_name is not None:
            to_name = to_name.strip()
            to_name = to_name.decode(charset)
            assert isinstance(to_name, unicode)
        else:
            to_name = from_name

        # Disallow slashes in both from_name and to_name, that would only
        # cause confusion.
        if "/" in from_name:
            raise WebError("from_name= may not contain a slash",
                           http.BAD_REQUEST)
        if "/" in to_name:
            raise WebError("to_name= may not contain a slash",
                           http.BAD_REQUEST)

        to_dir = get_arg(req, "to_dir")
        if to_dir is not None and to_dir != self.node.get_write_uri():
            to_dir = to_dir.strip()
            to_dir = to_dir.decode(charset)
            assert isinstance(to_dir, unicode)
            to_path = to_dir.split(u"/")
            to_root = self.client.nodemaker.create_from_cap(to_str(to_path[0]))
            if not IDirectoryNode.providedBy(to_root):
                raise WebError("to_dir is not a directory", http.BAD_REQUEST)
            d = to_root.get_child_at_path(to_path[1:])
        else:
            d = defer.succeed(self.node)

        def _got_new_parent(new_parent):
            if not IDirectoryNode.providedBy(new_parent):
                raise WebError("to_dir is not a directory", http.BAD_REQUEST)

            return self.node.move_child_to(from_name, new_parent,
                                           to_name, replace)
        d.addCallback(_got_new_parent)
        d.addCallback(lambda res: "thing moved")
        return d
Example #31
0
 def _POST_start_deep_check(self, ctx):
     # check this directory and everything reachable from it
     if not get_arg(ctx, "ophandle"):
         raise NeedOperationHandleError("slow operation requires ophandle=")
     verify = boolean_of_arg(get_arg(ctx, "verify", "false"))
     repair = boolean_of_arg(get_arg(ctx, "repair", "false"))
     add_lease = boolean_of_arg(get_arg(ctx, "add-lease", "false"))
     if repair:
         monitor = self.node.start_deep_check_and_repair(verify, add_lease)
         renderer = DeepCheckAndRepairResultsRenderer(self.client, monitor)
     else:
         monitor = self.node.start_deep_check(verify, add_lease)
         renderer = DeepCheckResultsRenderer(self.client, monitor)
     return self._start_operation(monitor, renderer, ctx)
Example #32
0
 def _POST_start_deep_check(self, ctx):
     # check this directory and everything reachable from it
     if not get_arg(ctx, "ophandle"):
         raise NeedOperationHandleError("slow operation requires ophandle=")
     verify = boolean_of_arg(get_arg(ctx, "verify", "false"))
     repair = boolean_of_arg(get_arg(ctx, "repair", "false"))
     add_lease = boolean_of_arg(get_arg(ctx, "add-lease", "false"))
     if repair:
         monitor = self.node.start_deep_check_and_repair(verify, add_lease)
         renderer = DeepCheckAndRepairResultsRenderer(self.client, monitor)
     else:
         monitor = self.node.start_deep_check(verify, add_lease)
         renderer = DeepCheckResultsRenderer(self.client, monitor)
     return self._start_operation(monitor, renderer, ctx)
Example #33
0
 def add_monitor(self, req, monitor, renderer):
     """
     :param allmydata.webish.MyRequest req:
     :param allmydata.monitor.Monitor monitor:
     :param allmydata.web.directory.ManifestResults renderer:
     """
     ophandle = get_arg(req, "ophandle")
     assert ophandle
     now = time.time()
     self.handles[ophandle] = (monitor, renderer, now)
     retain_for = get_arg(req, "retain-for", None)
     if retain_for is not None:
         self._set_timer(ophandle, int(retain_for))
     monitor.when_done().addBoth(self._operation_complete, ophandle)
Example #34
0
    def render_PUT(self, req):
        t = get_arg(req, "t", "").strip()
        replace = parse_replace_arg(get_arg(req, "replace", "true"))

        assert self.parentnode and self.name
        if req.getHeader("content-range"):
            raise WebError("Content-Range in PUT not yet supported",
                           http.NOT_IMPLEMENTED)
        if not t:
            return self.replace_me_with_a_child(req, self.client, replace)
        if t == "uri":
            return self.replace_me_with_a_childcap(req, self.client, replace)

        raise WebError("PUT to a file: bad t=%s" % t)
Example #35
0
    def render_PUT(self, ctx):
        req = IRequest(ctx)
        t = get_arg(req, "t", "").strip()
        replace = parse_replace_arg(get_arg(req, "replace", "true"))

        assert self.parentnode and self.name
        if req.getHeader("content-range"):
            raise WebError("Content-Range in PUT not yet supported", http.NOT_IMPLEMENTED)
        if not t:
            return self.replace_me_with_a_child(req, self.client, replace)
        if t == "uri":
            return self.replace_me_with_a_childcap(req, self.client, replace)

        raise WebError("PUT to a file: bad t=%s" % t)
Example #36
0
    def redirect_to(self, req):
        """
        :param allmydata.webish.MyRequest req:
        """
        ophandle = get_arg(req, "ophandle")
        assert ophandle
        target = get_root(req) + "/operations/" + ophandle
        output = get_arg(req, "output")
        if output:
            target = target + "?output=%s" % output

        # XXX: We have to use nevow.url here because nevow.appserver
        # is unhappy with anything else; so this gets its own ticket.
        # https://tahoe-lafs.org/trac/tahoe-lafs/ticket/3314
        return url.URL.fromString(target)
Example #37
0
def POSTUnlinkedCreateDirectory(req, client):
    # "POST /uri?t=mkdir", to create an unlinked directory.
    ct = req.getHeader("content-type") or ""
    if not ct.startswith("multipart/form-data"):
        # guard against accidental attempts to call t=mkdir as if it were
        # t=mkdir-with-children, but make sure we tolerate the usual HTML
        # create-directory form (in which the t=mkdir and redirect_to_result=
        # and other arguments can be passed encoded as multipath/form-data,
        # in the request body).
        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)
    d = client.create_dirnode()
    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
Example #38
0
    def render_GET(self, ctx):
        req = IRequest(ctx)
        # This is where all of the directory-related ?t=* code goes.
        t = get_arg(req, "t", "").strip()

        # t=info contains variable ophandles, t=rename-form contains the name
        # of the child being renamed. Neither is allowed an ETag.
        FIXED_OUTPUT_TYPES =  ["", "json", "uri", "readonly-uri"]
        if not self.node.is_mutable() and t in FIXED_OUTPUT_TYPES:
            si = self.node.get_storage_index()
            if si and req.setETag('DIR:%s-%s' % (base32.b2a(si), t or "")):
                return ""

        if not t:
            # render the directory as HTML, using the docFactory and Nevow's
            # whole templating thing.
            return DirectoryAsHTML(self.node,
                                   self.client.mutable_file_default)

        if t == "json":
            return DirectoryJSONMetadata(ctx, self.node)
        if t == "info":
            return MoreInfo(self.node)
        if t == "uri":
            return DirectoryURI(ctx, self.node)
        if t == "readonly-uri":
            return DirectoryReadonlyURI(ctx, self.node)
        if t == 'rename-form':
            return RenameForm(self.node)

        raise WebError("GET directory: bad t=%s" % t)
Example #39
0
def POSTUnlinkedCreateDirectory(req, client):
    # "POST /uri?t=mkdir", to create an unlinked directory.
    ct = req.getHeader("content-type") or ""
    if not ct.startswith("multipart/form-data"):
        # guard against accidental attempts to call t=mkdir as if it were
        # t=mkdir-with-children, but make sure we tolerate the usual HTML
        # create-directory form (in which the t=mkdir and redirect_to_result=
        # and other arguments can be passed encoded as multipath/form-data,
        # in the request body).
        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)
    d = client.create_dirnode()
    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
Example #40
0
    def replace_me_with_a_child(self, req, client, replace):
        # a new file is being uploaded in our place.
        mutable = boolean_of_arg(get_arg(req, "mutable", "false"))
        if mutable:
            req.content.seek(0)
            data = req.content.read()
            d = client.create_mutable_file(data)

            def _uploaded(newnode):
                d2 = self.parentnode.set_node(self.name, newnode, overwrite=replace)
                d2.addCallback(lambda res: newnode)
                return d2

            d.addCallback(_uploaded)
        else:
            uploadable = FileHandle(req.content, convergence=client.convergence)
            d = self.parentnode.add_file(self.name, uploadable, overwrite=replace)

        def _done(filenode):
            log.msg("webish upload complete", facility="tahoe.webish", level=log.NOISY, umid="TCjBGQ")
            if self.node:
                # we've replaced an existing file (or modified a mutable
                # file), so the response code is 200
                req.setResponseCode(http.OK)
            else:
                # we've created a new file, so the code is 201
                req.setResponseCode(http.CREATED)
            return filenode.get_uri()

        d.addCallback(_done)
        return d
Example #41
0
 def render_PUT(self, ctx):
     req = IRequest(ctx)
     # either "PUT /uri" to create an unlinked file, or
     # "PUT /uri?t=mkdir" to create an unlinked directory
     t = get_arg(req, "t", "").strip()
     if t == "":
         mutable = boolean_of_arg(get_arg(req, "mutable", "false").strip())
         if mutable:
             return unlinked.PUTUnlinkedSSK(req, self.client)
         else:
             return unlinked.PUTUnlinkedCHK(req, self.client)
     if t == "mkdir":
         return unlinked.PUTUnlinkedCreateDirectory(req, self.client)
     errmsg = ("/uri accepts only PUT, PUT?t=mkdir, POST?t=upload, "
               "and POST?t=mkdir")
     raise WebError(errmsg, http.BAD_REQUEST)
Example #42
0
 def render_POST(self, req):
     """
     "POST /uri?t=upload&file=newfile" to upload an
     unlinked file or "POST /uri?t=mkdir" to create a
     new directory
     """
     t = get_arg(req, "t", "").strip()
     if t in ("", "upload"):
         file_format = get_format(req)
         mutable_type = get_mutable_type(file_format)
         if mutable_type is not None:
             return unlinked.POSTUnlinkedSSK(req, self.client, mutable_type)
         else:
             return unlinked.POSTUnlinkedCHK(req, self.client)
     if t == "mkdir":
         return unlinked.POSTUnlinkedCreateDirectory(req, self.client)
     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)
Example #43
0
 def render_POST(self, ctx):
     req = IRequest(ctx)
     log.msg(format="User reports incident through web page: %(details)s",
             details=get_arg(req, "details", ""),
             level=log.WEIRD, umid="LkD9Pw")
     req.setHeader("content-type", "text/plain")
     return "An incident report has been saved to logs/incidents/ in the node directory."
Example #44
0
 def render_POST(self, ctx):
     req = IRequest(ctx)
     log.msg(format="User reports incident through web page: %(details)s",
             details=get_arg(req, "details", ""),
             level=log.WEIRD, umid="LkD9Pw")
     req.setHeader("content-type", "text/plain")
     return "Thank you for your report!"
Example #45
0
    def render_GET(self, ctx):
        req = IRequest(ctx)
        # This is where all of the directory-related ?t=* code goes.
        t = get_arg(req, "t", "").strip()

        # t=info contains variable ophandles, t=rename-form contains the name
        # of the child being renamed. Neither is allowed an ETag.
        FIXED_OUTPUT_TYPES =  ["", "json", "uri", "readonly-uri"]
        if not self.node.is_mutable() and t in FIXED_OUTPUT_TYPES:
            si = self.node.get_storage_index()
            if si and req.setETag('DIR:%s-%s' % (base32.b2a(si), t or "")):
                return ""

        if not t:
            # render the directory as HTML, using the docFactory and Nevow's
            # whole templating thing.
            return DirectoryAsHTML(self.node,
                                   self.client.mutable_file_default)

        if t == "json":
            return DirectoryJSONMetadata(ctx, self.node)
        if t == "info":
            return MoreInfo(self.node)
        if t == "uri":
            return DirectoryURI(ctx, self.node)
        if t == "readonly-uri":
            return DirectoryReadonlyURI(ctx, self.node)
        if t == 'rename-form':
            return RenameForm(self.node)

        raise WebError("GET directory: bad t=%s" % t)
Example #46
0
 def render_POST(self, ctx):
     req = IRequest(ctx)
     log.msg(format="User reports incident through web page: %(details)s",
             details=get_arg(req, "details", ""),
             level=log.WEIRD, umid="LkD9Pw")
     req.setHeader("content-type", "text/plain")
     return "Thank you for your report!"
Example #47
0
 def render_POST(self, ctx):
     req = IRequest(ctx)
     log.msg(format="User reports incident through web page: %(details)s",
             details=get_arg(req, "details", ""),
             level=log.WEIRD, umid="LkD9Pw")
     req.setHeader("content-type", "text/plain")
     return "An incident report has been saved to logs/incidents/ in the node directory."
Example #48
0
 def render_PUT(self, ctx):
     req = IRequest(ctx)
     # either "PUT /uri" to create an unlinked file, or
     # "PUT /uri?t=mkdir" to create an unlinked directory
     t = get_arg(req, "t", "").strip()
     if t == "":
         mutable = boolean_of_arg(get_arg(req, "mutable", "false").strip())
         if mutable:
             return unlinked.PUTUnlinkedSSK(req, self.client)
         else:
             return unlinked.PUTUnlinkedCHK(req, self.client)
     if t == "mkdir":
         return unlinked.PUTUnlinkedCreateDirectory(req, self.client)
     errmsg = ("/uri accepts only PUT, PUT?t=mkdir, POST?t=upload, "
               "and POST?t=mkdir")
     raise WebError(errmsg, http.BAD_REQUEST)
Example #49
0
    def got_child(self, node_or_failure, ctx, name):
        req = IRequest(ctx)
        method = req.method
        nonterminal = len(req.postpath) > 1
        t = get_arg(req, "t", "").strip()
        if isinstance(node_or_failure, Failure):
            f = node_or_failure
            f.trap(NoSuchChildError)
            # No child by this name. What should we do about it?
            if nonterminal:
                if should_create_intermediate_directories(req):
                    # create intermediate directories
                    d = self.node.create_subdirectory(name)
                    d.addCallback(make_handler_for,
                                  self.client, self.node, name)
                    return d
            else:
                # terminal node
                if (method,t) in [ ("POST","mkdir"), ("PUT","mkdir"),
                                   ("POST", "mkdir-with-children"),
                                   ("POST", "mkdir-immutable") ]:
                    # final directory
                    kids = {}
                    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)
                    file_format = get_format(req, None)
                    mutable = True
                    mt = get_mutable_type(file_format)
                    if t == "mkdir-immutable":
                        mutable = False

                    d = self.node.create_subdirectory(name, kids,
                                                      mutable=mutable,
                                                      mutable_version=mt)
                    d.addCallback(make_handler_for,
                                  self.client, self.node, name)
                    return d
                if (method,t) in ( ("PUT",""), ("PUT","uri"), ):
                    # we were trying to find the leaf filenode (to put a new
                    # file in its place), and it didn't exist. That's ok,
                    # since that's the leaf node that we're about to create.
                    # We make a dummy one, which will respond to the PUT
                    # request by replacing itself.
                    return PlaceHolderNodeHandler(self.client, self.node, name)
            # otherwise, we just return a no-such-child error
            return f

        node = node_or_failure
        if nonterminal and should_create_intermediate_directories(req):
            if not IDirectoryNode.providedBy(node):
                # we would have put a new directory here, but there was a
                # file in the way.
                raise WebError("Unable to create directory '%s': "
                               "a file was in the way" % name,
                               http.CONFLICT)
        return make_handler_for(node, self.client, self.node, name)
Example #50
0
    def render_POST(self, req):
        t = get_arg(req, "t", "").strip()
        replace = boolean_of_arg(get_arg(req, "replace", "true"))
        if t == "upload":
            # like PUT, but get the file data from an HTML form's input field.
            # We could get here from POST /uri/mutablefilecap?t=upload,
            # or POST /uri/path/file?t=upload, or
            # POST /uri/path/dir?t=upload&name=foo . All have the same
            # behavior, we just ignore any name= argument
            d = self.replace_me_with_a_formpost(req, self.client, replace)
        else:
            # t=mkdir is handled in DirectoryNodeHandler._POST_mkdir, so
            # there are no other t= values left to be handled by the
            # placeholder.
            raise WebError("POST to a file: bad t=%s" % t)

        return handle_when_done(req, d)
Example #51
0
 def renderHTTP(self, ctx):
     req = inevow.IRequest(ctx)
     t = get_arg(req, "t")
     if t == "json":
         stats = self.provider.get_stats()
         req.setHeader("content-type", "text/plain")
         return simplejson.dumps(stats, indent=1) + "\n"
     return rend.Page.renderHTTP(self, ctx)
Example #52
0
 def renderHTTP(self, ctx):
     req = inevow.IRequest(ctx)
     output = get_arg(req, "output", "html").lower()
     if output == "text":
         return self.text(req)
     if output == "json":
         return self.json(req)
     return rend.Page.renderHTTP(self, ctx)
Example #53
0
 def _render_si_link(self, req, storage_index):
     si_s = base32.b2a(storage_index)
     ophandle = req.prepath[-1]
     target = "%s/operations/%s/%s" % (get_root(req), ophandle, si_s)
     output = get_arg(req, "output")
     if output:
         target = target + "?output=%s" % output
     return tags.a(si_s, href=target)
Example #54
0
 def _POST_unlink(self, req):
     name = get_arg(req, "name")
     if name is None:
         # apparently an <input type="hidden" name="name" value="">
         # won't show up in the resulting encoded form.. the 'name'
         # field is completely missing. So to allow unlinking of a
         # child with a name that is the empty string, we have to
         # pretend that None means ''. The only downside of this is
         # a slightly confusing error message if someone does a POST
         # without a name= field. For our own HTML this isn't a big
         # deal, because we create the 'unlink' POST buttons ourselves.
         name = ''
     charset = get_arg(req, "_charset", "utf-8")
     name = name.decode(charset)
     d = self.node.delete(name)
     d.addCallback(lambda res: "thing unlinked")
     return d
Example #55
0
 def _POST_delete(self, req):
     name = get_arg(req, "name")
     if name is None:
         # apparently an <input type="hidden" name="name" value="">
         # won't show up in the resulting encoded form.. the 'name'
         # field is completely missing. So to allow deletion of an
         # empty file, we have to pretend that None means ''. The only
         # downside of this is a slightly confusing error message if
         # someone does a POST without a name= field. For our own HTML
         # this isn't a big deal, because we create the 'delete' POST
         # buttons ourselves.
         name = ''
     charset = get_arg(req, "_charset", "utf-8")
     name = name.decode(charset)
     d = self.node.delete(name)
     d.addCallback(lambda res: "thing deleted")
     return d
Example #56
0
 def _POST_delete(self, req):
     name = get_arg(req, "name")
     if name is None:
         # apparently an <input type="hidden" name="name" value="">
         # won't show up in the resulting encoded form.. the 'name'
         # field is completely missing. So to allow deletion of an
         # empty file, we have to pretend that None means ''. The only
         # downside of this is a slightly confusing error message if
         # someone does a POST without a name= field. For our own HTML
         # this isn't a big deal, because we create the 'delete' POST
         # buttons ourselves.
         name = ''
     charset = get_arg(req, "_charset", "utf-8")
     name = name.decode(charset)
     d = self.node.delete(name)
     d.addCallback(lambda res: "thing deleted")
     return d
Example #57
0
 def _POST_unlink(self, req):
     name = get_arg(req, "name")
     if name is None:
         # apparently an <input type="hidden" name="name" value="">
         # won't show up in the resulting encoded form.. the 'name'
         # field is completely missing. So to allow unlinking of a
         # child with a name that is the empty string, we have to
         # pretend that None means ''. The only downside of this is
         # a slightly confusing error message if someone does a POST
         # without a name= field. For our own HTML this isn't a big
         # deal, because we create the 'unlink' POST buttons ourselves.
         name = ''
     charset = get_arg(req, "_charset", "utf-8")
     name = name.decode(charset)
     d = self.node.delete(name)
     d.addCallback(lambda res: "thing unlinked")
     return d
Example #58
0
 def renderHTTP(self, ctx):
     req = inevow.IRequest(ctx)
     output = get_arg(req, "output", "html").lower()
     if output == "text":
         return self.text(req)
     if output == "json":
         return self.json(req)
     return rend.Page.renderHTTP(self, ctx)
Example #59
0
 def renderHTTP(self, ctx):
     req = inevow.IRequest(ctx)
     t = get_arg(req, "t")
     if t == "json":
         stats = self.provider.get_stats()
         req.setHeader("content-type", "text/plain")
         return simplejson.dumps(stats, indent=1) + "\n"
     return rend.Page.renderHTTP(self, ctx)
 def _render_si_link(self, ctx, storage_index):
     si_s = base32.b2a(storage_index)
     req = inevow.IRequest(ctx)
     ophandle = req.prepath[-1]
     target = "%s/operations/%s/%s" % (get_root(ctx), ophandle, si_s)
     output = get_arg(ctx, "output")
     if output:
         target = target + "?output=%s" % output
     return T.a(href=target)[si_s]