-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
feat: Allow large Parse File uploads #9286
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: alpha
Are you sure you want to change the base?
Changes from all commits
734d85e
088c669
3385d2f
0a2c904
d2c89af
216c078
a559453
39face2
aedd984
c814b30
0cf1391
92b5ec5
5bd46b6
01cce43
f296828
73bbdb0
d43a8ad
f817c20
aabae8b
07098f9
f09037f
5c298b3
e276df3
fad46b3
18157be
a87a452
7e23668
65b06b5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,79 @@ | ||||||||||||||||||||||||||||||||||||||||
| const fs = require('fs'); | ||||||||||||||||||||||||||||||||||||||||
| const path = require('path'); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| describe('FilesRouter', () => { | ||||||||||||||||||||||||||||||||||||||||
| describe_only_db('mongo')('File Uploads', () => { | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| beforeEach(async () => { | ||||||||||||||||||||||||||||||||||||||||
| // Set the maxUploadSize to 1GB | ||||||||||||||||||||||||||||||||||||||||
| await reconfigureServer({ | ||||||||||||||||||||||||||||||||||||||||
| maxUploadSize: '1GB', | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const V8_STRING_LIMIT_BYTES = 536_870_912; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||
| * Quick helper function to upload the file to the server via the REST API | ||||||||||||||||||||||||||||||||||||||||
| * We do this because creating a Parse.File object with a file over 512MB | ||||||||||||||||||||||||||||||||||||||||
| * will try to use the Web FileReader API, which will fail the test | ||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||
| * @param {string} fileName the name of the file | ||||||||||||||||||||||||||||||||||||||||
| * @param {string} filePath the path to the file locally | ||||||||||||||||||||||||||||||||||||||||
| * @returns | ||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||
| const postFile = async (fileName, filePath) => { | ||||||||||||||||||||||||||||||||||||||||
| const url = `${Parse.serverURL}/files/${fileName}`; | ||||||||||||||||||||||||||||||||||||||||
| const headers = { | ||||||||||||||||||||||||||||||||||||||||
| 'X-Parse-Application-Id': Parse.applicationId, | ||||||||||||||||||||||||||||||||||||||||
| 'X-Parse-Master-Key': Parse.masterKey, | ||||||||||||||||||||||||||||||||||||||||
| 'Content-Type': 'multipart/form-data', | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const fileStream = fs.createReadStream(filePath); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| // Send the request | ||||||||||||||||||||||||||||||||||||||||
| const response = await fetch(url, { | ||||||||||||||||||||||||||||||||||||||||
| method: 'POST', | ||||||||||||||||||||||||||||||||||||||||
| headers, | ||||||||||||||||||||||||||||||||||||||||
| body: fileStream, | ||||||||||||||||||||||||||||||||||||||||
| duplex: 'half' // This is required to send a stream | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| return response; | ||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| it('should allow Parse.File uploads under 512MB', async done => { | ||||||||||||||||||||||||||||||||||||||||
| const filePath = path.join(__dirname, 'file.txt'); | ||||||||||||||||||||||||||||||||||||||||
| await fs.promises.writeFile(filePath, Buffer.alloc(1024 * 1024)); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const response = await postFile('file.txt', filePath); | ||||||||||||||||||||||||||||||||||||||||
| expect(response.ok).toBe(true); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| fs.unlinkSync(filePath); | ||||||||||||||||||||||||||||||||||||||||
| done(); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+46
to
+55
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion | 🟠 Major Replace All three tests use the Based on learnings: "New tests in the parse-server repository should use async/await with promise-based patterns rather than callback patterns with Proposed fix (apply same pattern to all three tests)- it('should allow Parse.File uploads under 512MB', async done => {
+ it('should allow Parse.File uploads under 512MB', async () => {
const filePath = path.join(__dirname, 'file.txt');
await fs.promises.writeFile(filePath, Buffer.alloc(1024 * 1024));
const response = await postFile('file.txt', filePath);
expect(response.ok).toBe(true);
fs.unlinkSync(filePath);
- done();
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| it('should allow Parse.File uploads exactly 512MB', async done => { | ||||||||||||||||||||||||||||||||||||||||
| const filePath = path.join(__dirname, 'file.txt'); | ||||||||||||||||||||||||||||||||||||||||
| await fs.promises.writeFile(filePath, Buffer.alloc(V8_STRING_LIMIT_BYTES)); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const response = await postFile('file.txt', filePath); | ||||||||||||||||||||||||||||||||||||||||
| expect(response.ok).toBe(true); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| fs.unlinkSync(filePath); | ||||||||||||||||||||||||||||||||||||||||
| done(); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| it('should allow Parse.File uploads over 512MB', async done => { | ||||||||||||||||||||||||||||||||||||||||
| const filePath = path.join(__dirname, 'file.txt'); | ||||||||||||||||||||||||||||||||||||||||
| await fs.promises.writeFile(filePath, Buffer.alloc(V8_STRING_LIMIT_BYTES + 50 * 1024 * 1024)); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| const response = await postFile('file.txt', filePath); | ||||||||||||||||||||||||||||||||||||||||
| expect(response.ok).toBe(true); | ||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||
| fs.unlinkSync(filePath); | ||||||||||||||||||||||||||||||||||||||||
| done(); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Content-Type: multipart/form-datais semantically incorrect for a raw stream body.The request sends a raw file stream, not a multipart-encoded body.
multipart/form-datarequires boundary delimiters. Sinceexpress.raw()accepts any content type, this works by accident. Useapplication/octet-stream(or the actual MIME type) to be accurate.Proposed fix
const headers = { 'X-Parse-Application-Id': Parse.applicationId, 'X-Parse-Master-Key': Parse.masterKey, - 'Content-Type': 'multipart/form-data', + 'Content-Type': 'application/octet-stream', };📝 Committable suggestion
🤖 Prompt for AI Agents