I have a silly problem with response headers only showing in 304 responses. The server I am using is Tomcat 7. The java filter contains the following code:
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
httpResponse.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");
httpResponse.addHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
if (debug) {
httpResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate"); // HTTP 1.1
httpResponse.setHeader("Pragma", "no-cache"); // HTTP 1.0
httpResponse.setDateHeader("Expires", 0); // Proxies.
} else {
httpResponse.setHeader("Cache-Control", "public");
httpResponse.setDateHeader("Expires", System.currentTimeMillis() + 86400000L); // 1Day
}
It is important to note that this filter is the last to fire in the chain, it is the first filter to be mapped in the web.xml (makes no difference if it is the last either) and the above code runs after
chain.doFilter(request, response);
Using Chrome's audit tool to evaluate the headers I notice that on a 200 the headers are not in the response. I refresh the page, by pressing "F5", which leads to a 304 and the headers are there to be seen. Likewise I refresh again and get a 200 where the headers are not to be seen. Repeatedly refreshing the page alternates between 304 and 200 responses and on each 304 the headers are there, yet not on the 200.
The filter is mapped to all resources.
<filter-mapping>
<filter-name>AllowRemoteAccessHeaderFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>HttpCachingFilter</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
Additionally the filter fires on each refresh, irrespective of the response.
Can someone explain to me what is actually happening here? I am sure that I am missing something small. My goal is to have the headers there for a 200 response.
EDIT: Noticed that this works for the first page loaded, but not any of the resources that are loaded on that page, eg. scripts, images, css includes.
EDIT: Noticed as well that if I remove all scriptlets from the page then the headers come through. The two scriptlets each include data that was set in the request object via another filter. An example of the one that injects the compiled javascript is below:
<script type="text/javascript"><%= request.getAttribute("compiled-scripts")%></script>
PROBLEM: I might have found the cause of the problem, but not a solution. When I include the compiled scripts into the page the transfer encoding changes from having the content length set to:
Transfer-Encoding:chunked
The moment the transfer encoding is chunked the headers do not come through. This might explain why on a 304 the response headers come through, because the content length is known and therefore set. Where as on a 200 the content length is unknown and the transfer encoding chunked.
However, my problem still remains. I want to include the compiled scripts instead of referencing them to reduce latency and other reasons. I have read that to prevent transfer encoding chunked you need to set the content length manually, by reading the response in as bytes. I am not aware of how I can determine the response length in a filter.
Is it possible to have the response headers come through when the transfer encoding is chunked?