From 42358a022eecd924810ff9e3c3b4897f6c110c06 Mon Sep 17 00:00:00 2001 From: "tarstarcas@gmail.com" Date: Sat, 11 Apr 2026 17:17:01 +0300 Subject: [PATCH 1/4] solution --- .github/workflows/test.yml-template | 23 +++++++++ package-lock.json | 9 ++-- package.json | 2 +- src/createServer.js | 76 ++++++++++++++++++++++++++++- 4 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 .github/workflows/test.yml-template diff --git a/.github/workflows/test.yml-template b/.github/workflows/test.yml-template new file mode 100644 index 0000000..bb13dfc --- /dev/null +++ b/.github/workflows/test.yml-template @@ -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 diff --git a/package-lock.json b/package-lock.json index e696c03..db0b36a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,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", @@ -1485,10 +1485,11 @@ } }, "node_modules/@mate-academy/scripts": { - "version": "1.8.6", - "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-1.8.6.tgz", - "integrity": "sha512-b4om/whj4G9emyi84ORE3FRZzCRwRIesr8tJHXa8EvJdOaAPDpzcJ8A0sFfMsWH9NUOVmOwkBtOXDu5eZZ00Ig==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@mate-academy/scripts/-/scripts-2.1.3.tgz", + "integrity": "sha512-a07wHTj/1QUK2Aac5zHad+sGw4rIvcNl5lJmJpAD7OxeSbnCdyI6RXUHwXhjF5MaVo9YHrJ0xVahyERS2IIyBQ==", "dev": true, + "license": "MIT", "dependencies": { "@octokit/rest": "^17.11.2", "@types/get-port": "^4.2.0", diff --git a/package.json b/package.json index 73e02a4..d654180 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/src/createServer.js b/src/createServer.js index 1cf1dda..ff854fa 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,80 @@ '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; + + if (rawUrl.includes('//')) { + res.statusCode = 404; + res.setHeader('content-type', 'text/plain'); + res.end('Not found'); + + return; + } + + const urlPath = rawUrl.split('?')[0]; + + if (urlPath.startsWith('/file/')) { + const relativeRaw = urlPath.slice('/file/'.length); + + let relative; + + try { + relative = decodeURIComponent(relativeRaw); + } catch { + res.statusCode = 400; + res.end('Bad request'); + + return; + } + + 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; + res.end(data); + }); + + return; + } + + if (urlPath !== '/file') { + res.statusCode = 400; + res.setHeader('content-type', 'text/plain'); + res.end('Bad request'); + + return; + } + + res.statusCode = 200; + res.setHeader('content-type', 'text/plain'); + res.end('Use /file/ to serve a file from the public folder'); + }); + + return server; } module.exports = { From cb038b892474bb497bed4543f101f459a7497d68 Mon Sep 17 00:00:00 2001 From: "tarstarcas@gmail.com" Date: Sat, 11 Apr 2026 17:33:05 +0300 Subject: [PATCH 2/4] fix --- src/createServer.js | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index ff854fa..ffdffcf 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -7,8 +7,9 @@ const path = require('path'); function createServer() { const server = http.createServer((req, res) => { const rawUrl = req.url; + const urlPath = rawUrl.split('?')[0]; - if (rawUrl.includes('//')) { + if (urlPath.includes('//')) { res.statusCode = 404; res.setHeader('content-type', 'text/plain'); res.end('Not found'); @@ -16,8 +17,6 @@ function createServer() { return; } - const urlPath = rawUrl.split('?')[0]; - if (urlPath.startsWith('/file/')) { const relativeRaw = urlPath.slice('/file/'.length); @@ -27,11 +26,18 @@ function createServer() { relative = decodeURIComponent(relativeRaw); } catch { res.statusCode = 400; + res.setHeader('content-type', 'text/plain'); res.end('Bad request'); 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); @@ -55,6 +61,15 @@ function createServer() { } 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); }); @@ -69,6 +84,14 @@ function createServer() { return; } + if (path.extname(urlPath)) { + res.statusCode = 400; + res.setHeader('content-type', 'text/plain'); + res.end('Bad request'); + + return; + } + res.statusCode = 200; res.setHeader('content-type', 'text/plain'); res.end('Use /file/ to serve a file from the public folder'); From 6b3fde13e35e6060363c5a2d4461986626d6b479 Mon Sep 17 00:00:00 2001 From: "tarstarcas@gmail.com" Date: Sat, 11 Apr 2026 18:46:18 +0300 Subject: [PATCH 3/4] fix --- src/createServer.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/src/createServer.js b/src/createServer.js index ffdffcf..c46acad 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -76,22 +76,6 @@ function createServer() { return; } - if (urlPath !== '/file') { - res.statusCode = 400; - res.setHeader('content-type', 'text/plain'); - res.end('Bad request'); - - return; - } - - if (path.extname(urlPath)) { - res.statusCode = 400; - res.setHeader('content-type', 'text/plain'); - res.end('Bad request'); - - return; - } - res.statusCode = 200; res.setHeader('content-type', 'text/plain'); res.end('Use /file/ to serve a file from the public folder'); From 6cb5ff9bba6bbf0081c45d9c561b0af7da6a7692 Mon Sep 17 00:00:00 2001 From: "tarstarcas@gmail.com" Date: Sat, 11 Apr 2026 19:06:28 +0300 Subject: [PATCH 4/4] fix --- src/createServer.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/createServer.js b/src/createServer.js index c46acad..f371e33 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -76,6 +76,14 @@ function createServer() { return; } + if (urlPath !== '/file') { + res.statusCode = 400; + res.setHeader('content-type', 'text/plain'); + res.end('Bad request'); + + return; + } + res.statusCode = 200; res.setHeader('content-type', 'text/plain'); res.end('Use /file/ to serve a file from the public folder');