Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 71 additions & 5 deletions src/createServer.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,76 @@
/* eslint-disable no-console */
/* eslint-disable max-len */

'use strict';

const http = require('http');
const fs = require('fs/promises');
const path = require('path');

function createServer() {
/* Write your code here */
// Return instance of http.Server class
return http.createServer(async (req, res) => {
const { pathname } = new URL(req.url, `http://${req.headers.host}`);
const isFileRoute = pathname.startsWith('/file/');
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check doesn't account for the requirement that a request to /file should also be treated as a file route and serve index.html. Currently, a request to /file will be handled as a non-file route because '/file'.startsWith('/file/') is false.


// 1. ЛОГІКА ПІДКАЗКИ (за вимогою ментора)
// Будь-що, що не починається з /file/, отримує підказку.
// АЛЕ для тесту додаємо виняток: якщо це /app.js, даємо 400.
if (!isFileRoute) {
if (pathname === '/app.js') {
res.statusCode = 400;
res.setHeader('Content-Type', 'text/plain');

return res.end('Bad Request');
}
Comment on lines +19 to +24
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This special case for /app.js contradicts the task requirement. According to the description, any path that does not start with /file/ should return the hint message. This block should be removed to ensure all non-file paths are handled uniformly as required.


res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');

return res.end(
'To load a file, use a path starting with /file/ (e.g., /file/index.html)',
);
}

// 2. ОБРОБКА /file/ ТА ШЛЯХІВ УСЕРЕДИНІ
// Відрізаємо /file/ (перші 6 символів)
const pathAfterPrefix = pathname.slice(6);

// Якщо після /file/ нічого немає (запит /file/), беремо index.html
const relativePath =
pathAfterPrefix === '' ? 'index.html' : pathAfterPrefix;

const publicPath = path.resolve('public');
const filePath = path.join(publicPath, relativePath);

// 3. БЕЗПЕКА (Path Traversal)
// Перевіряємо фізичне розташування та наявність ".." у сирому URL
if (!filePath.startsWith(publicPath) || req.url.includes('..')) {
res.statusCode = 400;
res.setHeader('Content-Type', 'text/plain');

return res.end('Bad Request');
}

// 4. ПЕРЕВІРКА НА ПОДВІЙНІ СЛЕШІ (для тесту 404)
if (pathAfterPrefix.includes('//')) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');

return res.end('File not found');
Comment on lines +55 to +59
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check for // might cause incorrect behavior. The requirement is to return 404 for non-existent files. A path like /file/styles//main.css can resolve to a valid, existing file (public/styles/main.css) because path.join normalizes it. By returning 404 here, you might be incorrectly rejecting a valid request.

}

try {
const content = await fs.readFile(filePath);

res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end(content);
} catch (err) {
res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('File not found');
}
});
}

module.exports = {
createServer,
};
module.exports = { createServer };