From f54ca56c24311068097d705b56f79bb63becc464 Mon Sep 17 00:00:00 2001 From: Mykola Sheiko Date: Thu, 2 Apr 2026 13:39:38 +0000 Subject: [PATCH 1/2] task --- public/index.html | 27 ++++++++++++ src/createServer.js | 103 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 public/index.html diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..82942fc --- /dev/null +++ b/public/index.html @@ -0,0 +1,27 @@ + + + + + + File Compression + + +
+
+ + +
+
+ + +
+
+ +
+
+ + diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..de6fe8c 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,107 @@ 'use strict'; +const http = require('http'); +const fs = require('fs'); +const zlib = require('zlib'); +const { IncomingForm } = require('formidable'); + +const SUPPORTED_TYPES = new Set(['gzip', 'deflate', 'br']); + +function getFirstValue(value) { + return Array.isArray(value) ? value[0] : value; +} + +function createCompressionStream(compressionType) { + switch (compressionType) { + case 'gzip': + return zlib.createGzip(); + case 'deflate': + return zlib.createDeflate(); + case 'br': + return zlib.createBrotliCompress(); + default: + return null; + } +} + +function handleCompressRequest(req, res) { + if (req.method !== 'POST') { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad Request'); + + return; + } + + const form = new IncomingForm(); + + form.parse(req, (error, fields, files) => { + if (error) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad Request'); + + return; + } + + const file = getFirstValue(files.file); + const compressionType = getFirstValue(fields.compressionType); + const filename = file?.originalFilename || file?.filename; + + if (!file || !compressionType || !filename) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad Request'); + + return; + } + + if (!SUPPORTED_TYPES.has(compressionType)) { + res.writeHead(400, { 'Content-Type': 'text/plain' }); + res.end('Bad Request'); + + return; + } + + const compressionStream = createCompressionStream(compressionType); + + res.writeHead(200, { + 'Content-Type': 'application/octet-stream', + 'Content-Disposition': `attachment; filename=${filename}.${compressionType}`, + }); + + fs.createReadStream(file.filepath) + .on('error', () => { + res.writeHead(500, { 'Content-Type': 'text/plain' }); + res.end('Internal Server Error'); + }) + .pipe(compressionStream) + .on('error', () => { + res.writeHead(500, { 'Content-Type': 'text/plain' }); + res.end('Internal Server Error'); + }) + .pipe(res); + }); +} + function createServer() { - /* Write your code here */ - // Return instance of http.Server class + const server = http.createServer((req, res) => { + if (req.url === '/') { + const stream = fs.createReadStream('public/index.html'); + + res.writeHead(200, { 'Content-Type': 'text/html' }); + stream.pipe(res); + + stream.on('error', () => { + res.writeHead(500, { 'Content-Type': 'text/plain' }); + res.end('Error reading file'); + }); + } else if (req.url === '/compress') { + handleCompressRequest(req, res); + } else { + res.writeHead(404, { 'Content-Type': 'text/plain' }); + res.end('Not Found'); + } + }); + + return server; } module.exports = { From 81af5e57a75081186908efd82ced46428d945930 Mon Sep 17 00:00:00 2001 From: Mykola Sheiko Date: Thu, 2 Apr 2026 13:44:30 +0000 Subject: [PATCH 2/2] fix --- src/createServer.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/createServer.js b/src/createServer.js index de6fe8c..76ff667 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -7,6 +7,12 @@ const { IncomingForm } = require('formidable'); const SUPPORTED_TYPES = new Set(['gzip', 'deflate', 'br']); +const EXTENSION_MAP = { + gzip: 'gz', + deflate: 'dfl', + br: 'br', +}; + function getFirstValue(value) { return Array.isArray(value) ? value[0] : value; } @@ -64,7 +70,7 @@ function handleCompressRequest(req, res) { res.writeHead(200, { 'Content-Type': 'application/octet-stream', - 'Content-Disposition': `attachment; filename=${filename}.${compressionType}`, + 'Content-Disposition': `attachment; filename=${filename}.${EXTENSION_MAP[compressionType]}`, }); fs.createReadStream(file.filepath)