问题
ServletOutputStream.isReady() javadoc says the following:
Returns: true if a write to this ServletOutputStream will succeed, otherwise returns false.
In spite of that Jetty's ServletOutputStream
implementation, HttpOutput
seems to behave rather confusing in the case when the stream is in CLOSED
state. It returns true
:
case CLOSED:
return true;
Source: HttpOutput.java:1011.
Furthermore, all three write
methods in HttpOutput
throws EofException
when it's CLOSED
:
case CLOSED:
throw new EofException("Closed");
So it seems that write can never succeed. What's the reason behind this behavior?
回答1:
Key Fact: A close call implies a write operation.
The CLOSED internal state indicates that usage of the stream/output is CLOSED to that dispatch (not that the stream itself is actually closed).
How did we get into this state? Something has triggered the ServletOutputStream.close()
(and in turn HttpOutput.close()
) and now no more writes are allowed on that stream from the current dispatch.
In the CLOSED state, a flush occurs.
- A flush will commit the response
- A flush will finish writing the various buffers present on the various layers of the exchange / connection / output.
- If there is an aggregate buffer (for many small writes) it writes that out.
- If there is a compression layer (gzip) it will force a flush from there as well.
- Then all of those buffers also go through the
Transfer-Encoding
layer (eg: chunked). - Then the network write occurs.
The HttpOutput
is also the one point of output for all nested requests, such as using include()
from RequestDispatcher
which will reopen the HttpOutput
for use during the include()
and then close it again.
Once the HttpOutput
is fully and completely flushed/finished (no more dispatches, no more writes, etc), then the final buffer flush is done, transfer-encodings are completed, the HttpOutput is reset, recycled, and returned to the HttpConnection for use with the next exchange.
We could do a better job of javadoc'ing that in the codebase, or at least using constants and variable names that make more sense.
Opened https://github.com/eclipse/jetty.project/issues/2687
Regarding the Jetty EofException
(not the JVM EOFException
) on write.
Once the ServletOutputStream
is CLOSED for usage on the specific dispatch, further calls to write()
will result in a Jetty EofException
.
There is also a flavor of EofException
where your committed response details were violated.
Eg: you declared a response Content-Length
of say 40MB, but wrote 41MB, you exceeded the capability of that committed response, this is an IOException. And the Servlet spec tells us to throw an IOException
in this case.
Jetty will throw the Jetty internal EofException
(which extends IOException) to indicate this specific scenario and abort the connection, breaking any connection persistence you may have wanted.
来源:https://stackoverflow.com/questions/51101088/isready-returns-true-in-closed-state-why