Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/modules/datafile-manager/datafileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export interface DatafileManagerConfig {
updateInterval?: number;
urlTemplate?: string;
cache?: PersistentKeyValueCache;
customHeaders?: Record<string, string>;
}

export interface NodeDatafileManagerConfig extends DatafileManagerConfig {
Expand Down
11 changes: 10 additions & 1 deletion lib/modules/datafile-manager/httpPollingDatafileManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import { getLogger } from '../logging';
import { sprintf } from '../../utils/fns';
import { sprintf, assign } from '../../utils/fns';
import { DatafileManager, DatafileManagerConfig, DatafileUpdate } from './datafileManager';
import EventEmitter, { Disposer } from './eventEmitter';
import { AbortableRequest, Response, Headers } from './http';
Expand Down Expand Up @@ -96,6 +96,8 @@ export default abstract class HttpPollingDatafileManager implements DatafileMana

private sdkKey: string;

private customHeaders?: Record<string, string>;

// When true, this means the update interval timeout fired before the current
// sync completed. In that case, we should sync again immediately upon
// completion of the current request, instead of waiting another update
Expand All @@ -114,11 +116,13 @@ export default abstract class HttpPollingDatafileManager implements DatafileMana
updateInterval = DEFAULT_UPDATE_INTERVAL,
urlTemplate = DEFAULT_URL_TEMPLATE,
cache = noOpKeyValueCache,
customHeaders,
} = configWithDefaultsApplied;

this.cache = cache;
this.cacheKey = 'opt-datafile-' + sdkKey;
this.sdkKey = sdkKey;
this.customHeaders = customHeaders;
this.isReadyPromiseSettled = false;
this.readyPromiseResolver = (): void => { };
this.readyPromiseRejecter = (): void => { };
Expand Down Expand Up @@ -266,6 +270,11 @@ export default abstract class HttpPollingDatafileManager implements DatafileMana

private syncDatafile(): void {
const headers: Headers = {};

if (this.customHeaders) {
assign(headers, this.customHeaders);
}

if (this.lastResponseLastModified) {
headers['if-modified-since'] = this.lastResponseLastModified;
}
Expand Down
1 change: 1 addition & 0 deletions lib/shared_types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ export interface DatafileOptions {
updateInterval?: number;
urlTemplate?: string;
datafileAccessToken?: string;
customHeaders?: Record<string, string>;
}

export interface OdpOptions {
Expand Down
45 changes: 45 additions & 0 deletions tests/nodeDatafileManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,4 +183,49 @@ describe('nodeDatafileManager', () => {
expect(makeGetRequestSpy).toBeCalledWith('https://myawesomeurl/', expect.anything());
await manager.stop();
});

it('passes custom headers to makeGetRequest and merges with system headers', async () => {
makeGetRequestSpy.mockReturnValue({
abort: jest.fn(),
responsePromise: Promise.resolve({
statusCode: 200,
body: '{"foo":"bar"}',
headers: {
'last-modified': 'Fri, 08 Mar 2019 18:57:17 GMT',
},
}),
});
const manager = new NodeDatafileManager({
sdkKey: '1234',
autoUpdate: true,
customHeaders: {
'X-Custom-Header': 'custom-value',
'X-Environment': 'production',
},
});
manager.start();
await manager.onReady();

// First request should have custom headers
expect(makeGetRequestSpy).toBeCalledTimes(1);
expect(makeGetRequestSpy.mock.calls[0][0]).toBe('https://cdn.optimizely.com/datafiles/1234.json');
expect(makeGetRequestSpy.mock.calls[0][1]).toEqual({
'X-Custom-Header': 'custom-value',
'X-Environment': 'production',
});

// Advance time to trigger second request
await advanceTimersByTime(300000);

// Second request should have both custom headers AND if-modified-since
expect(makeGetRequestSpy).toBeCalledTimes(2);
expect(makeGetRequestSpy.mock.calls[1][0]).toBe('https://cdn.optimizely.com/datafiles/1234.json');
expect(makeGetRequestSpy.mock.calls[1][1]).toEqual({
'X-Custom-Header': 'custom-value',
'X-Environment': 'production',
'if-modified-since': 'Fri, 08 Mar 2019 18:57:17 GMT',
});

await manager.stop();
});
});
Loading