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
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 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