Skip to content

Commit f3da8d0

Browse files
authored
allow any type for customResponseHeaders config (elastic#66689) (elastic#66809)
* allow any type of value for customResponseHeaders and convert them * fix test config creation * add `?? {}` to avoid breaking all tests...
1 parent 04e835c commit f3da8d0

File tree

4 files changed

+63
-4
lines changed

4 files changed

+63
-4
lines changed

src/core/server/http/cookie_session_storage.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ configService.atPath.mockReturnValue(
6262
disableProtection: true,
6363
whitelist: [],
6464
},
65+
customResponseHeaders: {},
6566
} as any)
6667
);
6768

src/core/server/http/http_config.test.ts

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
*/
1919

2020
import uuid from 'uuid';
21-
import { config } from '.';
21+
import { config, HttpConfig } from './http_config';
22+
import { CspConfig } from '../csp';
2223

2324
const validHostnames = ['www.example.com', '8.8.8.8', '::1', 'localhost'];
2425
const invalidHostname = 'asdf$%^';
@@ -107,6 +108,23 @@ test('throws if xsrf.whitelist element does not start with a slash', () => {
107108
);
108109
});
109110

111+
test('accepts any type of objects for custom headers', () => {
112+
const httpSchema = config.schema;
113+
const obj = {
114+
customResponseHeaders: {
115+
string: 'string',
116+
bool: true,
117+
number: 12,
118+
array: [1, 2, 3],
119+
nested: {
120+
foo: 1,
121+
bar: 'dolly',
122+
},
123+
},
124+
};
125+
expect(() => httpSchema.validate(obj)).not.toThrow();
126+
});
127+
110128
describe('with TLS', () => {
111129
test('throws if TLS is enabled but `redirectHttpFromPort` is equal to `port`', () => {
112130
const httpSchema = config.schema;
@@ -173,3 +191,30 @@ describe('with compression', () => {
173191
expect(() => httpSchema.validate(obj)).toThrowErrorMatchingSnapshot();
174192
});
175193
});
194+
195+
describe('HttpConfig', () => {
196+
it('converts customResponseHeaders to strings or arrays of strings', () => {
197+
const httpSchema = config.schema;
198+
const rawConfig = httpSchema.validate({
199+
customResponseHeaders: {
200+
string: 'string',
201+
bool: true,
202+
number: 12,
203+
array: [1, 2, 3],
204+
nested: {
205+
foo: 1,
206+
bar: 'dolly',
207+
},
208+
},
209+
});
210+
const httpConfig = new HttpConfig(rawConfig, CspConfig.DEFAULT);
211+
212+
expect(httpConfig.customResponseHeaders).toEqual({
213+
string: 'string',
214+
bool: 'true',
215+
number: '12',
216+
array: ['1', '2', '3'],
217+
nested: '{"foo":1,"bar":"dolly"}',
218+
});
219+
});
220+
});

src/core/server/http/http_config.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export const config = {
5757
),
5858
schema.boolean({ defaultValue: false })
5959
),
60-
customResponseHeaders: schema.recordOf(schema.string(), schema.string(), {
60+
customResponseHeaders: schema.recordOf(schema.string(), schema.any(), {
6161
defaultValue: {},
6262
}),
6363
host: schema.string({
@@ -136,7 +136,7 @@ export class HttpConfig {
136136
public socketTimeout: number;
137137
public port: number;
138138
public cors: boolean | { origin: string[] };
139-
public customResponseHeaders: Record<string, string>;
139+
public customResponseHeaders: Record<string, string | string[]>;
140140
public maxPayload: ByteSizeValue;
141141
public basePath?: string;
142142
public rewriteBasePath: boolean;
@@ -153,7 +153,15 @@ export class HttpConfig {
153153
this.host = rawHttpConfig.host;
154154
this.port = rawHttpConfig.port;
155155
this.cors = rawHttpConfig.cors;
156-
this.customResponseHeaders = rawHttpConfig.customResponseHeaders;
156+
this.customResponseHeaders = Object.entries(rawHttpConfig.customResponseHeaders ?? {}).reduce(
157+
(headers, [key, value]) => {
158+
return {
159+
...headers,
160+
[key]: Array.isArray(value) ? value.map(e => convertHeader(e)) : convertHeader(value),
161+
};
162+
},
163+
{}
164+
);
157165
this.maxPayload = rawHttpConfig.maxPayload;
158166
this.name = rawHttpConfig.name;
159167
this.basePath = rawHttpConfig.basePath;
@@ -166,3 +174,7 @@ export class HttpConfig {
166174
this.xsrf = rawHttpConfig.xsrf;
167175
}
168176
}
177+
178+
const convertHeader = (entry: any): string => {
179+
return typeof entry === 'object' ? JSON.stringify(entry) : String(entry);
180+
};

src/core/server/http/test_utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ configService.atPath.mockReturnValue(
4545
disableProtection: true,
4646
whitelist: [],
4747
},
48+
customResponseHeaders: {},
4849
} as any)
4950
);
5051

0 commit comments

Comments
 (0)