allow any type for customResponseHeaders config (#66689) (#66809)

* allow any type of value for customResponseHeaders and convert them

* fix test config creation

* add `?? {}` to avoid breaking all tests...
This commit is contained in:
Pierre Gayvallet 2020-05-16 09:07:02 +02:00 committed by GitHub
parent 04e835cd03
commit f3da8d06a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 4 deletions

View file

@ -62,6 +62,7 @@ configService.atPath.mockReturnValue(
disableProtection: true,
whitelist: [],
},
customResponseHeaders: {},
} as any)
);

View file

@ -18,7 +18,8 @@
*/
import uuid from 'uuid';
import { config } from '.';
import { config, HttpConfig } from './http_config';
import { CspConfig } from '../csp';
const validHostnames = ['www.example.com', '8.8.8.8', '::1', 'localhost'];
const invalidHostname = 'asdf$%^';
@ -107,6 +108,23 @@ test('throws if xsrf.whitelist element does not start with a slash', () => {
);
});
test('accepts any type of objects for custom headers', () => {
const httpSchema = config.schema;
const obj = {
customResponseHeaders: {
string: 'string',
bool: true,
number: 12,
array: [1, 2, 3],
nested: {
foo: 1,
bar: 'dolly',
},
},
};
expect(() => httpSchema.validate(obj)).not.toThrow();
});
describe('with TLS', () => {
test('throws if TLS is enabled but `redirectHttpFromPort` is equal to `port`', () => {
const httpSchema = config.schema;
@ -173,3 +191,30 @@ describe('with compression', () => {
expect(() => httpSchema.validate(obj)).toThrowErrorMatchingSnapshot();
});
});
describe('HttpConfig', () => {
it('converts customResponseHeaders to strings or arrays of strings', () => {
const httpSchema = config.schema;
const rawConfig = httpSchema.validate({
customResponseHeaders: {
string: 'string',
bool: true,
number: 12,
array: [1, 2, 3],
nested: {
foo: 1,
bar: 'dolly',
},
},
});
const httpConfig = new HttpConfig(rawConfig, CspConfig.DEFAULT);
expect(httpConfig.customResponseHeaders).toEqual({
string: 'string',
bool: 'true',
number: '12',
array: ['1', '2', '3'],
nested: '{"foo":1,"bar":"dolly"}',
});
});
});

View file

@ -57,7 +57,7 @@ export const config = {
),
schema.boolean({ defaultValue: false })
),
customResponseHeaders: schema.recordOf(schema.string(), schema.string(), {
customResponseHeaders: schema.recordOf(schema.string(), schema.any(), {
defaultValue: {},
}),
host: schema.string({
@ -136,7 +136,7 @@ export class HttpConfig {
public socketTimeout: number;
public port: number;
public cors: boolean | { origin: string[] };
public customResponseHeaders: Record<string, string>;
public customResponseHeaders: Record<string, string | string[]>;
public maxPayload: ByteSizeValue;
public basePath?: string;
public rewriteBasePath: boolean;
@ -153,7 +153,15 @@ export class HttpConfig {
this.host = rawHttpConfig.host;
this.port = rawHttpConfig.port;
this.cors = rawHttpConfig.cors;
this.customResponseHeaders = rawHttpConfig.customResponseHeaders;
this.customResponseHeaders = Object.entries(rawHttpConfig.customResponseHeaders ?? {}).reduce(
(headers, [key, value]) => {
return {
...headers,
[key]: Array.isArray(value) ? value.map(e => convertHeader(e)) : convertHeader(value),
};
},
{}
);
this.maxPayload = rawHttpConfig.maxPayload;
this.name = rawHttpConfig.name;
this.basePath = rawHttpConfig.basePath;
@ -166,3 +174,7 @@ export class HttpConfig {
this.xsrf = rawHttpConfig.xsrf;
}
}
const convertHeader = (entry: any): string => {
return typeof entry === 'object' ? JSON.stringify(entry) : String(entry);
};

View file

@ -45,6 +45,7 @@ configService.atPath.mockReturnValue(
disableProtection: true,
whitelist: [],
},
customResponseHeaders: {},
} as any)
);