Skip to content
Open

task #357

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
107 changes: 105 additions & 2 deletions src/createServer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,111 @@
'use strict';

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

const TEXT_PLAIN = 'text/plain';

function sendText(res, statusCode, body) {
res.writeHead(statusCode, { 'Content-Type': TEXT_PLAIN });
res.end(body);
}

function sendInvalidFilePath(res) {
sendText(res, 400, 'Invalid file path');
}

function sendFileNotFound(res) {
sendText(res, 404, 'File not found');
}

function readTextFile(res, filePath) {
fs.readFile(filePath, (error, data) => {
if (error) {
sendFileNotFound(res);

return;
}

sendText(res, 200, data);
});
}

function decodePathname(requestPath) {
try {
return decodeURIComponent(requestPath);
} catch (error) {
return null;
}
}

function createServer() {
/* Write your code here */
// Return instance of http.Server class
const publicFolderPath = path.resolve(__dirname, '../public');

const server = http.createServer((req, res) => {
const rawUrl = req.url || '';
// Remove query parameters
const requestPath = rawUrl.split('?')[0];
// handle URL-encoded characters
const decodedPathname = decodePathname(requestPath);

if (!decodedPathname) {
sendInvalidFilePath(res);

return;
}

if (rawUrl.includes('..') || decodedPathname.includes('..')) {
sendInvalidFilePath(res);

return;
}

if (decodedPathname === '/file' || decodedPathname === '/file/') {
readTextFile(res, path.resolve(publicFolderPath, 'index.html'));

return;
}

if (!decodedPathname.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 condition doesn't account for the requirement that a request to /file should serve public/index.html. Currently, /file is treated as an invalid path and triggers the hint message.

if (path.extname(decodedPathname)) {
sendInvalidFilePath(res);

return;
}

sendText(res, 200, 'Invalid path. To load files, use: /file/filename');

return;
}

const requestedFile = decodedPathname.replace(/^\/file\//, '');
const pathSegments = requestedFile.split('/');

if (pathSegments.includes('..')) {
sendInvalidFilePath(res);

return;
}

if (pathSegments.some((segment) => segment.length === 0)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Requests to /file/ should serve public/index.html, but this check causes a 404 error instead. When the path is /file/, the requestedFile variable becomes an empty string, which makes this condition true. You should handle this case to serve the default file as required.

sendFileNotFound(res);

return;
}

const filePath = path.resolve(publicFolderPath, requestedFile);

if (!filePath.startsWith(`${publicFolderPath}${path.sep}`)) {
sendInvalidFilePath(res);

return;
}

readTextFile(res, filePath);
});

return server;
}

module.exports = {
Expand Down
Loading