diff --git a/gns3server/api/routes/controller/images.py b/gns3server/api/routes/controller/images.py index 9a43152ed..26b9a2ed2 100644 --- a/gns3server/api/routes/controller/images.py +++ b/gns3server/api/routes/controller/images.py @@ -154,6 +154,17 @@ async def upload_image( if os.path.commonprefix([base_images_directory, full_path]) != base_images_directory: raise ControllerForbiddenError(f"Cannot write image, '{image_path}' is forbidden") + # If the client sends X-MD5-Checksum, check for a duplicate before consuming the upload stream + checksum_header = request.headers.get("X-MD5-Checksum") + if checksum_header: + check_dir = os.path.dirname(full_path) if image_dir else None + duplicate = await images_repo.get_image_by_checksum(checksum_header, check_dir) + if duplicate: + location = f" in '{check_dir}'" if check_dir else "" + raise ControllerError( + f"Image '{duplicate.filename}' with the same checksum already exists{location}" + ) + try: allow_raw_image = Config.instance().settings.Server.allow_raw_images image = await write_image(image_path, full_path, request.stream(), images_repo, allow_raw_image=allow_raw_image) diff --git a/gns3server/db/repositories/images.py b/gns3server/db/repositories/images.py index 8f6c64dc9..fdb44944a 100644 --- a/gns3server/db/repositories/images.py +++ b/gns3server/db/repositories/images.py @@ -59,7 +59,7 @@ class ImagesRepository(BaseRepository): query = select(models.Image).\ where(models.Image.checksum == checksum, models.Image.path.startswith(image_dir)) result = await self._db_session.execute(query) - return result.scalars().one_or_none() + return result.scalars().first() else: query = select(models.Image).where(models.Image.checksum == checksum) result = await self._db_session.execute(query)