I am facing a strange problem with Tomcat 8 and CORS. I am developing a Hybrid web app using ionicframework, AngularJS, Cordova as front end and Tomcat 8 and Spring 3 as back-en
I just had the same problem. I may provide my solution. It is probably not the better way to do it as it involved to have access to the tomcat server configuration.
I defined a new filter which will set to null the desired header fields:
First, define the custom filter:
public class HttpHeaderNullifierFilter implements Filter {
/**
* init property name defining the headers names and values to set to null
*/
public static final String HEADERS_PROPERTY = "headers";
/**
* the names/values separator in the HEADERS_PROPERTY property
*/
public static final String HEADERS_SEPARATOR_PROPERTY = ",";
/**
* the key-value separator in the HEADERS_PROPERTY property
*/
public static final String HEADERS_KEY_VALUE_SEPARATOR_PROPERTY = "=";
/**
* the origin-header's names/values to set to null
*/
private Map> headersNamesValuesToNullify;
/**
* the request wrapper. override the specified fields with a null value
*/
public class CustomServletRequestWrapper extends HttpServletRequestWrapper {
/**
* constructor: wrap the request
*
* @param request
*/
public CustomServletRequestWrapper(HttpServletRequest request) {
super(request);
}
/**
* Check the header value: if the header-names'list contain the
* specified header, null is returned
*/
public String getHeader(String headerName) {
String result = super.getHeader(headerName);
if (headersNamesValuesToNullify.containsKey(headerName)) {
if(result != null && headersNamesValuesToNullify.get(headerName).contains(result)){
return null;
}
}
return result;
}
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
if (!(servletRequest instanceof HttpServletRequest)
|| !(servletResponse instanceof HttpServletResponse)) {
throw new ServletException("no HTTP request");
}
CustomServletRequestWrapper requestWrapper = new CustomServletRequestWrapper(
(HttpServletRequest) servletRequest);
// Forward the request down the filter chain.
filterChain.doFilter(requestWrapper, servletResponse);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
headersNamesValuesToNullify = new HashMap>();
if (filterConfig != null) {
String configAllowedOrigins = filterConfig.getInitParameter(HEADERS_PROPERTY);
if (configAllowedOrigins != null && configAllowedOrigins.length() > 0) {
if (configAllowedOrigins.indexOf(HEADERS_SEPARATOR_PROPERTY) > 0) {
for (String value : configAllowedOrigins.split(HEADERS_SEPARATOR_PROPERTY)) {
addKeyValueToMap(value, headersNamesValuesToNullify);
}
} else {
addKeyValueToMap(configAllowedOrigins, headersNamesValuesToNullify);
}
}
}
}
/**
* add the key-value par to the map
* @param keyValueStringValue the key-pair as one value
* @param map the map to add the key-pair value
*/
private void addKeyValueToMap(String keyValueStringValue, Map> map){
if(keyValueStringValue != null && keyValueStringValue.indexOf(HEADERS_KEY_VALUE_SEPARATOR_PROPERTY) > 0){
String[] keyValueSplit = keyValueStringValue.split(HEADERS_KEY_VALUE_SEPARATOR_PROPERTY);
String key = keyValueSplit[0];
String value = keyValueSplit[1];
if(! map.containsKey(key)){
map.put(key, new HashSet());
}
map.get(key).add(value);
}
}
}
This class define an "CustomServletRequestWrapper" class which will wrap the "HttpServletRequest". This wrapper override the "getHeader" method to implement our own behaviour: return a null value.
Then, when the filter receive a request, it wraps it and continue the filter-chain. Finally, when the tomcat's CORS-filter will access the "Origin" header-field, it will get a null value, a skip the CORS process.
This filter should be configured in the web.xml descriptor file as below :
CordovaOriginWrapper
your.package.HttpHeaderNullifierFilter
headers
Origin=file://
CorsFilter
...
...
CordovaOriginWrapper
/*
(it should be defined before the tomcat CORS-filter to be executed in the same order).
Hope it may help!