From 9b5b744e240e1b2aa76e3b1837b312f7ff8d97b1 Mon Sep 17 00:00:00 2001 From: Nina Berg Date: Mon, 7 Apr 2025 14:35:58 -0400 Subject: [PATCH] add changeset and tests Signed-off-by: Nina Berg --- .changeset/thin-trams-work.md | 5 ++ .../proxy-backend/src/service/router.test.ts | 47 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 .changeset/thin-trams-work.md diff --git a/.changeset/thin-trams-work.md b/.changeset/thin-trams-work.md new file mode 100644 index 0000000000..ddc31631d1 --- /dev/null +++ b/.changeset/thin-trams-work.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-proxy-backend': patch +--- + +Fixed handling of proxied sse connections when the upstream server closes the connection diff --git a/plugins/proxy-backend/src/service/router.test.ts b/plugins/proxy-backend/src/service/router.test.ts index 66d6de2f28..7d9a3dadbc 100644 --- a/plugins/proxy-backend/src/service/router.test.ts +++ b/plugins/proxy-backend/src/service/router.test.ts @@ -479,6 +479,7 @@ describe('buildMiddleware', () => { pragma: 'value', 'set-cookie': ['value'], }, + on: jest.fn(), } as Partial; expect(config).toBeDefined(); @@ -522,6 +523,7 @@ describe('buildMiddleware', () => { 'set-cookie': [], 'x-auth-request-user': 'asd', }, + on: jest.fn(), } as Partial; expect(config).toBeDefined(); @@ -603,4 +605,49 @@ describe('buildMiddleware', () => { ), ).toThrow(/Proxy target is not a valid URL/); }); + + it('closes SSE connections when backend closes the connection', async () => { + buildMiddleware( + '/proxy', + logger, + '/test', + { + target: 'http://mocked', + }, + httpRouterService, + ); + + expect(createProxyMiddleware).toHaveBeenCalledTimes(1); + + const config = mockCreateProxyMiddleware.mock.calls[0][1] as Options; + + const testServerResponse = { + headers: {}, + on: jest.fn((event, callback) => { + if (event === 'close') { + callback(); + } + return testServerResponse; + }), + } as Partial; + + const testClientResponse = { + writableEnded: false, + end: jest.fn(), + } as Partial; + + expect(config).toBeDefined(); + expect(config.onProxyRes).toBeDefined(); + + config.onProxyRes!( + testServerResponse as http.IncomingMessage, + {} as Request, + testClientResponse as Response, + ); + expect(testServerResponse.on).toHaveBeenCalledWith( + 'close', + expect.any(Function), + ); + expect(testClientResponse.end).toHaveBeenCalled(); + }); });