Ejemplo n.º 1
0
    def on_valid_request(self, request_dict):
        """
        Called when a valid JSON request has been sent from a client
        :param request_dict: JSON request converted to dict object
        """
        cred_store = self.server.get_cred_store()
        auth_enabled = cred_store is not None
        has_auth_header = auth_enabled and "Authorization" in self.headers
        is_authorized = not auth_enabled or (
            has_auth_header
            and cred_store.has_cred(self.headers["Authorization"]))

        if "User-Agent" not in self.headers or not self.headers[
                "User-Agent"].startswith("HttpFsClient"):
            raise RuntimeError(
                "Invalid User-Agent header: Client is not an HttpFsClient")
        if not is_authorized:
            logging.error("{} is not authorized".format(
                self.client_address[0]))
            response = HttpFsResponse(errno.EACCES,
                                      {"message": "Invalid API key"})
            self.send_json_response(http.HTTPStatus.UNAUTHORIZED,
                                    response.as_dict())
        else:
            try:
                request = HttpFsRequest.from_dict(request_dict)
                self._delegate_request(request)
            except Exception as e:
                response = HttpFsResponse(errno.EIO, {"message": str(e)})
                self.send_json_response(http.HTTPStatus.BAD_REQUEST,
                                        response.as_dict())
Ejemplo n.º 2
0
    def on_readdir(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_READDIR is requested
        :param httpfs_request_args: The client request args dict
        """
        path = self.get_abs_path(httpfs_request_args["path"])
        uid = httpfs_request_args["uid"]
        gid = httpfs_request_args["gid"]

        file_stats = os.stat(path)
        is_owner = file_stats.st_uid == uid
        is_group = file_stats.st_gid == gid

        response_obj = HttpFsResponse()

        if uid == 0:
            access_ok = True
        elif is_owner:
            access_ok = file_stats.st_mode & stat.S_IRUSR
        elif is_group:
            access_ok = file_stats.st_mode & stat.S_IRGRP
        else:
            access_ok = file_stats.st_mode & stat.S_IROTH

        if access_ok:
            dir_listing = os.listdir(path)
            dir_listing = [".", ".."] + dir_listing
            response_obj.set_data({"dir_listing": dir_listing})
        else:
            logging.warning("Error during readdir request: Access denied")
            response_obj.set_err_no(errno.EACCES)
            response_obj.set_data({"message": "Access denied"})

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 3
0
 def fake_send_request(request_type, **kwargs):
     assert request_type == HttpFsRequest.OP_CHMOD
     for required_key in ["uid", "gid"]:
         assert required_key in kwargs.keys()
     assert kwargs["path"] == fake_path
     assert kwargs["mode"] == fake_mode
     return HttpFsResponse()
Ejemplo n.º 4
0
 def fake_send_request(request_type, **kwargs):
     for arg in ["uid", "gid"]:
         assert arg in kwargs.keys()
     assert request_type == HttpFsRequest.OP_OPEN
     assert kwargs["path"] == fake_path
     assert kwargs["flags"] == fake_flags
     return HttpFsResponse()
Ejemplo n.º 5
0
 def fake_send_request(request_type, **kwargs):
     for arg in ["uid", "gid"]:
         assert arg in kwargs.keys()
     assert request_type == HttpFsRequest.OP_RENAME
     assert kwargs["old_path"] == fake_old_path
     assert kwargs["new_path"] == fake_new_path
     return HttpFsResponse()
Ejemplo n.º 6
0
 def fake_send_request(request_type, **kwargs):
     for arg in ["uid", "gid"]:
         assert arg in kwargs.keys()
     assert request_type == HttpFsRequest.OP_UTIMENS
     assert kwargs["path"] == fake_path
     assert kwargs["times"] == fake_times
     return HttpFsResponse()
Ejemplo n.º 7
0
    def on_rmdir(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_RMDIR is requested
        :param httpfs_request_args: The client request args dict
        """
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])
        _error = None
        _err = None
        try:
            os.rmdir(path)

        except FileNotFoundError as e:
            logging.error("{} not found".format(path))
            err = errno.ENOENT
            _error = e
        except OSError as e:
            err = e.errno
            _error = e
        except Exception as e:
            err = errno.EIO
            _error = e

        if _error != None:
            logging.error("Error during rmdir request: {}".format(_error))
            response_obj.set_err_no(_err)
            response_obj.set_data({"message": str(_error)})

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 8
0
 def fake_send_request(request_type, **kwargs):
     for arg in ["uid", "gid"]:
         assert arg in kwargs.keys()
     assert request_type == HttpFsRequest.OP_READDIR
     assert kwargs["path"] == fake_path
     resp = HttpFsResponse()
     resp._response_data["dir_listing"] = list()
     return resp
Ejemplo n.º 9
0
 def fake_send_request(request_type, **kwargs):
     assert request_type == HttpFsRequest.OP_CREATE
     for required_key in ["uid", "gid"]:
         assert required_key in kwargs.keys()
     assert kwargs["path"] == fake_path
     assert kwargs["mode"] == fake_mode
     resp = HttpFsResponse()
     resp._response_data["file_descriptor"] = 0
     return resp
Ejemplo n.º 10
0
 def fake_send_request(request_type, **kwargs):
     for arg in ["uid", "gid"]:
         assert arg in kwargs.keys()
     assert request_type == HttpFsRequest.OP_WRITE
     assert kwargs["file_descriptor"] == fake_fd
     assert kwargs["data"] == base64.standard_b64encode(fake_data).decode("utf-8")
     assert kwargs["offset"] == fake_offset
     resp = HttpFsResponse()
     resp._response_data["bytes_written"] = 10
     return resp
Ejemplo n.º 11
0
 def on_invalid_request(self, err_msg):
     """
     Called when invalid JSON has been sent as a request from a client
     :param err_msg: The error message
     """
     logging.debug("Invalid request received from {}: '{}'".format(
         self.client_address[0], err_msg))
     response_obj = HttpFsResponse(errno.EIO, {"message": err_msg})
     self.send_json_response(http.HTTPStatus.BAD_REQUEST,
                             response_obj.as_dict())
Ejemplo n.º 12
0
 def fake_send_request(request_type, **kwargs):
     for arg in ["uid", "gid"]:
         assert arg in kwargs.keys()
     assert request_type == HttpFsRequest.OP_READ
     assert kwargs["file_descriptor"] == fake_fd
     assert kwargs["size"] == fake_size
     assert kwargs["offset"] == fake_offset
     resp = HttpFsResponse()
     resp._response_data["bytes_read"] = bytes()
     return resp
Ejemplo n.º 13
0
    def on_statfs(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_STAT_FS is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        fs_path = self.get_abs_path(httpfs_request_args["path"])
        statfs_os_result = os.statvfs(fs_path)
        statfs_result = dict()

        for k in _HttpFsRequestHandler.STAT_FS_KEYS:
            statfs_result[k] = getattr(statfs_os_result, k)

        response_obj = HttpFsResponse(response_data=statfs_result)
        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 14
0
    def on_release(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_RELEASE is requested
        :param httpfs_request_args: The client request args dict
        """
        response_obj = HttpFsResponse()

        try:
            os.close(httpfs_request_args["file_descriptor"])
        except Exception as e:
            logging.error("Error during release request: {}".format(e))
            response_obj.set_err_no(errno.EIO)

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 15
0
    def on_flush(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_FLUSH is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        response_obj = HttpFsResponse()

        try:
            os.fsync(httpfs_request_args["file_descriptor"])
        except Exception as e:
            logging.error("Error during flush request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 16
0
    def on_mkdir(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_MKDIR is requested
        :param httpfs_request_args: The client request args dict
        """
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])

        try:
            os.mkdir(path, mode=httpfs_request_args["mode"])
        except Exception as e:
            logging.error("Error during mkdir request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 17
0
    def on_symlink(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_SYMLINK is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        response_obj = HttpFsResponse()
        source = self.get_abs_path(httpfs_request_args["source"])
        target = self.get_abs_path(httpfs_request_args["target"])

        try:
            os.symlink(source, target)
        except Exception as e:
            logging.error("Error during symlink request: {}".format(e))
            response_obj.set_err_no(errno.EIO)

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 18
0
    def on_read(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_READ is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        response_obj = HttpFsResponse()
        file_descriptor = httpfs_request_args["file_descriptor"]
        offset = httpfs_request_args["offset"]
        size = httpfs_request_args["size"]

        uid = httpfs_request_args["uid"]
        gid = httpfs_request_args["gid"]

        file_stats = os.stat(file_descriptor)
        is_owner = file_stats.st_uid == uid
        is_group = file_stats.st_gid == gid

        if uid == 0:
            access_ok = True
        elif is_owner:
            access_ok = file_stats.st_mode & stat.S_IRUSR
        elif is_group:
            access_ok = file_stats.st_mode & stat.S_IRGRP
        else:
            access_ok = file_stats.st_mode & stat.S_IROTH

        try:
            if access_ok:
                with self.server.get_fs_lock():
                    os.lseek(file_descriptor, offset, os.SEEK_SET)
                    bytes_read = os.read(file_descriptor, size)
                response_obj.set_data({
                    "bytes_read":
                    base64.standard_b64encode(bytes_read).decode("utf-8")
                })
            else:
                logging.warning("Error during read request: Access denied")
                response_obj.set_err_no(errno.EACCES)
                response_obj.set_data({"message": "Access denied"})

        except Exception as e:
            logging.error("Error during read request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 19
0
    def on_link(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_LINK is requested
        :param httpfs_request_args: The client request args dict
        """
        target_path = self.get_abs_path(httpfs_request_args["target"])
        source_path = self.get_abs_path(httpfs_request_args["source"])

        response_obj = HttpFsResponse()

        try:
            os.link(source_path, target_path)
        except Exception as e:
            logging.error("Error during link request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 20
0
    def on_truncate(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_TRUNCATE is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])
        length = httpfs_request_args["length"]

        try:
            with open(path, 'r+') as f:
                f.truncate(length)
        except Exception as e:
            logging.error("Error during truncate request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 21
0
    def on_readlink(self, httpfs_request_args):
        # TODO: This doesn't work
        """
        Called when HttpFsRequest.OP_RELEASE is requested
        :param httpfs_request_args: The client request args dict
        """
        response_obj = HttpFsResponse()
        link_path = self.get_abs_path(httpfs_request_args["link_path"])

        try:
            target = os.readlink(link_path)
            if target.startswith("/"):
                target = os.path.relpath(target, self.server.get_fs_root())
            response_obj.set_data({"target": target})
        except Exception as e:
            logging.error("Error during readlink request: {}".format(e))
            response_obj.set_err_no(errno.EIO)

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 22
0
    def on_create(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_ACCESS is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])
        uid = httpfs_request_args["uid"]
        gid = httpfs_request_args["gid"]

        dir_stats = os.stat(os.path.dirname(path))
        is_dir_owner = dir_stats.st_uid == uid
        is_dir_group = dir_stats.st_gid == gid

        if uid == 0:
            access_ok = True
        elif is_dir_owner:
            access_ok = dir_stats.st_mode & stat.S_IWUSR
        elif is_dir_group:
            access_ok = dir_stats.st_mode & stat.S_IWGRP
        else:
            access_ok = dir_stats.st_mode & stat.S_IWOTH

        try:
            if access_ok:
                fd = os.open(path,
                             flags=os.O_WRONLY | os.O_CREAT | os.O_TRUNC
                             | os.O_ASYNC | os.O_NOATIME,
                             mode=httpfs_request_args["mode"])
                os.chown(path, uid, gid)
                response_obj.set_data({"file_descriptor": fd})
            else:
                logging.warning("Error during create request: Access denied")
                response_obj.set_err_no(errno.EACCES)
                response_obj.set_data({"message": "Access denied"})

        except Exception as e:
            logging.error("Error during create request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 23
0
    def on_chown(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_FLUSH is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        client = self.client_address[0]
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])
        uid = httpfs_request_args["uid"]
        gid = httpfs_request_args["gid"]
        caller_uid = httpfs_request_args["caller_uid"]
        caller_gid = httpfs_request_args["caller_gid"]

        file_stats = os.stat(path)
        is_owner = file_stats.st_uid == caller_uid
        is_group = file_stats.st_gid == caller_gid

        if caller_uid == 0:
            access_ok = True
        elif is_owner:
            access_ok = file_stats.st_mode & stat.S_IWUSR
        elif is_group:
            access_ok = file_stats.st_mode & stat.S_IWGRP
        else:
            access_ok = file_stats.st_mode & stat.S_IWOTH

        # TODO: Don't let me if it isn't mine
        try:
            if access_ok:
                os.chown(path, uid, gid)
                logging.debug("Successful chown for {}".format(client))
            else:
                response_obj.set_err_no(errno.EACCES)
                response_obj.set_data({"message": "Access denied"})
                logging.warning("Error during chown request: Access denied")
        except Exception as e:
            logging.error("Error during chown request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 24
0
    def on_utimens(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_UTIMENS is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])
        times = httpfs_request_args["times"]
        if isinstance(times, list):
            times = tuple(times)

        uid = httpfs_request_args["uid"]
        gid = httpfs_request_args["gid"]

        file_stats = os.stat(path)
        is_owner = file_stats.st_uid == uid
        is_group = file_stats.st_gid == gid

        if uid == 0:
            access_ok = True
        elif is_owner:
            access_ok = file_stats.st_mode & stat.S_IWUSR
        elif is_group:
            access_ok = file_stats.st_mode & stat.S_IWGRP
        else:
            access_ok = file_stats.st_mode & stat.S_IWOTH

        try:
            if access_ok:
                os.utime(path, times)
            else:
                logging.warning("Error during write request: Access denied")
                response_obj.set_err_no(errno.EACCES)
                response_obj.set_data({"message": "Access denied"})

        except Exception as e:
            logging.error("Error during utimens request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 25
0
    def on_unlink(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_UNLINK is received from the client
        :param httpfs_request_args: The client request arg dict
        """
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])
        uid = httpfs_request_args["uid"]
        gid = httpfs_request_args["gid"]

        try:
            file_stats = os.stat(path)
            is_owner = file_stats.st_uid == uid
            is_group = file_stats.st_gid == gid

            if uid == 0:
                access_ok = True
            elif is_owner:
                access_ok = file_stats.st_mode & stat.S_IWUSR
            elif is_group:
                access_ok = file_stats.st_mode & stat.S_IWGRP
            else:
                access_ok = file_stats.st_mode & stat.S_IWOTH

            if access_ok:
                os.unlink(path)
            else:
                logging.warning("Error during unlink request: Access denied")
                response_obj.set_err_no(errno.EACCES)
                response_obj.set_data({"message": "Access denied"})
        except OSError as e:
            logging.error("Error during unlink request: {}".format(e))
            response_obj.set_err_no(e.errno)
            response_obj.set_data({"message": str(e)})
        except Exception as e:
            logging.error("Error during unlink request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 26
0
    def on_rename(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_RENAME is requested
        :param httpfs_request_args: The client request args dict
        """
        old_path = self.get_abs_path(httpfs_request_args["old_path"])
        new_path = self.get_abs_path(httpfs_request_args["new_path"])

        uid = httpfs_request_args["uid"]
        gid = httpfs_request_args["gid"]

        file_stats = os.stat(old_path)
        is_owner = file_stats.st_uid == uid
        is_group = file_stats.st_gid == gid

        response_obj = HttpFsResponse()

        if uid == 0:
            access_ok = True
        elif is_owner:
            access_ok = file_stats.st_mode & stat.S_IWUSR
        elif is_group:
            access_ok = file_stats.st_mode & stat.S_IWGRP
        else:
            access_ok = file_stats.st_mode & stat.S_IWOTH

        try:
            if access_ok:
                os.rename(old_path, new_path)
            else:
                logging.warning("Error during rename request: Access denied")
                response_obj.set_err_no(errno.EACCES)
                response_obj.set_data({"message": "Access denied"})
        except Exception as e:
            logging.error("Error during rename request: {}".format(e))
            response_obj.set_err_no(errno.EIO)
            response_obj.set_data({"message": str(e)})

        self.send_json_response(http.HTTPStatus.OK, response_obj.as_dict())
Ejemplo n.º 27
0
    def on_getattr(self, httpfs_request_args):
        """
        Called when HttpFsRequest.OP_GET_ATTR is requested
        :param httpfs_request_args: The client request args dict
        """
        response_obj = HttpFsResponse()
        path = self.get_abs_path(httpfs_request_args["path"])

        try:
            os_attrs = os.lstat(path)
            attrs = dict()

            for k in _HttpFsRequestHandler.GETATTR_KEYS:
                attrs[k] = getattr(os_attrs, k)

            response_obj.set_data(attrs)

        except FileNotFoundError:
            logging.warning("{} not found".format(path))
            response_obj.set_err_no(errno.ENOENT)

        self.send_json_response(200, response_obj.as_dict())
Ejemplo n.º 28
0
 def fake_send_request(request_type, **kwargs):
     assert request_type == HttpFsRequest.OP_TRUNCATE
     assert kwargs["path"] == fake_path
     assert kwargs["length"] == fake_len
     return HttpFsResponse()
Ejemplo n.º 29
0
 def fake_send_request(request_type, **kwargs):
     assert request_type == HttpFsRequest.OP_SYMLINK
     assert kwargs["target"] == fake_target
     assert kwargs["source"] == fake_source
     return HttpFsResponse()
Ejemplo n.º 30
0
 def fake_send_request(request_type, **kwargs):
     assert request_type == HttpFsRequest.OP_STAT_FS
     assert kwargs["path"] == fake_path
     return HttpFsResponse()