fix upload interruption

AuthorKonata <konata@posteo.jp>
Date
Commit263bf8fd29de7b2b6ddc430dd10628edf71f7321
Parent31ca3d1
1 file changed, 19 insertions(+)
Msrc/index.ts
@@ -100,6 +100,23 @@ class UploadError extends Error {
100100 }
101101 }
102102
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+
103120 async function pump(
104121 stream: ReadableStream<Uint8Array>,
105122 onChunk: (chunk: Uint8Array) => void | Promise<void>,
@@ -223,6 +240,7 @@ const app = new Elysia({
223240 if (config.uploadCooldownSeconds > 0) {
224241 const last = lastUpload.get(ip) ?? 0;
225242 if (now - last < config.uploadCooldownSeconds * 1000) {
243+ await drainBody(request);
226244 set.status = 429; // Too Many Requests
227245 return "Upload cooldown active, please wait before uploading again";
228246 }
@@ -230,6 +248,7 @@ const app = new Elysia({
230248
231249 const contentType = request.headers.get("content-type") ?? "";
232250 if (!contentType.includes("multipart/form-data") || !request.body) {
251+ await drainBody(request);
233252 set.status = 400;
234253 return "Expected a multipart/form-data upload";
235254 }