Skip to content

Commit 746a007

Browse files
cursoragentntucker
andcommitted
fix(rest): throw on binary content-type with normalizable schema in auto-detection path
When content is not set and parseResponse auto-detects a binary content-type, response.blob() was returned immediately without any schema validation. An endpoint with a normalizable schema (e.g., schema: Article) that unexpectedly receives a binary content-type like application/octet-stream would silently return a Blob to the normalizer instead of throwing a descriptive error. Add the same schema compatibility check that exists for the explicit content property path and the text response path, so binary auto-detection now throws a NetworkError with status 400 when a normalizable schema is present. Co-authored-by: Nathaniel Tucker <me@ntucker.me>
1 parent 7b14dc4 commit 746a007

2 files changed

Lines changed: 32 additions & 1 deletion

File tree

packages/rest/src/RestEndpoint.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,19 @@ export default class RestEndpoint extends Endpoint {
174174

175175
const contentType = response.headers.get('content-type');
176176
if (contentType?.includes('json')) return jsonResponse(response);
177-
if (contentType && !textLikeRe.test(contentType)) return response.blob();
177+
if (contentType && !textLikeRe.test(contentType)) {
178+
if (
179+
this.schema != null &&
180+
typeof this.schema !== 'string' &&
181+
typeof this.schema !== 'undefined'
182+
) {
183+
const error = new NetworkError(response);
184+
error.status = 400;
185+
error.message = `Binary content-type '${contentType}' is incompatible with schema. Binary responses cannot be normalized. Use schema: undefined or set content: 'blob'.`;
186+
throw error;
187+
}
188+
return response.blob();
189+
}
178190

179191
return response.text().then(text => {
180192
if (

packages/rest/src/__tests__/RestEndpoint.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1955,6 +1955,25 @@ describe('auto-detection (no content)', () => {
19551955
expect(result).toBeInstanceOf(Blob);
19561956
});
19571957

1958+
it('binary Content-Type with normalizable schema throws', async () => {
1959+
nock(/.*/)
1960+
.defaultReplyHeaders({
1961+
'Access-Control-Allow-Origin': '*',
1962+
'Content-Type': 'application/octet-stream',
1963+
})
1964+
.get('/files/1')
1965+
.reply(200, Buffer.from([1, 2, 3]));
1966+
1967+
const ep = new RestEndpoint({
1968+
path: 'http\\://test.com/files/:id',
1969+
schema: User,
1970+
});
1971+
await expect(async () => await ep({ id: 1 })).rejects.toMatchObject({
1972+
status: 400,
1973+
message: expect.stringContaining('incompatible with schema'),
1974+
});
1975+
});
1976+
19581977
it('Content-Type: text/plain returns text (unchanged)', async () => {
19591978
nock(/.*/)
19601979
.defaultReplyHeaders({

0 commit comments

Comments
 (0)