I was recently working on a project where we needed to stream and render PDF documents from a Java servlet. Sounds easy and straight-forward, right? When initially developed, all browsers were rendering in the development environment (non-SSL). Here is the code snippet for how we were initially rendering the PDFs:
Standard Headers
private void setHttpResponseHeaders(HttpServletRequest _request, HttpServletResponse _response, int _contentLength) { _response.setContentType("application/pdf"); _response.setContentLength(_contentLength); _response.setHeader("Cache-Control", "no-cache"); _response.addHeader("Cache-Control", "no-store"); _response.addHeader("Cache-Control", "private"); _response.addHeader("Cache-Control", "must-revalidate"); _response.addHeader("Cache-Control", "maxage=1"); _response.setHeader("Pragma", "no-cache"); _response.addHeader("Pragma", "private"); _response.setHeader("Content-Disposition", "inline; filename=form.pdf"); }
Once we deployed to our test environment (SSL), we started to run into issues with Internet Explorer failing to render the documents. Apparently, this is a common issue. One of my co-workers originally tackled the issue by adding the “Accept-Ranges” header and the issue with IE was resolved. However, Firefox started to have issues over SSL with an error “File does not begin with %PDF-“. After much head-scratching over issues with different browsers and their behavior via SSL and non-SSL connections, the following is the final code that seems to solve the issue for most browsers:
Final
private void setHttpResponseHeaders(HttpServletRequest _request, HttpServletResponse _response, int _contentLength) { _response.setContentType("application/pdf"); _response.setContentLength(_contentLength); _response.setHeader("Cache-Control", "no-cache"); _response.addHeader("Cache-Control", "no-store"); _response.addHeader("Cache-Control", "private"); _response.addHeader("Cache-Control", "must-revalidate"); _response.addHeader("Cache-Control", "maxage=1"); _response.setHeader("Pragma", "no-cache"); _response.addHeader("Pragma", "private"); // only add the "accept-ranges" header if the "user-agent" header indicates Internet Explorer String userAgent = _request.getHeader("User-Agent"); if (userAgent != null && userAgent.indexOf("MSIE") > -1) { _response.setHeader("Accept-Ranges", "bytes"); } _response.setHeader("Content-Disposition", "inline; filename=form.pdf"); }
The following is a matrix of our findings:
Browser | SSL | non-SSL |
---|---|---|
Internet Explorer | requires “Accept-Ranges” header | standard headers |
Firefox | forbids “Accept-Ranges” header | standard headers |
Google Chrome | forbids “Accept-Ranges” header | standard headers |
Safari PC | standard headers | standard headers |