diff --git a/booklore-api/src/main/java/com/adityachandel/booklore/service/reader/CbxReaderService.java b/booklore-api/src/main/java/com/adityachandel/booklore/service/reader/CbxReaderService.java index ff8e9cce8..98ece43af 100644 --- a/booklore-api/src/main/java/com/adityachandel/booklore/service/reader/CbxReaderService.java +++ b/booklore-api/src/main/java/com/adityachandel/booklore/service/reader/CbxReaderService.java @@ -57,7 +57,14 @@ public class CbxReaderService { try { long maxCacheSizeBytes = mbToBytes(appSettingService.getAppSettings().getCbxCacheSizeInMb()); long estimatedSize = estimateArchiveSize(cbzPath); - if (estimatedSize > maxCacheSizeBytes) { + + if (estimatedSize == -1) { + long fileSize = Files.size(cbzPath); + if (fileSize > maxCacheSizeBytes) { + log.warn("Cache skipped: Physical file size {} exceeds max cache size {} (Estimation failed)", fileSize, maxCacheSizeBytes); + throw ApiError.CACHE_TOO_LARGE.createException(); + } + } else if (estimatedSize > maxCacheSizeBytes) { log.warn("Cache skipped: Estimated archive size {} exceeds max cache size {}", estimatedSize, maxCacheSizeBytes); throw ApiError.CACHE_TOO_LARGE.createException(); } @@ -78,7 +85,7 @@ public class CbxReaderService { } } catch (IOException e) { log.error("Failed to cache CBZ for book {}", bookId, e); - return List.of(); + throw ApiError.FILE_READ_ERROR.createException("Failed to read archive: " + e.getMessage()); } try (var stream = Files.list(cacheDir)) { @@ -360,7 +367,7 @@ public class CbxReaderService { } catch (Exception e) { log.warn("Failed to estimate archive size for {}", cbxPath, e); } - return Long.MAX_VALUE; + return -1; } private long estimateCbzArchiveSize(Path cbxPath) throws IOException { @@ -384,7 +391,7 @@ public class CbxReaderService { } log.warn("Unable to estimate archive size for {} with any supported encoding", cbxPath); - return Long.MAX_VALUE; + return -1; } private long estimateCbzWithEncoding(Path cbxPath, Charset charset, boolean useFastPath) throws IOException { @@ -405,7 +412,7 @@ public class CbxReaderService { total += (size >= 0) ? size : entry.getCompressedSize(); } } - return total > 0 ? total : Long.MAX_VALUE; + return total > 0 ? total : -1; } } diff --git a/booklore-api/src/test/java/com/adityachandel/booklore/service/reader/CbxReaderServiceTest.java b/booklore-api/src/test/java/com/adityachandel/booklore/service/reader/CbxReaderServiceTest.java index 61da7c925..fc936e828 100644 --- a/booklore-api/src/test/java/com/adityachandel/booklore/service/reader/CbxReaderServiceTest.java +++ b/booklore-api/src/test/java/com/adityachandel/booklore/service/reader/CbxReaderServiceTest.java @@ -1,6 +1,8 @@ package com.adityachandel.booklore.service.reader; +import com.adityachandel.booklore.exception.APIException; import com.adityachandel.booklore.model.dto.settings.AppSettings; +import com.adityachandel.booklore.exception.ApiError; import com.adityachandel.booklore.model.entity.BookEntity; import com.adityachandel.booklore.model.entity.LibraryPathEntity; import com.adityachandel.booklore.repository.BookRepository; @@ -167,6 +169,22 @@ class CbxReaderServiceTest { "Page count should be exactly 130 (actual comic pages only)"); } + @Test + void getAvailablePages_whenArchiveIsCorrupt_shouldThrowFileReadError() throws IOException { + Path corruptCbz = tempDir.resolve("corrupt.cbz"); + Files.writeString(corruptCbz, "This is not a zip file"); + + testBook.setFileName(corruptCbz.getFileName().toString()); + testBook.getLibraryPath().setPath(tempDir.toString()); + + APIException exception = assertThrows(APIException.class, () -> service.getAvailablePages(bookId)); + + assertNotEquals(ApiError.CACHE_TOO_LARGE.getMessage(), exception.getMessage(), + "Should not throw CACHE_TOO_LARGE for a corrupt file"); + assertTrue(exception.getMessage().startsWith("Error reading files from path"), + "Should throw FILE_READ_ERROR (message starts with 'Error reading files from path'), actual: '" + exception.getMessage() + "'"); + } + private void createTestCbzWithMacOsFiles(File cbzFile) throws IOException { try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(cbzFile))) { for (int i = 1; i <= 130; i++) {