Send PDF, docx, etc. files from node.js - node.js

I'm trying to send file's content requested by user using AngularJS on clientside.
This is how I send file from node:
res.download(filePath, req.param('fileName'));
And this is how I read and save file in Angular:
$http.get('/attachment/' + req.fileName, {responseType: 'arraybuffer'}).success(function (data, status, headers, config) {
var element = angular.element('<a/>');
var file = '';
var bytes = new Uint8Array(data);
for (var i = 0; i < bytes.byteLength; i++) {
file += String.fromCharCode(bytes[i]);
}
element.attr({
href: 'data:application/force-download,' + encodeURI(file),
target: '_blank',
download: fileName
})[0].click();
});
It seems to work but only for trivial files (TXT, CSV etc.) but after requesting PDF client get file with proper page count but all pages are blank.
I suppose it must be something wrong with content encoding.
Have anyone had similar issue and already fixed it?

Related

imap nodejs download link consists utf8 encoded special characters not coming out right

imap node module to parse the body of the email which consists of a download link, now the new link has been changed to UTF encoding, thus the already implemented code is screwing up the decoding of the link somehow
Is there some different kind of encoding that is happening that I might be missing
Old URL copied from email
https://www.yyyy.com/Distributor/Requests/Req_allrptslink.aspx?qrytype=U3xXQlJJQTI3Mjg2NDg4ODQ5MnwyMDIyMTAyNg==
Old URL after parsing
Click Here<https://www.yyyy.com/Distributor/Requests/Req_allrptslink.aspx?qrytype=U3xXQlJJQTI3Mjg2NDg4ODQ5MnwyMDIyMTAyNg==> to download
New URL copied from email
https://www.xxxx.com/c/?u=iuuqt%3B00ngt%2Flgjoufdi%2Fdpn0ngt0Ejtusjcvups0Sfrvftut0Sfr%60bmmsqutmjol%2Fbtqy%40rszuzqf%3EV4yYRmKKRUJ4Nkh3OUl2OkNzPYxzNEJzNUFxNx%3E%3E&p=qqttqbdb.bqeesknn--215863907-4CBE237A-EDDA-4E4B-BA14-F8CF20433D79.1.1&e=s1 (it might not be the same url as below, as i just picked it up from one of the urls, but just giving idea of the structure)
New URL parsed by the code
`<https://www.xxxx.com/c/?u=3Dundefined&p=3Dqqttqbdb.=
bqeesknn--215863899-9FB37C90-7A33-4C85-A59B-C65016E89B11.1.2&e=3Ds1=20
Dear Client,=20`
there is no ending symbol > which is very weird
code snippet :
parseBody(stream, info) {
let buffer = '';
stream.on('data', function(chunk) {
buffer += chunk.toString('utf8');
});
stream.once('end', () => { processBody(buffer) });
}
function removeCarriageReturn(body) {
return body.replace(/\r?\n|\r/g, "");
}
processBody(body) {
body = utils.removeCarriageReturn(body);
if( body.toString().includes("www.xxxx")) {
var host = "https://www.xxxx.com/c/?";
} else {
var host = "https://www.yyyyy.com/Distributor/Requests/Req_allrptslink.aspx?";
}
const linkDelimiter = '>';
let url = body.toString().split(host)[1].split(linkDelimiter)[0];
url = host + url;
.... more lines
}
parsebody is used in msg.on() under fetch emails u can read the similar sample code here https://www.npmjs.com/package/imap. Can someone give some insights on how to debug atleast thanks.

Node JS / Generate PDF server side

I need to create PDF files via server side. I have a pug file with the HTML and it's working as expected (the format and the content is perfect). Also, I have a service that gets the HTML from the pug file in a string. The problem is that I'm facing issues using the node-html-pdf library to generate a PDF.
let config = {
format: 'Letter',
orientation: 'portrait',
type: 'pdf'
};
pdf.create(htmlConverted, config).toBuffer((errConvertingHtml, buffer) => {
if (errConvertingHtml) {
this.logError(errConvertingHtml, null, `${this.className} createPDF`);
return this.returnResult(errConvertingHtml, false, null);
} else {
const filename = 'Invoice' + '.pdf';
const base64PDF = buffer.toString('base64');
const email = new models.EmailModel();
email.to.email = order.email;
email.to.name = order.full_name;
email.template_id = subscriptionTemplate.value;
email.dynamic_template_data = dynamic_data;
email.attachments = [
{
filename: filename,
content: base64PDF,
type: 'application/pdf',
disposition: 'attachment'
}
];
let mailIntegration = new integrations.MailIntegration();
mailIntegration.SendNow(email);
}
});
This code works, but the PDF attach in the email doesn't have the right format, it's really small. I can use another library, or another implementation, I don't have any issue with that. Any suggestions or recommendations for this code? I have been searching for another library, but honestly, I haven't found something to convert the HTML string to PDF and then the PDF to a buffer and then to base64. Any help is well received. Thanks, I really appreciate your responses.

Upload a binary encoded audio file via ajax and save

I have an audio file saved locally that I want to read, upload to a server via ajax and then store on the server. Somewhere along this process the file gets corrupted such that the file that's saved on the server cannot be played.
I'll list simplified bits of code that show the process I'm going through so hopefully it'll be evident where I'm going wrong.
1) After audio is recorded (using getUserMedia and MediaRecorder), a local file is saved:
var audioData = new Blob(chunks, { type: 'audio/webm' });
var fileReader = new FileReader();
fileReader.onloadend = function() {
var buffer = this.result,
uint8Array = new Uint8Array(buffer);
fs.writeFile('path/to/file.webm', uint8Array, { flags: 'w' });
}
fileReader.readAsArrayBuffer(audioData);
2) Later this local file is read and sent to a server (using the library axios to send the ajax request)
fs.readFile('path/to/file.webm', 'binary', (err, data) => {
var formData = new FormData();
formData.append('file', new Blob([data], {type: 'audio/webm'}), 'file.webm');
axios.put('/upload', formData);
});
3) The server then handles this request and saves the file
[HttpPut]
public IActionResult Upload(IFormFile file)
{
using (var fileStream = new FileStream("path/to/file.webm", FileMode.Create))
{
file.CopyTo(fileStream);
}
}
The local audio file can be played successfully however the audio file on the server does not play.
I'm not sure if this is helpful information, but here are the first few lines of text I see when I open the local file in a text editor (notepad++):
And the same when I open the one on the server:
So kinda the same... but different. I've tried encoding a myriad of different ways but everything seems to fail. Fingers crossed someone can point me in the right direction here.
The problem was with how I was passing through the file contents from fs.readFile. If I passed a base64 encoded raw buffer from fs.readFile via json, converted that to a byte array on the server and saved that, then I can successfully play it on the server.
fs.readFile('path/to/file.webm', (err, data) => {
axios.put('/upload', { audioData: data.toString('base64') });
});
[HttpPut]
public IActionResult Upload([FromBody]UploadViewModel upload)
{
var audioDataBytes = Convert.FromBase64String(upload.AudioData);
using (var memoryStream = new MemoryStream(audioDataBytes))
using (var fileStream = new FileStream("path/to/file.webm", FileMode.Create))
{
await memoryStream.CopyToAsync(fileStream);
}
}
Actually, this is a problem of character encoding. You are probably mixing UTF-8 and ISO-8859 which causes the file to be corrupted.
You should probably set the charset in the HTML page to the one expected on the server. Or perform preliminary checks on the server if you do not know the charset of the data you will receive.
Converting to base64 will solve the issue because then it will only use characters in the ASCII range.

How to save pdf to android file system and then view PDF - react-native

I am using the react-native-fs and I am trying to save a base64 of a pdf file to my android emulators file system.
I receive base64 encoded pdf from the server.
I then decode the base64 string with the line:
var pdfBase64 = 'data:application/pdf;base64,'+base64Str;
saveFile() function
saveFile(filename, pdfBase64){
// create a path you want to write to
var path = RNFS.DocumentDirectoryPath + '/' + filename;
// write the file
RNFS.writeFile(path, base64Image, 'base64').then((success) => {
console.log('FILE WRITTEN!');
})
.catch((err) => {
console.log("SaveFile()", err.message);
});
}
Error
When I try saving the pdfBase64 the saveFile() function catches the following error:
bad base-64
Question
Can anyone tell where or what I am doing wrong?
Thanks.
For anyone having the same problem, here is the solution.
Solution
react-nativive-pdf-view must take the file path to the pdf_base64.
Firstly, I used the react-native-fetch-blob to request the pdf base64 from the server.(Because RN fetch API does not yet support BLOBs).
Also I discovered that react-native-fetch-blob also has a FileSystem API which is way better documented and easier to understand than the 'react-native-fs' library. (Check out its FileSystem API documentation)
Receiving base64 pdf and saving it to a file path:
var RNFetchBlob = require('react-native-fetch-blob').default;
const DocumentDir = RNFetchBlob.fs.dirs.DocumentDir;
getPdfFromServer: function(uri_attachment, filename_attachment) {
return new Promise((RESOLVE, REJECT) => {
// Fetch attachment
RNFetchBlob.fetch('GET', config.apiRoot+'/app/'+uri_attachment)
.then((res) => {
let base64Str = res.data;
let pdfLocation = DocumentDir + '/' + filename_attachment;
RNFetchBlob.fs.writeFile(pdfLocation, pdf_base64Str, 'base64');
RESOLVE(pdfLocation);
})
}).catch((error) => {
// error handling
console.log("Error", error)
});
}
What I was doing wrong was instead of saving the pdf_base64Str to the file location like I did in the example above. I was saving it like this:
var pdf_base64= 'data:application/pdf;base64,'+pdf_base64Str;
which was wrong.
Populate PDF view with file path:
<PDFView
ref={(pdf)=>{this.pdfView = pdf;}}
src={pdfLocation}
style={styles.pdf}
/>
There is a new package to handle the fetching (based on react-native-fetch-blob) and displaying of the PDF via URL: react-native-pdf.
Remove application type in base64 string and it's working for me
var pdfBase64 = 'data:application/pdf;base64,'+base64Str;
To
var pdfBase64 = base64Str;

Generating zip archive on-the-fly using Express and node-archiver

I'm trying to generate a zip archive of icons on-the-fly and stream the response to the user to download, via a JSON POST request.
The zip itself is created and the response is returned, but the client-side is not prompted to download the file, and the response is garbled (which I assume is the contents of the archive).
app.post('/download', function(request, response) {
var icons = request.body;
var filename = 'icons.zip';
response.attachment(filename);
var zip = Archiver('zip');
zip.on('finish', function(error) {
return response.end();
});
zip.pipe(response);
for (var i = 0; i < icons.length; i++) {
var icon = getIcon(icons[i]);
zip.append(fs.createReadStream('public/' + icon.svg), { name: icon.title + '.svg' });
}
zip.finalize();
});
I'm wondering if there's anything missing from the server-side code that's preventing the download on the client-side, but from the example I've followed (https://github.com/archiverjs/node-archiver/blob/master/examples/express.js), it doesn't seem to be the case.
Here's some screenshots of the request made and the response received:
AJAX calls don't trigger file downloads in a browser, so you need to work around that.
One possibility is to change the request from a POST to a GET and put the names of the icons in the URL as parameters.
Your Express route would look like this:
app.get('/download/*?', function(request, response) {
// Make sure icons names were provided:
if (! request.params[0]) {
return response.sendStatus(400);
}
// Split on `/`, which is used as separator between icon names:
var icons = request.params[0].split(/\//);
// The rest can be the same
...
});
Client-side, you would use this:
location.href = 'http://your-server/download/Chevron%20Down/Close/Trash';
(obviously you can also generate that URL dynamically based on user input, as long as you make sure that the icon names are properly URL-encoded)

Resources