본문 바로가기
IT/JAVA

ServletFilter 를 이용한 Download File 분석

by 최고영회 2020. 9. 29.
728x90
반응형
SMALL

요구사항

- 사용자가 Download 받는 File을 Copy 해서 별도 분석 모듈에게 전달해야 함

- 사용자는 File Download 를 받는데 달라지는 점이 없어야 함

- 사용자가 File Download 를 받는데 속도 저하가 없어야 함

구현방법

- HttpServletResponse 를 copy 한다.

- filter chain에 copy한 response를 보내고 flulsh 한다.

- finally 에서 copy 본을 이용하여 File 을 생성한다.

 

HttpServletResponseCopier responseCopier = new HttpServletResponseCopier((HttpServletResponse) response);

try {
  chain.doFilter(request, responseCopier);
  responseCopier.flushBuffer();
} finally {
  writeNewFile(responseCopier.getCopy());
}

코드를 살펴보면 간단하다 .

ServletOutputStream 을 extends 받아 class를 하나 만들고 ByteArrayOutputStream copy를 둬서 write가 호출될 때 copy에도 같이 쓰도록 한다.

HttpServletResponseWrapper 를 extends 받아 class를 하나 맏들고 똑같이 outputStream과 더불어 copy본을 선언해 두고 getWriter, getOutputStream이 호출될 때 copy본을 만들도록 한다.

Filter 에서는 이 copy본을 이용하여 File을 만드는 것이다.

사용자에게 File이 모두 download 된 후에 File이 만들어지기 때문에 사용자 입장에서 속도 저하는 없다.

 

public class HttpServletResponseCopier extends HttpServletResponseWrapper {
  private ServletOutputStream outputStream;
  private PrintWriter writer;
  private ServletOutputStreamCopier copier;
  public HttpServletResponseCopier(HttpServletResponse response) throws IOException {
      super(response);
  }
  @Override
  public ServletOutputStream getOutputStream() throws IOException {
      if (writer != null) {
          throw new IllegalStateException("getWriter() has already been called on this response.");
      }
      if (outputStream == null) {
          outputStream = getResponse().getOutputStream();
          copier = new ServletOutputStreamCopier(outputStream);
      }
      return copier;
  }
  @Override
  public PrintWriter getWriter() throws IOException {
      if (outputStream != null) {
          throw new IllegalStateException("getOutputStream() has already been called on this response.");
      }
      if (writer == null) {
          copier = new ServletOutputStreamCopier(getResponse().getOutputStream());
          writer = new PrintWriter(new OutputStreamWriter(copier, getResponse().getCharacterEncoding()), true);
      }
      return writer;
  }
  @Override
  public void flushBuffer() throws IOException {
      if (writer != null) {
          writer.flush();
      } else if (outputStream != null) {
          copier.flush();
      }
  }
  public byte[] getCopy() {
      if (copier != null) {
          return copier.getCopy();
      } else {
          return new byte[0];
      }
  }
}

 

public class ServletOutputStreamCopier extends ServletOutputStream {
  private OutputStream outputStream;
  private ByteArrayOutputStream copy;
  public ServletOutputStreamCopier(OutputStream outputStream) {
      this.outputStream = outputStream;
      this.copy = new ByteArrayOutputStream(1024);
  }
  @Override
  public void write(int b) throws IOException {
      outputStream.write(b);
      copy.write(b);
  }
  public byte[] getCopy() {
      return copy.toByteArray();
  }
  @Override
  public boolean isReady() {
    return false;
  }
  @Override
  public void setWriteListener(WriteListener writeListener) {
  }
}

 

이제 복사된 파일을 분석하면 된다.

위 코드에서 생략한 부분은

- 분석이 필요한 부분일 경우에만 file 생성하도록 처리하는 부분

- 동일한 파일이 이전에 복사된 적이 있을 경우 (file hash 비교 처리)에 대한 처리

728x90
반응형
LIST