United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: 6672144 HttpURLConnection.getInputStream sends POST request after failed chunked send
6672144 : HttpURLConnection.getInputStream sends POST request after failed chunked send

Details
Type:
Bug
Submit Date:
2008-03-06
Status:
Closed
Updated Date:
2011-04-11
Project Name:
JDK
Resolved Date:
2011-03-08
Component:
core-libs
OS:
generic,linux_redhat_5.2
Sub-Component:
java.net
CPU:
generic
Priority:
P2
Resolution:
Fixed
Affected Versions:
6u5,6u23
Fixed Versions:
7

Related Reports
Backport:
Backport:
Backport:
Backport:
Duplicate:

Sub Tasks

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
                                     
2010-09-21
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 ...
                                     
2010-09-20
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.
                                     
2010-09-20



Hardware and Software, Engineered to Work Together