Оболочка ответа сервлета имеет проблему с кодировкой - PullRequest
2 голосов
/ 15 января 2011

Оболочка ответа сервлета используется в фильтре сервлета. Идея заключается в том, что ответом манипулируют, а значение «nonce» вводят в формы как часть защиты от CSRF-атак.

Веб-приложение везде использует UTF-8. Когда фильтр сервлетов отсутствует, проблем нет. Когда фильтр добавлен, возникают проблемы с кодировкой. (Кажется, что ответ возвращается к 8859-1.)

Внутренности кода:

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

Насколько я понимаю, переход между byte-land и String-land должен указывать кодировку. Это делается здесь, как вы можете видеть, в двух местах. Значение переменной 'encoding' равно 'UTF-8'; изменение самой строки является стандартным манипулированием строкой (с регулярным выражением) и никогда не определяет кодировку (addHiddenParamToPostedForms).

Где я ошибаюсь по поводу кодировки?

EDIT: Вот базовый класс (извините, он довольно длинный):

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

Ответы [ 2 ]

5 голосов
/ 15 января 2011

Из new PrintWriter(OutputStream) Javadoc :

Создает новый PrintWriter, без автоматической очистки строки, из существующего OutputStream. Этот удобный конструктор создает необходимый промежуточный OutputStreamWriter, который преобразует символы в байты с использованием кодировки символов по умолчанию .

Вот ваш виновник. Взгляните на OutputStreamWriter, где вы можете указать кодировку.

0 голосов
/ 15 января 2011

Код, который вы предоставляете, не содержит ошибок.

Что ты делаешь в другом месте?

  • есть ли в цепочке другие фильтры, которые могут манипулировать потоком кодирования / байтов, возможно, у вас проблема с позицией фильтра
  • Исправлено ли «кодирование» или динамически считывается из запроса?
...