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, ), )
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, )
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, )
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, )
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, )
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
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, ), )