Skip to content

Commit 292c688

Browse files
fix(storage): set application/json Content-Type for impersonated ADC requests (#8419)
* feat(storage): set Content-Type to application/json in decorateRequest when json is present and header is missing * fix(storage): ensure Headers instance supports 'has' method before setting content-type and skip test if Headers is undefined * fix: mutating issue Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 0c96646 commit 292c688

2 files changed

Lines changed: 76 additions & 0 deletions

File tree

handwritten/storage/src/nodejs-common/util.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -970,6 +970,24 @@ export class Util {
970970
delete reqOpts.json.autoPaginate;
971971
delete reqOpts.json.autoPaginateVal;
972972
reqOpts.json = replaceProjectIdToken(reqOpts.json, projectId);
973+
974+
const headers = reqOpts.headers || {};
975+
if (
976+
typeof (headers as any).set === 'function' &&
977+
typeof (headers as any).has === 'function'
978+
) {
979+
if (!(headers as any).has('content-type')) {
980+
(headers as any).set('Content-Type', 'application/json');
981+
}
982+
reqOpts.headers = headers;
983+
} else {
984+
const hasContentType = Object.keys(headers).some(
985+
key => key.toLowerCase() === 'content-type'
986+
);
987+
reqOpts.headers = hasContentType
988+
? headers
989+
: { ...headers, 'Content-Type': 'application/json' };
990+
}
973991
}
974992

975993
reqOpts.uri = replaceProjectIdToken(reqOpts.uri, projectId);

handwritten/storage/test/nodejs-common/util.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1805,6 +1805,64 @@ describe('common/util', () => {
18051805
assert.deepStrictEqual(decoratedRequest.json, decoratedJson);
18061806
});
18071807

1808+
it('should set Content-Type header on plain headers object when json is set', () => {
1809+
const projectId = 'project-id';
1810+
const reqOpts = {
1811+
uri: 'http://',
1812+
json: {},
1813+
headers: {},
1814+
};
1815+
replaceProjectIdTokenOverride = (x: any) => x;
1816+
1817+
const decoratedRequest = util.decorateRequest(reqOpts, projectId);
1818+
assert.strictEqual(
1819+
(decoratedRequest.headers as any)['Content-Type'],
1820+
'application/json'
1821+
);
1822+
});
1823+
1824+
it('should set Content-Type header on Headers instance when json is set', () => {
1825+
if (typeof Headers === 'undefined') {
1826+
return;
1827+
}
1828+
const projectId = 'project-id';
1829+
const headersInstance = new Headers();
1830+
const reqOpts = {
1831+
uri: 'http://',
1832+
json: {},
1833+
headers: headersInstance,
1834+
};
1835+
replaceProjectIdTokenOverride = (x: any) => x;
1836+
1837+
const decoratedRequest = util.decorateRequest(reqOpts as any, projectId);
1838+
assert.strictEqual(
1839+
(decoratedRequest.headers as any).get('Content-Type'),
1840+
'application/json'
1841+
);
1842+
});
1843+
1844+
it('should not overwrite existing Content-Type header if already present', () => {
1845+
const projectId = 'project-id';
1846+
const reqOpts = {
1847+
uri: 'http://',
1848+
json: {},
1849+
headers: {
1850+
'content-type': 'application/x-protobuf',
1851+
},
1852+
};
1853+
replaceProjectIdTokenOverride = (x: any) => x;
1854+
1855+
const decoratedRequest = util.decorateRequest(reqOpts, projectId);
1856+
assert.strictEqual(
1857+
(decoratedRequest.headers as any)['content-type'],
1858+
'application/x-protobuf'
1859+
);
1860+
assert.strictEqual(
1861+
(decoratedRequest.headers as any)['Content-Type'],
1862+
undefined
1863+
);
1864+
});
1865+
18081866
it('should decorate the request', () => {
18091867
const projectId = 'project-id';
18101868
const reqOpts = {

0 commit comments

Comments
 (0)