Chunked Upload Extension
This is an Almond-specific resumable upload protocol; BUD-10 specifies the client-side blossom: URI scheme and does not define multipart uploads.
Features
- OPTIONS /upload: Signals support for multi-part uploads with
Allow: PUT, HEAD, OPTIONS, PATCHheader - PATCH /upload: Handles chunked uploads with proper validation and reconstruction
- Authorization: Full Nostr authorization support for chunked uploads
- Chunk validation: Ensures chunks are properly ordered and cover the full upload length
- SHA256 verification: Validates the final reconstructed blob matches the expected hash
API Endpoints
OPTIONS /upload
Returns 204 No Content with Allow: PUT, HEAD, OPTIONS, PATCH header to signal multi-part upload support.
PATCH /upload
Uploads a chunk of a multi-part upload. Requires the following headers:
X-SHA-256: SHA256 hash of the final blobUpload-Type: MIME type of the final blobUpload-Length: Total length of the blobContent-Length: Length of the current chunkUpload-Offset: Offset of the chunk in the blobContent-Type: Must beapplication/octet-streamAuthorization: Nostr authorization event
Response Codes
204 No Content: Chunk accepted, upload not complete200 OK: Upload complete, returns blob descriptor400 Bad Request: Invalid headers or chunk data401 Unauthorized: Invalid or missing authorization500 Internal Server Error: Server error during processing
Authorization
The Nostr authorization event must include:
ttag set touploadxtags for each chunk with the SHA256 hash of the chunkxtag with the SHA256 hash of the final blob
Example Usage
bash
# Check if chunked uploads are supported
curl -X OPTIONS http://localhost:3000/upload
# Upload first chunk
curl -X PATCH http://localhost:3000/upload \
-H "X-SHA-256: b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553" \
-H "Upload-Type: application/pdf" \
-H "Upload-Length: 184292" \
-H "Upload-Offset: 0" \
-H "Content-Length: 46073" \
-H "Content-Type: application/octet-stream" \
-H "Authorization: Nostr <base64-encoded-event>" \
--data-binary "@chunk_aa"
# Upload remaining chunks...
curl -X PATCH http://localhost:3000/upload \
-H "X-SHA-256: b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553" \
-H "Upload-Type: application/pdf" \
-H "Upload-Length: 184292" \
-H "Upload-Offset: 46073" \
-H "Content-Length: 46073" \
-H "Content-Type: application/octet-stream" \
-H "Authorization: Nostr <base64-encoded-event>" \
--data-binary "@chunk_ab"Implementation Details
Data Structures
ChunkUpload: Tracks ongoing chunked uploadsChunkInfo: Stores individual chunk metadata and file paths- File-based storage of chunk data during upload process (prevents memory exhaustion for large files)
Chunk Processing
- Validation: Headers and chunk data are validated
- Storage: Chunks are streamed directly to temporary files (prevents memory exhaustion)
- Reconstruction: When upload is complete, chunks are sorted by offset and read from files
- Verification: Final blob SHA256 is verified against expected hash
- Persistence: Reconstructed blob is saved to final location and indexed
- Cleanup: Temporary chunk files are automatically cleaned up after successful reconstruction
Error Handling
- Invalid headers return
400 Bad Request - Missing or invalid authorization returns
401 Unauthorized - Chunk size mismatches return
400 Bad Request - SHA256 verification failures return
500 Internal Server Error - Gaps in chunk coverage return
500 Internal Server Error
Testing
Use the provided test_chunked_upload.py script to test the implementation:
bash
python3 test_chunked_upload.pyThe test script:
- Creates a test file
- Splits it into chunks
- Uploads chunks via PATCH requests
- Verifies the final result
Configuration
No additional configuration is required. The chunked upload functionality uses the same storage and authorization settings as regular uploads.
