Skip to content

Commit 2d356de

Browse files
authored
fix(interceptors): prevent overriding existing headers
2 parents 22fc464 + a2c1b77 commit 2d356de

File tree

3 files changed

+54
-3
lines changed

3 files changed

+54
-3
lines changed

src/interceptors/http.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,16 @@ export class HttpInterceptors {
2626
*```
2727
*/
2828
public static setDefaultHeaders(): RequestInterceptor {
29+
const DEFAULT_HEADERS = new Map([['Content-Type', 'application/json']]);
30+
2931
return ({ request }) => {
30-
request.headers.set('Content-Type', 'application/json');
32+
for (const [key, value] of DEFAULT_HEADERS.entries()) {
33+
const hasHeader = request.headers.has(key);
34+
35+
if (!hasHeader) {
36+
request.headers.set(key, value);
37+
}
38+
}
3139

3240
return { request };
3341
};

tests/unit/interceptors/http.test.ts

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ describe('HTTP Interceptors', () => {
1616
expect(request.headers.get('Content-Type')).toBe('application/json');
1717
});
1818

19-
it('should override the headers in the given request', async () => {
19+
it('should not override the headers if a value is already set', async () => {
2020
// Arrange
2121
const request = new Request('https://example.com', {
2222
headers: { 'Content-Type': 'text/plain' },
@@ -28,7 +28,22 @@ describe('HTTP Interceptors', () => {
2828
await interceptor({ request });
2929

3030
// Assert
31-
expect(request.headers.get('Content-Type')).toBe('application/json');
31+
expect(request.headers.get('Content-Type')).toBe('text/plain');
32+
});
33+
34+
it('should perform case insensitive checks on headers', async () => {
35+
// Arrange
36+
const request = new Request('https://example.com', {
37+
headers: { 'content-type': 'text/plain' },
38+
});
39+
40+
const interceptor = HttpInterceptors.setDefaultHeaders();
41+
42+
// Act
43+
await interceptor({ request });
44+
45+
// Assert
46+
expect(request.headers.get('Content-Type')).toBe('text/plain');
3247
});
3348
});
3449

tests/unit/sdk.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,34 @@ describe('Strapi', () => {
192192
expect((headers as Headers).get('Content-Type')).toBe('application/json');
193193
});
194194

195+
it('should not set the application/json Content-Type header if it has been manually set', async () => {
196+
// Arrange
197+
const path = '/upload';
198+
const contentType = 'multipart/form-data';
199+
200+
const config = { baseURL: 'https://localhost:1337/api' } satisfies StrapiConfig;
201+
const init = {
202+
method: 'POST',
203+
headers: { 'Content-Type': contentType },
204+
} satisfies RequestInit;
205+
206+
const mockValidator = new MockStrapiConfigValidator();
207+
const mockAuthManager = new MockAuthManager();
208+
209+
const sdk = new Strapi(config, mockValidator, mockAuthManager, mockHttpClientFactory);
210+
211+
const fetchSpy = jest.spyOn(MockHttpClient.prototype, 'fetch');
212+
213+
// Act
214+
await sdk.fetch(path, init);
215+
const headers = fetchSpy.mock.lastCall?.[1]?.headers;
216+
217+
// Assert
218+
expect(headers).toBeDefined();
219+
expect(headers).toBeInstanceOf(Headers);
220+
expect((headers as Headers).get('Content-Type')).toBe(contentType);
221+
});
222+
195223
it.each([
196224
['Bad Request', StatusCode.BAD_REQUEST, HTTPBadRequestError],
197225
['Unauthorized', StatusCode.UNAUTHORIZED, HTTPAuthorizationError],

0 commit comments

Comments
 (0)