From 213f10c34b8d6a61af96373a5386cdb6675c1f96 Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Fri, 27 Jun 2025 13:17:08 +0200 Subject: [PATCH 1/2] node: suppress stream errors when uploading --- .../node/src/BacktraceNodeRequestHandler.ts | 30 +++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/packages/node/src/BacktraceNodeRequestHandler.ts b/packages/node/src/BacktraceNodeRequestHandler.ts index 49d0af33..c8be31ad 100644 --- a/packages/node/src/BacktraceNodeRequestHandler.ts +++ b/packages/node/src/BacktraceNodeRequestHandler.ts @@ -10,7 +10,7 @@ import { import FormData from 'form-data'; import http, { ClientRequest, IncomingMessage } from 'http'; import https from 'https'; -import { Readable } from 'stream'; +import { PassThrough, Readable } from 'stream'; export interface BacktraceNodeRequestHandlerOptions { readonly timeout?: number; @@ -238,13 +238,39 @@ export class BacktraceNodeRequestHandler implements BacktraceRequestHandler { } for (const attachment of attachments) { - const data = attachment.get(); + let data = attachment.get(); if (!data) { continue; } + + if (data instanceof Readable) { + data = wrapReadableSuppressErrors(data); + } + formData.append(`attachment_${attachment.name}`, data, attachment.name); } return formData; } } + +/** + * When inputStream emits an error, it will be suppressed, and the stream will be closed. + */ +function wrapReadableSuppressErrors(inputStream: Readable) { + const safeStream = new PassThrough(); + + inputStream.on('data', (chunk) => { + safeStream.write(chunk); + }); + + inputStream.on('end', () => { + safeStream.end(); + }); + + inputStream.on('error', () => { + safeStream.end(); + }); + + return safeStream; +} From 66027a259929773eaa0ddfdfde51a8ce2ad2149d Mon Sep 17 00:00:00 2001 From: Sebastian Alex Date: Mon, 30 Jun 2025 17:18:41 +0200 Subject: [PATCH 2/2] node: move wrapReadableSuppressErrors to a private class method --- .../node/src/BacktraceNodeRequestHandler.ts | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/node/src/BacktraceNodeRequestHandler.ts b/packages/node/src/BacktraceNodeRequestHandler.ts index c8be31ad..3699a6e2 100644 --- a/packages/node/src/BacktraceNodeRequestHandler.ts +++ b/packages/node/src/BacktraceNodeRequestHandler.ts @@ -244,7 +244,7 @@ export class BacktraceNodeRequestHandler implements BacktraceRequestHandler { } if (data instanceof Readable) { - data = wrapReadableSuppressErrors(data); + data = this.wrapReadableSuppressErrors(data); } formData.append(`attachment_${attachment.name}`, data, attachment.name); @@ -252,25 +252,25 @@ export class BacktraceNodeRequestHandler implements BacktraceRequestHandler { return formData; } -} -/** - * When inputStream emits an error, it will be suppressed, and the stream will be closed. - */ -function wrapReadableSuppressErrors(inputStream: Readable) { - const safeStream = new PassThrough(); + /** + * When inputStream emits an error, it will be suppressed, and the stream will be closed. + */ + private wrapReadableSuppressErrors(inputStream: Readable) { + const safeStream = new PassThrough(); - inputStream.on('data', (chunk) => { - safeStream.write(chunk); - }); + inputStream.on('data', (chunk) => { + safeStream.write(chunk); + }); - inputStream.on('end', () => { - safeStream.end(); - }); + inputStream.on('end', () => { + safeStream.end(); + }); - inputStream.on('error', () => { - safeStream.end(); - }); + inputStream.on('error', () => { + safeStream.end(); + }); - return safeStream; + return safeStream; + } }