I am trying to read data from an http image file upload. It seems to read the file, but for some reason the output file is about twice the size of the original file.
Original: 94.7KB
Temp File: 168.8 KB
When I open both files in a text editor, they have the same number of lines, and the starting and ending characters are the same. This leaves me to believe that the uploaded file is getting saved as a string instead of binary data.
I believe that the important parts are the following
The reading of the data:
let body = ''
req.on('data', data => {
body += data.toString()
}).on('end', data => {
if (data) body += data.toString()
// Rest of block
})
The saving of the data:
// If there is a filename grab the file data
if (result.filename.length > 0) {
// Create a temporary url
let temp = join(os.tmpdir(), (Math.random() * 10000).toString(12).substr(5, 10))
// Get the data between the blocks after the first two newlines
let matches = item.match(/^.+?(\r\n\r\n|\n\n)(.+)/s)
// Write the data to file
fs.createWriteStream(temp).write(matches[2])
}
Here is the full parsing of the data:
http.createServer((req, res) => {
let body = ''
req.on('data', data => {
body += data.toString()
}).on('end', data => {
if (data) body += data.toString()
let boundary = req.headers['content-type'].split('boundary=')[1]
// Split all the boundary items and loop over them
body.split(new RegExp(`(--${boundary}|--${boundary}--)`)).forEach(item => {
if (item.trim().toLowerCase().startsWith('content-disposition')) {
item = item.trim()
// Find the name and filename
let result = item.split(':')[1].split(';').map(i => i.trim()).reduce((obj, itm) => {
if (itm.startsWith('name=')) obj.name = itm.match(/^name="(.+)"/)[1]
if (itm.startsWith('filename=')) obj.filename = itm.match(/^filename="(.+)"/)[1]
return obj
}, { name: '', filename: '' })
// If there is a filename grab the file data
if (result.filename.length > 0) {
// Create a temporary url
let temp = join(os.tmpdir(), (Math.random() * 10000).toString(12).substr(5, 10))
// Get the data
let matches = item.match(/^.+?(\r\n\r\n|\n\n)(.+)/s)
// Write the data to file
fs.createWriteStream(temp).write(matches[2])
}
}
})
})
})
So, I was somewhat correct in both cases...
First, I must read the data as binary data like this:
body += data.toString('binary')
Next when saving, I need to save as binary data like this:
fs.createWriteStream(temp).write(matches[2], 'binary')
This now saves as the correct file size and the image is readable!