Search code examples
javascriptangularjsnode.jsmongodbbusboy

how to set encoding file upload


I'm using angular-file-upload, and when I upload a document that isn't txt, like a picture, pdf or doc document and I try to download it, the file is different from the one I've uploaded( take a look to the picture ), I'm not sure if this is because a wrong encoding when uploading the file..

enter image description here The left document is the original file.

The client:

var uploader = $scope.uploader = new FileUploader({
   scope: $scope,
   url: '/file/upload/',
   method:'POST',
   headers: {
    'X-XSRF-TOKEN': 'some token'
   }
});

$scope.upload = function(){
    uploader.queue.forEach(function(item){
        item.formData = [
        {'filename': 'friendlyName' },
        {'objectType': 'element' },
        {'elementId': 'someId'}
        ];
    });
    uploader.uploadAll();
};

The backend POST...

In here the encoding variable within the file event of busboy is '7bit'..

exports.uploadDocument = function(req,res){
    req.pipe(req.busboy);
    var doc = new DocumentModel();

    req.busboy.on('file',function(fieldname, file, filename, encoding, contentType){
        doc.contentType = contentType;
        doc.encoding= encoding;
        doc.filename= filename;
        doc.content = '';
        doc.size = 0;
        file.on('data',function(data){
            doc.content += data;
            doc.size += data.length;
        });
    });

    //updating req.body with busboy parameters
    req.busboy.on('field',function(fieldname,val){
        req.body[fieldname] = val;
    });

    req.busboy.on('finish', function() {
        if(req.body.hasOwnProperty('filename')){
            doc.friendlyName = req.body.filename;
        }
        if(req.body.hasOwnProperty('objectType')){
            doc.reference.objectType = req.body.objectType;
        }
        if(req.body.hasOwnProperty('elementId')){
            doc.reference._id= req.body.elementId;
        }
        doc.save(function(err,savedFile){
            if(err){
                res.json(500,err.message);
            }else{
                res.json(200,doc);
            }
        });
    });
};

Backend: GET...

exports.downloadDocument = function(req,res){
    var id = mongoose.Types.ObjectId(req.params.documentId);
        DocumentModel.findOneAsync({_id:id}).then(
        function(doc){
            console.log('doc', doc);
            if(doc!==undefined){
                DocumentModel.getFile(doc.fileInfoId).then(function(binaryData){
                    res.setHeader('x-timestamp', Date.now());
                    res.setHeader('x-sent',true);
                    res.setHeader('Content-disposition', 'attachment; filename=' + doc.filename);
                    res.setHeader('Content-Type',doc.contentType);
                    res.send(binaryData);   
                }).error(function(e){
                    res.status(500).send(e.message);
                });
            }
            else{
                res.status(404).send('file not found.');
            }
        });
};

How can I set the correct encoding ? or is not an encoding issue?

This is the error I get when I try to see the downloaded file. enter image description here

Thanks in advance.

PD: Im using gridFS to store the document in mongoDB.


Solution

  • You're converting binary data to UTF-8 implicitly by appending the data Buffers to doc.content, which is a string.

    What you should probably do is make sure that the content field in your schema is set to Buffer and then you simply concatenate file chunk Buffers to keep the binary data intact. Example:

    var bufs = [];
    doc.size = 0;
    file.on('data',function(data) {
      bufs[bufs.length] = data;
      doc.size += data.length;
    }).on('end', function() {
      doc.content = Buffer.concat(bufs, doc.size);
    });