Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8084220 | emb-9 | Chris Hegarty | P4 | Resolved | Fixed | team |
JDK-8067584 | 8u45 | Ivan Gerasimov | P4 | Resolved | Fixed | b01 |
JDK-8065537 | 8u40 | Ivan Gerasimov | P4 | Resolved | Fixed | b17 |
JDK-8070072 | emb-8u47 | Ivan Gerasimov | P4 | Resolved | Fixed | team |
JDK-8072330 | 7u85 | Ivan Gerasimov | P4 | Resolved | Fixed | b01 |
JDK-8065629 | 7u80 | Ivan Gerasimov | P4 | Resolved | Fixed | b04 |
java version "1.7.0_60"
Java(TM) SE Runtime Environment (build 1.7.0_60-b19)
Java HotSpot(TM) 64-Bit Server VM (build 24.60-b09, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
Linux x.example.com 3.14.8-100.fc19.x86_64 #1 SMP Mon Jun 16 21:53:59 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
Parentheses are misplaced in sun.net.www.http.HttpClient.parseHTTP() and parseHTTPHeader(). When a streaming PUT request fails with an IOException, the PUT request is retried with an empty body. Like streaming POST, streaming PUT requests must not be retried.
Current jre code:
} catch (IOException e) {
closeServer();
cachedHttpClient = false;
if (!failedOnce && requests != null) {
failedOnce = true;
if (getRequestMethod().equals("CONNECT") ||
(httpuc.getRequestMethod().equals("POST") &&
(!retryPostProp || streaming))) {
// do not retry the request
} else {
// try once more
openServer();
if (needsTunneling()) {
httpuc.doTunneling();
}
afterConnect();
writeRequests(requests, poster);
return parseHTTP(responses, pi, httpuc);
}
}
Incorrect parentheses:
if (getRequestMethod().equals("CONNECT") ||
(httpuc.getRequestMethod().equals("POST") &&
(!retryPostProp || streaming))) {
Corrected parentheses:
if (getRequestMethod().equals("CONNECT") ||
(httpuc.getRequestMethod().equals("POST") &&
!retryPostProp) ||
streaming) {
Note that this is also the cause of bug 6944020.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Send a large streaming PUT, e.g. 5MB. Repeat many times over a typical internet connection where errors occasionally occur. Occasionally an IOException occurs and an empty body is PUT on the retry.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Streaming PUT should throw an IOException and not retry with an empty body.
ACTUAL -
An empty body is sent with the PUT instead of the correct content.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.net.URL;
public class Put {
// changing the method or the streaming avoids the issue
static final String METHOD = "PUT";
static final boolean STREAMING = true;
public static void main(String[] args) {
try {
int port = 8000;
String path = "/testput";
URL url = new URL("http://localhost:" + port + path);
byte[] buf = new byte[5000];
new MyServer(port).start();
for (int i = 0; i < 3; i++) {
try {
HttpURLConnection conn = (HttpURLConnection)
url.openConnection();
conn.setRequestMethod(METHOD);
conn.setRequestProperty("Content-Type",
"application/octet-stream");
conn.setConnectTimeout(2000);
conn.setReadTimeout(2000);
if (STREAMING) {
conn.setFixedLengthStreamingMode(buf.length);
}
conn.setDoOutput(true);
conn.getOutputStream().write(buf);
int code = conn.getResponseCode();
System.out.println("Client received response: "
+ code + "\n");
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (MalformedURLException e) {
}
}
public static void readFully(BufferedReader reader) throws IOException {
String line;
int contentLength = -1;
int bytesRead = 0;
do {
line = reader.readLine();
if (line == null) {
throw new IOException("read failed");
}
System.out.println(line);
if (line.toLowerCase().startsWith("content-length: ")) {
contentLength = Integer.parseInt(line.substring(16));
}
} while (line.length() > 0);
if (contentLength > 0) {
char[] buffer = new char[contentLength];
while (bytesRead < contentLength) {
int remaining = contentLength - bytesRead;
int n = 0;
try {
n = reader.read(buffer, bytesRead, remaining);
} catch (SocketTimeoutException e) {
System.out.println("Server read timeout");
}
if (n > 0) {
bytesRead += n;
} else {
break;
}
}
}
System.out.println("Server received " + bytesRead + " bytes\n");
}
static class MyServer extends Thread {
private int port;
MyServer(int port) {
this.port = port;
this.setDaemon(true);
}
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
Socket clientSocket = serverSocket.accept();
clientSocket.setSoTimeout(1000);
new ServerThread(clientSocket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class ServerThread extends Thread {
private Socket socket;
ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
try {
InputStream in = socket.getInputStream();
BufferedReader reader = new BufferedReader(
new InputStreamReader(in));
OutputStream out = socket.getOutputStream();
BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(out));
String response = "HTTP/1.1 200 OK\nContent-Length: 0";
readFully(reader);
writer.write(response);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Apache HttpClient is an alternative to java.net.HttpURLConnection.
- backported by
-
JDK-8065537 Misplaced parentheses in sun.net.www.http.HttpClient break HTTP PUT streaming
- Resolved
-
JDK-8065629 Misplaced parentheses in sun.net.www.http.HttpClient break HTTP PUT streaming
- Resolved
-
JDK-8067584 Misplaced parentheses in sun.net.www.http.HttpClient break HTTP PUT streaming
- Resolved
-
JDK-8070072 Misplaced parentheses in sun.net.www.http.HttpClient break HTTP PUT streaming
- Resolved
-
JDK-8072330 Misplaced parentheses in sun.net.www.http.HttpClient break HTTP PUT streaming
- Resolved
-
JDK-8084220 Misplaced parentheses in sun.net.www.http.HttpClient break HTTP PUT streaming
- Resolved
- duplicates
-
JDK-8065321 Body of PUT request is not retransmitted in streaming mode of HttpURLConnection
- Closed
- relates to
-
JDK-6944020 transferTo() over the network: Sometimes nothing is written (EPIPE)
- Open
-
JDK-8065072 [TEST_BUG] sun/net/www/http/HttpClient/StreamingRetry.java failed intermittently
- Closed