From 2f13b8be31f587ede2491adfc5582737cffac6c4 Mon Sep 17 00:00:00 2001 From: Alina Luchytska Date: Wed, 18 Mar 2026 20:31:24 +0200 Subject: [PATCH 1/4] ver1 --- src/createServer.js | 82 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..296049f 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,90 @@ 'use strict'; +const http = require('http'); +const zlib = require('node:zlib'); + function createServer() { /* Write your code here */ + const server = http.createServer((req, res) => { + if (req.url === '/' && req.method === 'GET') { + res.writeHead(200, { 'Content-Type': 'text/plain' }); + res.end('hello world'); + } + + if (req.url === '/compress') { + if (req.method === 'GET') { + res.statusCode = 400; + + return res.end('trouble'); + } + + let body = ''; + + req.on('data', (chunk) => { + body += chunk.toString(); + }); + + req.on('end', () => { + const filenameMatch = body.match(/filename="(.+?)"/); + const filename = filenameMatch ? filenameMatch[1] : 'file'; + + if (!filename || !body.includes('name="file"')) { + res.statusCode = 400; + + return res.end(); + } + + let compressionType = null; + + if (body.includes('gzip')) { + compressionType = 'gzip'; + } else if (body.includes('deflate')) { + compressionType = 'deflate'; + } else if (body.includes('br')) { + compressionType = 'br'; + } + + if (!compressionType) { + res.statusCode = 400; + + return res.end(); + } + + let compressor; + let ext; + + if (compressionType === 'gzip') { + compressor = zlib.createGzip(); + ext = '.gzip'; + } else if (compressionType === 'deflate') { + compressor = zlib.createDeflate(); + ext = '.deflate'; + } else if (compressionType === 'br') { + compressor = zlib.createBrotliCompress(); + ext = '.br'; + } + + res.statusCode = 200; + + res.setHeader( + 'Content-Disposition', + `attachment; filename=${filename}${ext}`, + ); + + req.pipe(compressor).pipe(res); + }); + + return; + } + + if (req.method !== 'GET' || req.url !== '/') { + res.statusCode = 404; + res.end('Not Found'); + } + }); + // Return instance of http.Server class + return server; } module.exports = { From 1611b428409ec93b5ce0628cc19811c8b4494819 Mon Sep 17 00:00:00 2001 From: Alina Luchytska Date: Wed, 18 Mar 2026 20:47:03 +0200 Subject: [PATCH 2/4] solution --- src/createServer.js | 35 ++++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index 296049f..93997b2 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -34,14 +34,29 @@ function createServer() { return res.end(); } + const boundaryObj = + req.headers['content-type'] && + req.headers['content-type'].match(/boundary=(.*)/); + const boundary = boundaryObj ? boundaryObj[1] : ''; + const parts = body.split(`--${boundary}`); + let fileContent = ''; let compressionType = null; - if (body.includes('gzip')) { - compressionType = 'gzip'; - } else if (body.includes('deflate')) { - compressionType = 'deflate'; - } else if (body.includes('br')) { - compressionType = 'br'; + for (const part of parts) { + if (part.includes('name="file"')) { + const fileStart = part.indexOf('\r\n\r\n') + 4; + + fileContent = part.substring(fileStart, part.lastIndexOf('\r\n')); + } else if (part.includes('name="compressionType"')) { + const valStart = part.indexOf('\r\n\r\n') + 4; + const parsedType = part + .substring(valStart, part.lastIndexOf('\r\n')) + .trim(); + + if (['gzip', 'deflate', 'br'].includes(parsedType)) { + compressionType = parsedType; + } + } } if (!compressionType) { @@ -71,7 +86,13 @@ function createServer() { `attachment; filename=${filename}${ext}`, ); - req.pipe(compressor).pipe(res); + const { Readable } = require('stream'); + const fileStream = new Readable(); + + fileStream.push(fileContent); + fileStream.push(null); + + fileStream.pipe(compressor).pipe(res); }); return; From 9276c639a791ad8c9ced88f1422a9a07ea36c06f Mon Sep 17 00:00:00 2001 From: Alina Luchytska Date: Thu, 19 Mar 2026 21:53:53 +0200 Subject: [PATCH 3/4] fix part --- src/createServer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/createServer.js b/src/createServer.js index 93997b2..be71d90 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -2,6 +2,7 @@ const http = require('http'); const zlib = require('node:zlib'); +const { Readable } = require('stream'); function createServer() { /* Write your code here */ @@ -86,7 +87,6 @@ function createServer() { `attachment; filename=${filename}${ext}`, ); - const { Readable } = require('stream'); const fileStream = new Readable(); fileStream.push(fileContent); From 6b58a723b3c2bd8a3b761fb48bdab90e853f6421 Mon Sep 17 00:00:00 2001 From: Alina Luchytska Date: Sat, 21 Mar 2026 23:09:33 +0200 Subject: [PATCH 4/4] fix solution --- src/createServer.js | 67 ++++++++++++++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 22 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index be71d90..618087f 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -10,44 +10,59 @@ function createServer() { if (req.url === '/' && req.method === 'GET') { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.end('hello world'); + + return; } if (req.url === '/compress') { - if (req.method === 'GET') { + if (req.method !== 'POST') { res.statusCode = 400; return res.end('trouble'); } - let body = ''; + const contentType = req.headers['content-type'] || ''; + const boundaryMatch = contentType.match(/boundary=(.*)/); + + if (!boundaryMatch) { + res.statusCode = 400; + + return res.end(); + } + + const boundary = boundaryMatch[1]; + + const chunks = []; req.on('data', (chunk) => { - body += chunk.toString(); + chunks.push(chunk); }); req.on('end', () => { - const filenameMatch = body.match(/filename="(.+?)"/); - const filename = filenameMatch ? filenameMatch[1] : 'file'; - - if (!filename || !body.includes('name="file"')) { - res.statusCode = 400; - - return res.end(); - } + const buffer = Buffer.concat(chunks); + const body = buffer.toString('binary'); - const boundaryObj = - req.headers['content-type'] && - req.headers['content-type'].match(/boundary=(.*)/); - const boundary = boundaryObj ? boundaryObj[1] : ''; const parts = body.split(`--${boundary}`); - let fileContent = ''; + + let fileContent = null; + let filename = 'file'; let compressionType = null; for (const part of parts) { if (part.includes('name="file"')) { + const filenameMatch = part.match(/filename="(.+?)"/); + + if (filenameMatch) { + filename = filenameMatch[1]; + } + const fileStart = part.indexOf('\r\n\r\n') + 4; + const fileEnd = part.lastIndexOf('\r\n'); - fileContent = part.substring(fileStart, part.lastIndexOf('\r\n')); + fileContent = Buffer.from( + part.substring(fileStart, fileEnd), + 'binary', + ); } else if (part.includes('name="compressionType"')) { const valStart = part.indexOf('\r\n\r\n') + 4; const parsedType = part @@ -60,6 +75,12 @@ function createServer() { } } + if (fileContent === null || !filename) { + res.statusCode = 400; + + return res.end(); + } + if (!compressionType) { res.statusCode = 400; @@ -95,16 +116,18 @@ function createServer() { fileStream.pipe(compressor).pipe(res); }); + req.on('error', () => { + res.statusCode = 500; + res.end(); + }); + return; } - if (req.method !== 'GET' || req.url !== '/') { - res.statusCode = 404; - res.end('Not Found'); - } + res.statusCode = 404; + res.end('Not Found'); }); - // Return instance of http.Server class return server; }