fix upload interruption
Msrc/index.ts
| @@ -100,6 +100,23 @@ class UploadError extends Error { | |||
|---|---|---|---|
| 100 | 100 | } | |
| 101 | 101 | } | |
| 102 | 102 | ||
| 103 | + | // Read and discard the rest of a request body. When /upload rejects a request | |
| 104 | + | // before it parses the body (cooldown, bad content type), the client is still | |
| 105 | + | // streaming the file up; returning immediately cancels that in-flight stream and | |
| 106 | + | // the client sees a reset (NET_INTERRUPTED / H3_REQUEST_CANCELLED over HTTP/2/3) | |
| 107 | + | // instead of our response. Draining lets the request finish so the error gets | |
| 108 | + | // delivered. Best-effort: a client that hangs up mid-drain just errors here. | |
| 109 | + | async function drainBody(request: Request): Promise<void> { | |
| 110 | + | if (!request.body) return; | |
| 111 | + | const reader = request.body.getReader(); | |
| 112 | + | try { | |
| 113 | + | while (!(await reader.read()).done) {} | |
| 114 | + | } catch { | |
| 115 | + | } finally { | |
| 116 | + | reader.releaseLock(); | |
| 117 | + | } | |
| 118 | + | } | |
| 119 | + | ||
| 103 | 120 | async function pump( | |
| 104 | 121 | stream: ReadableStream<Uint8Array>, | |
| 105 | 122 | onChunk: (chunk: Uint8Array) => void | Promise<void>, | |
| @@ -223,6 +240,7 @@ const app = new Elysia({ | |||
|---|---|---|---|
| 223 | 240 | if (config.uploadCooldownSeconds > 0) { | |
| 224 | 241 | const last = lastUpload.get(ip) ?? 0; | |
| 225 | 242 | if (now - last < config.uploadCooldownSeconds * 1000) { | |
| 243 | + | await drainBody(request); | |
| 226 | 244 | set.status = 429; // Too Many Requests | |
| 227 | 245 | return "Upload cooldown active, please wait before uploading again"; | |
| 228 | 246 | } | |
| @@ -230,6 +248,7 @@ const app = new Elysia({ | |||
|---|---|---|---|
| 230 | 248 | ||
| 231 | 249 | const contentType = request.headers.get("content-type") ?? ""; | |
| 232 | 250 | if (!contentType.includes("multipart/form-data") || !request.body) { | |
| 251 | + | await drainBody(request); | |
| 233 | 252 | set.status = 400; | |
| 234 | 253 | return "Expected a multipart/form-data upload"; | |
| 235 | 254 | } | |