Fix async file deletion bugs in assets endpoint (#5363) The delete handler had a missing `return` before `sendStatus(400)`, causing execution to fall through to `sendStatus(200)`, a double-send that triggers ERR_HTTP_HEADERS_SENT, which the catch block then compounds by attempting a third `sendStatus(500)`. Both the delete and download handlers used callback-based `fs.unlink()` without awaiting completion. In the download handler, this caused a race with `createWriteStream({ flags: 'wx' })` (which fails if the file still exists). In both handlers, `throw err` inside the callback was an unhandled exception that could never be caught by the outer try/catch. Replace callback-based `fs.unlink()` with `await fs.promises.unlink()` and add missing `return` statements to prevent response cascades.
Signed| @@ -232,9 +232,7 @@ router.post('/download', async (request, response) => { | |||
| 232 | const destination = path.resolve(temp_path); | 232 | const destination = path.resolve(temp_path); |
| 233 | // Delete if previous download failed | 233 | // Delete if previous download failed |
| 234 | if (fs.existsSync(temp_path)) { | 234 | if (fs.existsSync(temp_path)) { |
| 235 | fs.unlink(temp_path, (err) => { | 235 | await fs.promises.unlink(temp_path); |
| 236 | if (err) throw err; | ||
| 237 | }); | ||
| 238 | } | 236 | } |
| 239 | const fileStream = fs.createWriteStream(destination, { flags: 'wx' }); | 237 | const fileStream = fs.createWriteStream(destination, { flags: 'wx' }); |
| 240 | // @ts-ignore | 238 | // @ts-ignore |
| @@ -291,21 +289,17 @@ router.post('/delete', async (request, response) => { | |||
| 291 | console.info('Request received to delete', category, file_path); | 289 | console.info('Request received to delete', category, file_path); |
| 292 | 290 | ||
| 293 | try { | 291 | try { |
| 294 | // Delete if previous download failed | 292 | if (!fs.existsSync(file_path)) { |
| 295 | if (fs.existsSync(file_path)) { | ||
| 296 | fs.unlink(file_path, (err) => { | ||
| 297 | if (err) throw err; | ||
| 298 | }); | ||
| 299 | console.info('Asset deleted.'); | ||
| 300 | } else { | ||
| 301 | console.error('Asset not found.'); | 293 | console.error('Asset not found.'); |
| 302 | response.sendStatus(400); | 294 | return response.sendStatus(400); |
| 303 | } | 295 | } |
| 304 | // Move into asset place | 296 | |
| 305 | response.sendStatus(200); | 297 | await fs.promises.unlink(file_path); |
| 298 | console.info('Asset deleted.'); | ||
| 299 | return response.sendStatus(200); | ||
| 306 | } catch (error) { | 300 | } catch (error) { |
| 307 | console.error(error); | 301 | console.error(error); |
| 308 | response.sendStatus(500); | 302 | return response.sendStatus(500); |
| 309 | } | 303 | } |
| 310 | }); | 304 | }); |
| 311 | 305 | ||