def post(self, request, *args, **kwargs): metadata = self.get_metadata(request) metadata["filename"] = self.validate_filename(metadata) message_id = request.META.get("HTTP_MESSAGE_ID") if message_id: metadata["message_id"] = base64.b64decode(message_id) if (settings.TUS_EXISTING_FILE == "error" and settings.TUS_FILE_NAME_FORMAT == "keep" and TusFile.check_existing_file(metadata.get("filename"))): return TusResponse(status=409, reason="File with same name already exists") file_size = int(request.META.get( "HTTP_UPLOAD_LENGTH", "0")) # TODO: check min max upload size tus_file = TusFile.create_initial_file(metadata, file_size) return TusResponse( status=201, extra_headers={ "Location": "{}{}".format(request.build_absolute_uri(), tus_file.resource_id) }, )
def rename(self): setting = settings.TUS_FILE_NAME_FORMAT if setting == "keep": if TusFile.check_existing_file(self.filename): return TusResponse(status=409, reason="File with same name already exists") if setting == "replace": TusFile.remove_existing_file(self.filename) elif setting == "random": self.filename = FilenameGenerator( self.filename).create_random_name() elif setting == "random-suffix": self.filename = FilenameGenerator( self.filename).create_random_suffix_name() elif setting == "increment": self.filename = FilenameGenerator( self.filename).create_incremented_name() else: return TusResponse( status=409, reason="Incorrect TUS_FILE_NAME_FORMAT setting: %s" % (setting), ) os.rename(self.get_path(), os.path.join(settings.TUS_DESTINATION_DIR, self.filename)) return TusResponse(status=200)
def patch(self, request, resource_id, *args, **kwargs): tus_file = TusFile(str(resource_id)) chunk = TusChunk(request) if not tus_file.is_valid(): return TusResponse(status=410) if chunk.offset != tus_file.offset: return TusResponse(status=409) if chunk.offset > tus_file.file_size: return TusResponse(status=413) tus_file.write_chunk(chunk=chunk) if tus_file.is_complete(): # file transfer complete, rename from resource id to actual filename response = tus_file.rename() if response.status_code != 200: return response tus_file.clean() self.send_signal(tus_file) self.finished() return TusResponse(status=204, extra_headers={"Upload-Offset": tus_file.offset})
def head(self, request, resource_id): resource_id = str(resource_id) offset = cache.get("tus-uploads/{}/offset".format(resource_id)) file_size = cache.get("tus-uploads/{}/file_size".format(resource_id)) if offset is None: return TusResponse(status=404) return TusResponse(status=200, extra_headers={ 'Upload-Offset': offset, 'Upload-Length': file_size })
def write_chunk(self, chunk): try: with open(self.get_path(), "r+b") as f: f.seek(chunk.offset) f.write(chunk.content) self.offset = cache.incr( "tus-uploads/{}/offset".format(self.resource_id), chunk.chunk_size) except IOError: logger.error( "patch", extra={ "request": chunk.META, "tus": { "resource_id": self.resource_id, "filename": self.filename, "file_size": self.file_size, "metadata": self.metadata, "offset": self.offset, "upload_file_path": self.get_path(), }, }, ) return TusResponse(status=500)
def write_init_file(self): try: with open(self.get_path(), 'wb') as f: f.seek(self.file_size - 1) f.write(b'\0') except IOError as e: error_message = "Unable to create file: {}".format(e) logger.error(error_message, exc_info=True) return TusResponse(status=500, reason=error_message)
def head(self, request, resource_id): tus_file = TusFile.get_tusfile_or_404(str(resource_id)) return TusResponse(status=200, extra_headers={ 'Upload-Offset': tus_file.offset, 'Upload-Length': tus_file.file_size })
def dispatch(self, *args, **kwargs): if not self.request.META.get("HTTP_TUS_RESUMABLE"): return TusResponse(status=405, content="Method Not Allowed") override_method = self.request.META.get("HTTP_X_HTTP_METHOD_OVERRIDE") if override_method: self.request.method = override_method return super(TusUpload, self).dispatch(*args, **kwargs)
def write_init_file(self): os.makedirs(settings.TUS_DESTINATION_DIR, exist_ok=True) os.makedirs(settings.TUS_UPLOAD_DIR, exist_ok=True) try: with open(self.get_path(), "wb") as f: f.seek(self.file_size - 1) f.write(b"\0") except IOError as e: error_message = "Unable to create file: {}".format(e) logger.error(error_message, exc_info=True) return TusResponse(status=500, reason=error_message)
def rename(self): setting = settings.TUS_FILE_NAME_FORMAT if setting == 'keep': if self.check_existing_file(self.filename): return TusResponse(status=409, reason="File with same name already exists") elif setting == 'random': self.filename = FilenameGenerator(self.filename).create_random_name() elif setting == 'random-suffix': self.filename = FilenameGenerator(self.filename).create_random_suffix_name() elif setting == 'increment': self.filename = FilenameGenerator(self.filename).create_incremented_name() else: return ValueError() os.rename(self.get_path(), os.path.join(settings.TUS_DESTINATION_DIR, self.filename))
def get_tusfile_or_404(resource_id): if TusFile.resource_exists(str(resource_id)): return TusFile(resource_id) else: raise TusResponse(status=404)
def options(self, request, *args, **kwargs): return TusResponse(status=204)