FULL PRODUCT VERSION :
Tested on
java version "1.4.2_09"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_09-b05)
Java HotSpot(TM) Client VM (build 1.4.2_09-b05, mixed mode)
and
java version "1.5.0_06"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
Java HotSpot(TM) Server VM (build 1.5.0_06-b05, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Tested on
Linux localhost.localdomain 2.4.30 #3 SMP Thu May 4 03:16:40 EDT 2006 i686 unknown
but I believe it applies to all OSes.
A DESCRIPTION OF THE PROBLEM :
When contacting an HTTP server that closes the TCP connection without sending back an HTTP response, HttpURLConnection automatically reconnects and retries the request once. (For example, see Bug 4242616)
According to the HTTP spec (RFC 2616 section 8.1.4):
This means that clients, servers, and proxies MUST be able to recover
from asynchronous close events. Client software SHOULD reopen the
transport connection and retransmit the aborted sequence of requests
without user interaction so long as the request sequence is
idempotent (see section 9.1.2). Non-idempotent methods or sequences
MUST NOT be automatically retried, although user agents MAY offer a
human operator the choice of retrying the request(s).
The GET method is idempotent but the POST method is not (see section 9.1.2), so
while GET requests SHOULD be retried, POST requests MUST NOT be retried. Thus in the case of a POST request, HttpURLConnection violates the HTTP specification by automatically retrying the request.
The next section of the HTTP spec:
... Confirmation by
user-agent software with semantic understanding of the application
MAY substitute for user confirmation. The automatic retry SHOULD NOT
be repeated if the second sequence of requests fails.
suggests that it would be permissable for the automatic retry behavior in the JDK to be configurable for use by user agents which meet the criterion given. However, the JDK does not qualify as it cannot possibly have a semantic understanding of all applications that might use it.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Set up an "HTTP server" which closes the connection without sending back a response. Example server:
socat tcp4-listen:8080,fork,reuseaddr system:"sleep 1"\!\!stdout
2. Run the example client below, which sends an HTTP POST request to the server
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Client sees SocketException: Unexpected end of file from server.
Server sees a single POST request from the client.
ACTUAL -
Client sees SocketException: Unexpected end of file from server.
Server sees two POST requests from the client.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.net.URLConnection;
import java.net.URL;
public class URLTest {
public static void main(String[] args) throws Exception {
String spec = "http://10.5.3.117:8080";
URL url = new URL(spec);
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
conn.getOutputStream().write("test\r\n".getBytes());
conn.getInputStream();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
There is no workaround when using the built-in HttpURLConnection.