In this article, we will build a static file web server which will list out all the files in the directory and on clicking the file name it displays the file content. Steps for creating a static file server is as follows:
- Step 1: Importing necessary modules, and defining MIME types which helps browser to understand the type of file that is being sent.
Javascript
// Importing necessary modules const http = require( 'http' );
const url = require( 'url' );
const fs = require( 'fs' );
const path = require( 'path' );
// Port on which the server will create const PORT = 1800; // Maps file extension to MIME types which // helps the browser to understand what to // do with the file const mimeType = { '.ico' : 'image/x-icon' ,
'.html' : 'text/html' ,
'.js' : 'text/javascript' ,
'.json' : 'application/json' ,
'.css' : 'text/css' ,
'.png' : 'image/png' ,
'.jpg' : 'image/jpeg' ,
'.wav' : 'audio/wav' ,
'.mp3' : 'audio/mpeg' ,
'.svg' : 'image/svg+xml' ,
'.pdf' : 'application/pdf' ,
'.doc' : 'application/msword' ,
'.eot' : 'application/vnd.ms-fontobject' ,
'.ttf' : 'application/font-sfnt'
}; |
- Step 2: Creating a server at the port specified (say 1800).
Javascript
// Creating a server and listening the port 1800 http.createServer( (req, res) => { }).listen(PORT); |
- Step 3: We will respond the URL “/” to list all the files in the directory. We will limit this article to the current working directory only. Add the below code to the server’s function call.
Javascript
// Parsing the requested URL const parsedUrl = url.parse(req.url); // If requested url is "/" like "http://localhost:8100/" if (parsedUrl.pathname=== "/" ) {
var filesLink= "<ul>" ;
res.setHeader( 'Content-type' , 'text/html' );
var filesList=fs.readdirSync( "./" );
filesList.forEach(element => {
if (fs.statSync( "./" +element).isFile()) {
filesLink +=`<br/><li><a href= './${element}' >
${element}
</a></li>` ;
}
});
filesLink+= "</ul>" ;
res.end( "<h1>List of files:</h1> " + filesLink);
} |
- Step 4: Preprocessing the requested file pathname to avoid directory traversal (like http://localhost:1800/../fileOutofContext.txt) by replacing ‘../’ with ‘ ’.
Javascript
/* processing the requested file pathname to avoid directory traversal like, by limiting to the current directory only */ const sanitizePath = path.normalize(parsedUrl.pathname).replace(/^(\.\.[\/\\])+/, '' );
let pathname = path.join(__dirname, sanitizePath); |
- Step 5: Finally, check whether the file exists. If exists then send the file with the proper header ‘Content-type’ having value as per the file extension mapped with the MIME type above. Else if not exist then send File not found! with 404 status code.
Javascript
if (!fs.existsSync(pathname)) {
// If the file is not found, return 404
res.statusCode = 404;
res.end(`File ${pathname} not found!`);
} else {
// Read file from file system limit to the
// current directory only.
fs.readFile(pathname, function (err, data) {
if (err) {
res.statusCode = 500;
res.end(`Error in getting the file.`);
}
else {
// Based on the URL path, extract the file
// extension. Ex .js, .doc, ...
const ext = path.parse(pathname).ext;
// If the file is found, set Content-type
// and send data
res.setHeader( 'Content-type' ,
mimeType[ext] || 'text/plain' );
res.end(data);
}
});
} |
Complete Code:
Javascript
/* Node.js static file web server */ // Importing necessary modules const http = require( 'http' );
const url = require( 'url' );
const fs = require( 'fs' );
const path = require( 'path' );
// Port on which the server will create const PORT = 1800; // Maps file extension to MIME types which // helps browser to understand what to do // with the file const mimeType = { '.ico' : 'image/x-icon' ,
'.html' : 'text/html' ,
'.js' : 'text/javascript' ,
'.json' : 'application/json' ,
'.css' : 'text/css' ,
'.png' : 'image/png' ,
'.jpg' : 'image/jpeg' ,
'.wav' : 'audio/wav' ,
'.mp3' : 'audio/mpeg' ,
'.svg' : 'image/svg+xml' ,
'.pdf' : 'application/pdf' ,
'.doc' : 'application/msword' ,
'.eot' : 'application/vnd.ms-fontobject' ,
'.ttf' : 'application/font-sfnt'
}; // Creating a server and listening at port 1800 http.createServer( (req, res) => { // Parsing the requested URL
const parsedUrl = url.parse(req.url);
// If requested url is "/" like "http://localhost:1800/"
if (parsedUrl.pathname=== "/" ){
var filesLink= "<ul>" ;
res.setHeader( 'Content-type' , 'text/html' );
var filesList=fs.readdirSync( "./" );
filesList.forEach(element => {
if (fs.statSync( "./" +element).isFile()){
filesLink+=`<br/><li><a href= './${element}' >
${element}
</a></li>` ;
}
});
filesLink+= "</ul>" ;
res.end( "<h1>List of files:</h1> " + filesLink);
}
/* Processing the requested file pathname to
avoid directory traversal like,
by limiting to the current directory only. */
const sanitizePath =
path.normalize(parsedUrl.pathname).replace(/^(\.\.[\/\\])+/, '' );
let pathname = path.join(__dirname, sanitizePath);
if (!fs.existsSync(pathname)) {
// If the file is not found, return 404
res.statusCode = 404;
res.end(`File ${pathname} not found!`);
}
else {
// Read file from file system limit to
// the current directory only.
fs.readFile(pathname, function (err, data) {
if (err){
res.statusCode = 500;
res.end(`Error in getting the file.`);
}
else {
// Based on the URL path, extract the
// file extension. Ex .js, .doc, ...
const ext = path.parse(pathname).ext;
// If the file is found, set Content-type
// and send data
res.setHeader( 'Content-type' ,
mimeType[ext] || 'text/plain' );
res.end(data);
}
});
}
}).listen(PORT); console.log(`Server listening on port ${PORT}`); |
Output
Article Tags :