@trayio/express 4.93.0 → 4.94.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"ExpressHttpController.d.ts","sourceRoot":"","sources":["../../src/http/ExpressHttpController.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AASnD,OAAO,EACN,cAAc,EAEd,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAW1D,qBAAa,qBAAqB;IAEhC,SAAS,CAAC,UAAU,EAAE,cAAc;IACpC,SAAS,CAAC,2BAA2B,EAAE,MAAM;IAC7C,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;gBAFzB,UAAU,EAAE,cAAc,EAC1B,2BAA2B,EAAE,MAAe,EAC5C,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IAGpC,OAAO,CAAC,QAAQ,CAiGd;IAEF,SAAS,WAAY,MAAM,YAKzB;IAEF,OAAO,CAAC,gBAAgB,CAoBtB;IAGF,OAAO,CAAC,uBAAuB,CAI7B;IAEF,OAAO,CAAC,sBAAsB,CAmC3B;IAEH,OAAO,CAAC,aAAa,CAenB;IAEF,OAAO,CAAC,YAAY,CAkBlB;IAEF,OAAO,CAAC,+BAA+B,CAWpC;CACH"}
1
+ {"version":3,"file":"ExpressHttpController.d.ts","sourceRoot":"","sources":["../../src/http/ExpressHttpController.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,CAAC,MAAM,cAAc,CAAC;AAClC,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AASnD,OAAO,EACN,cAAc,EAEd,MAAM,qCAAqC,CAAC;AAG7C,OAAO,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAW1D,qBAAa,qBAAqB;IAEhC,SAAS,CAAC,UAAU,EAAE,cAAc;IACpC,SAAS,CAAC,2BAA2B,EAAE,MAAM;IAC7C,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;gBAFzB,UAAU,EAAE,cAAc,EAC1B,2BAA2B,EAAE,MAAe,EAC5C,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC;IAGpC,OAAO,CAAC,QAAQ,CA2Fd;IAEF,SAAS,WAAY,MAAM,YAKzB;IAEF,OAAO,CAAC,gBAAgB,CAoBtB;IAGF,OAAO,CAAC,uBAAuB,CAI7B;IAEF,OAAO,CAAC,sBAAsB,CAmC3B;IAEH,OAAO,CAAC,aAAa,CAenB;IAEF,OAAO,CAAC,YAAY,CAkBlB;IAEF,OAAO,CAAC,+BAA+B,CAWpC;CACH"}
@@ -84,14 +84,10 @@ class ExpressHttpController {
84
84
  processedValue = value.join(','); // flatten arrays
85
85
  }
86
86
  // Convert to string and sanitize for HTTP header compliance
87
- // Remove control characters (0x00-0x1F, 0x7F), line breaks, and other invalid chars
88
- return (String(processedValue)
89
- .replace(/\r\n/g, '_') // CRLF line breaks first
90
- .replace(/[\r\n]/g, '_') // remaining CR or LF
91
- // eslint-disable-next-line no-control-regex
92
- .replace(/[\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F]/g, '_') // other control characters (excluding \n and \r)
93
- .replace(/["\\]/g, '_') // quotes and backslashes
94
- .trim()); // remove leading/trailing whitespace
87
+ // Keep only valid HTTP header characters: tab, printable ASCII (0x20-0x7E), and extended ASCII (0x80-0xFF)
88
+ return String(processedValue)
89
+ .replace(/[^\t\x20-\x7e\x80-\xff]/g, '_')
90
+ .trim();
95
91
  };
96
92
  const response = Object.entries(httpResponse.headers)
97
93
  .reduce((acc, [key, value]) => acc.setHeader(key, sanitizeHeaderValue(value)), res)
@@ -141,9 +141,9 @@ describe('ExpressHttpController', () => {
141
141
  };
142
142
  mockEndpoint.execute.mockReturnValue(() => T.of(httpResponse));
143
143
  await routeHandler(mockReq, mockRes);
144
- expect(mockRes.setHeader).toHaveBeenCalledWith('test-header', 'value_with_line_breaks');
144
+ expect(mockRes.setHeader).toHaveBeenCalledWith('test-header', 'value_with_line__breaks');
145
145
  });
146
- it('should sanitize header values with quotes and backslashes', async () => {
146
+ it('should preserve quotes and backslashes as valid characters', async () => {
147
147
  const httpResponse = {
148
148
  statusCode: 200,
149
149
  headers: {
@@ -157,7 +157,7 @@ describe('ExpressHttpController', () => {
157
157
  };
158
158
  mockEndpoint.execute.mockReturnValue(() => T.of(httpResponse));
159
159
  await routeHandler(mockReq, mockRes);
160
- expect(mockRes.setHeader).toHaveBeenCalledWith('test-header', 'value_with_quotes');
160
+ expect(mockRes.setHeader).toHaveBeenCalledWith('test-header', 'value"with\\quotes');
161
161
  });
162
162
  it('should trim whitespace from header values', async () => {
163
163
  const httpResponse = {
@@ -221,7 +221,23 @@ describe('ExpressHttpController', () => {
221
221
  };
222
222
  mockEndpoint.execute.mockReturnValue(() => T.of(httpResponse));
223
223
  await routeHandler(mockReq, mockRes);
224
- expect(mockRes.setHeader).toHaveBeenCalledWith('test-header', 'value_with__multiple_issues_');
224
+ expect(mockRes.setHeader).toHaveBeenCalledWith('test-header', 'value_with__"multiple\\issues"');
225
+ });
226
+ it('should sanitize header values with em dash character', async () => {
227
+ const httpResponse = {
228
+ statusCode: 200,
229
+ headers: {
230
+ 'test-header': 'value–with–em–dash',
231
+ },
232
+ body: new stream_1.Readable({
233
+ read() {
234
+ this.push(null);
235
+ },
236
+ }),
237
+ };
238
+ mockEndpoint.execute.mockReturnValue(() => T.of(httpResponse));
239
+ await routeHandler(mockReq, mockRes);
240
+ expect(mockRes.setHeader).toHaveBeenCalledWith('test-header', 'value_with_em_dash');
225
241
  });
226
242
  });
227
243
  describe('error handling', () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trayio/express",
3
- "version": "4.93.0",
3
+ "version": "4.94.0",
4
4
  "description": "Express extensions and implementations",
5
5
  "exports": {
6
6
  "./*": "./dist/*.js"
@@ -14,7 +14,7 @@
14
14
  "access": "public"
15
15
  },
16
16
  "dependencies": {
17
- "@trayio/commons": "4.93.0",
17
+ "@trayio/commons": "4.94.0",
18
18
  "cors": "2.8.5",
19
19
  "express": "4.20.0",
20
20
  "formidable": "3.5.1"