2011-02-15 16 views
10

Espero que alguien ya haya escrito esto:¿Dónde puedo encontrar un filtro de servlet Java que aplique expresiones regulares a la salida?

Un filtro de servlet que se puede configurar con patrones de búsqueda/reemplazo de expresiones regulares y los aplica a la salida HTML.

¿Existe tal cosa?

+0

¿Qué es exactamente lo que quiere cambiar? La URL de la solicitud o el cuerpo de respuesta? El UrlRewriteFilter de Tuckey es excelente, pero está pensado para reescribir las URL (como sea posible con la conocida RewriteRule de Apache HTTPD). Para cambiar el cuerpo de la respuesta, deberá ser más específico sobre el requisito funcional. No me viene a la mente ningún filtro, pero esto huele demasiado a desinfectar la entrada controlada por el usuario para evitar el XSS. En tal caso, regex es absolutamente la herramienta incorrecta para el trabajo. – BalusC

+0

Lo siento, no estaba claro. He editado la pregunta para indicar que quiero modificar el resultado HTML. –

+0

¿Qué hay exactamente en la salida de HTML? Dado que el uso de expresiones regulares para analizar y modificar HTML es una práctica extremadamente pobre, nunca se escribió ese filtro. Por favor, aclare el requisito funcional más. ¿Por qué necesitarías un filtro para esto? ¿Por qué no hacer los cambios directamente en el lado de la vista? Etc. – BalusC

Respuesta

14

no pude encontrar uno, así que escribió uno:

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); 
    } 
} 

Ejemplo 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> 
+0

¡Cosas increíbles, acabo de usar esto para ayudarme a resolver un problema similar! – Zugwalt

+0

Recomendaría un out.flush() antes del out.close() para evitar errores como estos: java.net.ProtocolException: No cumplió con el contenido de longitud establecido, escribió: '27026' bytes en lugar de declarado: '27023 'bytes. – rudolfv

4

No estoy seguro de si esto es lo que está buscando, pero hay un filtro de reescritura de URL. Es compatible con expresiones regulares. Por favor, mira aquí http://www.tuckey.org/urlrewrite/

Espero que esto ayude.

+0

Esta biblioteca admite no solo la reescritura de URL entrantes sino también la modificación de enlaces en la página HTML: http://urlrewritefilter.googlecode.com/svn/trunk/src/doc/manual/4.0/index.html#outbound -rule Nice. – rwitzel

Cuestiones relacionadas