-
Notifications
You must be signed in to change notification settings - Fork 274
add solution #186
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: master
Are you sure you want to change the base?
add solution #186
Changes from all commits
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 |
|---|---|---|
| @@ -1,8 +1,110 @@ | ||
| 'use strict'; | ||
|
|
||
| const http = require('http'); | ||
| const fs = require('fs'); | ||
| const zlib = require('zlib'); | ||
| const formidable = require('formidable'); | ||
|
|
||
| function createServer() { | ||
| /* Write your code here */ | ||
| // Return instance of http.Server class | ||
| return http.createServer((req, res) => { | ||
| if (req.url === '/' && req.method === 'GET') { | ||
| res.writeHead(200, { 'Content-Type': 'text/html' }); | ||
|
|
||
| res.end(` | ||
| <form action="/compress" method="POST" enctype="multipart/form-data"> | ||
| <input type="file" name="file" required /> | ||
| <select name="compressionType" required> | ||
| <option value="gzip">gzip</option> | ||
| <option value="deflate">deflate</option> | ||
| <option value="br">br</option> | ||
| </select> | ||
| <button type="submit">Compress</button> | ||
| </form> | ||
| `); | ||
|
Comment on lines
+13
to
+23
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. The HTML form served at |
||
| } else if (req.url === '/compress' && req.method === 'POST') { | ||
| const form = new formidable.IncomingForm(); | ||
|
|
||
| form.parse(req, (error, fields, files) => { | ||
| if (error) { | ||
| res.statusCode = 400; | ||
|
|
||
| return res.end('Error parsing form'); | ||
| } | ||
|
|
||
| const compressionType = String(fields.compressionType || '') | ||
| .trim() | ||
| .toLowerCase(); | ||
|
|
||
| const supported = ['gzip', 'deflate', 'br']; | ||
|
|
||
| if (!supported.includes(compressionType)) { | ||
| res.statusCode = 400; | ||
|
|
||
| return res.end('Unsupported compression type'); | ||
| } | ||
|
|
||
| const fileData = files.file?.[0]; | ||
|
|
||
| if (!fileData) { | ||
| res.statusCode = 400; | ||
|
|
||
| return res.end('Error parsing file'); | ||
| } | ||
|
|
||
| const uploadedFile = files.file?.[0]; | ||
| const uploadedFilePath = uploadedFile?.filepath; | ||
|
|
||
| const originalNameSafe = uploadedFile.originalFilename || 'file'; | ||
|
Comment on lines
+46
to
+57
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. File extraction: const fileData = files.file; // or files.file[0] only if your formidable version actually returns an array
const uploadedFilePath = fileData && (fileData.filepath || fileData.path);
const originalNameSafe = fileData && (fileData.originalFilename || fileData.originalname || 'file');Then validate
Comment on lines
+46
to
+57
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. Incorrect access to the uploaded file object. You use |
||
|
|
||
| if (!uploadedFilePath) { | ||
| res.statusCode = 400; | ||
|
|
||
| return res.end('File path not found'); | ||
| } | ||
|
|
||
| let compressStream; | ||
|
|
||
| switch (compressionType) { | ||
| case 'gzip': | ||
| compressStream = zlib.createGzip(); | ||
| break; | ||
| case 'deflate': | ||
| compressStream = zlib.createDeflate(); | ||
| break; | ||
| case 'br': | ||
| compressStream = zlib.createBrotliCompress(); | ||
| break; | ||
| } | ||
|
|
||
| const readStream = fs.createReadStream(uploadedFilePath); | ||
|
|
||
| readStream.on('error', () => { | ||
| res.statusCode = 500; | ||
| res.end('Error reading file'); | ||
| }); | ||
|
|
||
| compressStream.on('error', () => { | ||
| res.statusCode = 500; | ||
| res.end('Error compressing file'); | ||
| }); | ||
|
|
||
| res.writeHead(200, { | ||
| 'Content-Type': 'application/octet-stream', | ||
| 'Content-Disposition': `attachment; filename=${originalNameSafe}.${compressionType}`, | ||
|
Comment on lines
+91
to
+93
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. Incorrect output filename extension in |
||
| }); | ||
|
Comment on lines
+91
to
+94
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. Filename extension mapping is incorrect. The response currently appends the raw const extMap = { gzip: 'gz', deflate: 'dfl', br: 'br' };
const ext = extMap[compressionType];
'Content-Disposition': `attachment; filename="${originalNameSafe}.${ext}"`,Update the header so the client receives the correctly named file. |
||
|
|
||
| readStream.pipe(compressStream).pipe(res); | ||
|
Comment on lines
+79
to
+96
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. Use const { pipeline } = require('stream');
res.setHeader('Content-Type', 'application/octet-stream');
res.setHeader('Content-Disposition', `attachment; filename="${originalNameSafe}.${ext}"`);
pipeline(readStream, compressStream, res, (err) => {
if (err) {
// if headers not sent, send 500; otherwise destroy response
if (!res.headersSent) {
res.statusCode = 500;
res.end('Error processing file');
} else {
res.destroy(err);
}
}
});This ensures robust error handling for streams and prevents the server from crashing (required).
Comment on lines
+79
to
+96
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. Fragile stream handling: currently you attach separate error handlers to
This ensures stream errors are handled properly and the server does not incorrectly return 200 on failure, meeting the streams and error-handling requirements. |
||
| }); | ||
| } else if (req.url === '/compress') { | ||
| res.statusCode = 400; | ||
|
|
||
| return res.end('Only POST allowed on /compress'); | ||
| } else { | ||
| res.statusCode = 404; | ||
|
|
||
| return res.end('Not Found'); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| module.exports = { | ||
|
|
||
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.
Positive: the HTML form at
/contains afileinput and aselectnamedcompressionTypewith the exact optionsgzip,deflate,br, and submits via POST to/compress(lines 14–22). That satisfies the front-end checklist items for the form. Keep this as-is.