Conversation
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
I am requesting changes as there are a few critical issues that prevent the server from functioning correctly. You've done a great job setting up the server structure and using streams, but some key logic needs adjustment.
Here are the main points to address:
- Race Condition: The
fs.createReadStreamcall runs beforefs.renamefinishes, causing an error. All logic that depends on the renamed file needs to be moved inside the callback forfs.rename. - Server Crashes: In your error handling blocks, you call
res.end()but don'treturn. This causes the code to continue executing, leading to a server crash. Please add areturnafter eachres.end()in these paths. - Incorrect Filename: The server expects the file input field to be named
filePicker, but the requirements specifyfile. - Incorrect Output Naming: The compressed file's name is being altered incorrectly (e.g.,
file.txtbecomesfile-txt.gzip). The requirement is to append the correct extension (like.gz) to the original filename, resulting infile.txt.gz.
Fixing these issues will get your project working as required. Keep up the great work!
✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨
Important
Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.
Tip
If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.
Caution
Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.
Footnotes
src/createServer.js
Outdated
|
|
||
| const compressionType = fields.compressionType[0]; | ||
|
|
||
| const uploadedFile = files.filePicker[0]; |
There was a problem hiding this comment.
The requirements state that the file input field should have the name file. The code is currently looking for filePicker, which will prevent it from finding the uploaded file in the form data.
| // double sanity for non-valid input | ||
| if (!compressionType || !uploadedFile) { | ||
| res.statusCode = 400; | ||
| res.end('Invalid input!'); |
There was a problem hiding this comment.
After sending a response with res.end(), you should add a return statement. Without it, the code will continue executing and attempt to access properties of uploadedFile (on line 109), which could be undefined here, causing the server to crash.
| uploadedFile.originalFilename, | ||
| ); | ||
|
|
||
| fs.rename(uploadedFile.filepath, correctUploadedFilePath, (_err) => { |
There was a problem hiding this comment.
fs.rename is an asynchronous function. The code on the next line (fs.createReadStream) will execute immediately without waiting for the rename operation to finish, leading to a race condition and likely a 'file not found' error. All the logic that depends on the renamed file (from line 119 onwards) should be placed inside the callback function of fs.rename to ensure it runs only after the file has been successfully renamed.
src/createServer.js
Outdated
| const zippedFilePath = | ||
| path | ||
| .basename(correctUploadedFilePath) | ||
| .replaceAll(' ', '-') | ||
| .replaceAll(',', '-') | ||
| .replaceAll('.', '-') + '.gzip'; |
There was a problem hiding this comment.
The requirements specify that the compressed filename should be the original filename with the new extension appended (e.g., file.txt becomes file.txt.gz).
This implementation incorrectly alters the original filename by using .replaceAll('.', '-'), which would turn file.txt into file-txt. Additionally, the required extension for gzip is .gz, but the code uses .gzip. This issue with replacing dots also affects the 'deflate' and 'br' cases.
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
Great job addressing the race condition from the previous review! The code is much more robust now. However, this requires a few changes to address some critical issues that are preventing the server from working correctly.
The most important issue is with the stream handling logic. Response headers (like res.statusCode = 200 and res.setHeader) must be set before you call pipeline(). Otherwise, the server will crash. The pipeline function handles ending the response on its own, so you should remove res.end() from its callback.
Additionally, please make these two adjustments to meet the requirements:
- The server should expect the uploaded file in
files.file, notfiles.filePicker. - The file extension for
gzipcompression needs to be.gzinstead of.gzip.
Once these are fixed, you'll be all set. Keep up the great work!
✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨
Important
Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.
Tip
If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.
Caution
Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.
Footnotes
src/createServer.js
Outdated
|
|
||
| const compressionType = fields.compressionType[0]; | ||
|
|
||
| const uploadedFile = files.filePicker[0]; |
There was a problem hiding this comment.
According to the task description, the file input field should have the name attribute set to file. The server should therefore expect the uploaded file data in files.file, not files.filePicker. This requirement was also mentioned in the previous review.
src/createServer.js
Outdated
| // ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION | ||
|
|
||
| const zippedFilePath = | ||
| path.basename(correctUploadedFilePath) + '.gzip'; |
There was a problem hiding this comment.
The task requirements specify that the extension for gzip compression should be .gz. The current code uses .gzip, which is incorrect.
src/createServer.js
Outdated
| pipeline(readStream, gzip, res, (error) => { | ||
| res.statusCode = 500; | ||
| res.end(`Error while piping: ${error}`); | ||
| }); | ||
|
|
||
| // and if everything is OK, let's finalize | ||
| // our Response with all needed headers | ||
| res.statusCode = 200; | ||
|
|
||
| res.setHeader( | ||
| 'Content-Disposition', | ||
| `attachment; filename=${zippedFilePath}`, | ||
| ); | ||
| res.setHeader('Content-Type', mimeType); | ||
| res.setHeader('Content-Encoding', 'gzip'); |
There was a problem hiding this comment.
This block has a critical logic error. Response headers (like status code and content-disposition) must be set before the pipeline starts sending the file. Please move all res.setHeader() calls and res.statusCode = 200 to be before the pipeline() call.
Additionally, the pipeline callback is misused. When pipeline finishes successfully, it has already ended the response stream (res). Calling res.end() again in the callback will crash the server. This callback should primarily be used for logging or cleanup, not for sending response data.
This same logic error is present in the deflate and br blocks as well.
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
Excellent work getting so close to the final solution! I am approving this submission as an educational override to help you move forward, as there is one critical issue remaining.
The main thing to fix is the logic inside your pipeline callbacks. Currently, you are trying to modify the response (e.g., res.statusCode = 500 or res.end()) within the callback. This will cause the server to crash because the pipeline function automatically handles ending the response stream, both on success and on error. The callback's purpose is for server-side actions like logging, not for sending data to the client. This issue occurs for all three compression types.
Also, a minor suggestion: one of your variables holding a Brotli stream is named deflate, which could be confusing. Renaming it would improve clarity. You've done a fantastic job addressing the previous feedback!
✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨
Footnotes
| pipeline(readStream, gzip, res, (error) => { | ||
| res.statusCode = 500; | ||
| res.end(`Error while piping: ${error}`); | ||
| }); |
There was a problem hiding this comment.
The logic inside this pipeline callback will cause the server to crash.
- If the pipeline succeeds,
pipelineautomatically ends the response (res). Callingres.end()again will cause a 'write after end' error. - If the pipeline fails, headers have already been sent with status 200. Trying to set
res.statusCode = 500will cause a 'Cannot set headers' error.
The callback's purpose here is for logging or cleanup, not for modifying the response. Please remove the code that changes the response from this callback.
| pipeline(readStream, deflate, res, (error) => { | ||
| res.statusCode = 500; | ||
| res.end(`Error while piping: ${error}`); | ||
| }); |
There was a problem hiding this comment.
This pipeline callback has the same issue as the one in the 'gzip' case. The response stream is managed by pipeline itself, and you should not attempt to modify the response or call res.end() here. Doing so will cause the server to crash.
| } | ||
|
|
||
| case 'br': { | ||
| const deflate = zlib.createBrotliCompress(); |
There was a problem hiding this comment.
This variable holds a Brotli compression stream from zlib.createBrotliCompress(), but it's named deflate. This is a bit confusing. It's better to name it something that reflects its actual type, like brotliStream or compressStream, to make the code easier to understand.
| pipeline(readStream, deflate, res, (error) => { | ||
| res.statusCode = 500; | ||
| res.end(`Error while piping: ${error}`); | ||
| }); |
There was a problem hiding this comment.
Similar to the other compression types, this pipeline callback will cause a crash. Please remove the code that modifies the response from this callback, as pipeline already handles stream termination correctly.
No description provided.