Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-6472250

HttpURLConnection.getOutputStream streaming mode bug when called multiple times

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P4 P4
    • 7
    • 5.0
    • core-libs
    • b03
    • x86
    • windows_xp
    • Verified

      FULL PRODUCT VERSION :
      java version "1.5.0_06"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_06-b05)
      Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      A DESCRIPTION OF THE PROBLEM :
      I was modifying some working, existing code that constructed an HttpUrlConnection and wrote to the output stream similar to this:

                  connection.getOutputStream().write(data);
                  connection.getOutputStream().close();

      As that size of the data buffer got much bigger I needed to explicitly set the content-length before writing to the output stream similar to this:

                  connection.setFixedLengthStreamingMode(data.length);

      This led to the following error though: "java.io.IOException: insufficient data written".

      Calling getOutputStream() only once and reusing the result makes the error go away. This is a bug because calling setFixedLengthStreamingMode() should not force me to change how many times I call getOutputStream().

      I haven't looked at the actual source code but a quick run through JAD shows the following code in HttpURLConnection.

          public synchronized OutputStream getOutputStream()
      ...
                  if(streaming())
                  {
                      if(fixedContentLength != -1)
                          strOutputStream = new StreamingOutputStream(ps, fixedContentLength);
                      else
                      if(chunkLength != -1)
                          strOutputStream = new StreamingOutputStream(new ChunkedOutputStream(ps, chunkLength), -1);
                      return strOutputStream;
                  }
      ...
              if(poster == null)
                  poster = new PosterOutputStream();
              return poster;
          }

      As you can see when it is not in streaming mode it reuses the PosterOutputStream object. When it is in streaming mode it creates a new StreamingOutputStream object. Each StreamingOutputStream object keeps an internal count of the number of bytes written and verifies this number matches the specified fixedContentLength on close. write() and close() are operating on two different objects so they have two different counters.

      This code should be changed to only construct the strOutputStream object once similar to how the poster object is.


      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      java.io.IOException: insufficient data written
      at sun.net.www.protocol.http.HttpURLConnection$StreamingOutputStream.close(HttpURLConnection.java:2249)

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import java.io.OutputStream;
      import java.net.HttpURLConnection;
      import java.net.URL;

      public class AmazonSearch {
          public static void main(String[] args) {
              try {
                  URL url = new URL("http://www.amazon.com/s.html");
                  String keyword = "java";
                  String query = "url=index%3Dblended&keywords=" + keyword;

                  HttpURLConnection connection = (HttpURLConnection)url.openConnection();
                  connection.setRequestMethod("POST");
                  connection.setDoOutput(true);
                  connection.setDoInput(true);

      //*** Problem area
                  // Leave the following line off to see it work fine in non-streaming mode
                  connection.setFixedLengthStreamingMode(query.getBytes().length);
                  connection.getOutputStream().write(query.getBytes());
                  connection.getOutputStream().close();
      //***

                  System.out.println("rc = " + connection.getResponseCode());

                  BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
                  String line = null;
                  while ((line = reader.readLine()) != null) {
                      System.out.println(line);
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      Only call getOutputStream() once when using streaming mode. Replace the code in the problem area of the sample with the following:
       
                  connection.setFixedLengthStreamingMode(query.getBytes().length);
                  OutputStream outputStream = connection.getOutputStream();
                  outputStream.write(query.getBytes());
                  outputStream.close();

            chegar Chris Hegarty
            ndcosta Nelson Dcosta (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: