From 3bfc33381d5854d0279d7dee7113348b4df56db2 Mon Sep 17 00:00:00 2001 From: Sidach Ruslan Date: Wed, 24 Jun 2026 14:12:37 +0300 Subject: [PATCH] add solution --- src/createServer.js | 142 ++++++++++++++++++++++++++++++++++++++++++- src/index.html | 31 ++++++++++ src/styles/style.css | 17 ++++++ 3 files changed, 188 insertions(+), 2 deletions(-) create mode 100644 src/index.html create mode 100644 src/styles/style.css diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..793f17e 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,146 @@ 'use strict'; +const http = require('http'); +const path = require('path'); +const zlib = require('zlib'); +const fs = require('fs'); +const { IncomingForm } = require('formidable'); +const { pipeline } = require('stream'); + +const compressionTypes = { + gzip: { + createStream: zlib.createGzip, + extension: '.gz', + }, + deflate: { + createStream: zlib.createDeflate, + extension: '.dfl', + }, + br: { + createStream: zlib.createBrotliCompress, + extension: '.br', + }, +}; + +function sendHtml(response) { + const filePath = path.join(__dirname, 'index.html'); + + const stream = fs.createReadStream(filePath); + + stream.pipe(response); +} + +function sendCss(response) { + const filePath = path.join(__dirname, 'styles', 'style.css'); + + response.setHeader('Content-Type', 'text/css'); + + fs.createReadStream(filePath).pipe(response); +} + function createServer() { - /* Write your code here */ - // Return instance of http.Server class + return http.createServer((request, response) => { + const { method, url } = request; + + if (method === 'GET' && url === '/') { + sendHtml(response); + + return; + } + + if (method === 'GET' && url === '/styles/style.css') { + sendCss(response); + + return; + } + + if (method === 'GET' && url === '/compress') { + response.writeHead(400, { + 'Content-Type': 'text/plain; charset=utf-8', + }); + response.end('Bad request'); + + return; + } + + if (method === 'POST' && url === '/compress') { + const form = new IncomingForm({ + multiples: false, + keepExtensions: true, + }); + + form.parse(request, (error, fields, files) => { + if (error) { + response.writeHead(400, { + 'Content-Type': 'text/plain; charset=utf-8', + }); + response.end('Bad request'); + + return; + } + + const compressionType = Array.isArray(fields.compressionType) + ? fields.compressionType[0] + : fields.compressionType; + + if (!Object.hasOwn(compressionTypes, compressionType)) { + response.writeHead(400, { + 'Content-Type': 'text/plain; charset=utf-8', + }); + response.end('Compression type is unsupported'); + + return; + } + + const uploaded = files.file; + + if (!uploaded) { + response.writeHead(400, { + 'Content-Type': 'text/plain; charset=utf-8', + }); + response.end('Request has not file'); + + return; + } + + const file = Array.isArray(uploaded) ? uploaded[0] : uploaded; + + const tempPath = file.filepath; + + const originalName = file.originalFilename || 'file'; + const safeName = + path.basename(originalName) + + compressionTypes[compressionType].extension; + + const encodedName = encodeURIComponent(safeName); + + response.writeHead(200, { + 'Content-Type': 'application/octet-stream', + 'Content-Disposition': `attachment; filename=${encodedName}`, + }); + + pipeline( + fs.createReadStream(tempPath), + compressionTypes[compressionType].createStream(), + response, + (err) => { + fs.unlink(tempPath, () => {}); + + if (err) { + } + }, + ); + }); + + return; + } + + response.writeHead(404, { + 'Content-Type': 'text/plain; charset=utf-8', + }); + + response.end('Non found'); + }); } module.exports = { diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..3d5ea96 --- /dev/null +++ b/src/index.html @@ -0,0 +1,31 @@ + + + + + + + Document + + +
+

Compress file

+
+ + + +
+
+ + diff --git a/src/styles/style.css b/src/styles/style.css new file mode 100644 index 0000000..7968d36 --- /dev/null +++ b/src/styles/style.css @@ -0,0 +1,17 @@ +.label { + display: flex; + flex-direction: column; + gap: 6px; + + & input{ + display: block; + width: fit-content; + margin: 0; + padding: 0; + } +} + +.form { + display: flex; + gap: 20px; +}