Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] [jetty 9.1.1] Callback to WriteListener.onWritePossible() broken after set Content-Length response header

Hi,

On Sat, Feb 8, 2014 at 10:53 AM, Zen Zhong <zenzhong8383@xxxxxxxxx> wrote:
> Hi,
>
> I'm running jetty 9.1.1, the last invocation of
> ServletOutputStream.isReady() will return true in
> WriteListener.onWritePossible(), but after I set Content-Length response
> header, then it doesn't work.
>
> test code (2 classes):
> @WebServlet(name = "EchoAsyncServlet", urlPatterns = { "/echo_async" },
> asyncSupported = true)
> public class EchoAsyncServlet extends HttpServlet {
>
>     private static final long serialVersionUID = -8434727468202612595L;
>
>     private static final byte[] RESPONSE = "V".getBytes();
>
>     @Override
>     public void service(final HttpServletRequest req, final
> HttpServletResponse resp) throws IOException {
>         AsyncContext asyncCtx = req.startAsync(req, resp);
>         asyncCtx.setTimeout(10_000);
>         ServletOutputStream out = resp.getOutputStream();
>         out.setWriteListener(new TextWriteListener(RESPONSE, asyncCtx,
> out));
>     }
>
> }
>
> public class TextWriteListener implements WriteListener {
>
>     private final byte[] text;
>     private final AsyncContext asyncCtx;
>     private final ServletOutputStream out;
>
>     public TextWriteListener(byte[] text, AsyncContext asyncCtx,
> ServletOutputStream out) {
>         super();
>         this.text = text;
>         this.asyncCtx = asyncCtx;
>         this.out = out;
>     }
>
>     @Override
>     public void onError(Throwable t) {
>         t.printStackTrace();
>         asyncCtx.complete();
>     }
>
>     private boolean written;
>
>     @Override
>     public synchronized void onWritePossible() throws IOException {
>         while (true) {
>             final boolean ready = out.isReady();
>             System.out.println(String.format("onWritePossible> asyncCtx=%s,
> ready=%s, written=%s", asyncCtx, ready,
>                     written));
>             if (!ready) {
>                 break;
>             }
>             if (written) {
>                 asyncCtx.complete();
>                 return;
>             } else {
>                 // comment this line to test
>                 ((HttpServletResponse)
> asyncCtx.getResponse()).setHeader("Content-Length",
> String.valueOf(text.length));
>                 out.write(text);
>                 written = true;
>             }
>         }
>     }
>
> }
>
> output:
> onWritePossible>
> asyncCtx=org.eclipse.jetty.server.AsyncContextState@64e0bfc9, ready=true,
> written=false
> onWritePossible>
> asyncCtx=org.eclipse.jetty.server.AsyncContextState@64e0bfc9, ready=false,
> written=true
> org.eclipse.jetty.io.EofException: Closed
>         at
> org.eclipse.jetty.server.HttpOutput$AsyncICB.completed(HttpOutput.java:725)
>         at
> org.eclipse.jetty.util.IteratingCallback.processIterations(IteratingCallback.java:200)
>         at
> org.eclipse.jetty.util.IteratingCallback.iterate(IteratingCallback.java:126)
>         at org.eclipse.jetty.server.HttpOutput.write(HttpOutput.java:270)
>         at java.io.OutputStream.write(OutputStream.java:75)
>         at TextWriteListener.onWritePossible(TextWriteListener.java:43)
>         at org.eclipse.jetty.server.HttpOutput.run(HttpOutput.java:690)
>         at
> org.eclipse.jetty.server.handler.ContextHandler.handle(ContextHandler.java:1159)
>         at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:335)
>         at
> org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:232)
>         at
> org.eclipse.jetty.io.AbstractConnection$1.run(AbstractConnection.java:505)
>         at
> org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:607)
>         at
> org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:536)
>         at java.lang.Thread.run(Thread.java:722)

I tried your example converting it to a test, therefore not using
annotations for the servlet, and works for me in the latest master
branch.

Your output is strange: it reports that 2 "onWritePossible>" calls are
invoked, the last with ready=false, but from the stack trace it looks
like the condition if (!ready) break is not executed and it goes on to
write more ?

Are you sure the code and the stack trace match ?

Other than that your code looks good.

-- 
Simone Bordet
----
http://cometd.org
http://webtide.com
http://intalio.com
Developer advice, training, services and support
from the Jetty & CometD experts.
Intalio, the modern way to build business applications.


Back to the top