Пример #1
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
Пример #2
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
Пример #3
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
Пример #4
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
Пример #5
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)
Пример #6
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)
Пример #7
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
Пример #8
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
Пример #9
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
Пример #10
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
Пример #11
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
Пример #12
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
Пример #13
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
Пример #14
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
Пример #15
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
Пример #16
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
Пример #17
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
Пример #18
0
 def _POST_set_children(self, req):
     replace = boolean_of_arg(get_arg(req, "replace", "true"))
     req.content.seek(0)
     body = req.content.read()
     try:
         children = simplejson.loads(body)
     except ValueError, le:
         le.args = tuple(le.args + (body,))
         # TODO test handling of bad JSON
         raise
Пример #19
0
 def _POST_set_children(self, req):
     replace = boolean_of_arg(get_arg(req, "replace", "true"))
     req.content.seek(0)
     body = req.content.read()
     try:
         children = simplejson.loads(body)
     except ValueError, le:
         le.args = tuple(le.args + (body, ))
         # TODO test handling of bad JSON
         raise
Пример #20
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
Пример #21
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
Пример #22
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)
Пример #23
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)
Пример #24
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)
Пример #25
0
    def _POST_uri(self, req):
        childcap = get_arg(req, "uri")
        if not childcap:
            raise WebError("set-uri requires a uri")
        name = get_arg(req, "name")
        if not name:
            raise WebError("set-uri requires a name")
        charset = get_arg(req, "_charset", "utf-8")
        name = name.decode(charset)
        replace = boolean_of_arg(get_arg(req, "replace", "true"))

        # We mustn't pass childcap for the readcap argument because we don't
        # know whether it is a read cap. Passing a read cap as the writecap
        # argument will work (it ends up calling NodeMaker.create_from_cap,
        # which derives a readcap if necessary and possible).
        d = self.node.set_uri(name, childcap, None, overwrite=replace)
        d.addCallback(lambda res: childcap)
        return d
Пример #26
0
    def _POST_uri(self, req):
        childcap = get_arg(req, "uri")
        if not childcap:
            raise WebError("set-uri requires a uri")
        name = get_arg(req, "name")
        if not name:
            raise WebError("set-uri requires a name")
        charset = get_arg(req, "_charset", "utf-8")
        name = name.decode(charset)
        replace = boolean_of_arg(get_arg(req, "replace", "true"))

        # We mustn't pass childcap for the readcap argument because we don't
        # know whether it is a read cap. Passing a read cap as the writecap
        # argument will work (it ends up calling NodeMaker.create_from_cap,
        # which derives a readcap if necessary and possible).
        d = self.node.set_uri(name, childcap, None, overwrite=replace)
        d.addCallback(lambda res: childcap)
        return d
Пример #27
0
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
Пример #28
0
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/" + urlquote(res.get_uri())
            req.setResponseCode(http.SEE_OTHER)  # 303
            req.setHeader('location', new_url)
            return ''

        d.addCallback(_then_redir)
    else:
        d.addCallback(lambda dirnode: dirnode.get_uri())
    return d
Пример #29
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"))

        if mutable:
            data = self._read_data_from_formpost(req)
            d = client.create_mutable_file(data)
            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
        # create an immutable file
        contents = req.fields["file"]
        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
Пример #30
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 == "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)

        when_done = get_arg(req, "when_done", None)
        if when_done:
            d.addCallback(lambda res: url.URL.fromString(when_done))
        return d
Пример #31
0
    def render_POST(self, req):
        t = get_arg(req, b"t", b"").strip()
        replace = boolean_of_arg(get_arg(req, b"replace", b"true"))
        if t == b"check":
            d = self._POST_check(req)
        elif t == b"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" % str(t, "ascii"))

        return handle_when_done(req, d)
Пример #32
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:
                arg = get_arg(req, "mutable-type", None)
                version = parse_mutable_type_arg(arg)
                if version == "invalid":
                    errmsg = "Unknown type: %s" % arg
                    raise WebError(errmsg, http.BAD_REQUEST)

                return unlinked.PUTUnlinkedSSK(req, self.client, version)
            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)
Пример #33
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
Пример #34
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"))

        if mutable:
            data = self._read_data_from_formpost(req)
            d = client.create_mutable_file(data)

            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
        # create an immutable file
        contents = req.fields["file"]
        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
Пример #35
0
    def render(self, req):
        gte = static.getTypeAndEncoding
        ctype, encoding = gte(self.filename,
                              static.File.contentTypes,
                              static.File.contentEncodings,
                              defaultType="text/plain")
        req.setHeader("content-type", ctype)
        if encoding:
            req.setHeader("content-encoding", encoding)

        if boolean_of_arg(get_arg(req, "save", "False")):
            # tell the browser to save the file rather display it we don't
            # try to encode the filename, instead we echo back the exact same
            # bytes we were given in the URL. See the comment in
            # FileNodeHandler.render_GET for the sad details.
            req.setHeader("content-disposition",
                          'attachment; filename="%s"' % self.filename)

        filesize = self.filenode.get_size()
        assert isinstance(filesize, (int, long)), filesize
        first, size = 0, None
        contentsize = filesize
        req.setHeader("accept-ranges", "bytes")

        # TODO: for mutable files, use the roothash. For LIT, hash the data.
        # or maybe just use the URI for CHK and LIT.
        rangeheader = req.getHeader('range')
        if rangeheader:
            ranges = self.parse_range_header(rangeheader)

            # ranges = None means the header didn't parse, so ignore
            # the header as if it didn't exist.  If is more than one
            # range, then just return the first for now, until we can
            # generate multipart/byteranges.
            if ranges is not None:
                first, last = ranges[0]

                if first >= filesize:
                    raise WebError('First beyond end of file',
                                   http.REQUESTED_RANGE_NOT_SATISFIABLE)
                else:
                    first = max(0, first)
                    last = min(filesize - 1, last)

                    req.setResponseCode(http.PARTIAL_CONTENT)
                    req.setHeader(
                        'content-range', "bytes %s-%s/%s" %
                        (str(first), str(last), str(filesize)))
                    contentsize = last - first + 1
                    size = contentsize

        req.setHeader("content-length", b"%d" % contentsize)
        if req.method == "HEAD":
            return ""

        d = self.filenode.read(req, first, size)

        def _error(f):
            if f.check(defer.CancelledError):
                # The HTTP connection was lost and we no longer have anywhere
                # to send our result.  Let this pass through.
                return f
            if req.startedWriting:
                # The content-type is already set, and the response code has
                # already been sent, so we can't provide a clean error
                # indication. We can emit text (which a browser might
                # interpret as something else), and if we sent a Size header,
                # they might notice that we've truncated the data. Keep the
                # error message small to improve the chances of having our
                # error response be shorter than the intended results.
                #
                # We don't have a lot of options, unfortunately.
                return b"problem during download\n"
            else:
                # We haven't written anything yet, so we can provide a
                # sensible error message.
                return f

        d.addCallbacks(
            lambda ignored: None,
            _error,
        )
        return d
Пример #36
0
    def renderHTTP(self, ctx):
        req = IRequest(ctx)
        gte = static.getTypeAndEncoding
        ctype, encoding = gte(self.filename,
                              static.File.contentTypes,
                              static.File.contentEncodings,
                              defaultType="text/plain")
        req.setHeader("content-type", ctype)
        if encoding:
            req.setHeader("content-encoding", encoding)

        if boolean_of_arg(get_arg(req, "save", "False")):
            # tell the browser to save the file rather display it we don't
            # try to encode the filename, instead we echo back the exact same
            # bytes we were given in the URL. See the comment in
            # FileNodeHandler.render_GET for the sad details.
            req.setHeader("content-disposition",
                          'attachment; filename="%s"' % self.filename)

        filesize = self.filenode.get_size()
        assert isinstance(filesize, (int, long)), filesize
        first, size = 0, None
        contentsize = filesize
        req.setHeader("accept-ranges", "bytes")
        if not self.filenode.is_mutable():
            # TODO: look more closely at Request.setETag and how it interacts
            # with a conditional "if-etag-equals" request, I think this may
            # need to occur after the setResponseCode below
            si = self.filenode.get_storage_index()
            if si:
                req.setETag(base32.b2a(si))
        # TODO: for mutable files, use the roothash. For LIT, hash the data.
        # or maybe just use the URI for CHK and LIT.
        rangeheader = req.getHeader('range')
        if rangeheader:
            ranges = self.parse_range_header(rangeheader)

            # ranges = None means the header didn't parse, so ignore
            # the header as if it didn't exist.  If is more than one
            # range, then just return the first for now, until we can
            # generate multipart/byteranges.
            if ranges is not None:
                first, last = ranges[0]

                if first >= filesize:
                    raise WebError('First beyond end of file',
                                   http.REQUESTED_RANGE_NOT_SATISFIABLE)
                else:
                    first = max(0, first)
                    last = min(filesize - 1, last)

                    req.setResponseCode(http.PARTIAL_CONTENT)
                    req.setHeader(
                        'content-range', "bytes %s-%s/%s" %
                        (str(first), str(last), str(filesize)))
                    contentsize = last - first + 1
                    size = contentsize

        req.setHeader("content-length", str(contentsize))
        if req.method == "HEAD":
            return ""

        # Twisted >=9.0 throws an error if we call req.finish() on a closed
        # HTTP connection. It also has req.notifyFinish() to help avoid it.
        finished = []

        def _request_finished(ign):
            finished.append(True)

        if hasattr(req, "notifyFinish"):
            req.notifyFinish().addBoth(_request_finished)

        d = self.filenode.read(req, first, size)

        def _finished(ign):
            if not finished:
                req.finish()

        def _error(f):
            lp = log.msg("error during GET",
                         facility="tahoe.webish",
                         failure=f,
                         level=log.UNUSUAL,
                         umid="xSiF3w")
            if finished:
                log.msg("but it's too late to tell them",
                        parent=lp,
                        level=log.UNUSUAL,
                        umid="j1xIbw")
                return
            req._tahoe_request_had_error = f  # for HTTP-style logging
            if req.startedWriting:
                # The content-type is already set, and the response code has
                # already been sent, so we can't provide a clean error
                # indication. We can emit text (which a browser might
                # interpret as something else), and if we sent a Size header,
                # they might notice that we've truncated the data. Keep the
                # error message small to improve the chances of having our
                # error response be shorter than the intended results.
                #
                # We don't have a lot of options, unfortunately.
                req.write("problem during download\n")
                req.finish()
            else:
                # We haven't written anything yet, so we can provide a
                # sensible error message.
                eh = MyExceptionHandler()
                eh.renderHTTP_exception(ctx, f)

        d.addCallbacks(_finished, _error)
        return req.deferred
Пример #37
0
    def renderHTTP(self, ctx):
        req = IRequest(ctx)
        gte = static.getTypeAndEncoding
        ctype, encoding = gte(self.filename,
                              static.File.contentTypes,
                              static.File.contentEncodings,
                              defaultType="text/plain")
        req.setHeader("content-type", ctype)
        if encoding:
            req.setHeader("content-encoding", encoding)

        if boolean_of_arg(get_arg(req, "save", "False")):
            # tell the browser to save the file rather display it we don't
            # try to encode the filename, instead we echo back the exact same
            # bytes we were given in the URL. See the comment in
            # FileNodeHandler.render_GET for the sad details.
            req.setHeader("content-disposition",
                          'attachment; filename="%s"' % self.filename)

        filesize = self.filenode.get_size()
        assert isinstance(filesize, (int,long)), filesize
        first, size = 0, None
        contentsize = filesize
        req.setHeader("accept-ranges", "bytes")

        # TODO: for mutable files, use the roothash. For LIT, hash the data.
        # or maybe just use the URI for CHK and LIT.
        rangeheader = req.getHeader('range')
        if rangeheader:
            ranges = self.parse_range_header(rangeheader)

            # ranges = None means the header didn't parse, so ignore
            # the header as if it didn't exist.  If is more than one
            # range, then just return the first for now, until we can
            # generate multipart/byteranges.
            if ranges is not None:
                first, last = ranges[0]

                if first >= filesize:
                    raise WebError('First beyond end of file',
                                   http.REQUESTED_RANGE_NOT_SATISFIABLE)
                else:
                    first = max(0, first)
                    last = min(filesize-1, last)

                    req.setResponseCode(http.PARTIAL_CONTENT)
                    req.setHeader('content-range',"bytes %s-%s/%s" %
                                  (str(first), str(last),
                                   str(filesize)))
                    contentsize = last - first + 1
                    size = contentsize

        req.setHeader("content-length", b"%d" % contentsize)
        if req.method == "HEAD":
            return ""

        finished = []
        def _request_finished(ign):
            finished.append(True)
        req.notifyFinish().addBoth(_request_finished)

        d = self.filenode.read(req, first, size)

        def _finished(ign):
            if not finished:
                req.finish()
        def _error(f):
            lp = log.msg("error during GET", facility="tahoe.webish", failure=f,
                         level=log.UNUSUAL, umid="xSiF3w")
            if finished:
                log.msg("but it's too late to tell them", parent=lp,
                        level=log.UNUSUAL, umid="j1xIbw")
                return
            req._tahoe_request_had_error = f # for HTTP-style logging
            if req.startedWriting:
                # The content-type is already set, and the response code has
                # already been sent, so we can't provide a clean error
                # indication. We can emit text (which a browser might
                # interpret as something else), and if we sent a Size header,
                # they might notice that we've truncated the data. Keep the
                # error message small to improve the chances of having our
                # error response be shorter than the intended results.
                #
                # We don't have a lot of options, unfortunately.
                req.write("problem during download\n")
                req.finish()
            else:
                # We haven't written anything yet, so we can provide a
                # sensible error message.
                eh = MyExceptionHandler()
                eh.renderHTTP_exception(ctx, f)
        d.addCallbacks(_finished, _error)
        return req.deferred