Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 453805

Summary: response.getOutputStream().write() hangs forever if client doesn't consume the response
Product: [RT] Jetty Reporter: Benjamin Jaton <benjamin.jaton>
Component: serverAssignee: Greg Wilkins <gregw>
Status: RESOLVED INVALID QA Contact:
Severity: normal    
Priority: P3 CC: gregw, jetty-inbox, joakim.erdfelt, laeubi
Version: 8.1.16   
Target Milestone: 9.2.x   
Hardware: All   
OS: All   
Whiteboard:
Attachments:
Description Flags
Jetty server class
none
Client class
none
Reproducible TestCase
none
jetty-9 version of testcase none

Description Benjamin Jaton CLA 2014-12-01 12:49:01 EST
Created attachment 249070 [details]
Jetty server class

I am creating a simple embedded Jetty server (see attachments)

The client is using Apache HttpClient. It doesn't consume the response and exits right after the execute():
  HttpClient client = new DefaultHttpClient();
  HttpGet get = new HttpGet("http://localhost:8080/");
  HttpResponse response = client.execute(get);

Using 8.1.16.v20140903 or 9.3.0.M1:
If I use response.getOutputStream().write(data), the write() hangs forever and the doGet() method never completes (more than 15 hours).
Now if I use response.getWriter().write(data), the write returns right away (with checkErrors = true).

I believe the OutputStream should have the same behaviour as the Writer: the Writer seems to have the information about the client being gone, but the OutputStream has no clue and stays stuck.

Interestingly, in version 8.1.0.RC1, the Writer hangs in that scenario as well, and in version 8.1.0.RC2 it returns.
I couldn't find the changelog for RC2 but that change should be applied for the OutputStream as well.

With such a behaviour, it's easy to bring the server to a DOS since the server never releases the resources for that request.

Tried with:
- Ubuntu 12.04 / JDK 8u05
- Windows 7 pro / JDK 8u11
Comment 1 Benjamin Jaton CLA 2014-12-01 12:49:30 EST
Created attachment 249071 [details]
Client class
Comment 2 Benjamin Jaton CLA 2014-12-01 13:03:04 EST
Created attachment 249073 [details]
Reproducible TestCase
Comment 3 Christoph Laeubrich CLA 2014-12-01 14:04:35 EST
Can you check with LSOF if there are any "hang" sockets shown?
Comment 4 Benjamin Jaton CLA 2014-12-01 18:04:41 EST
$ lsof -i | grep 15043
java      15043 benji   25u  IPv6 512348321      0t0  TCP *:http-alt (LISTEN)

Hope that helps!
Comment 5 Joakim Erdfelt CLA 2015-03-10 12:39:03 EDT
Created attachment 251437 [details]
jetty-9 version of testcase
Comment 6 Joakim Erdfelt CLA 2015-03-10 12:46:55 EDT
Jetty 8 is EOL, no further updates to Jetty 8 will be done.

Testcase attached by Benjamin does not run/execute as-is.

If we fix the testcase, and upgrade it to Jetty 9, we can show that the behavior is as expected per the servlet spec.

there are 4 possible scenarios.

1) Servlet -> OutputStream -> Client Reads
2) Servlet -> OutputStream -> Client Does Not Read
3) Servlet -> Writer       -> Client Reads
4) Servlet -> Writer       -> Client Does Not Read

If the Client does not read the response data, then a Timeout occurs and the connection is closed.

If the Servlet uses OutputStream, then the timeout is detected as a IOException

If the Servlet uses PrintWriter, then the write operation completes immediately, and is handled by the servlet container.  No exception is thrown.  The timeout is eventually caught by the internal mechanisms of Jetty and the connection is closed.

If the client reads the response data, then the connection is terminated normally (following http/1.1 persistent connection rules)
Comment 7 Joakim Erdfelt CLA 2015-03-10 12:56:36 EDT
Closing as INVALID