servlet filter buffer question

S

Steve

I have a filter that I wrote to scoop the output of a JSP and save it to
a file. It worked fine in Tomcat 4.x, but in Tomcat 5.5 it gives me
nothing for a small amount of output, and for a large amount of output I
get some content, but it is cut off at some point. So it seems like
there is an issue with the buffer

I've tried setting the JSP page's buffer and autoflush to various
combinations, with no success, and have tried calling setBufferSize in
the response wrapper before calling doFilter, also to no avail.

Is there a Tomcat setting I need to monkey with perhaps? Or something
in my JSP or Java code?
 
M

Matt Humphrey

Steve said:
I have a filter that I wrote to scoop the output of a JSP and save it to a
file. It worked fine in Tomcat 4.x, but in Tomcat 5.5 it gives me nothing
for a small amount of output, and for a large amount of output I get some
content, but it is cut off at some point. So it seems like there is an
issue with the buffer

I've tried setting the JSP page's buffer and autoflush to various
combinations, with no success, and have tried calling setBufferSize in the
response wrapper before calling doFilter, also to no avail.

Is there a Tomcat setting I need to monkey with perhaps? Or something in
my JSP or Java code?

If the JSP page regularly appears correctly in a browser, the problem will
probably be in your code. Show us the code for reading the output and
writing the file. You may not be reading all the output or closing the file
properly.

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
S

Steve

Matt said:
If the JSP page regularly appears correctly in a browser, the problem will
probably be in your code. Show us the code for reading the output and
writing the file. You may not be reading all the output or closing the file
properly.

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
Here it is:

package filtertest;

import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
import java.net.*;
import java.util.*;

public class PrePostFilterMain extends GenericFilter {

public void doFilter(final ServletRequest request,
final ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
OutputStream out = response.getOutputStream();
GenericResponseWrapper wrapper =
new GenericResponseWrapper((HttpServletResponse) response);

wrapper.setBufferSize(16384);
chain.doFilter(request, wrapper);

// look up file name that matches the original request URL
String filename = null;

String requestedPage = ((HttpServletRequest) request).getServletPath();
requestedPage =
requestedPage.substring(requestedPage.lastIndexOf('/') + 1);
ServletContext sc = getFilterConfig().getServletContext();
if (sc == null)
throw new javax.servlet.ServletException("Servlet context missing");

filename = sc.getInitParameter(requestedPage + ".file");
if (filename == null)
throw new javax.servlet.ServletException("lookup of property \"" +
requestedPage + ".file\"
failed");

byte[] data = wrapper.getData();
createFile(data, filename);
out.write(("<hr>PrePostFilterMain output sent to file: " + filename
+ ": " +
data.length + "/" + wrapper.getContentLength() + "
bytes<hr>").getBytes());
out.write(data);
out.write("<hr>FilterTest Post<hr>".getBytes());
out.flush();
out.close();
}

public void createFile(byte[] data, String filename)
throws IOException {
ServletContext sc = getFilterConfig().getServletContext();
String path = sc.getRealPath(filename);
FileOutputStream fos = new FileOutputStream(path);
fos.write(data);
fos.flush();
fos.close();
}

}
//------------------------------------------------------------

package filtertest;

import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
import java.net.*;
import java.util.*;

public class GenericFilter implements javax.servlet.Filter {

private FilterConfig fc;

public GenericFilter() { }

public void doFilter(final ServletRequest request,
final ServletResponse response,
FilterChain chain)
throws java.io.IOException, javax.servlet.ServletException {

chain.doFilter(request, response);
}

public FilterConfig getFilterConfig() {
return fc;
}


public void init(FilterConfig fc) {
this.fc = fc;
}

public void destroy() {
this.fc = null;
}
}


//--------------------------------------------------------------------

package filtertest;

import javax.servlet.http.*;
import javax.servlet.*;
import java.io.*;
import java.net.*;
import java.util.*;

public class GenericResponseWrapper extends HttpServletResponseWrapper {

private ByteArrayOutputStream output;
private int contentLength;
private String contentType;

public GenericResponseWrapper(HttpServletResponse response) {
super(response);
output = new ByteArrayOutputStream();
}

public ServletOutputStream getOutputStream() {
return new FilterServletOutputStream(output);
}

public byte[] getData() {
return output.toByteArray();
}

public PrintWriter getWriter() {
return new PrintWriter(getOutputStream(), true);
}

public void setContentType(String type) {
this.contentType = type;
super.setContentType(type);
}

public String getContentType() {
return this.contentType;
}

public int getContentLength() {
return contentLength;
}

public void setContentLength(int length) {
this.contentLength = length;
super.setContentLength(length);
}

}
 
M

Matt Humphrey

Steve said:
Here it is:

package filtertest;

<code snip>

I've looked this over several times now and I'm not seeing anything that
looks suspicious. Your buffer handling looks correct. There's an
assumption at one point that the bytes retreived from the JSP page encode
characters the same was as the filter does for output, but I would expect
that to be the case anyway. And similarly that the wrapping HTML that you
convert to bytes with .getBytes () will use the same encoding as the
content. For these you might want to use the getBytes("encoding") to be
explicit, but I'm not confident that that's the problem.

It almost looks like chain.doFilter is not waiting for the entire response.
What function does the filter chain do here?

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
S

Steve

Matt said:
<code snip>

I've looked this over several times now and I'm not seeing anything that
looks suspicious. Your buffer handling looks correct. There's an
assumption at one point that the bytes retreived from the JSP page encode
characters the same was as the filter does for output, but I would expect
that to be the case anyway. And similarly that the wrapping HTML that you
convert to bytes with .getBytes () will use the same encoding as the
content. For these you might want to use the getBytes("encoding") to be
explicit, but I'm not confident that that's the problem.

It almost looks like chain.doFilter is not waiting for the entire response.
What function does the filter chain do here?

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
I had iso-8859-1, but tried switching to UTF-8 to no avail.

It seems that the buffer is empty unless it is full -- i.e., it doesn't
work if the data written is less than the buffer size. If I have more
content than the buffer size, then I get content of exactly the size of
the buffer. If I have less content, then I get nothing. (You can see
my code where I report the array length and the getContentLength() value
-- for a small amount of content it says 0/0)

So I suppose I could try to read the size of the content written to the
output buffer at the end of the JSP and then pad it out to the full
length of the buffer, but that seems like an incredible kludge.
 
S

Steve

Steve said:
I had iso-8859-1, but tried switching to UTF-8 to no avail.

It seems that the buffer is empty unless it is full -- i.e., it doesn't
work if the data written is less than the buffer size. If I have more
content than the buffer size, then I get content of exactly the size of
the buffer. If I have less content, then I get nothing. (You can see
my code where I report the array length and the getContentLength() value
-- for a small amount of content it says 0/0)

So I suppose I could try to read the size of the content written to the
output buffer at the end of the JSP and then pad it out to the full
length of the buffer, but that seems like an incredible kludge.

An update -- it seems like dynamically padding isn't possible -- I don't
see any way to read the size of the written content. But, If I pad the
end of the page with 8192-plus spaces, it "works". So it seems to be
ignoring my buffer size request in the JSP and doing it in 8kb chunks.
If I force the last real content to fill a chunk, that gets written, and
the content gets cut off somewhere in the middle of my padding.

BTW, I'm not sure if I understand your question "What function does the
filter chain do here?" If you mean what is the application, I'm sending
a dynamic page and saving a copy of what was sent.
 
M

Matt Humphrey

Steve said:
An update -- it seems like dynamically padding isn't possible -- I don't
see any way to read the size of the written content. But, If I pad the
end of the page with 8192-plus spaces, it "works". So it seems to be
ignoring my buffer size request in the JSP and doing it in 8kb chunks. If
I force the last real content to fill a chunk, that gets written, and the
content gets cut off somewhere in the middle of my padding.

The content-length header isn't always correct because it's sent before the
actual content is sent.. I'm thinking that Tomcat 4.x did the right thing
and looked at the actual size of the content, whereas 5.5 is looking at the
declared buffer size or the content header
BTW, I'm not sure if I understand your question "What function does the
filter chain do here?" If you mean what is the application, I'm sending a
dynamic page and saving a copy of what was sent.

I was just wondering if the filter chain could be interfering with the read
/ write operation--I'm unfamiliar with them. I can't think of anything else
and I'm too unfamiliar with the nuances of Tomcat.

Good luck,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top