Skip to content

Instantly share code, notes, and snippets.

@kirsle
Created July 15, 2015 00:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kirsle/b3f8f28e1606cda7077c to your computer and use it in GitHub Desktop.
Save kirsle/b3f8f28e1606cda7077c to your computer and use it in GitHub Desktop.
##
# Problem: sending a binary download in ExpressJS.
#
# I was trying to proxy download a binary file from S3 and serve it to the user with a different name.
# Using the `request` module didn't work; text files came back fine but binary files would be corrupted
# in strange ways (see attached diff).
#
# I ended up using the built-in `https` module and doing it the hard way.
#
# My theory: the request module expects to only work with text and was performing some UTF-8 coercion
# of the binary data.
##
https = require('https')
urllib = require('url')
download = (req, res) ->
s3url = "https://something-s3.amazonaws.com/file/sdsdf09sd7f90s8d7f.gif"
origName = "filename.gif"
# Proxy the download to the user, but give it the new name.
https.get urllib.parse(s3url), (response) ->
# The response is given to us one chunk at a time, in Buffer objects.
data = []
response.on("data", (chunk) ->
data.push chunk
).on("end", ->
# data is an array of Buffers, so we take each octet of each buffer
# and combine them into one big octet array to pass to a new Buffer
# instance for sending to the browser.
# See: http://chad.pantherdev.com/node-js-binary-http-streams/
buffer = new Buffer(data.reduce (prev, current) ->
return prev.concat(Array.prototype.slice.call(current))
, [])
res.setHeader "Content-Disposition", "attachment; filename=#{origName}"
res.setHeader "Content-Type", "application/octet-stream"
res.end buffer, 'binary'
)
##
# The following DID NOT WORK. It would corrupt the binary files, see
# the attached diff. Un-commented out for syntax highlighting.
##
# Proxy the download to the user, but give it the new name.
request s3url, (error, response, body) ->
if !error and response.statusCode is 200
res.setHeader "Content-Disposition", "attachment; filename=#{origName}"
res.setHeader "Content-Type", response.headers["content-type"]
#res.send(new Buffer(body, 'binary')) # this does the same as res.end below
res.end body, 'binary'
else
res.send 500, message: "Failed to download file."
-00000000 47 49 46 38 39 61 10 00 10 00 c2 00 00 00 00 00 |GIF89a..........|
+00000000 47 49 46 38 39 61 10 00 10 00 fd 00 00 00 00 00 |GIF89a..........|
-00000010 00 98 fd 88 88 88 ff ff ff 00 ba 00 44 44 44 22 |............DDD"|
+00000010 00 fd fd fd fd fd fd fd fd 00 fd 00 44 44 44 22 |............DDD"|
-00000020 22 22 00 00 00 21 f9 04 01 00 00 03 00 2c 00 00 |""...!.......,..|
+00000020 22 22 00 00 00 21 fd 04 01 00 00 03 00 2c 00 00 |""...!.......,..|
-00000030 00 00 10 00 10 00 00 03 35 38 ba dc fe 70 80 39 |........58...p.9|
+00000030 00 00 10 00 10 00 00 03 35 38 fd fd fd 70 fd 39 |........58...p.9|
-00000040 a3 34 25 1b e0 a8 ff 9c 02 08 64 69 0a a1 64 52 |.4%.......di..dR|
+00000040 fd 34 25 1b fd fd fd fd 02 08 64 69 0a fd 64 52 |.4%.......di..dR|
-00000050 eb 32 92 5c 10 bc a8 5b 02 f2 7c db 30 e1 d3 29 |.2.\...[..|.0..)|
+00000050 fd 32 fd 5c 10 fd fd 5b 02 fd 7c fd 30 fd fd 29 |.2.\...[..|.0..)|
-00000060 1a 6a d2 12 9d 8e 41 10 c8 c2 6c 3a 19 09 00 3b |.j....A...l:...;|
+00000060 1a 6a fd 12 fd fd 41 10 fd fd 6c 3a 19 09 00 3b |.j....A...l:...;|
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment