Created
March 10, 2011 23:58
-
-
Save mckamey/865216 to your computer and use it in GitHub Desktop.
Servlet Filter for JAX-RS content negotiation which fixes WebKit Accept header and adds extension support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.example.www.filters; | |
import java.io.IOException; | |
import java.util.*; | |
import javax.servlet.*; | |
import javax.servlet.http.*; | |
/** | |
* Modifies Accept headers and allows URL extensions to improve JAX-RS content negotiation | |
* Adds "Vary: accept" header to response | |
* | |
* Adapted from: http://www.zienit.nl/blog/2010/01/rest/control-jax-rs-content-negotiation-with-filters | |
*/ | |
public class AcceptFilter implements Filter { | |
private final Map<String,String> extensions = new HashMap<String,String>(); | |
@SuppressWarnings("unchecked") | |
public void init(FilterConfig config) throws ServletException { | |
Enumeration<String> exts = config.getInitParameterNames(); | |
while (exts.hasMoreElements()) { | |
String ext = exts.nextElement(); | |
if (ext != null && !ext.isEmpty()) { | |
this.extensions.put("."+ext.toLowerCase(), config.getInitParameter(ext)); | |
} | |
} | |
} | |
public void destroy() {} | |
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { | |
HttpServletRequest httpRequest = (HttpServletRequest)request; | |
String uri = httpRequest.getRequestURI(); | |
String ext = this.getExtension(uri); | |
String accept = this.extensions.get(ext); | |
if (accept == null) { | |
// This workaround may no longer needed with the ";qs=2" answer | |
// http://stackoverflow.com/questions/5250923/http-content-negotiation-conflicts-in-jax-rs-jersey/5536837#5536837 | |
accept = httpRequest.getHeader("accept"); | |
if (accept != null && accept.indexOf("text/html") > 0) { | |
// patch WebKit-style Accept headers by elevating "text/html" | |
accept = "text/html,"+accept; | |
request = new RequestWrapper(httpRequest, uri, accept); | |
} | |
} else { | |
// remove extension and remap the Accept header | |
uri = uri.substring(0, uri.length() - ext.length()); | |
request = new RequestWrapper(httpRequest, uri, accept); | |
} | |
// add "Vary: accept" to the response headers | |
HttpServletResponse httpResponse = (HttpServletResponse)response; | |
httpResponse.addHeader("Vary", "accept"); | |
chain.doFilter(request, response); | |
} | |
private String getExtension(String path) { | |
int index = path.lastIndexOf('.'); | |
if (index < 0 || path.lastIndexOf('/') > index) { | |
return ""; | |
} | |
return path.substring(index); | |
} | |
private static class RequestWrapper extends HttpServletRequestWrapper { | |
private final String uri; | |
private final String accept; | |
public RequestWrapper(HttpServletRequest request, String uri, String accept) { | |
super(request); | |
this.uri = uri; | |
this.accept = accept; | |
} | |
@Override | |
public String getRequestURI() { | |
return this.uri; | |
} | |
@Override | |
public Enumeration getHeaders(String name) { | |
if (!"accept".equalsIgnoreCase(name)) { | |
return super.getHeaders(name); | |
} | |
Vector<String> values = new Vector<String>(1); | |
values.add(this.accept); | |
return values.elements(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" | |
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" | |
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> | |
<filter> | |
<filter-name>accept-filter</filter-name> | |
<filter-class>org.example.www.filters.AcceptFilter</filter-class> | |
<init-param> | |
<param-name>html</param-name> | |
<param-value>text/html</param-value> | |
</init-param> | |
<init-param> | |
<param-name>xml</param-name> | |
<param-value>application/xml</param-value> | |
</init-param> | |
<init-param> | |
<param-name>json</param-name> | |
<param-value>application/json</param-value> | |
</init-param> | |
</filter> | |
<filter-mapping> | |
<filter-name>accept-filter</filter-name> | |
<url-pattern>/*</url-pattern> | |
</filter-mapping> | |
</web-app> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
At line 52 you have "Very"... when comment says "Vary".. IIRC comment is correct!
Also I'd not, prefix extensions hashmap key with dots and convert returned ext to lowercase without the dot, so .XML or .xml would work...
ie.
Line 24:
this.extensions.put(ext.toLowerCase(), config.getInitParameter(ext));
Line 46:
uri = uri.substring(0, uri.length() - ext.length()-1);