mirror of
https://github.com/tiennm99/rplace.git
synced 2026-10-11 03:13:48 +00:00
fix(canvas): make multi-chunk pixel writes atomic and refund cooldown on failure
- wrap writePixels in state.storage.transactionSync so a partial multi-chunk failure doesn't leave the canvas half-written or out of sync with the WS broadcast - size new chunk buffer against chunkSize(chunkId) instead of the persisted blob's length so writes after a canvas-grow no longer silently drop OOB bytes in the formerly-last short chunk - refund the cooldown row when writePixels throws so transient storage errors stop soft-DOSing the user (and halving image-uploader throughput) - bound readAllChunks by chunk_id < CHUNK_COUNT and trim oversized blobs so orphan rows from a future shrink no longer crash GET /api/canvas - require a positive Content-Length on /api/place (411) and reject above the pre-parse cap (413); previously a missing or zero header bypassed the cap - drop String(err) from the 500 response body - drain the INSERT cursor symmetrically with the UPDATE branch in tryAcquire - assert CHUNK_BYTES <= 2 MB at module load (DO SQLite per-cell BLOB cap) - correct the inverted webSocketClose comment and guard the re-close call - add tests for missing / zero / oversized Content-Length Plan: plans/260510-0232-fix-do-migration-followups/phase-01-do-storage-atomicity.md
This commit is contained in:
1 parent
a977adc62d
commit
3c1263add6
15 files changed
+1686
-24
No files matched your search
+7
-1
@@ -21,7 +21,13 @@ app.get('/api/canvas', async (c) => {
|
||||
|
||||
/** POST /api/place — validate at the edge, forward to the DO. */
|
||||
app.post('/api/place', async (c) => {
|
||||
const contentLength = parseInt(c.req.header('content-length') || '0', 10);
|
||||
// Require a positive Content-Length. Missing or zero would otherwise let a
|
||||
// chunked-transfer-encoded body bypass the MAX_BODY_BYTES pre-parse cap.
|
||||
const contentLengthRaw = c.req.header('content-length');
|
||||
const contentLength = parseInt(contentLengthRaw ?? '', 10);
|
||||
if (!Number.isFinite(contentLength) || contentLength <= 0) {
|
||||
return c.json({ error: 'content_length_required' }, 411);
|
||||
}
|
||||
if (contentLength > MAX_BODY_BYTES) {
|
||||
return c.json({ error: 'body_too_large', max: MAX_BODY_BYTES }, 413);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user