Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jetty Filter to modify the Response - java.lang.IllegalStateException: WRITER

I am trying to modify the http response in a filter and am getting the following exception

java.lang.IllegalStateException: WRITER at org.eclipse.jetty.server.Response.getOutputStream(Response.java:657) at javax.servlet.ServletResponseWrapper.getOutputStream(ServletResponseWrapper.java:142) at org.eclipse.jetty.servlets.ProxyServlet.service(ProxyServlet.java:414) at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:643) at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1331) at com.cisco.vsx.node.proxy.http.RegexFilter.doFilter(RegexFilter.java:36)

I am using SelectChannelSelector and ProxyServlet.Transparent proxy.

Below is the snippet from test class

ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");

ProxyServlet.Transparent p1 = new ProxyServlet.Transparent("/proxy",
    "www.cisco.com", 80);
ServletHolder servletHolder = new ServletHolder(p1);
context.addServlet(servletHolder, "/proxy/*"); 
context.addFilter(new FilterHolder(RegexFilter.class), "/*", null);

server.setHandler(context);

server.start();
server.join();

This is the code from filter class

PrintWriter out = response.getWriter();
CharResponseWrapper wrapper = new CharResponseWrapper((HttpServletResponse) response);

chain.doFilter(request, wrapper);

String html = wrapper.toString();
if (regex != null && response.getContentType() != null 
        && response.getContentType().startsWith("text/html")) {
    Matcher matcher = regex.matcher(html);
    Map<Integer, Integer> matches = new LinkedHashMap<Integer, Integer>();
    while (matcher.find()) {
        int start = matcher.start(1);
        System.out.println("START" + start);
        int end = matcher.end(1);
        System.out.println("END" + end);
        matches.put(start, end - start);
    }
    StringBuffer sb = new StringBuffer();
    int start = 0;
    for (int startIndex : matches.keySet()) {
        String str = html.substring(start, startIndex) + "/proxy/";
        sb.append(str);
        start = startIndex + matches.get(startIndex);
    }
    html = sb.toString();
}

response.setContentLength(html.getBytes().length);
out.write(html);

Not sure where stuff is going wrong.

like image 313
Sahil Sharma Avatar asked Nov 28 '12 18:11

Sahil Sharma


1 Answers

Your Jetty Response can be in two (technically three) distinct modes. One is the writer mode, the other one is the streaming mode (and the third one is basically the undecided mode).

If you call getWriter() on an 'undecided' response, you're putting it in writer mode, which can't be reversed. If something later tries to use this response in streaming mode (by calling getOutputStream()) the Exception you see is thrown.

To fix this, don't use this response in writer mode and 'do your thing' on the OutputStream instead. If you were accessing the writer at a later point (after doChain), you'd get the inverse Exception

java.lang.IllegalStateException: STREAM

instead.

like image 190
Nicktar Avatar answered Oct 24 '22 23:10

Nicktar