I'm hoping someone has already written this:
A servlet filter that can be configured with regular expression search/replace patterns and applies them to the HTML output.
Does such a thing exist?
I couldn't find one, so I wrote one:
RegexFilter.java
package com.example;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
/**
* Applies search and replace patterns. To initialize this filter, the
* param-names should be "search1", "replace1", "search2", "replace2", etc.
*/
public final class RegexFilter implements Filter {
private List<Pattern> searchPatterns;
private List<String> replaceStrings;
/**
* Finds the search and replace strings in the configuration file. Looks for
* matching searchX and replaceX parameters.
*/
public void init(FilterConfig filterConfig) {
Map<String, String> patternMap = new HashMap<String, String>();
// Walk through the parameters to find those whose names start with
// search
Enumeration<String> names = (Enumeration<String>) filterConfig.getInitParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
if (name.startsWith("search")) {
patternMap.put(name.substring(6), filterConfig.getInitParameter(name));
}
}
this.searchPatterns = new ArrayList<Pattern>(patternMap.size());
this.replaceStrings = new ArrayList<String>(patternMap.size());
// Walk through the parameters again to find the matching replace params
names = (Enumeration<String>) filterConfig.getInitParameterNames();
while (names.hasMoreElements()) {
String name = names.nextElement();
if (name.startsWith("replace")) {
String searchString = patternMap.get(name.substring(7));
if (searchString != null) {
this.searchPatterns.add(Pattern.compile(searchString));
this.replaceStrings.add(filterConfig.getInitParameter(name));
}
}
}
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Wrap the response in a wrapper so we can get at the text after calling the next filter
PrintWriter out = response.getWriter();
CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, wrapper);
// Extract the text from the completed servlet and apply the regexes
String modifiedHtml = wrapper.toString();
for (int i = 0; i < this.searchPatterns.size(); i++) {
modifiedHtml = this.searchPatterns.get(i).matcher(modifiedHtml).replaceAll(this.replaceStrings.get(i));
}
// Write our modified text to the real response
response.setContentLength(modifiedHtml.getBytes().length);
out.write(modifiedHtml);
out.close();
}
public void destroy() {
this.searchPatterns = null;
this.replaceStrings = null;
}
}
CharResponseWrapper.java
package com.example;
import java.io.CharArrayWriter;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* Wraps the response object to capture the text written to it.
*/
public class CharResponseWrapper extends HttpServletResponseWrapper {
private CharArrayWriter output;
public CharResponseWrapper(HttpServletResponse response) {
super(response);
this.output = new CharArrayWriter();
}
public String toString() {
return output.toString();
}
public PrintWriter getWriter() {
return new PrintWriter(output);
}
}
Example web.xml
<web-app>
<filter>
<filter-name>RegexFilter</filter-name>
<filter-class>com.example.RegexFilter</filter-class>
<init-param><param-name>search1</param-name><param-value><![CDATA[(<\s*a\s[^>]*)(?<=\s)target\s*=\s*(?:'_parent'|"_parent"|_parent|'_top'|"_top"|_top)]]></param-value></init-param>
<init-param><param-name>replace1</param-name><param-value>$1</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>RegexFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With