Tomcat: Cache-Control - java

Jetty has a CacheControl parameter (can be specified webdefault.xml) that determines the caching behavior of clients (by affecting headers sent to clients).
Does Tomcat has a similar option?
In short, I want to turn off caching of all pages delivered by a tomcat server and/or by a specific webapp?
Update
Please note that I am not referring to server-side caching. I want the server to tell all clients (browsers) not to use their own cache and to always fetch the content from the server. I want to do it for all resources, including static resources (.css, .js, etc.) at once.

Since Tomcat 7 there is a container provided expires filter that may help. See:
Tomcat 10: https://tomcat.apache.org/tomcat-10.0-doc/config/filter.html#Expires_Filter
Tomcat 9: https://tomcat.apache.org/tomcat-9.0-doc/config/filter.html#Expires_Filter
Tomcat 8: https://tomcat.apache.org/tomcat-8.0-doc/config/filter.html#Expires_Filter
Tomcat 7: https://tomcat.apache.org/tomcat-7.0-doc/config/filter.html#Expires_Filter
Tomcat 6 (unofficial backport): https://github.com/bnegrao/ExpiresFilter
ExpiresFilter is a Java Servlet API port of Apache mod_expires. This filter controls the setting of the Expires HTTP header and the max-age directive of the Cache-Control HTTP header in server responses. The expiration date can set to be relative to either the time the source file was last modified, or to the time of the client access.
<filter>
<filter-name>ExpiresFilter</filter-name>
<filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class>
<init-param>
<param-name>ExpiresByType image</param-name>
<param-value>access plus 10 days</param-value>
</init-param>
<init-param>
<param-name>ExpiresByType text/css</param-name>
<param-value>access plus 10 hours</param-value>
</init-param>
<init-param>
<param-name>ExpiresByType application/javascript</param-name>
<param-value>access plus 10 minutes</param-value>
</init-param>
<!-- Let everything else expire immediately -->
<init-param>
<param-name>ExpiresDefault</param-name>
<param-value>access plus 0 seconds</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>ExpiresFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>

Similar to the post above, except there are some issues with that code. This will disable all browser caching:
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;
public class CacheControlFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
resp.setHeader("Expires", "Tue, 03 Jul 2001 06:00:00 GMT");
resp.setDateHeader("Last-Modified", new Date().getTime());
resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0");
resp.setHeader("Pragma", "no-cache");
chain.doFilter(request, response);
}
}
and then map in web.xml as described in Stu Thompson's answer.

I don't believe there is a configuration to do this. But it should not be much of an effort to write a filter to set the Cache-Control header on a per webapp-basis. E.g.:
public class test implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
chain.doFilter(request, response);
((StatusResponse)response).setHeader("Cache-Control",
"max-age=0, private, must-revalidate");
}
public void destroy() {}
public void init(FilterConfig arg0) throws ServletException {}
}
And you'd place this snippet into your webapp's web.xml file.
<filter>
<filter-name>SetCacheControl</filter-name>
<filter-class>ch.dietpizza.cacheControlFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SetCacheControl</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

There actually are several elements in the Tomcat configuration which directly affect this. See documentation at http://tomcat.apache.org/tomcat-6.0-doc/config/valve.html for example.
Atlassian recommends the following two statements to ENABLE browser-side caching so that Microsoft Internet Explorer will be able to correctly download and view attached documents:
<Valve className="org.apache.catalina.authenticator.FormAuthenticator" securePagesWithPragma="false" />
<Valve className="org.apache.catalina.authenticator.NonLoginAuthenticator" securePagesWithPragma="false" />

may be this what you are looking for :
http://tomcat.apache.org/tomcat-6.0-doc/config/context.html#Context%20Parameters
cachingAllowed : If the value of this flag is true, the cache for static
resources will be used. If not specified, the default value of the flag is true.
Also delete the application cache folder in /work/Catalina/localhost after changing this flag.

The only param I know of is disableProxyCaching on <Valve> elements. See here.

Related

Java Spring: No 'Access-Control-Allow-Origin' header is present on the requested resource

I am trying to hack around on a project that requires CORS. When I request the Java Spring Rest API, I receive:
No 'Access-Control-Allow-Origin' header is present on the requested resource
My stack is quite simple. I am using Java Spring with Tomcat. On the front end, I am making the request with jquery.
I do not see any logs from Spring regarding this and haven't seen any action in the threads shown in the debugger for the java spring application (making it really hard to debug where this is being blocked).
As far as my spring resource class, Ive included the cross origin annotation (#CrossOrigin()) on top of the class. Ive also tried putting that same annotation on the methods for the resource as well (without any luck). As a long shot, I also tried putting in some configuration within a new web.xml file to configure a CORS filter the old fashioned way:
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
<init-param>
<param-name>cors.allowed.origins</param-name>
<param-value>*</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.methods</param-name>
<param-value>GET,POST,HEAD,OPTIONS,PUT</param-value>
</init-param>
<init-param>
<param-name>cors.allowed.headers</param-name>
<param-value>Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
</init-param>
<init-param>
<param-name>cors.exposed.headers</param-name>
<param-value>Access-Control-Allow-Origin,Access-Control-Allow-Credentials</param-value>
</init-param>
<init-param>
<param-name>cors.support.credentials</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>cors.preflight.maxage</param-name>
<param-value>10</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The last detail that I would like to add is that when I make a non-CORS request to the previously mentioned APIs (with CORS annotations on them), I do not see any headers returned that are related to allowing all or any specific origin. This makes me wonder if the annotations are being blocked by something.
I realize that without much code and logs, the community cant really help me. I am asking for guidance on how I can debug this. Thank you for helping!
spring version conflict is causing this for you. You may want to check the versions. if versions are not an issue add a class like this.
#Component
public class MyCORSFilter implements Filter {
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, remember-me");
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig filterConfig) {
}
#Override
public void destroy() {
}
}
There is a simpler way to verify. You can use the postman or open the F12 developer tool to see the response body of the request(Request with non CORS). If the Response header has access-control-allow-origin:*, it means the setting is successful, and then check if there is an OPTION request, because the browser will not directly request the request, but will Send an OPTION request to see if the site supports CORS. If the OPTION request is indeed sent, if the response code of this request is not 200, it will cause CORS failure, so you only need to respond to this OPTION request correctly.

x-power-by display in response header

As per the security of web application x-power-by should set to empty when it displays in response header..
In our application we did this by implementing a filter.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
// App specific logic...
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader("X-Powered-By","");
chain.doFilter(request, response);
httpResponse.setHeader("X-Powered-By"," ");
}
It is showing blank value in response header for x-power-by when hitting the URL, That's well and good but in our application when we hit the URL with query string appended with the URL then for the first request it shows :
x-power-by= JSF1.2
We have also commented out the below portion of x-power-by in web.xml as our application use jboss 5.0.1.
<filter>
<filter-name>CommonHeadersFilter</filter-name>
<filter-class>
org.jboss.web.tomcat.filters.ReplyHeaderFilter</filter-class>
<!--
<init-param>
<param-name>X-Powered-By</param-name>
<param-value>Servlet 2.5; JBoss-5.0/JBossWeb-2.1</param-value>
</init-param>
-->
</filter>
But doing all the two things mention above I am getting x-power-by displayed in the response header when I hit the URL with query string appended for the 1st time.
URL like:
https://example.com?html="abcd",p_ab="shdhsgdhs"
Don't know how to resolve it,any help is highly appreciated.
1) Add following entry to your application web.xml.
<context-param>
<param-name>com.sun.faces.sendPoweredByHeader</param-name>
<param-value>false</param-value>
</context-param>
2) I don't think you need any filter to overwrite this header (based on jboss documentation).

limit access to servlets

I have a gateway sevlet that forward users to many servlets that processes tasks.
each users must go first through the gateway servlet then it forwards them to the proper servlet.
I create a RequestDispatcher and execute it's forward function to the proper servlet.
the problem is that all the servlets are publicly available so they user can actually go and execute any servlets they want.
I want to allow access only to the gateway servlet and to restrict access to all others. but of course to allow the gateway to forward to the servlets.
how can it be done?
thank you!
using apache tomcat 7
Using filter to check that the current user is logged in, you'll need to write the method userIsLoggedIn() yourself, by checking session attributes:
public class LoginFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
if (userIsLoggedIn()) {
//process request normally, pass up the filter chain to the servlet:
chain.doFilter(req, res);
} else {
//go to login screen instead
RequestDispatcher dispatcher = getRequestDispatcher("login");
dispatcher.forward( request, response );
}
}
}
In you web.xml, you'll need to declare your filter:
<filter>
<filter-name>loginFilter</filter-name>
<filter-class>
com.foo.LoginFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>loginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Force Specific Response Header for JSF webapplication on Glassfish

We have a Java EE 6 web application with JSF 2.0 running on Glassfish 3.1.
There we encountered a strange bug: the Mime type of the response header send by Glassfish to the client depends on the order of the allowed Mime types in the request header send by the Browser. So in some cases (depending on the browser), the Mime type of the response is wrong, resulting in a broken html page.
But it would take pretty long to explain that thing. So to workaround this problem we now want to do just one thing:
Force the response header type for the whole web-application to "text/html".
Currently, we do that with a Servlet Filter configured in the Web.xml:
#WebFilter("/BaseFilter")
public class BaseFilter implements Filter {
public BaseFilter() {
}
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
response.setContentType("text/html;charset=UTF-8");
chain.doFilter(request, response);
}
public void init(FilterConfig fConfig) throws ServletException {
}
}
configuration in web.xml:
<filter>
<filter-name>BaseFilter</filter-name>
<filter-class>com.company.web.filter.BaseFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>BaseFilter</filter-name>
<url-pattern>/*</url-pattern>
<!-- these patterns should match cached resources -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
So my question is, is there a better way to enforce a specific response header, especially by just configuring it instead of implementing a ServletFilter?
Is there a Glassfish option to do that?
You can specify it in the default template by the contentType attribute of the <f:view>.
<f:view contentType="text/html">

Display forwarded JSP with url-pattern "/*"

To improve my java skills, I'm trying to build a simple j2ee framework (MVC).
I built it to handle every request in a FrontServlet. Here is the mapping that I used :
web.xml :
<servlet>
<servlet-name>Front</servlet-name>
<servlet-class>test.FrontServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Front</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
My problem is that when I forward the request from the FrontServlet to a JSP, obviously, the JSP request is handle by the FrontServlet and the view isn't rendered.
How can I resolve this problem by keeping the url-pattern "/*" ?
Is there a way to render a JSP in a Servlet without performance losses ?
Thanks in advance for your reply !
Solution 1 (#Bryan Kyle)
I'm trying to follow your advise. I created this filter :
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException
{
HttpServletRequest req = (HttpServletRequest) request;
if(!req.getRequestURL().toString().endsWith("jsp"))
{
// I changed the servlet url-pattern to "/front.controller"
req.getRequestDispatcher("/front.controller").forward(req, response);
/*chain.doFilter(req, resp);*/
}
}
<filter>
<filter-name>Filter</filter-name>
<filter-class>test.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Is it right?
Thanks !
A Filter is an inappropriate solution for a front controller approach.
You want to refine the url-pattern of your servlet so that it matches e.g. /pages/* or *.do. You don't want your front controller to kick in on irrelevant requests like CSS/JS/images/etc. To take /pages/* as an example, assuming that you've a JSP in /WEB-INF/foo.jsp, then the following in a servlet
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response);
}
should display the JSP in question on http://localhost:8080/contextname/pages/foo.
See also:
Design patterns in Java web applications
Hidden features of JSP/Servlet
I think the problem here might be that you're using a Servlet instead of a ServletFilter.
A ServletFilter, as the name suggests filters requests by providing pre- and post-processing on the request. You'd probably want to use a Filter if you needed to do something like the following:
Provide security checks across an entire application
Set request properties that are picked up by a servlet or jsp
Compress a response
Log timing information
Etc.
Have a look at the documentation about Servlet Filters.

Categories