[ 
https://issues.apache.org/jira/browse/WW-5496?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17906112#comment-17906112
 ] 

Günter Paul edited comment on WW-5496 at 12/16/24 6:12 PM:
-----------------------------------------------------------

Filter-class
{code:java}
package de.guenterpaul.servlet;import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.util.StringTokenizer;

public class BlankFilter
  implements Filter
{  
  @Override
  public void init(FilterConfig pFilterConfig)
  {
    setTrimOnly(pFilterConfig.getInitParameter("trimOnly"));
    if (m_Logger.isDebugEnabled()) m_Logger.debug("init filter: " + this);
  }  

  @Override
  public void doFilter(ServletRequest pServletRequest,
                       ServletResponse pServletResponse,
                       FilterChain pFilterChain)
  {
    HttpServletRequest lHttpServletRequest = (HttpServletRequest) 
pServletRequest;
    if (m_Logger.isInfoEnabled()) m_Logger.info("Start Blank-Filter >" + 
lHttpServletRequest.getRequestURI() + "< " + this);    try
    {
      HttpServletResponse lHttpServletResponse = (HttpServletResponse) 
pServletResponse;
      StringResponseWrapper lResponseWrapper = new 
StringResponseWrapper(lHttpServletResponse);      
pFilterChain.doFilter(pServletRequest,lResponseWrapper);      if 
(m_Logger.isDebugEnabled()) m_Logger.debug("ContentType >" + 
lResponseWrapper.getContentType() + "<");
      if ( (lResponseWrapper.getContentType() != null) && 
(lResponseWrapper.getContentType().startsWith("text/html")) )
      {
        if (m_Logger.isInfoEnabled())
        {
          m_Logger.info("BlankFilter Text >" + 
lResponseWrapper.getContentType() + "< Size: " + 
lResponseWrapper.getBufferSize());
        }
        StringBuilder lStringBuffer = new StringBuilder();        String 
lsResponse = lResponseWrapper.toString().trim();
        if (m_Logger.isDebugEnabled())
        {
          m_Logger.debug("Response >" + lsResponse + "<");
        }
        lsResponse = lsResponse.replaceAll("\r\n", "\n");        
StringTokenizer lStringTokenizer = new StringTokenizer(lsResponse, "\n");
        while (lStringTokenizer.hasMoreTokens())
        {
          String lsZeile = lStringTokenizer.nextToken().trim();
          if (m_Logger.isDebugEnabled()) m_Logger.debug("Zeile >" + lsZeile + 
"<");
          if (lsZeile.isEmpty() == false)
          {
            lStringBuffer.append(lsZeile.trim());
            if (isTrimOnly() == true)
            {
              lStringBuffer.append("\r\n");
            }
          }
        }        if (m_Logger.isInfoEnabled()) m_Logger.info("Laenge Ausgabe: " 
+ lStringBuffer.toString().length());
        if (m_Logger.isDebugEnabled())
        {
          m_Logger.debug(lStringBuffer);
        }        
lHttpServletResponse.setContentType(lResponseWrapper.getContentType());
        
lHttpServletResponse.setContentLength(lStringBuffer.toString().length());
        lHttpServletResponse.getWriter().print(lStringBuffer);
      }
      else
      {
        m_Logger.debug("Standard Ausgabe: " + lResponseWrapper.getBufferSize());
        if ( (lResponseWrapper.getBufferSize() > 0) && 
(lResponseWrapper.toString() != null) )
        {
          
pServletResponse.getOutputStream().write(lResponseWrapper.toString().getBytes());
        }
      }
      if (m_Logger.isDebugEnabled())
      {
        m_Logger.debug("Ende Request BlankFilter >" +  
lHttpServletRequest.getRequestURI() + "<");
      }
    }
    catch (Exception ex)
    {
      m_Logger.error("Fehler: " + ex.getMessage(), ex);
    }    if (m_Logger.isDebugEnabled()) m_Logger.debug("Ende  Blank-Filter");
  }  

  @Override
  public void destroy()
  {
    if (m_Logger.isDebugEnabled()) m_Logger.debug("destroy filter");
  }

  public boolean isTrimOnly()
  {
    return m_bTrimOnly;
  }

  public void setTrimOnly(boolean pbTrimOnly)
  {
    if (m_Logger.isDebugEnabled()) m_Logger.debug("B: TrimOnly: " + pbTrimOnly);
    this.m_bTrimOnly = pbTrimOnly;
  }

  public void setTrimOnly(String psTrimOnly)
  {
    boolean lbTrimOnly = isTrimOnly();
    if ((psTrimOnly != null) && (psTrimOnly.isEmpty() == false) )
    {
      if (psTrimOnly.toLowerCase().equals(Boolean.TRUE.toString()))
      {
        lbTrimOnly = true;
      }
      else if (psTrimOnly.toLowerCase().equals(Boolean.FALSE.toString()))
      {
        lbTrimOnly = false;
      }
    }
    if (m_Logger.isDebugEnabled()) m_Logger.debug("S: TrimOnly >" + psTrimOnly 
+ "< : " + lbTrimOnly);
    setTrimOnly(lbTrimOnly);
  }

  @Override
  public String toString()
  {
    return "BlankFilter{" + "m_bTrimOnly=" + m_bTrimOnly + '}';
  }  private static final Logger m_Logger = 
LogManager.getLogger(BlankFilter.class.getName());  private boolean m_bTrimOnly 
= false;
}
 {code}
ResponseWrapper-class
{code:java}
package de.guenterpaul.servlet;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

public class StringResponseWrapper extends HttpServletResponseWrapper
{
  private final ByteArrayOutputStream capture;
  private ServletOutputStream output;
  private PrintWriter writer;

  public StringResponseWrapper(HttpServletResponse response) {    
super(response);
    capture = new ByteArrayOutputStream(response.getBufferSize());
  }

  @Override
  public ServletOutputStream getOutputStream()
 {
    if (writer != null) {
      throw new IllegalStateException("getWriter() has already been called on 
this response.");
    }
    if (output == null) {
      // inner class - lets the wrapper manipulate the response
      output = new ServletOutputStream()
      {
        @Override
        public boolean isReady()
        {
          return true;
        }
        @Override
        public void setWriteListener(WriteListener writeListener)
        {        }
        @Override
        public void write(int b)
        {          capture.write(b);
        }
        @Override
        public void flush() throws IOException {          capture.flush();
        }
        @Override
        public void close() throws IOException {          capture.close();
        }
      };
    }
    return output;
  }
  @Override
  public PrintWriter getWriter() throws IOException
  {    if (output != null) {
      throw new IllegalStateException("getOutputStream() has already been 
called on this response.");
    }
    if (writer == null) {
      writer = new PrintWriter(new OutputStreamWriter(capture, 
getCharacterEncoding()));
    }
    return writer;
  }

  @Override
  public void flushBuffer() throws IOException {
    super.flushBuffer();
    if (writer != null) {
      writer.flush();
    } else if (output != null) {
      output.flush();
    }
  }

  public byte[] getCaptureAsBytes() throws IOException
  {
    flushBuffer();
    if (writer != null) {
      writer.close();
    } else if (output != null) {
      output.close();
    }
    return capture.toByteArray();
  }

  public String getCaptureAsString() throws IOException
  {
    return new String(getCaptureAsBytes(), getCharacterEncoding());
  }

  @Override
  public String toString()
  {
    try
    {
      return getCaptureAsString();
    }
    catch (IOException e)
    {
      return super.toString();
    }
  }
}
 {code}
 


was (Author: guenterpaul):
Filter-class
{code:java}
package de.guenterpaul.servlet;import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.util.StringTokenizer;

public class BlankFilter
  implements Filter
{  
  @Override
  public void init(FilterConfig pFilterConfig)
  {
    setTrimOnly(pFilterConfig.getInitParameter("trimOnly"));
    if (m_Logger.isDebugEnabled()) m_Logger.debug("init filter: " + this);
  }  @Override
  public void doFilter(ServletRequest pServletRequest,
                       ServletResponse pServletResponse,
                       FilterChain pFilterChain)
  {
    HttpServletRequest lHttpServletRequest = (HttpServletRequest) 
pServletRequest;
    if (m_Logger.isInfoEnabled()) m_Logger.info("Start Blank-Filter >" + 
lHttpServletRequest.getRequestURI() + "< " + this);    try
    {
      HttpServletResponse lHttpServletResponse = (HttpServletResponse) 
pServletResponse;
      StringResponseWrapper lResponseWrapper = new 
StringResponseWrapper(lHttpServletResponse);      
pFilterChain.doFilter(pServletRequest,lResponseWrapper);      if 
(m_Logger.isDebugEnabled()) m_Logger.debug("ContentType >" + 
lResponseWrapper.getContentType() + "<");
      if ( (lResponseWrapper.getContentType() != null) && 
(lResponseWrapper.getContentType().startsWith("text/html")) )
      {
        if (m_Logger.isInfoEnabled())
        {
          m_Logger.info("BlankFilter Text >" + 
lResponseWrapper.getContentType() + "< Size: " + 
lResponseWrapper.getBufferSize());
        }
        StringBuilder lStringBuffer = new StringBuilder();        String 
lsResponse = lResponseWrapper.toString().trim();
        if (m_Logger.isDebugEnabled())
        {
          m_Logger.debug("Response >" + lsResponse + "<");
        }
        lsResponse = lsResponse.replaceAll("\r\n", "\n");        
StringTokenizer lStringTokenizer = new StringTokenizer(lsResponse, "\n");
        while (lStringTokenizer.hasMoreTokens())
        {
          String lsZeile = lStringTokenizer.nextToken().trim();
          if (m_Logger.isDebugEnabled()) m_Logger.debug("Zeile >" + lsZeile + 
"<");
          if (lsZeile.isEmpty() == false)
          {
            lStringBuffer.append(lsZeile.trim());
            if (isTrimOnly() == true)
            {
              lStringBuffer.append("\r\n");
            }
          }
        }        if (m_Logger.isInfoEnabled()) m_Logger.info("Laenge Ausgabe: " 
+ lStringBuffer.toString().length());
        if (m_Logger.isDebugEnabled())
        {
          m_Logger.debug(lStringBuffer);
        }        
lHttpServletResponse.setContentType(lResponseWrapper.getContentType());
        
lHttpServletResponse.setContentLength(lStringBuffer.toString().length());
        lHttpServletResponse.getWriter().print(lStringBuffer);
      }
      else
      {
        m_Logger.debug("Standard Ausgabe: " + lResponseWrapper.getBufferSize());
        if ( (lResponseWrapper.getBufferSize() > 0) && 
(lResponseWrapper.toString() != null) )
        {
          
pServletResponse.getOutputStream().write(lResponseWrapper.toString().getBytes());
        }
      }
      if (m_Logger.isDebugEnabled())
      {
        m_Logger.debug("Ende Request BlankFilter >" +  
lHttpServletRequest.getRequestURI() + "<");
      }
    }
    catch (Exception ex)
    {
      m_Logger.error("Fehler: " + ex.getMessage(), ex);
    }    if (m_Logger.isDebugEnabled()) m_Logger.debug("Ende  Blank-Filter");
  }  @Override
  public void destroy()
  {
    if (m_Logger.isDebugEnabled()) m_Logger.debug("destroy filter");
  }  public boolean isTrimOnly()
  {
    return m_bTrimOnly;
  }  public void setTrimOnly(boolean pbTrimOnly)
  {
    if (m_Logger.isDebugEnabled()) m_Logger.debug("B: TrimOnly: " + pbTrimOnly);
    this.m_bTrimOnly = pbTrimOnly;
  }  public void setTrimOnly(String psTrimOnly)
  {
    boolean lbTrimOnly = isTrimOnly();
    if ((psTrimOnly != null) && (psTrimOnly.isEmpty() == false) )
    {
      if (psTrimOnly.toLowerCase().equals(Boolean.TRUE.toString()))
      {
        lbTrimOnly = true;
      }
      else if (psTrimOnly.toLowerCase().equals(Boolean.FALSE.toString()))
      {
        lbTrimOnly = false;
      }
    }
    if (m_Logger.isDebugEnabled()) m_Logger.debug("S: TrimOnly >" + psTrimOnly 
+ "< : " + lbTrimOnly);
    setTrimOnly(lbTrimOnly);
  }  @Override
  public String toString()
  {
    return "BlankFilter{" + "m_bTrimOnly=" + m_bTrimOnly + '}';
  }  private static final Logger m_Logger = 
LogManager.getLogger(BlankFilter.class.getName());  private boolean m_bTrimOnly 
= false;
}
 {code}
ResponseWrapper-class
{code:java}
package de.guenterpaul.servlet;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.WriteListener;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletResponseWrapper;import 
java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;public class StringResponseWrapper extends 
HttpServletResponseWrapper
{
  private final ByteArrayOutputStream capture;
  private ServletOutputStream output;
  private PrintWriter writer;  public StringResponseWrapper(HttpServletResponse 
response) {    super(response);
    capture = new ByteArrayOutputStream(response.getBufferSize());
  }  @Override
  public ServletOutputStream getOutputStream() {    if (writer != null) {
      throw new IllegalStateException("getWriter() has already been called on 
this response.");
    }    if (output == null) {
      // inner class - lets the wrapper manipulate the response
      output = new ServletOutputStream()
      {
        @Override
        public boolean isReady()
        {
          return true;
        }        @Override
        public void setWriteListener(WriteListener writeListener)
        {        }        @Override
        public void write(int b)
        {          capture.write(b);
        }        @Override
        public void flush() throws IOException {          capture.flush();
        }        @Override
        public void close() throws IOException {          capture.close();
        }
      };
    }    return output;
  }  @Override
  public PrintWriter getWriter() throws IOException {    if (output != null) {
      throw new IllegalStateException("getOutputStream() has already been 
called on this response.");
    }    if (writer == null) {
      writer = new PrintWriter(new OutputStreamWriter(capture, 
getCharacterEncoding()));
    }    return writer;
  }  @Override
  public void flushBuffer() throws IOException {    super.flushBuffer();    if 
(writer != null) {
      writer.flush();
    } else if (output != null) {
      output.flush();
    }
  }  public byte[] getCaptureAsBytes() throws IOException
  {
    flushBuffer();
    if (writer != null) {
      writer.close();
    } else if (output != null) {
      output.close();
    }    return capture.toByteArray();
  }  public String getCaptureAsString() throws IOException {    return new 
String(getCaptureAsBytes(), getCharacterEncoding());
  }  @Override
  public String toString()
  {
    try
    {
      return getCaptureAsString();
    }
    catch (IOException e)
    {
      return super.toString();
    }
  }
}
 {code}

> Struts filter and HttpServletResponseWrapper
> --------------------------------------------
>
>                 Key: WW-5496
>                 URL: https://issues.apache.org/jira/browse/WW-5496
>             Project: Struts 2
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 7.0.0
>            Reporter: Günter Paul
>            Priority: Minor
>             Fix For: 7.1.0
>
>
> I've been using a servlet filter for a long time. It removes spaces in the 
> lines (trim()) and line breaks (only for *.action requests).
> The filter is installed in the web.xml before the struts filter. It works 
> very well so far, even with the current Struts 7.0.0-M10 version.
> Until now I was using Tomcat 10. After switching to Tomcat 11, only blank 
> pages are displayed.
> If I use a web-application without struts, the filter works fine. Only when 
> the Struts filter (StrutsPrepareAndExecuteFilter) is installed does the 
> output of the wrapper appear to no longer be included in the output stream.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to