[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [jetty-users] Question about behavior of WriteListener
|
Hi,
On Wed, Oct 19, 2016 at 12:12 PM, Christoph Läubrich
<laeubi@xxxxxxxxxxxxxx> wrote:
> I have a question about the usage/behavior of WriteListener because I
> encountered a strange problem: Writing works most of the time, but as soon
> as the data hit some magic size-limit it is truncated.
>
> I created a very simplified class like this:
>
> public class ByteArrayWriteListener implements WriteListener {
>
> private ServletOutputStream stream;
> private byte[] data;
> private AsyncContext asyncContext;
>
> public ByteArrayWriteListener(byte[] data, AsyncContext asyncContext,
> ServletOutputStream stream) {
> this.data = data;
> this.asyncContext = asyncContext;
> this.stream = stream;
> }
>
> @Override
> public void onError(Throwable t) {
> }
>
> @Override
> public void onWritePossible() throws IOException {
> stream.write(data);
> asyncContext.complete();
Uh, no.
> }
>
> }
>
> all data is written as a big bunch and then the AsyncContext is immediately
> completed (note that it doesn't matter if complete is called outside the
> write-listener).
That's wrong.
> This leads to the effect that the client simply gets only
> partial of the data when it grows up to a magic limit (maybe some response
> buffer size or so seem to depend on client load also...), setting the
> content-length prior to writing data has no effect. If I modify* the code
> that it checks (after the write) that the stream is ready then everything
> works.
Yep.
> Question: is it expected that a prior write is not completed if asyncContext
> is completed?
The semantic of write(), in case of async I/O, has changed so that it
does not guarantee that a write happens at all.
It could write 0 bytes, 1, N, or all of them.
Calling AsyncContext.complete() tells the container that you are done
writing, but you are actually not done until the write is actually
completed.
> I can't find in the Javadoc any hint that AsyncContext.complete() might stop
> any already issued writes, and would expect that it throws an exception like
> calling stream.flush() for example if not isReady was called before.
>
> Thanks in advance for any clarification :-)
>
> * Modified code:
> @Override
> public void onWritePossible() throws IOException {
> if (!dataWritten) {
> stream.write(data);
> dataWritten = true;
Small nit on the variable naming:
Here it may not be true that the data is *written*.
It is true that you have a write *pending*.
It *may* be completed, but you can only know by calling isReady().
> }
> if (stream.isReady()) {
> asyncContext.complete();
> }
> }
So yes, this code works because the write is not done twice thanks to
the flag, and AsyncContext.complete() is called when the write is
actually finished.
--
Simone Bordet
----
http://cometd.org
http://webtide.com
Developer advice, training, services and support
from the Jetty & CometD experts.