diff --git a/src/createServer.js b/src/createServer.js
index 1cf1dda..67a52ca 100644
--- a/src/createServer.js
+++ b/src/createServer.js
@@ -1,10 +1,183 @@
'use strict';
+const http = require('http');
+const zlib = require('zlib');
+const { Readable } = require('stream');
+
+const COMPRESSION_TYPES = {
+ gzip: { create: () => zlib.createGzip(), extension: 'gz' },
+ deflate: { create: () => zlib.createDeflate(), extension: 'dfl' },
+ br: { create: () => zlib.createBrotliCompress(), extension: 'br' },
+};
+
+const FORM_HTML = `
+
+
File Compressor
+
+ File Compressor
+
+
+`;
+
+function sendError(res, status, message) {
+ res.statusCode = status;
+ res.setHeader('Content-Type', 'text/plain');
+ res.end(message);
+}
+
+function getBoundary(contentType) {
+ const match = contentType.match(/boundary=(.+)$/);
+
+ return match ? match[1] : null;
+}
+
+function parseMultipart(buffer, boundary) {
+ const fields = {};
+ const sep = Buffer.from('--' + boundary);
+ const parts = [];
+
+ let start = 0;
+
+ while (start < buffer.length) {
+ const sepIdx = buffer.indexOf(sep, start);
+
+ if (sepIdx === -1) {
+ break;
+ }
+
+ const afterSep = sepIdx + sep.length;
+
+ if (buffer[afterSep] === 45 && buffer[afterSep + 1] === 45) {
+ break;
+ }
+
+ const headerStart = afterSep + 2;
+ const headerEnd = buffer.indexOf(Buffer.from('\r\n\r\n'), headerStart);
+
+ if (headerEnd === -1) {
+ break;
+ }
+
+ const headerStr = buffer.slice(headerStart, headerEnd).toString();
+ const bodyStart = headerEnd + 4;
+ const nextSep = buffer.indexOf(sep, bodyStart);
+ const bodyEnd = nextSep - 2;
+ const body = buffer.slice(bodyStart, bodyEnd);
+
+ parts.push({ headers: headerStr, body });
+ start = nextSep;
+ }
+
+ for (const part of parts) {
+ const nameMatch = part.headers.match(/name="([^"]+)"/);
+ const filenameMatch = part.headers.match(/filename="([^"]+)"/);
+
+ if (!nameMatch) {
+ continue;
+ }
+
+ const name = nameMatch[1];
+
+ if (filenameMatch) {
+ fields[name] = { filename: filenameMatch[1], data: part.body };
+ } else {
+ fields[name] = part.body.toString();
+ }
+ }
+
+ return fields;
+}
+
+function handleCompress(req, res) {
+ const contentType = req.headers['content-type'] || '';
+ const boundary = getBoundary(contentType);
+
+ if (!boundary) {
+ return sendError(res, 400, 'Bad Request: multipart/form-data required.');
+ }
+
+ const chunks = [];
+
+ req.on('data', (chunk) => chunks.push(chunk));
+
+ req.on('end', () => {
+ const buffer = Buffer.concat(chunks);
+ const fields = parseMultipart(buffer, boundary);
+
+ const file = fields['file'];
+ const compressionType = fields['compressionType'];
+
+ if (!file || !file.filename) {
+ return sendError(res, 400, 'Bad Request: file is required.');
+ }
+
+ if (!compressionType) {
+ return sendError(res, 400, 'Bad Request: compressionType is required.');
+ }
+
+ const compression = COMPRESSION_TYPES[compressionType];
+
+ if (!compression) {
+ return sendError(
+ res,
+ 400,
+ `Bad Request: unsupported compression type "${compressionType}".`,
+ );
+ }
+
+ const outputFilename = `${file.filename}.${compression.extension}`;
+
+ res.statusCode = 200;
+
+ res.setHeader(
+ 'Content-Disposition',
+ `attachment; filename=${outputFilename}`,
+ );
+ res.setHeader('Content-Type', 'application/octet-stream');
+
+ const readable = new Readable();
+
+ readable.push(file.data);
+ readable.push(null);
+
+ readable.pipe(compression.create()).pipe(res);
+ });
+
+ req.on('error', () => sendError(res, 400, 'Bad Request: stream error.'));
+}
+
function createServer() {
- /* Write your code here */
- // Return instance of http.Server class
+ return http.createServer((req, res) => {
+ const { method, url } = req;
+
+ if (method === 'GET' && url === '/') {
+ res.statusCode = 200;
+ res.setHeader('Content-Type', 'text/html');
+ res.end(FORM_HTML);
+
+ return;
+ }
+
+ if (url === '/compress') {
+ if (method !== 'POST') {
+ return sendError(res, 400, 'Bad Request: use POST method.');
+ }
+
+ return handleCompress(req, res);
+ }
+
+ sendError(res, 404, 'Not Found');
+ });
}
-module.exports = {
- createServer,
-};
+module.exports = { createServer };