icebear icebear0828 commited on
Commit
45525c6
·
unverified ·
1 Parent(s): 385b0e1

fix: handle stream disconnection properly in curl transport and proxy handler (#108)

Browse files

1. curl-cli-transport: signal error (not close) when curl exits with
non-zero code mid-stream, so downstream readers get a proper error
instead of a silent truncation.

2. proxy-handler: catch s.write() failures during streaming to detect
client disconnects, abort the upstream curl process, and stop the
stream cleanly instead of leaking resources.

3. proxy-handler: don't re-throw after sending error SSE event — the
stream is already closing, re-throwing causes unhandled rejection.

Co-authored-by: icebear0828 <icebear0828@users.noreply.github.com>

src/routes/shared/proxy-handler.ts CHANGED
@@ -153,7 +153,13 @@ export async function handleProxyRequest(
153
  () => {},
154
  req.tupleSchema,
155
  )) {
156
- await s.write(chunk);
 
 
 
 
 
 
157
  }
158
  } catch (err) {
159
  // P2-8: Send error SSE event to client before closing
@@ -161,7 +167,6 @@ export async function handleProxyRequest(
161
  const errMsg = err instanceof Error ? err.message : "Stream interrupted";
162
  await s.write(`data: ${JSON.stringify({ error: { message: errMsg, type: "stream_error" } })}\n\n`);
163
  } catch { /* client already gone */ }
164
- throw err;
165
  } finally {
166
  // P0-2: Kill curl subprocess if still running
167
  abortController.abort();
 
153
  () => {},
154
  req.tupleSchema,
155
  )) {
156
+ try {
157
+ await s.write(chunk);
158
+ } catch {
159
+ // Client disconnected mid-stream — stop reading upstream
160
+ abortController.abort();
161
+ return;
162
+ }
163
  }
164
  } catch (err) {
165
  // P2-8: Send error SSE event to client before closing
 
167
  const errMsg = err instanceof Error ? err.message : "Stream interrupted";
168
  await s.write(`data: ${JSON.stringify({ error: { message: errMsg, type: "stream_error" } })}\n\n`);
169
  } catch { /* client already gone */ }
 
170
  } finally {
171
  // P0-2: Kill curl subprocess if still running
172
  abortController.abort();
src/tls/curl-cli-transport.ts CHANGED
@@ -151,8 +151,14 @@ export class CurlCliTransport implements TlsTransport {
151
  }
152
  if (!headersParsed) {
153
  reject(new Error(`curl exited with code ${code}: ${stderrBuf}`));
 
 
 
 
 
 
 
154
  }
155
- bodyController?.close();
156
  });
157
 
158
  child.on("error", (err) => {
 
151
  }
152
  if (!headersParsed) {
153
  reject(new Error(`curl exited with code ${code}: ${stderrBuf}`));
154
+ } else if (code !== 0 && code !== null) {
155
+ // curl died mid-stream (e.g. connection reset, SIGPIPE) — signal error to reader
156
+ try {
157
+ bodyController?.error(new Error(`curl exited with code ${code} mid-stream: ${stderrBuf.trim() || "connection lost"}`));
158
+ } catch { /* stream already closed */ }
159
+ } else {
160
+ bodyController?.close();
161
  }
 
162
  });
163
 
164
  child.on("error", (err) => {