I have written a Java HTTP Response filter in which I am modifying the HTTP response body. Since I am changing the HTTP responce body, I have to update the http content-length header filed in response in accordance with new content. I am doing it in the following way.
response.setContentLength( next.getBytes().length );
hear next is a string
However, this method is unable to set the new content length of the HTTP response. Could somebody advice me whats the correct way to get it done in Java filter
package com.test;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class DumpFilter implements Filter {
private static class ByteArrayServletStream extends ServletOutputStream {
ByteArrayOutputStream baos;
ByteArrayServletStream(ByteArrayOutputStream baos) {
this.baos = baos;
}
public void write(int param) throws IOException {
baos.write(param);
}
}
private static class ByteArrayPrintWriter {
private ByteArrayOutputStream baos = new ByteArrayOutputStream();
private PrintWriter pw = new PrintWriter(baos);
private ServletOutputStream sos = new ByteArrayServletStream(baos);
public PrintWriter getWriter() {
return pw;
}
public ServletOutputStream getStream() {
return sos;
}
byte[] toByteArray() {
return baos.toByteArray();
}
}
private class BufferedServletInputStream extends ServletInputStream {
ByteArrayInputStream bais;
public BufferedServletInputStream(ByteArrayInputStream bais) {
this.bais = bais;
}
public int available() {
return bais.available();
}
public int read() {
return bais.read();
}
public int read(byte[] buf, int off, int len) {
return bais.read(buf, off, len);
}
}
private class BufferedRequestWrapper extends HttpServletRequestWrapper {
ByteArrayInputStream bais;
ByteArrayOutputStream baos;
BufferedServletInputStream bsis;
byte[] buffer;
public BufferedRequestWrapper(HttpServletRequest req) throws IOException {
super(req);
InputStream is = req.getInputStream();
baos = new ByteArrayOutputStream();
byte buf[] = new byte[1024];
int letti;
while ((letti = is.read(buf)) > 0) {
baos.write(buf, 0, letti);
}
buffer = baos.toByteArray();
}
public ServletInputStream getInputStream() {
try {
bais = new ByteArrayInputStream(buffer);
bsis = new BufferedServletInputStream(bais);
} catch (Exception ex) {
ex.printStackTrace();
}
return bsis;
}
public byte[] getBuffer() {
return buffer;
}
}
private boolean dumpRequest;
private boolean dumpResponse;
public void init(FilterConfig filterConfig) throws ServletException {
dumpRequest = Boolean.valueOf(filterConfig.getInitParameter("dumpRequest"));
dumpResponse = Boolean.valueOf(filterConfig.getInitParameter("dumpResponse"));
}
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest)servletRequest;
BufferedRequestWrapper bufferedRequest= new BufferedRequestWrapper(httpRequest);
if (dumpRequest) {
System.out.println("REQUEST -> " + new String(bufferedRequest.getBuffer()));
}
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final ByteArrayPrintWriter pw = new ByteArrayPrintWriter();
HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {
public PrintWriter getWriter() {
return pw.getWriter();
}
public ServletOutputStream getOutputStream() {
return pw.getStream();
}
};
filterChain.doFilter(bufferedRequest, wrappedResp);
byte[] bytes = pw.toByteArray();
String s = new String(bytes);
String next = "test message";
response.getOutputStream().write(next.getBytes());
///response.setHeader("Content-Length", String.valueOf(next.length()));
response.setContentLength( next.getBytes().length );
// if (dumpResponse) System.out.println("RESPONSE -> " + s);
}
public void destroy() {}
}
given above is the Filter class, but you may not need to read the whole class. Following is the doFilter code where I am modifying the http body and setting the content length filed.
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
final HttpServletRequest httpRequest = (HttpServletRequest)servletRequest;
BufferedRequestWrapper bufferedRequest= new BufferedRequestWrapper(httpRequest);
if (dumpRequest) {
System.out.println("REQUEST -> " + new String(bufferedRequest.getBuffer()));
}
final HttpServletResponse response = (HttpServletResponse) servletResponse;
final ByteArrayPrintWriter pw = new ByteArrayPrintWriter();
HttpServletResponse wrappedResp = new HttpServletResponseWrapper(response) {
public PrintWriter getWriter() {
return pw.getWriter();
}
public ServletOutputStream getOutputStream() {
return pw.getStream();
}
};
filterChain.doFilter(bufferedRequest, wrappedResp);
byte[] bytes = pw.toByteArray();
String s = new String(bytes);
String next = "test message";
response.getOutputStream().write(next.getBytes());
///response.setHeader("Content-Length", String.valueOf(next.length()));
response.setContentLength( next.getBytes().length );
// if (dumpResponse) System.out.println("RESPONSE -> " + s);
}