Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js http server + image

So, I am making a website with Node.js, and am using an http server. I am trying to serve an image with it. The image is definitely shown, but only the very top part of it. Here is the image, what happens, and the server code (in that order).enter image description here

enter image description here

const server = http.createServer((req, res) => {
// get the file path from req.url, or '/public/index.html' if req.url is '/'
const filePath = ( req.url === '/' ) ? '/public/index.html' : req.url;

// determine the contentType by the file extension
const extname = path.extname(filePath);
let contentType = 'text/html';
if (extname === '.js') contentType = 'text/javascript';
else if (extname === '.css') contentType = 'text/css';
else if(extname === (".png")) {
    var imagePath = path.join(__dirname, '/', req.url);
    var fileStream = fs.createReadStream(imagePath);
    res.writeHead(200, {"Content-Type": "image/png"});
    fileStream.pipe(res);
}

// pipe the proper file to the res object
res.writeHead(200, { 'Content-Type': contentType });
fs.createReadStream(`${__dirname}/${filePath}`, 'utf8').pipe(res);
});

Also, I am using websocket, if that helps.

like image 884
Awesome Name Avatar asked Sep 01 '25 10:09

Awesome Name


1 Answers

If your image is a PNG, then you attempt to call res.writeHead(...) twice and you attempt to .pipe(res) twice. That will definitely cause a problem.

It seems like you don't need a whole code separate path to .pipe() for png files and could do this:

const server = http.createServer((req, res) => {
    // get the file path from req.url, or '/public/index.html' if req.url is '/'
    const filePath = (req.url === '/') ? '/public/index.html' : req.url;

    // determine the contentType by the file extension
    const extname = path.extname(filePath);
    let contentType = 'text/html';
    if (extname === '.js') {
        contentType = 'text/javascript';
    } else if (extname === '.css') {
        contentType = 'text/css';
    } else if (extname === '.png') {
        contentType = 'image/png';
    }

    // pipe the proper file to the res object
    res.writeHead(200, { 'Content-Type': contentType });
    fs.createReadStream(`${__dirname}/public/${filePath}`).pipe(res);
});

Also, note that your code has a bad security vulnerability (which I have patched in my code example above). Your code allows an attacker to read any file in your __dirname directory (including all your server files) by simply appending that file to the URL. You should never allow this. Publicly served files that are looked up by matching URL to filename like this should only ever be served from a directory that is devoted ONLY to publicly available files. Usually, one would create a public directory and serve files only from that directory hierarchy. Note, I changed the code from this:

${__dirname}/${filePath}

to this:

${__dirname}/public/${filePath}

And, you would need to move the publicly available files that you intend to match with this code into that sub-directory and make sure that sub-directory contains ONLY files freely available to the public.


Also note that the very simple Express framework for creating a web server in nodejs has express.static() which already does all this for you. You just create a directory of publicly available files (of any common file type), put one line of middleware in your Express setup that points at that directory of files and it will automatically serve any of those files when requested by a URL that matches the leaf part of the filename. It automatically handles content-type setting, automatically looks for index.html for / requests, automatically strips .. requests from the URL, and so on and is well scrutinized for security issues.

Other than for learning/academic reasons, most people don't make a web serve from scratch in nodejs, but start with one of the very helpful and simple frameworks such as Express or nextjs because they have pre-built, pre-tested code for many of the simple things you want to do in a web server.

like image 93
jfriend00 Avatar answered Sep 04 '25 01:09

jfriend00