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 |