コード例 #1
0
ファイル: uploader.py プロジェクト: joskid/http-api
    def chunk_upload(
            self,
            upload_dir: str,
            filename: str,
            chunk_size: Optional[int] = None) -> Tuple[bool, Response]:
        filename = secure_filename(filename)

        range_header = request.headers.get("Content-Range", "")
        total_length, start, stop = self.parse_content_range(range_header)

        if total_length is None or start is None or stop is None:
            raise BadRequest("Invalid request")

        completed = stop >= total_length

        # Default chunk size, put this somewhere
        if chunk_size is None:
            chunk_size = 1048576

        file_path = os.path.join(upload_dir, filename)
        with open(file_path, "ab") as f:
            while True:
                chunk = request.stream.read(chunk_size)
                if not chunk:
                    break
                f.seek(start)
                f.write(chunk)

        if completed:
            return (
                completed,
                EndpointResource.response(
                    {
                        "filename": filename,
                        "meta": self.get_file_metadata(file_path)
                    },
                    code=200,
                ),
            )

        return (
            completed,
            EndpointResource.response(
                "partial",
                headers={
                    "Access-Control-Expose-Headers": "Range",
                    "Range": "0-{}".format(stop - 1),
                },
                code=206,
            ),
        )
コード例 #2
0
    def upload(self, subfolder: Path, force: bool = False) -> Response:

        if "file" not in request.files:
            raise BadRequest("No files specified")

        myfile = request.files["file"]

        if not myfile.filename:  # pragma: no cover
            raise BadRequest("Invalid filename")

        if not self.allowed_file(myfile.filename):
            raise BadRequest("File extension not allowed")

        Uploader.validate_upload_folder(subfolder)

        if not subfolder.exists():
            subfolder.mkdir(parents=True, exist_ok=True)

        fname = secure_filename(myfile.filename)
        abs_file = subfolder.joinpath(fname)

        log.info("File request for [{}]({})", myfile, abs_file)

        if abs_file.exists():
            if not force:
                raise Conflict(
                    f"File '{fname}' already exists, use force parameter to overwrite"
                )
            abs_file.unlink()

        # Save the file
        try:
            myfile.save(abs_file)
            log.debug("Absolute file path should be '{}'", abs_file)
        except Exception as e:  # pragma: no cover
            log.error(e)
            raise ServiceUnavailable(
                "Permission denied: failed to write the file")

        # Check exists - but it is basicaly a test that cannot fail...
        # The has just been uploaded!
        if not abs_file.exists():  # pragma: no cover
            raise ServiceUnavailable("Unable to retrieve the uploaded file")

        ########################
        # ## Final response

        abs_file.chmod(DEFAULT_PERMISSIONS)

        # Default redirect is to 302 state, which makes client
        # think that response was unauthorized....
        # see http://dotnet.dzone.com/articles/getting-know-cross-origin

        return EndpointResource.response(
            {
                "filename": fname,
                "meta": self.get_file_metadata(abs_file)
            },
            code=200,
        )
コード例 #3
0
ファイル: uploader.py プロジェクト: joskid/http-api
    def upload(self,
               subfolder: Optional[str] = None,
               force: bool = False) -> Response:

        if "file" not in request.files:
            raise BadRequest("No files specified")

        myfile = request.files["file"]

        # Check file extension?
        if not self.allowed_file(myfile.filename):
            raise BadRequest("File extension not allowed")

        # Check file name
        fname = secure_filename(myfile.filename)
        abs_file = Uploader.absolute_upload_file(fname, subfolder)
        log.info("File request for [{}]({})", myfile, abs_file)

        if os.path.exists(abs_file):
            if not force:
                raise BadRequest(
                    f"File '{fname}' already exists, use force parameter to overwrite"
                )
            os.remove(abs_file)
            log.debug("Already exists, forced removal")

        # Save the file
        try:
            myfile.save(abs_file)
            log.debug("Absolute file path should be '{}'", abs_file)
        except Exception:  # pragma: no cover
            raise ServiceUnavailable(
                "Permission denied: failed to write the file")

        # Check exists - but it is basicaly a test that cannot fail...
        # The has just been uploaded!
        if not os.path.exists(abs_file):  # pragma: no cover
            raise ServiceUnavailable("Unable to retrieve the uploaded file")

        ########################
        # ## Final response

        # Default redirect is to 302 state, which makes client
        # think that response was unauthorized....
        # see http://dotnet.dzone.com/articles/getting-know-cross-origin

        return EndpointResource.response(
            {
                "filename": fname,
                "meta": self.get_file_metadata(abs_file)
            },
            code=200,
        )
コード例 #4
0
ファイル: uploader.py プロジェクト: joskid/http-api
    def init_chunk_upload(self,
                          upload_dir: str,
                          filename: str,
                          force: bool = True) -> Response:

        if not os.path.exists(upload_dir):  # pragma: no cover
            os.makedirs(upload_dir)

        filename = secure_filename(filename)

        file_path = os.path.join(upload_dir, filename)

        if os.path.exists(file_path):
            log.warning("File already exists")
            if force:
                os.remove(file_path)
                log.debug("Forced removal")
            else:
                return EndpointResource.response(
                    f"File '{filename}' already exists",
                    code=400,
                )

        host = get_backend_url()
        url = f"{host}{request.path}/{filename}"

        log.info("Upload initialized on url: {}", url)

        return EndpointResource.response(
            "",
            headers={
                "Access-Control-Expose-Headers": "Location",
                "Location": url
            },
            code=201,
        )
コード例 #5
0
    def init_chunk_upload(self,
                          upload_dir: Path,
                          filename: str,
                          force: bool = True) -> Response:

        if not self.allowed_file(filename):
            raise BadRequest("File extension not allowed")

        Uploader.validate_upload_folder(upload_dir)

        if not upload_dir.exists():
            upload_dir.mkdir(parents=True, exist_ok=True)

        filename = secure_filename(filename)

        file_path = upload_dir.joinpath(filename)

        if file_path.exists():
            log.warning("File already exists")
            if force:
                file_path.unlink()
                log.debug("Forced removal")
            else:
                raise Conflict(f"File '{filename}' already exists")

        file_path.touch()

        host = get_backend_url()
        url = f"{host}{request.path}/{filename}"

        log.info("Upload initialized on url: {}", url)

        return EndpointResource.response(
            "",
            headers={
                "Access-Control-Expose-Headers": "Location",
                "Location": url
            },
            code=201,
        )
コード例 #6
0
    def test_responses(self, faker: Faker) -> None:
        class MySchema(Schema):
            name = fields.Str()

        f = "myfield"
        assert (
            ResponseMaker.get_schema_type(f, fields.Str(metadata={"password": True}))
            == "password"
        )
        assert ResponseMaker.get_schema_type(f, fields.Bool()) == "boolean"
        assert ResponseMaker.get_schema_type(f, fields.Boolean()) == "boolean"
        assert ResponseMaker.get_schema_type(f, fields.Date()) == "date"
        assert ResponseMaker.get_schema_type(f, fields.DateTime()) == "datetime"
        assert ResponseMaker.get_schema_type(f, fields.AwareDateTime()) == "datetime"
        assert ResponseMaker.get_schema_type(f, fields.NaiveDateTime()) == "datetime"
        assert ResponseMaker.get_schema_type(f, fields.Decimal()) == "number"
        # This is because Email is not typed on marshmallow
        assert ResponseMaker.get_schema_type(f, fields.Email()) == "email"  # type: ignore
        assert ResponseMaker.get_schema_type(f, fields.Float()) == "number"
        assert ResponseMaker.get_schema_type(f, fields.Int()) == "int"
        assert ResponseMaker.get_schema_type(f, fields.Integer()) == "int"
        assert ResponseMaker.get_schema_type(f, fields.Number()) == "number"
        assert ResponseMaker.get_schema_type(f, fields.Str()) == "string"
        assert ResponseMaker.get_schema_type(f, fields.String()) == "string"
        assert ResponseMaker.get_schema_type(f, fields.Dict()) == "dictionary"
        assert ResponseMaker.get_schema_type(f, fields.List(fields.Str())) == "string[]"
        assert ResponseMaker.get_schema_type(f, fields.Nested(MySchema())) == "nested"
        # Unsupported types, fallback to string
        assert ResponseMaker.get_schema_type(f, fields.URL()) == "string"
        assert ResponseMaker.get_schema_type(f, fields.Url()) == "string"
        assert ResponseMaker.get_schema_type(f, fields.UUID()) == "string"
        # assert ResponseMaker.get_schema_type(f, fields.Constant("x")) == "string"
        assert ResponseMaker.get_schema_type(f, fields.Field()) == "string"
        # assert ResponseMaker.get_schema_type(f, fields.Function()) == "string"
        # assert ResponseMaker.get_schema_type(f, fields.Mapping()) == "string"
        # assert ResponseMaker.get_schema_type(f, fields.Method()) == "string"
        # assert ResponseMaker.get_schema_type(f, fields.Raw()) == "string"
        # assert ResponseMaker.get_schema_type(f, fields.TimeDelta()) == "string"

        assert not ResponseMaker.is_binary(None)
        assert not ResponseMaker.is_binary("")
        assert not ResponseMaker.is_binary("application/json")
        assert ResponseMaker.is_binary("application/octet-stream")
        assert ResponseMaker.is_binary("application/x-bzip")
        assert ResponseMaker.is_binary("application/x-bzip2")
        assert ResponseMaker.is_binary("application/pdf")
        assert ResponseMaker.is_binary("application/msword")
        assert ResponseMaker.is_binary("application/rtf")
        assert ResponseMaker.is_binary("application/x-tar")
        assert ResponseMaker.is_binary("application/gzip")
        assert ResponseMaker.is_binary("application/zip")
        assert ResponseMaker.is_binary("application/x-7z-compressed")
        assert not ResponseMaker.is_binary("text/plain")
        assert not ResponseMaker.is_binary("text/css")
        assert not ResponseMaker.is_binary("text/csv")
        assert not ResponseMaker.is_binary("text/html")
        assert not ResponseMaker.is_binary("text/javascript")
        assert not ResponseMaker.is_binary("text/xml")
        assert ResponseMaker.is_binary("image/gif")
        assert ResponseMaker.is_binary("image/jpeg")
        assert ResponseMaker.is_binary("image/png")
        assert ResponseMaker.is_binary("image/svg+xml")
        assert ResponseMaker.is_binary("image/tiff")
        assert ResponseMaker.is_binary("image/webp")
        assert ResponseMaker.is_binary("image/bmp")
        assert ResponseMaker.is_binary("image/aac")
        assert ResponseMaker.is_binary("audio/midi")
        assert ResponseMaker.is_binary("audio/mpeg")
        assert ResponseMaker.is_binary("audio/wav")
        assert ResponseMaker.is_binary("audio/anyother")
        assert ResponseMaker.is_binary("video/mpeg")
        assert ResponseMaker.is_binary("video/ogg")
        assert ResponseMaker.is_binary("video/webm")
        assert ResponseMaker.is_binary("video/anyother")
        assert ResponseMaker.is_binary("video/anyother")
        assert not ResponseMaker.is_binary(faker.pystr())

        response = EndpointResource.response("", code=200)
        assert response[1] == 200  # type: ignore
        response = EndpointResource.response(None, code=200)
        assert response[1] == 204  # type: ignore
        response = EndpointResource.response(None, code=200, head_method=True)
        assert response[1] == 200  # type: ignore
コード例 #7
0
    def chunk_upload(
            self,
            upload_dir: Path,
            filename: str,
            chunk_size: Optional[int] = None) -> Tuple[bool, Response]:

        Uploader.validate_upload_folder(upload_dir)

        filename = secure_filename(filename)

        range_header = request.headers.get("Content-Range", "")
        total_length, start, stop = self.parse_content_range(range_header)

        if total_length is None or start is None or stop is None:
            raise BadRequest("Invalid request")

        completed = stop >= total_length

        # Default chunk size, put this somewhere
        if chunk_size is None:
            chunk_size = 1048576

        file_path = upload_dir.joinpath(filename)

        # Uhm... this upload is not initialized?
        if not file_path.exists():
            raise ServiceUnavailable(
                "Permission denied: the destination file does not exist")

        try:
            with open(file_path, "ab") as f:
                while True:
                    chunk = request.stream.read(chunk_size)
                    if not chunk:
                        break
                    f.seek(start)
                    f.write(chunk)
        except PermissionError:
            raise ServiceUnavailable(
                "Permission denied: failed to write the file")

        if completed:
            file_path.chmod(DEFAULT_PERMISSIONS)
            return (
                completed,
                EndpointResource.response(
                    {
                        "filename": filename,
                        "meta": self.get_file_metadata(file_path)
                    },
                    code=200,
                ),
            )

        return (
            completed,
            EndpointResource.response(
                "partial",
                headers={
                    "Access-Control-Expose-Headers": "Range",
                    "Range": f"0-{stop - 1}",
                },
                code=206,
            ),
        )