Skip to content

Commit a66bb06

Browse files
authored
feat: Add request header X-Parse-Upload-Mode to identify file upload as binary data via Buffer, Readable, ReadableStream (#2927)
1 parent 2ea5755 commit a66bb06

2 files changed

Lines changed: 27 additions & 0 deletions

File tree

src/ParseFile.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,6 +592,7 @@ const DefaultController = {
592592

593593
const headers: Record<string, string> = {
594594
'X-Parse-Application-ID': CoreManager.get('APPLICATION_ID'),
595+
'X-Parse-Upload-Mode': 'stream',
595596
};
596597
headers['Content-Type'] = (source.type || 'application/octet-stream').replace(/[\r\n]/g, '');
597598
const jsKey = CoreManager.get('JAVASCRIPT_KEY');

src/__tests__/ParseFile-test.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ describe('FileController', () => {
914914
'Content-Type': 'application/octet-stream',
915915
'X-Parse-Application-ID': 'testAppId',
916916
'X-Parse-JavaScript-Key': 'testJsKey',
917+
'X-Parse-Upload-Mode': 'stream',
917918
}),
918919
expect.any(Object)
919920
);
@@ -966,11 +967,34 @@ describe('FileController', () => {
966967
expect.objectContaining({
967968
'Content-Type': 'text/plain',
968969
'X-Parse-Application-ID': 'testAppId',
970+
'X-Parse-Upload-Mode': 'stream',
969971
}),
970972
expect.any(Object)
971973
);
972974
});
973975

976+
it('base64 uploads do not include X-Parse-Upload-Mode header', async () => {
977+
const request = jest.fn().mockResolvedValue({
978+
name: 'parse.txt',
979+
url: 'https://files.example.com/a/parse.txt',
980+
});
981+
const ajax = jest.fn();
982+
CoreManager.setRESTController({ request, ajax });
983+
CoreManager.set('APPLICATION_ID', 'testAppId');
984+
985+
const file = new ParseFile('parse.txt', [61, 170, 236, 120]);
986+
await file.save();
987+
988+
expect(request).toHaveBeenCalledWith(
989+
'POST',
990+
'files/parse.txt',
991+
expect.objectContaining({ base64: expect.any(String) }),
992+
expect.any(Object)
993+
);
994+
// Binary path (which sets X-Parse-Upload-Mode) should not be taken
995+
expect(ajax).not.toHaveBeenCalled();
996+
});
997+
974998
it('saveBinary includes session token from options', async () => {
975999
const ajax = jest.fn().mockResolvedValue({
9761000
response: { name: 'parse.txt', url: 'https://files.example.com/a/parse.txt' },
@@ -1225,6 +1249,8 @@ describe('FileController', () => {
12251249
// Web ReadableStream (no .pipe/.read) should be passed directly as body
12261250
const body = ajax.mock.calls[0][2];
12271251
expect(body).toBe(stream);
1252+
const headers = ajax.mock.calls[0][3];
1253+
expect(headers['X-Parse-Upload-Mode']).toBe('stream');
12281254
} finally {
12291255
globalThis.ReadableStream = origReadableStream;
12301256
}

0 commit comments

Comments
 (0)