0

I am working on a filter, this code fails to execute/response.write if there is a 'forward' involved in the request. But it works fine for basic servlets that simply steam HTML content to the user. How can address "forwards" with this code.

For example, here is the filter that simple captures text content and attempts to manipulate that content.

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;           
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpSession session = request.getSession(false);                
        CharResponseWrapper responseWrapper = new CharResponseWrapper((HttpServletResponse) response);
        chain.doFilter(request, responseWrapper);       
                final boolean commit1 = responseWrapper.isCommitted();           
                final boolean commit2 = response.isCommitted();             
            if (!commit2) {
                final String res = responseWrapper.toString().replaceAll("(?i)</form>", "<input type=\"hidden\" name=\"superval\" value=\""+superval"\"/></form>");             
                response.getWriter().write(res);                        
            }
        return;

    }

... This works for most basic servlets, the goal is at the line with the "replaceAll".

Now, if I create a servlet with a 'forward' the code does not work, it fails at the line with 'if (!commit2)' because the stream is already committed apparently?

For example, if I make a request to this servlet and tie the filter to this servlet, then the filter does not execute completely.

public class TestCommitServlet extends HttpServlet {    
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        
        req.getRequestDispatcher("TestCommitServlet2").forward(req, resp);
    }    
    @Override    
    protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

And here is the servlet that I am forwarding to:

public class TestCommitServlet2 extends HttpServlet {    
    private static final long serialVersionUID = 1L;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        final PrintWriter out = resp.getWriter();
        resp.setContentType("text/html");
        out.println("<html><body>(v-1)testing<form action='test'><input type='submit' value='Run' /> </form></body></html>");             
    }    
    @Override    
    protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

Tl;dr : Do I have to make this call 'if (!commit2) {' The code works without it. Under this code, how would I avoid Response already committed or IllegalStateExceptions (around the line with response.getWriter().write(res);

More on the issue here:

https://codereview.stackexchange.com/questions/41260/capturing-content-within-a-j2ee-filter-and-then-replacing-this-text-request-for

Community
  • 1
  • 1
Berlin Brown
  • 11,504
  • 37
  • 135
  • 203
  • It looks like when a redirect occurs, the header is committed and cannot have additional information added to it. See http://stackoverflow.com/questions/11305563/cause-of-servlets-response-already-committed and http://stackoverflow.com/questions/18211497/servlet-cannot-forward-after-response-has-been-committed – EdH Feb 07 '14 at 01:13
  • Still though, with this container (websphere), I am still able to send a rseponse out. if (!commit2) { ... If I remove this line then the "response.getWriter()" code still works. – Berlin Brown Feb 07 '14 at 18:09

1 Answers1

3

I´m using Servlet API 3.0 to check this scenario. What I found is the following. Using your code for the servlet and the filters when I call the TestCommitServlet2 , I´m able to see the following output.

http://localhost:8080/Question/TestCommitServlet2

(v-1)testing
Button here
com.koitoer.CharResponseWrapper@5b5b6746

When I call the servlet TestCommitServlet , Im able to see the following.

http://localhost:8080/Question/TestCommitServlet
(v-1)testing
Button here

this shown that filter is not apply to this forwarded request at all.

So, I remember that some filters can act in diverse DispatcherTypes as FORWARD, INCLUDE, ERROR, ASYNC and the commong REQUEST, what I decide is change the filter declaration to.

@WebFilter(filterName = "/MyFilter", urlPatterns = { "/TestCommitServlet2" }, dispatcherTypes = {
        DispatcherType.FORWARD, DispatcherType.REQUEST })
public class MyFilter implements Filter {

Then when I excecute a GET over the servlet TestCommitServlet I got:

(v-1)testing
 Button
com.koitoer.CharResponseWrapper@1b3bea22

the above shown that Filter is now applied to the forward request.

Also if I remove or comment lines for if (!commit2) { code still works, so there is no IllegalStateException as request need to pass over the filter which is who invoke the doChain method.

One note more, if you try to replace the content of the response using this.

responseWrapper.toString().replaceAll

You are doing it wrong as responseWrapper.toString() returns something like this CharResponseWrapper@5b5b6746, not the content, if you want to modify the response use a Wrapper that extends from HttpServletResponseWrapper and override the correct methos to manipulate the outpustream.

Koitoer
  • 18,778
  • 7
  • 63
  • 86