Created
July 14, 2010 23:26
-
-
Save fberger/476245 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
import com.sun.jersey.spi.container.ContainerRequest; | |
import com.sun.jersey.spi.container.ContainerResponse; | |
import com.sun.jersey.spi.container.ContainerResponseFilter; | |
import com.sun.jersey.spi.container.ContainerResponseWriter; | |
import javax.ws.rs.core.HttpHeaders; | |
import javax.ws.rs.core.MediaType; | |
import javax.ws.rs.core.MultivaluedMap; | |
import java.io.IOException; | |
import java.io.OutputStream; | |
import java.nio.charset.Charset; | |
import java.util.Collections; | |
/** | |
* Container response filter that wraps responses of type {@link javax.ws.rs.core.MediaType#APPLICATION_JSON_TYPE} and | |
* {@link #OPENSEARCH_SUGGESTIONS_JSON_UTF8_MEDIA_TYPE} into Javascript function calls if all of the following | |
* conditions are met: | |
* <ul> | |
* <li>the http method is GET</li> | |
* <li>no cookies are being sent in the request (this prevents cross site scripting attacks)</li> | |
* <li>no Authorization header is included in the request (this prevents cross site scripting attacks)</li> | |
* <li>a query parameter named callback is specified (http://url/?callback=functionName)</li> | |
* </ul> | |
*/ | |
public class JSONPContainerResponseFilter implements ContainerResponseFilter { | |
private static final MediaType OPENSEARCH_SUGGESTIONS_JSON_UTF8_MEDIA_TYPE = MediaType.valueOf("application/x-suggestions+json"); | |
private static final String APPLICATION_JAVASCRIPT_NO_CHARSET = "application/javascript"; | |
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) { | |
if (!request.getMethod().equals("GET")) { | |
return response; | |
} | |
MediaType responseType = response.getMediaType(); | |
if (responseType == null) { | |
return response; | |
} | |
if (!responseType.isCompatible(MediaType.APPLICATION_JSON_TYPE) && !responseType.isCompatible(OPENSEARCH_SUGGESTIONS_JSON_UTF8_MEDIA_TYPE)) { | |
return response; | |
} | |
if (!request.getCookies().isEmpty()) { | |
return response; | |
} | |
if (request.getHeaderValue(HttpHeaders.AUTHORIZATION) != null) { | |
return response; | |
} | |
MultivaluedMap<String, String> parameters = request.getQueryParameters(); | |
String callback = parameters.getFirst("callback"); | |
if (callback == null) { | |
return response; | |
} | |
String charset = responseType.getParameters().get("charset"); | |
response.setContainerResponseWriter(new JSONPContainerResponseWriter(callback, response.getContainerResponseWriter(), charset)); | |
response.getHttpHeaders().putSingle(HttpHeaders.CONTENT_TYPE, | |
charset != null ? | |
new MediaType("application", "javascript", Collections.singletonMap("charset", charset)).toString() : | |
APPLICATION_JAVASCRIPT_NO_CHARSET); | |
return response; | |
} | |
private static final class JSONPContainerResponseWriter implements ContainerResponseWriter { | |
private final String callback; | |
private final ContainerResponseWriter crw; | |
private final byte[] prefix; | |
private final byte[] postfix; | |
private OutputStream out; | |
JSONPContainerResponseWriter(String callback, ContainerResponseWriter containerResponseWriter, String encoding) { | |
this.callback = callback; | |
this.crw = containerResponseWriter; | |
// if no charset is specified use http default content charset iso-8859-1 | |
Charset charset = encoding != null ? Charset.forName(encoding) : Charset.forName("ISO-8859-1"); | |
this.prefix = (callback + "(").getBytes(charset); | |
this.postfix = ");".getBytes(charset); | |
} | |
public OutputStream writeStatusAndHeaders(long contentLength, ContainerResponse response) throws IOException { | |
out = crw.writeStatusAndHeaders(contentLength == -1 ? -1 : contentLength + prefix.length + postfix.length, response); | |
out.write(prefix); | |
return out; | |
} | |
public void finish() throws IOException { | |
out.write(postfix); | |
crw.finish(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment