Skip to content
Open
Show file tree
Hide file tree
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
23 changes: 23 additions & 0 deletions .github/workflows/test.yml-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Test

on:
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [20.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"devDependencies": {
"@faker-js/faker": "^8.4.1",
"@mate-academy/eslint-config": "latest",
"@mate-academy/scripts": "^1.8.6",
"@mate-academy/scripts": "^2.1.3",
"axios": "^1.7.2",
"eslint": "^8.57.0",
"eslint-plugin-jest": "^28.6.0",
Expand Down
91 changes: 89 additions & 2 deletions src/createServer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,95 @@
'use strict';

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

function createServer() {
/* Write your code here */
// Return instance of http.Server class
const server = http.createServer((req, res) => {
const rawUrl = req.url;
const urlPath = rawUrl.split('?')[0];

if (urlPath.includes('//')) {
res.statusCode = 404;
res.setHeader('content-type', 'text/plain');
res.end('Not found');

return;
}

if (urlPath.startsWith('/file/')) {
const relativeRaw = urlPath.slice('/file/'.length);

let relative;

try {
relative = decodeURIComponent(relativeRaw);
Comment on lines +21 to +26
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

When the request is /file/ the relativeRaw will be an empty string; per requirements you must return public/index.html. Right now the code will try to read the directory (and likely return 404). Detect an empty relative (or a trailing /) and use index.html as the target file.

} catch {
res.statusCode = 400;
res.setHeader('content-type', 'text/plain');
res.end('Bad request');
Comment on lines +27 to +30
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

In the decodeURIComponent catch you set res.statusCode = 400 but do not set a Content-Type header. All error responses must use text/plain, so set content-type: text/plain before res.end here.


return;
}

if (relative === '') {
relative = 'index.html';
} else if (relative.endsWith('/')) {
relative = `${relative}index.html`;
}

const publicDir = path.resolve(__dirname, '../public');
const filePath = path.resolve(publicDir, relative);

const relativePath = path.relative(publicDir, filePath);

if (relativePath.startsWith('..') || path.isAbsolute(relativePath)) {
res.statusCode = 400;
res.setHeader('content-type', 'text/plain');
res.end('Bad request');

return;
}

fs.readFile(filePath, (err, data) => {
if (err) {
res.statusCode = 404;
res.setHeader('content-type', 'text/plain');
res.end('Not found');

return;
}

res.statusCode = 200;

const extension = path.extname(filePath);

if (extension === '.html') {
res.setHeader('content-type', 'text/html');
} else if (extension === '.css') {
res.setHeader('content-type', 'text/css');
}

res.end(data);
Comment on lines +63 to +73
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On successful file reads you set statusCode = 200 but never set Content-Type. The spec requires .html -> text/html and .css -> text/css. Determine the file extension (e.g. with path.extname(filePath)) and set the appropriate content-type header before res.end(data).

});

return;
}

if (urlPath !== '/file') {
res.statusCode = 400;
res.setHeader('content-type', 'text/plain');
res.end('Bad request');

return;
Comment on lines +79 to +84
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 branch handles requests not equal to /file by returning 400 Bad request. The specification requires that requests whose pathname does not start with /file/ (for example /anything) return a hint message (with text/plain). Adjust the logic so non-/file/ paths return the hint message, and keep /file itself returning the hint as implemented below.

Comment on lines +79 to +84
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 block returns 400 Bad Request for any pathname that is not exactly /file. That makes requests like /anything return 400, which violates the requirements — non-/file/ paths (and /file) should return the hint message with status 200 and Content-Type: text/plain. Change the logic so only paths that start with /file/ go into the file-serving branch; everything else should short-circuit to the hint response.

}
Comment on lines +78 to +85
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 block returns a 400 for any request whose pathname is not exactly /file. According to the spec, any pathname that does NOT start with /file/ (for example /anything) should return the hint message with Content-Type: text/plain (not a 400). You should change the logic so that only requests starting with /file/ go to the file-serving branch; all other paths (including /anything) should return the hint. Keep the existing behavior for /file which should also return the hint.


res.statusCode = 200;
res.setHeader('content-type', 'text/plain');
res.end('Use /file/<filename> to serve a file from the public folder');
});

return server;
}

module.exports = {
Expand Down
Loading