2011년 7월 8일 금요일

[node.js] Static File Serving

Node.JS로 만들어진 기본 웹서버 템플릿에는 고정파일(Static File) 서빙 기능이 없다. 즉, 단순히 말해서 특정 경로의 html 파일을 표시해 주거나 이미지 파일을 읽어서 웹브라우저에 표시해 줄 수가 없다. 이런 기능은 직접 구현해야 한다.

서버 자체를 만들기 위해서 존재하는 Node.JS인 만큼 귀차니즘을 이겨내서 코드를 하나 만들어 봤다.

목표는 서버 스크립트가 존재하는 디렉토리에 'static' 이라는 디렉토리가 있고 이 밑의 파일을 읽어서 웹브라우저에 전달해 주는 것.
var fs = require('fs'),
    http = require('http'),
    url = require('url'),
    path = require('path');

http.createServer(function(req, res) {
    var requrl = url.parse(req.url, true);
    var reqpath = './static' + requrl.pathname;
    path.exists(reqpath, function(exists) {
        if (exists) {
            var ext = path.extname(reqpath).toLowerCase();
            var ctype = 'text/plain';
            if (ext == '.jpg' || ext == '.jpeg') ctype = 'image/jpeg';
            else if (ext == '.gif') ctype = 'image/gif';
            else if (ext == '.png') ctype = 'image/png';
            else if (ext == 'htm' || ext == '.html') ctype = 'text/html';

            fs.readFile(reqpath, "binary", function(err, file) {
                if (err) {
                    res.writeHead(500, {'Content-Type':'text/plain'});
                    res.end(err + '\n');
                    return;
                }
                res.writeHead(200, {'Content-Type':ctype});
                res.write(file, "binary");
                res.end();
            });
        } else {
            res.writeHead(404, {'Content-Type':'text/plain'});
            res.end(requrl.pathname + ' FILE NOT FOUND');
        }
    });
}).listen(8118);
아주 직관적으로, 파일 확장자를 이용해 파일의 종류를 파악해서 Content-Type을 설정해 주고 나머지를 파일 내용을 그냥 읽어서 넘겨주는 것이 전부다. 코드가 쓸데없이 긴 건 에러 처리 및 다양한 종류의 파일을 처리해 주기 위한 점 밖에 안되니...

추신) 이 코드에는 인젝션 버그가 있을 수도 있다. URL에 http://localhost:8118/../somefile 이런 식으로 입력하면 대체로 브라우저는 '../' 이라는 부분을 없애버리는 것 같은데 만약의 사태를 대비하는건 매우 중요할 것이다. 결론적으로 '..'이라는 부분이 들어오게 되면 무시하거나 잘라내 버리기만 해도 될 것 같기도...

댓글 2개 :

익명 :

../ 관련해서는 노드 자체 함수가 있지 않은가요?

Seorenn :

경로 처리 관련 모듈을 찾아보면 있을지도 모르겠습니다만 웹 프레임워크에서 자동으로 해 주지 않는다는 점이 중요하겠네요...