Why can't an internet browser download a PDF using NodeJS and Express?

I have a website that I create using NodeJS, which should serve some PDF files (among other files).

For reasons that I cannot determine, Internet Explorer 8 will not be able to fully load PDFs into Acrobat Viewer for the first time (and sometimes several times after). Saving a file directly works just fine, but it's not perfect. Chrome works fine, although I have not tested other browsers.

There is no error message, except the status bar stops updating and shows: Downloaded (2.97 MB of 16.33 MB):
(source: twimg.com )

I transfer the file through NodeJS and the Express (v3, beta2) / Connect platform (this is the Connect Static middleware that serves the file). I also pass it over SSL, but disabling it does not help.

Thanks for any idea! Thanks

EDIT - to include more details:

Firstly, I upgraded Express v2 to v3 to try to solve the problem - no luck.

This is the application route that serves the files. The static maintenance component really works, so the problem is how IE retrieves files or how Express transfers them to IE.

app.get('/store/*', ensureAuthenticated, express.static(__dirname + '/../uploads')); function ensureAuthenticated(req, res, next) { if (req.isAuthenticated()) { return next(); } } else { res.redirect('/login'); } 

As for the errors - I do not see the 404 error or something in IE. It just hangs with a blank screen and the image above showing the number of downloaded files in the lower left status bar. Ultimately, Adobe (~ 5 minutes) fails with the error: "This file is corrupt and cannot be restored." I know that the file is not corrupted because sometimes IE will load it (see Fiddler requests below).

In Fiddler, I see the following. Multiple requests from IE for the PDF. 2 fail, 1 succeeds

The first two requests were not completed, and the third successfully delivered the PDF file.

If there is anything else I can provide, let me know.

+2
internet-explorer ssl pdf
source share
1 answer

So, I figured out the problem (or at least a solution or 4).

It took me some time and an extensive amount of research, test cases and all sorts of things, but I still got there.

When IE8 (and possibly other browsers too, but I have not tested it) uses the Adobe 9 plugin (not tested with Adobe X or any other version) to request a PDF file, sometimes it will extract the whole file as one. This is the success I saw and matches request 22 in the Fiddler screenshot above. It seems to have captured the whole file if the file is small, but in this case I tested a 16 megabyte PDF file.

In other cases, Adobe will send the range header of this form:

 Range: bytes=ab, cd 

Where ab is a range and cd is a range which, in his opinion, is not continuous.

My knowledge of Range headers is not so extensive, so I'm not sure if this is true. The research that I did does not suggest.

In either case, in Connect static.js, it uses the range parsing method in lib / util.js called parseRange. This method returns an array of ranges as follows:

 [ { start: a, end: b }, { start: c, end: d} ] 

In static.js, he calls this method and assigns values ​​to ranges, then it uses ranges [0] to calculate the range, ignoring the values ​​of c and d. The range between a and b is only the data read from the file and sent to the request.

I believe that Adobe 9 then continues to wait for more data, which causes the visibility that I saw.

Solutions

  • The easiest solution is to remove the "Accept-Ranges" header in static.js
  • The more complicated (and not necessarily correct) solution that I implemented is to take a minimum of a and c and a maximum of b and d to create a new range and return it to the range check code. This meaning shows what I did: https://gist.github.com/2930131
  • The third (possible) solution, in my opinion, will track when the client will wait for data and do something with the connection (close it, send more data - I'm not sure!). I have no idea how this will work, but I will try to pass it on to those who can.

The second solution works for me in my use case. I hope if you stumble upon it, this is also useful for you!

+5
source share

All Articles