JDK-6672144 : HttpURLConnection.getInputStream sends POST request after failed chunked send
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 6u5,6u23
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic,linux_redhat_5.2
  • CPU: generic
  • Submitted: 2008-03-06
  • Updated: 2011-04-11
  • Resolved: 2011-03-08
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7
6u24-revFixed 7 b114Fixed
Related Reports
Duplicate :  
Description
If a HttpURLConnection is using either fixed content length or chunked transfer to POST request body and for some reason the OutputStream throws an IOException while writing the output data, a subsequent call to getResponseCode or getInputStream will resend the POST request headers initiating a new connection to the server. This is clearly not correct as no request body can be sent with the POST through the getResponseCode/getInputStream API.
The following bug seems to be related to this one. 
Attaching a test case, a web serivce calls itself via its own proxy recursively.
- HttpURLConnection sends a request and waits for ever in getResponseCode(). But the request doesn't reach GFv2UR2(same goes with tomcat)
- The test case works well when keep-alive is disabled

Running the test case:
- Make sure that GF uses 8080 port(which is its default)
- increase http request threads to 25 in  $GF/domains/domain1/config/domain.xml
<request-processing header-buffer-length-in-bytes="8192" initial-thread-count="2" request-timeout-in-seconds="30" thread-count="25" thread-increment="1"/>
- cp BreakMeAgain.jar $GF/domains/domain1/autodeploy/
- $GF/bin/asadmin start-domain
- Use browser to start the test: http://localhost:8080/BreakmeService/BreakMeService?tester
  use 10 as input. GF server.log only prints 10,9 and see that a thread is hanging in HttpURLConnection.getResponseCode(). If the keep-alive is disabled, it prints 10,9,8,7, ...

Jean Francois, can you provide more details of the analysis.

Comments
EVALUATION Changeset: cd4aad589b3f Author: chegar Date: 2010-09-21 15:58 +0100 URL: http://hg.openjdk.java.net/jdk7/tl/jdk/rev/cd4aad589b3f 6672144: HttpURLConnection.getInputStream sends POST request after failed chunked Reviewed-by: michaelm ! src/share/classes/sun/net/www/http/HttpClient.java ! src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java + test/sun/net/www/http/HttpClient/StreamingRetry.java
21-09-2010

WORK AROUND From JDK6 you can set the system property, sun.net.http.retryPost, to false to prevent the HTTP client from silently resending the POST request. java -Dsun.net.http.retryPost=false ...
20-09-2010

EVALUATION Here is the ordering of what happens, as per the test: 1) Client: sends a GET request, 2) Server: receives the GET and responds as expected 3) Client: closes inputStream which triggers the connection to be put in the keepalive cache. Java SE has a default policy to cache HTTP 1.1 connections for 5 seconds. 4) Server is stopped. ALL connections are closed. 5) Server is created 6) Client: sends POST request. Java SE implementation sees that we already have a connection to the server in the keepalive cache and tries to use it. HTTP headers are sent successfully; at least so far as we get no Exception sending to the half open (FIN send by server) socket. 7) Client: user land code, i.e URLConnectionClientHandler.writeEntity, tries to send the request body. MessageBodyWriter.writeTo seems to write the actual data. I should be throwing an IOException ( an it does not ). The ChunkedOutputStream implementation does not check for an error if very little data is written. 8) Client: user land code, i.e URLConnectionClientHandler._invoke, calls getResponseCode, which in turn invokes getInputStream on the HttpURLConnection. HttpClient.parseHTTPHeader will retry with a new connection if an IOException is encoutered. This creates a new connection to the server and sends the POST request headers, NO data is sent. 9) Server: times out on new connection made by 8) When we're in streaming mode (chunked or fixed length) the HTTP client implementation does not buffer the output data (this is the intention of streaming mode). Since we don't know the users data then we cannot silently retry in the event of an error when reading the response headers.
20-09-2010