Servlet response wrapper has encoding problem

Posted by John O on Stack Overflow See other posts from Stack Overflow or by John O
Published on 2011-01-14T23:31:18Z Indexed on 2011/01/15 3:53 UTC
Read the original article Hit count: 219

A servlet response wrapper is being used in a Servlet Filter. The idea is that the response is manipulated, with a 'nonce' value being injected into forms, as part of defence against CSRF attacks.

The web app is using UTF-8 everywhere. When the Servlet Filter is absent, no problems. When the filter is added, encoding issues occur. (It seems as if the response is reverting to 8859-1.)

The guts of the code :

final class CsrfResponseWrapper extends AbstractResponseWrapper {
   ...
   byte[] modifyResponse(byte[] aInputResponse){
      ...
      String originalInput = new String(aInputResponse, encoding);
      String modifiedResult = addHiddenParamToPostedForms(originalInput);
      result = modifiedResult.getBytes(encoding);
      ...
   }
   ...
}

As I understand it, the transition between byte-land and String-land should specify an encoding. That is done here, as you can see, in two places. The value of the 'encoding' variable is 'UTF-8'; the alteration of the String itself is standard string manipulation (with a regex), and never specifies an encoding (addHiddenParamToPostedForms).

Where am I in error about the encoding?

EDIT: Here is the base class (sorry it's rather long):

package hirondelle.web4j.security;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

/**
 Abstract Base Class for altering response content.
 (May be useful in future contexts as well. For now, keep package-private.)  
*/
abstract class AbstractResponseWrapper extends HttpServletResponseWrapper {

  AbstractResponseWrapper(ServletResponse aServletResponse) throws IOException {
    super((HttpServletResponse)aServletResponse);
    fOutputStream = new ModifiedOutputStream(aServletResponse.getOutputStream());
    fWriter = new PrintWriter(fOutputStream);
  }

  /** Return the modified response. */
  abstract byte[] modifyResponse(byte[] aInputResponse);

  /** Standard servlet method.  */
  public final ServletOutputStream getOutputStream() {
    //fLogger.fine("Modified Response : Getting output stream.");
    if ( fWriterReturned ) {
      throw new IllegalStateException();
    }
    fOutputStreamReturned = true;
    return fOutputStream;
  }

  /** Standard servlet method.  */
  public final PrintWriter getWriter() {
    //fLogger.fine("Modified Response : Getting writer.");
    if ( fOutputStreamReturned ) {
      throw new IllegalStateException();
    }
    fWriterReturned = true;
    return fWriter;
  }

  // PRIVATE

  /*
   Well-behaved servlets return either an OutputStream or a PrintWriter, but not both.
  */
  private PrintWriter fWriter; 
  private ModifiedOutputStream fOutputStream;

  /*
   These items are used to implement conformance to the 
   javadoc for ServletResponse, regarding exceptions being thrown.
  */
  private boolean fWriterReturned;
  private boolean fOutputStreamReturned;

  /** Modified low level output stream.  */
  private class ModifiedOutputStream extends ServletOutputStream {
    public ModifiedOutputStream(ServletOutputStream aOutputStream) {
      fServletOutputStream = aOutputStream;
      fBuffer = new ByteArrayOutputStream();
    }
    /** Must be implemented to make this class concrete.   */
    public void write(int aByte) {
      fBuffer.write(aByte);
    }
    public void close() throws IOException {
      if ( !fIsClosed ){
        processStream();
        fServletOutputStream.close();
        fIsClosed = true;
      }
    }
    public void flush() throws IOException {
      if ( fBuffer.size() != 0 ){
        if ( !fIsClosed ) {
          processStream(); 
          fBuffer = new ByteArrayOutputStream();
        }
      }
    }
    /** Perform the core processing, by calling the abstract method.  */
    public void processStream() throws IOException {
      fServletOutputStream.write(modifyResponse(fBuffer.toByteArray()));
      fServletOutputStream.flush();
    }
    // PRIVATE //
    private ServletOutputStream fServletOutputStream;
    private ByteArrayOutputStream fBuffer;
    /** Tracks if this stream has been closed.    */
    private boolean fIsClosed = false;
  }
}

© Stack Overflow or respective owner

Related posts about java

Related posts about servlets