Search |
||
Blarg #22: A Filter that auto-encodes session IDs on relative page links.Posted by jfalkner on March 27, 2006 at 10:43 PM PST
This is an example Filter that auto-encodes all relative links on a website using the HttpServletResponse.encodeURL() method. It was originally encoded as an example during a Develop Mentor course I taught. It is a nice example of a servlet filter that buffers a response, locates links using a simple regular expression, and replaces links with encoded links. The code. Remember each filter has three parts: the Filter, ServletResponseWrapper, and ServletOutputStream sub-class.
EncodeSessionInURLFilter.javaThis filter does nothing more than wraps the HttpServletResponse in order to buffer text sent out to a client. package example;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class EncodeSessionInURLFilter implements Filter {
ServletContext sc = null;
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
// check that it is a HTTP request
if (req instanceof HttpServletRequest) {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
// nonce encode the normal output
EncodeSessionInURLResponseWrapper wrappedResponse = new EncodeSessionInURLResponseWrapper(
response, sc);
// make sure a session exists
HttpSession session = request.getSession(true);
chain.doFilter(req, wrappedResponse);
// finish the respone
wrappedResponse.finishResponse();
}
}
public void init(FilterConfig filterConfig) {
// reference the context
sc = filterConfig.getServletContext();
}
public void destroy() {
// noop
}
}
EncodeSessionInURLResponseWrapper.javaThis wrapper sends back a custom ServletOutputStream object in order to buffer all text that is being sent to the client. package example;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class EncodeSessionInURLResponseWrapper extends HttpServletResponseWrapper {
protected HttpServletResponse origResponse = null;
protected ServletOutputStream stream = null;
protected PrintWriter writer = null;
ServletContext sc;
public EncodeSessionInURLResponseWrapper(HttpServletResponse response, ServletContext sc) {
super(response);
this.sc = sc;
origResponse = response;
}
public ServletOutputStream createOutputStream() throws IOException {
return (new EncodeSessionInURLResponseStream(origResponse, sc));
}
public void finishResponse() {
try {
if (writer != null) {
writer.close();
} else {
if (stream != null) {
stream.close();
}
}
} catch (IOException e) {}
}
public void flushBuffer() throws IOException {
stream.flush();
}
public ServletOutputStream getOutputStream() throws IOException {
if (writer != null) {
throw new IllegalStateException("getWriter() has already been called!");
}
if (stream == null)
stream = createOutputStream();
return (stream);
}
public PrintWriter getWriter() throws IOException {
if (writer != null) {
return (writer);
}
if (stream != null) {
throw new IllegalStateException("getOutputStream() has already been called!");
}
stream = createOutputStream();
// BUG FIX 2003-12-01 Reuse content's encoding, don't assume UTF-8
writer = new PrintWriter(new OutputStreamWriter(stream, origResponse.getCharacterEncoding()));
return (writer);
}
public void setContentLength(int length) {}
}
EncodeSessionInURLResponseStream.javaThis response stream buffers all text that is send to the client and uses a regular expression to locate and replace links with encoded links. package example; import java.io.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.servlet.*; import javax.servlet.http.*; /** * * @author Jayson Falkner - jayson@jspinsider.com */ public class EncodeSessionInURLResponseStream extends ServletOutputStream { // abstraction of the output stream used for compression protected OutputStream bufferedOutput = null; // state keeping variable for if close() has been called protected boolean closed = false; // reference to original response protected HttpServletResponse response = null; // reference to the output stream to the client's browser protected ServletOutputStream output = null; // default size of the in-memory buffer private int bufferSize = 50000; ServletContext sc; public EncodeSessionInURLResponseStream(HttpServletResponse response, ServletContext sc) throws IOException { super(); closed = false; this.sc = sc; this.response = response; this.output = response.getOutputStream(); bufferedOutput = new ByteArrayOutputStream(); } public void close() throws IOException { // make up a nonce String nonce = Integer.toString((int)(Math.random()*Integer.MAX_VALUE)); // set the nonce in app scope sc.setAttribute("nonce", nonce); // get the content ByteArrayOutputStream baos = (ByteArrayOutputStream) bufferedOutput; // make a string out of the response String pageText = new String(baos.toByteArray()); // use regex to find the links Pattern p = Pattern.compile(" href=\"[^\"]*|action=\"[^\"]*"); Matcher m = p.matcher(pageText); String newText = ""; int offset = 0; while (m.find(offset)) { // update the text newText += pageText.substring(offset, m.start()); // update the offset offset = m.end(); // get the matching string String match = pageText.substring(m.start(), m.end()); // get the URL String[] split = match.split("\""); String url = split[1]; // encode the match String encoded = response.encodeURL(url); // add the match to the new text newText += split[0]+"\""+encoded; } // add the final text newText += pageText.substring(offset, pageText.length()); // set appropriate HTTP headers // response.setContentLength(compressedBytes.length); output.write(newText.getBytes()); output.flush(); output.close(); closed = true; } public void flush() throws IOException { if (closed) { throw new IOException("Cannot flush a closed output stream"); } bufferedOutput.flush(); } public void write(int b) throws IOException { if (closed) { throw new IOException("Cannot write to a closed output stream"); } // write the byte to the temporary output bufferedOutput.write((byte) b); } public void write(byte b[]) throws IOException { write(b, 0, b.length); } public void write(byte b[], int off, int len) throws IOException { System.out.println("writing..."); if (closed) { throw new IOException("Cannot write to a closed output stream"); } // write the content to the buffer bufferedOutput.write(b, off, len); } public boolean closed() { return (this.closed); } public void reset() { //noop } } »
Comments
Comments are listed in date ascending order (oldest first)
|
||
|
|