Image upload to server in node.js without using express

javascript, node.js

Solution

What has to be taken into consideration is the fact that the received data from the upload has this sort of format:

------WebKitFormBoundary9BhXe3lt2UddCDz9
Content-Disposition: form-data; name="document"; filename="globeSS.jpg"
Content-Type: image/jpeg

ÿØÿà JFIF   d d  ÿì Ducky     d  ÿá
//[binary binary binary...]
Ï[leñnœ“}ÛOyŠVÑ0êãXÂ}Ö'±”É iÉöÚ$GTQ7äŽø
uÚ_êÍòXgV¿Õ=€q`]a­KRÐÀ
ò<ÿÙ
------WebKitFormBoundary9BhXe3lt2UddCDz9--

To get the binary data only( and thus the file), the programmer has to figure out a way to clip the binary out of that data. In the below code, binary of the picture is all saved in memory, so if the user uploads a particularly large file, the following implementation might fail. It'd be best to try to write down the file in chucks.

request.setEncoding('binary'); 

//Grabbing all data from the image
var body = ''
var binaryEnd; //gets the string that indicates the location of the end of the binary file
var first = true;
request.on('data', function(data) {
    if(first)
        binaryEnd = data.toString().substring(0, data.toString().indexOf('\n')-1);
    first = false;
    body += data
});

//Dealing with the image once we have everything 
request.on('end', function() {      

    var note = querystring.parse(body, '\r\n', ':')
    console.log(note)

    //making sure than an image was submitted 
    if (note['Content-Type'].indexOf("image") != -1)
    {   
        //get the filename 
        var fileInfo = note['Content-Disposition'].split('; ');
        for (value in fileInfo){
            if (fileInfo[value].indexOf("filename=") != -1){
                fileName = fileInfo[value].substring(10, fileInfo[value].length-1); 

                if (fileName.indexOf('\\') != -1)
                    fileName = fileName.substring(fileName.lastIndexOf('\\')+1);
                console.log("My filename: " + fileName); 
            }   
        }

                    //Get the type of the image (eg. image/gif or image/png)
        var entireData = body.toString();           
        var contentTypeRegex = /Content-Type: image\/.*/;

        contentType = note['Content-Type'].substring(1); 

                    //Get the location of the start of the binary file, 
                    //which happens to be where contentType ends
        var upperBoundary = entireData.indexOf(contentType) + contentType.length; 
        var shorterData = entireData.substring(upperBoundary); 

                    //replace trailing and starting spaces 
        var binaryDataAlmost = shorterData.replace(/^\s\s*/, '').replace(/\s\s*$/, '');

                    //Cut the extra things at the end of the data (Webkit stuff)
        var binaryData = binaryDataAlmost.substring(0, binaryDataAlmost.indexOf(firstLine));        

                    //Write to a file 
        fs.writeFile('./images/' + fileName  , binaryData, 'binary', function(err)
        {
                            //forward to another location after writing data 
            response.writeHead(302, {
                'location':'/index.html'
            });
            response.end();
        });
    }
    else
        respond(404, "Please input an image", response); 
});     

This should work in all browsers (please note that internet explorer does not limit its data with `------WebkitFormBoundary`, but something else (I think only `-----`, but I forgot.)

Problem

Below is my server code where I try to get the file that was uploaded. However, `fs.writeFile`doesn't work, so I'm assuming that I'm doing something wrong. ``` server.on('request', function(request, response){ .... if((pathArray[1] == "photos") && (pathArray[2] = "new")){ var imagesPath = './images'; uploadPhoto(response, imagesPath); } else if(path == '/document/save'){ console.log("path: " + path); var body = ''; request.on('data', function(data){ body += data; }); request.on('end', function() { var note = querystring.parse(body); console.log("Body data: " + note); var newPath = "./images/myimage.jpg"; fs.writeFile( newPath, body, function (err) { if (err) throw err; }); }); } ``` Here is my HTML for the form, if it helps anyone: ``` function uploadPhoto(response, imageLoc){ response.writeHead(200, { 'Content-Type': 'text/html' }); response.write('<html><body>'); response.write('<div class="uploadFile">'); response.write('<link rel="stylesheet" type="text/css" href="style.css">'); response.write('<form action =/document/save>'); response.write('<method = "post">'); response.write('<enctype="multipart/form-data">'); response.write('<label for="name">Upload new photo</label>'); response.write('<br></br>'); response.write('<input type="file" name="name">'); response.write('<br></br>'); response.write('<button type="submit">Upload</button>'); response.write('</div>'); response.write('</body></html>'); response.write('</form>'); response.end(); } ``` After I upload the file, url goes to /document/save/uploadImage.jpg. But when I try to read the content of the image ("body") to save the image into a folder and then display it, seems that the content of the object of the request is empty. How do I get the content of the image using `node.js` without express, or any other external libraries than what I have? Is `fs.writeFile` a good function to use when writing a binary file?

Original source