-
Bug
-
Resolution: Fixed
-
P4
-
5.0
-
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();
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();