BeNdErR
BeNdErR

Reputation: 17927

Serving image file with Buffers - corrupted image

I'm trying to get into Node.js, I'm following some tutorials and I'm now stuck on an example that explains how to create a simple web server to serve static files, using Buffers.

Here is the relevant code:

function serveStaticFile(file, res){
    var rs = fs.createReadStream(file);
    var ct = contentTypeForFile(file);
    res.writeHead(200, { "Content-Type" : ct });

    rs.on('readable', function(){
        var d = rs.read();
        if (d) {
            if ( typeof d == 'string' ) 
                res.write(d);
            else if ( typeof d == 'object' && d instanceof Buffer )
                res.write(d.toString('utf8'));
        }
    });
    rs.on('error', function(e){
        res.writeHead(404, { "Content-Type" : "application/json" });
        var out = { error : "not_found", message : "'" + file + "' not found" };
        res.end(JSON.stringify(out) + "\n");
    });
    rs.on('end', function(){
        res.end();
    });
}

the function serveStaticFile runs on incoming requests, file is the filename of the file you want to retrieve.

This is contentTypeForFile():

function contentTypeForFile(file){
    var ext = path.extname(file);
    switch(ext){
    case '.html': return "text/html";
    case '.js' : return "text/javascript";
    case '.css' : return "text/css";
    case '.jpg' :
    case '.jpeg' : return "image/jpeg";
    default : return "text/plain";
    }
}

Running this command curl -o test.jpg http://localhost:8000/photo.jpg in the cmd actually downloads and creates a test.jpg file in my folder, the problem is that when I try to open the image the image itself seems to be corrupted.

What am I doing wrong? How can I convert the d.toString('utf8') back to an actual image once it is downloaded?


EDIT: I think the problem is that the response headers are saved toghether with the file content itself.. if I open the image file with a text editor, this is the content:

HTTP/1.1 200 OK
Content-Type: image/jpeg
Date: Sat, 30 Aug 2014 00:31:58 GMT
Connection: keep-alive
Transfer-Encoding: chunked

���� [ ... ]        

How can I get rid of the headers while saving the file?

Thanks in advance, regards

Upvotes: 0

Views: 2158

Answers (1)

Mike S
Mike S

Reputation: 42325

Just remove the .toString('utf8'), you don't want or need it there. As a matter of fact, you can probably change this:

if (d) {
    if ( typeof d == 'string' ) 
        res.write(d);
    else if ( typeof d == 'object' && d instanceof Buffer )
        res.write(d.toString('utf8'));
}

To simply:

if (d) {
    res.write(d);
}

res.write already handles checking the type of data you're passing to it and encoding it properly. The only time you need to worry about it is if you send it a string that is not utf8 encoded. From the docs:

This sends a chunk of the response body. This method may be called multiple times to provide successive parts of the body. chunk can be a string or a buffer. If chunk is a string, the second parameter specifies how to encode it into a byte stream. By default the encoding is utf8.


I just re-read second part of your question and realized that you said that you found headers in the test.jpg file when you opened it with a text editor. The only way I know of that that can happen when using curl is by specifying the -i option. Something like: curl -i -o test.jpg http://localhost:8000/photo.jpg. For the most part, I wouldn't recommend using that option with curl since it will corrupt any binary files it downloads. There are certainly use cases for it, but this isn't one of them.

Regardless of what was going on with curl, it's important to know that the server code has nothing to do with what the client side does with the headers it receives. Once the server sends the headers (and the content for that matter), it's completely out of its hands. I can not think of any way the code on the server could force the client to save headers in a file along with the actual content; that's completely up to the client.

Note: If you want to see the headers curl is receiving (and sending for that matter), try the -v option. Received headers will be prefixed with < and sent with >; lines prefixed with * have to do with the connection itself. It looks something like this:

* Connected to localhost (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.30.0
> Host: localhost:8000
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/plain
< Date: Sat, 30 Aug 2014 15:54:14 GMT
< Connection: keep-alive
< Transfer-Encoding: chunked
< 
[data not shown]

Upvotes: 1

Related Questions