fix: enforce the analysis image cap while reading, not after
The OCR and vision dispatchers read the whole page image into a Vec via storage.get() and only then checked max_image_bytes, so the cap couldn't bound the read. Stream via get_stream() + safety::accumulate_capped so the read bails as soon as the running total exceeds the cap. Bump to 0.124.6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -99,6 +99,36 @@ async fn dispatch_persists_ocr_lines_and_search_doc(pool: PgPool) {
|
||||
assert!(has_doc, "search_doc must be populated from OCR text");
|
||||
}
|
||||
|
||||
#[sqlx::test(migrations = "./migrations")]
|
||||
async fn dispatch_rejects_page_image_over_the_byte_cap(pool: PgPool) {
|
||||
let dir = TempDir::new().unwrap();
|
||||
let storage: Arc<dyn Storage> = Arc::new(LocalStorage::new(dir.path()));
|
||||
let key = "mangas/x/big.png";
|
||||
// 4 KiB on disk, 1 KiB cap — the streamed read must bail on the cap
|
||||
// rather than buffering the whole blob and OCR-ing it.
|
||||
storage.put(key, &vec![0u8; 4096]).await.unwrap();
|
||||
let page_id = seed_page(&pool, key).await;
|
||||
|
||||
let dispatcher = OcrAnalyzeDispatcher {
|
||||
db: pool.clone(),
|
||||
storage: Arc::clone(&storage),
|
||||
engine: StubOcrEngine::new(&["should not run"]),
|
||||
max_image_bytes: 1024,
|
||||
ocr_permits: Arc::new(tokio::sync::Semaphore::new(1)),
|
||||
};
|
||||
let err = dispatcher.dispatch(page_id).await.unwrap_err();
|
||||
assert!(
|
||||
err.chain().any(|c| c.to_string().contains("cap")),
|
||||
"expected an over-cap error, got: {err:#}"
|
||||
);
|
||||
|
||||
// A rejected page must not land an analysis row.
|
||||
assert!(repo::page_analysis::load(&pool, page_id)
|
||||
.await
|
||||
.unwrap()
|
||||
.is_none());
|
||||
}
|
||||
|
||||
#[sqlx::test(migrations = "./migrations")]
|
||||
async fn dispatch_missing_page_is_noop(pool: PgPool) {
|
||||
let dir = TempDir::new().unwrap();
|
||||
|
||||
Reference in New Issue
Block a user