From 019518817974b90c47cb787a231f08aadf026f4f Mon Sep 17 00:00:00 2001 From: Olga Berezhna <57196165+oberezhnay@users.noreply.github.com> Date: Tue, 6 Jan 2026 21:35:22 +0200 Subject: [PATCH 1/4] Solution --- src/createServer.js | 127 +++++++++++++++++++++++++++++++++++++++++++- src/index.html | 24 +++++++++ 2 files changed, 149 insertions(+), 2 deletions(-) create mode 100644 src/index.html diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..7c8c7ac 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,131 @@ 'use strict'; +const http = require('http'); +const fs = require('fs'); +const path = require('path'); +const { pipeline, Readable } = require('stream'); +const zlib = require('zlib'); + +const COMPRESSION_TYPES = ['gzip', 'deflate', 'br']; + +function sendStatus(res, code) { + if (!res.headersSent) { + res.writeHead(code); + res.end(); + } +} + function createServer() { - /* Write your code here */ - // Return instance of http.Server class + return http.createServer((req, res) => { + const { url, method, headers } = req; + + if (url === '/' && method === 'GET') { + const htmlPath = path.join(__dirname, 'index.html'); + const readStream = fs.createReadStream(htmlPath, 'utf-8'); + + res.writeHead(200, { 'Content-Type': 'text/html' }); + + pipeline(readStream, res, (err) => { + if (err) { + sendStatus(res, 500); + } + }); + + return; + } + + if (method === 'GET' && url === '/compress') { + sendStatus(res, 400); + + return; + } + + if (method === 'POST' && url === '/compress') { + const contentType = headers['content-type']; + + if (!contentType || !contentType.includes('multipart/form-data')) { + res.statusCode = 400; + + return; + } + + const boundary = '--' + contentType.split('boundary=')[1]; + + let body = Buffer.alloc(0); + + req.on('data', (chunk) => { + body = Buffer.concat([body, chunk]); + }); + + req.on('end', () => { + const parts = body.toString('binary').split(boundary); + + let fileBuffer; + let fileName; + let compressionType; + + for (const part of parts) { + if (part.includes('name="compressionType"')) { + compressionType = part.split('\r\n\r\n')[1]?.trim(); + } + + if (part.includes('name="file"')) { + const match = part.match(/filename="(.+?)"/); + + if (match) { + fileName = match[1]; + + const fileContent = part.split('\r\n\r\n')[1]; + + fileBuffer = Buffer.from( + fileContent.slice(0, fileContent.lastIndexOf('\r\n')), + 'binary', + ); + } + } + } + + if (!fileBuffer || !fileName || !compressionType) { + return sendStatus(res, 400); + } + + if (!COMPRESSION_TYPES.includes(compressionType)) { + return sendStatus(res, 400); + } + + let compressor; + let extension; + + if (compressionType === 'gzip') { + compressor = zlib.createGzip(); + extension = '.gzip'; + } + + if (compressionType === 'deflate') { + compressor = zlib.createDeflate(); + extension = '.deflate'; + } + + if (compressionType === 'br') { + compressor = zlib.createBrotliCompress(); + extension = '.br'; + } + + res.writeHead(200, { + 'Content-Disposition': `attachment; filename=${fileName}${extension}`, + 'Content-Type': 'application/octet-stream', + }); + + pipeline(Readable.from(fileBuffer), compressor, res, () => {}); + + }); + + return; + } + + res.statusCode = 404; + res.end('Not Found'); + }); } module.exports = { diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..7d3bfe3 --- /dev/null +++ b/src/index.html @@ -0,0 +1,24 @@ + + + + + + Document + + +
+ + + + + +
+ + + + + From 73b9c58a071bf0f86b05cf451e7881b2c50995f2 Mon Sep 17 00:00:00 2001 From: Olga Berezhna <57196165+oberezhnay@users.noreply.github.com> Date: Tue, 6 Jan 2026 21:51:42 +0200 Subject: [PATCH 2/4] add fixes after review --- src/createServer.js | 5 +---- src/index.html | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 7c8c7ac..2c856fc 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -44,9 +44,7 @@ function createServer() { const contentType = headers['content-type']; if (!contentType || !contentType.includes('multipart/form-data')) { - res.statusCode = 400; - - return; + return sendStatus(res, 400); } const boundary = '--' + contentType.split('boundary=')[1]; @@ -117,7 +115,6 @@ function createServer() { }); pipeline(Readable.from(fileBuffer), compressor, res, () => {}); - }); return; diff --git a/src/index.html b/src/index.html index 7d3bfe3..e9e6127 100644 --- a/src/index.html +++ b/src/index.html @@ -6,11 +6,11 @@ Document -
+
- + - +