Skip to content

Instantly share code, notes, and snippets.

@unicolet
Created December 18, 2012 12:18
A (working, if it doesn't let me know) HttpServletRequestWrapper that supports: * multiple calls to getInputStream, no more pain when writing filters * programmatic injection of the Principal * post params will be fetched from the local request body cache so you can now still call getParameter after someone else called getInpuStream
package java.is.awesome; // joking
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import javax.servlet.ServletInputStream;
import javax.servlet.http.*;
import java.io.*;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
/**
* AwesomeRequestWrapper adds two important features:
*
* 1. allow to set the user principal on the request so that the CAS can trust the user id
* 2. cache post data and parse them offline so that inpustream can be read multiple times
*/
public class AwesomeRequestWrapper extends HttpServletRequestWrapper {
Logger logger;
Principal awesomePrincipal = null;
Map parameters = null;
byte[] postData = null;
public AwesomeRequestWrapper(HttpServletRequest request) {
super(request);
logger = Logger.getLogger(this.getClass());
parameters = new HashMap();
}
public Principal getUserPrincipal() {
if (awesomePrincipal == null) {
return super.getUserPrincipal();
}
return awesomePrincipal;
}
public String getRemoteUser() {
if (awesomePrincipal == null) {
return super.getRemoteUser();
}
return awesomePrincipal.getName();
}
void setUserPrincipal(Principal p) {
awesomePrincipal = p;
}
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value == null) {
value = (String) parameters.get(name);
}
return value;
}
@Override
public ServletInputStream getInputStream() throws IOException {
logger.trace("called getInputStream");
if (postData == null) {
postData = IOUtils.toByteArray(super.getInputStream());
parameters = getQueryMap(new String(postData));
}
logger.trace("post data read, parsed and cached: " + new String(postData));
return new BAServletInputStream(new ByteArrayInputStream(postData));
}
private class BAServletInputStream extends ServletInputStream {
InputStream is;
BAServletInputStream(InputStream is) {
this.is = is;
}
@Override
public int read() throws IOException {
return is.read();
}
@Override
public int readLine(byte[] b, int off, int len) throws IOException {
return is.read(b, off, len);
}
@Override
public int read(byte[] bytes) throws IOException {
return is.read(bytes);
}
@Override
public int read(byte[] bytes, int i, int i1) throws IOException {
return is.read(bytes, i, i1);
}
@Override
public long skip(long l) throws IOException {
return is.skip(l);
}
}
/* this could actually be improved, there should be a method that does the same in Spring */
public Map<String, String> getQueryMap(String query) {
String[] params = query.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params) {
try {
String name = URIUtil.decode(param.split("=")[0]);
String value = URIUtil.decode(param.split("=")[1]);
map.put(name, value);
} catch (Exception e) {
logger.error("Cannot decode request parameter: " + e.getMessage());
}
}
return map;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment