Skip to content

Commit

Permalink
fix(interceptors): prevent overriding existing headers
Browse files Browse the repository at this point in the history
  • Loading branch information
Convly authored Jan 30, 2025
2 parents 22fc464 + a2c1b77 commit 2d356de
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 3 deletions.
10 changes: 9 additions & 1 deletion src/interceptors/http.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,16 @@ export class HttpInterceptors {
*```
*/
public static setDefaultHeaders(): RequestInterceptor {
const DEFAULT_HEADERS = new Map([['Content-Type', 'application/json']]);

return ({ request }) => {
request.headers.set('Content-Type', 'application/json');
for (const [key, value] of DEFAULT_HEADERS.entries()) {
const hasHeader = request.headers.has(key);

if (!hasHeader) {
request.headers.set(key, value);
}
}

return { request };
};
Expand Down
19 changes: 17 additions & 2 deletions tests/unit/interceptors/http.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ describe('HTTP Interceptors', () => {
expect(request.headers.get('Content-Type')).toBe('application/json');
});

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

// Assert
expect(request.headers.get('Content-Type')).toBe('application/json');
expect(request.headers.get('Content-Type')).toBe('text/plain');
});

it('should perform case insensitive checks on headers', async () => {
// Arrange
const request = new Request('https://example.com', {
headers: { 'content-type': 'text/plain' },
});

const interceptor = HttpInterceptors.setDefaultHeaders();

// Act
await interceptor({ request });

// Assert
expect(request.headers.get('Content-Type')).toBe('text/plain');
});
});

Expand Down
28 changes: 28 additions & 0 deletions tests/unit/sdk.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,34 @@ describe('Strapi', () => {
expect((headers as Headers).get('Content-Type')).toBe('application/json');
});

it('should not set the application/json Content-Type header if it has been manually set', async () => {
// Arrange
const path = '/upload';
const contentType = 'multipart/form-data';

const config = { baseURL: 'https://localhost:1337/api' } satisfies StrapiConfig;
const init = {
method: 'POST',
headers: { 'Content-Type': contentType },
} satisfies RequestInit;

const mockValidator = new MockStrapiConfigValidator();
const mockAuthManager = new MockAuthManager();

const sdk = new Strapi(config, mockValidator, mockAuthManager, mockHttpClientFactory);

const fetchSpy = jest.spyOn(MockHttpClient.prototype, 'fetch');

// Act
await sdk.fetch(path, init);
const headers = fetchSpy.mock.lastCall?.[1]?.headers;

// Assert
expect(headers).toBeDefined();
expect(headers).toBeInstanceOf(Headers);
expect((headers as Headers).get('Content-Type')).toBe(contentType);
});

it.each([
['Bad Request', StatusCode.BAD_REQUEST, HTTPBadRequestError],
['Unauthorized', StatusCode.UNAUTHORIZED, HTTPAuthorizationError],
Expand Down

0 comments on commit 2d356de

Please sign in to comment.