FULL PRODUCT VERSION :
java version " 1.7.0_25 "
Java(TM) SE Runtime Environment (build 1.7.0_25-b16)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Concurrent HTTP requests sent by HttpUrlConnection using either setFixedLengthStreamingMode or setChunkedStreamingMode can cause a SocketTimeoutException on the server.
If the requests are sent sequentially, no error occurs.
Only in the case of neither setFixedLengthStreaminMode nor setChunkedStreamingMode is used, the requets can be sent simultaneously.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Client side:
java.io.IOException: Server returned HTTP response code: 500 for URL: http://localhost:8080/server/PutServlet
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at de.wi.PutClient.runPut(PutClient.java:111)
at de.wi.PutClient.access$0(PutClient.java:67)
at de.wi.PutClient$1.run(PutClient.java:55)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Server side:
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:532)
at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:501)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
// Client code
package de.wi;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PutClient {
// Number of PUT requests sent simultaneously.
// Set >1 to produce the error.
final static int nbOfSimPuts = 10;
// Use setFixedLengthStreamingMode
enum EMode { InternalBuffering, FixedLengthStreamingMode, ChunkedStreamingMode };
final static EMode mode = EMode.ChunkedStreamingMode;
final static String surl = " http://localhost:8080/server/PutServlet " ;
public static void main(String[] args) {
System.out.println( " start FLSM test " );
System.out.println(System.getProperty( " java.version " ));
try {
System.setProperty( " http.maxConnections " , " 100 " );
ExecutorService tpool = Executors.newCachedThreadPool();
// Run test 1Mio times...
for (int i = 0; i < 1000 * 1000; i++) {
testSimPuts(tpool, nbOfSimPuts);
}
// Shutdown thread pool
tpool.shutdown();
tpool.awaitTermination(100, TimeUnit.SECONDS);
} catch (InterruptedException e) {e.printStackTrace(); }
System.out.println( " end FLSM test " );
}
// Start PUT requests in background, nbOfSimPuts are started at the same time
private static void testSimPuts(Executor tpool, int nbOfSimPuts) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(nbOfSimPuts);
for (int j = 0 ; j < nbOfSimPuts; j++) {
tpool.execute(new Runnable() {
public void run() {
try {
runPut();
}
finally {
cdl.countDown();
}
}
});
}
// Wait for all PUT requests finished
cdl.await(1000, TimeUnit.SECONDS);
}
private static void runPut() {
HttpURLConnection conn = null;
OutputStream os = null;
final int contentLength = 1;
ByteArrayInputStream is = new ByteArrayInputStream(new byte[contentLength]);
try {
final URL url = new URL(surl);
conn = (HttpURLConnection)url.openConnection();
conn.setConnectTimeout(100 * 1000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod( " PUT " );
switch (mode) {
case FixedLengthStreamingMode:
conn.setFixedLengthStreamingMode(contentLength);
// conn.setInstanceFollowRedirects( false ); does not help
break;
case ChunkedStreamingMode:
conn.setChunkedStreamingMode(0);
break;
default:
// Internal buffering
}
conn.setRequestProperty( " Content-Type " , " application/octet-stream " );
os = conn.getOutputStream();
byte[] buf = new byte[8 * 1000];
int len = 0;
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len);
}
os.close();
os = null;
try {
InputStream isResp = conn.getInputStream();
if (isResp != null) {
while (isResp.read() != -1) {}
isResp.close();
}
}
catch (IOException e) {
InputStream errStrm = conn.getErrorStream();
if (errStrm != null) {
while (errStrm.read() != -1) {}
errStrm.close();
}
throw e;
}
}
catch (Throwable e) {
e.printStackTrace();
}
finally {
if (os != null) try { os.close(); } catch (IOException ignored) {}
if (conn != null) conn.disconnect();
}
}
}
// Server code
package de.wi;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet( " /PutServlet " )
public class PutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
InputStream is = request.getInputStream();
while (is.read() != -1) {}
is.close();
}
}
---------- END SOURCE ----------
java version " 1.7.0_25 "
Java(TM) SE Runtime Environment (build 1.7.0_25-b16)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]
A DESCRIPTION OF THE PROBLEM :
Concurrent HTTP requests sent by HttpUrlConnection using either setFixedLengthStreamingMode or setChunkedStreamingMode can cause a SocketTimeoutException on the server.
If the requests are sent sequentially, no error occurs.
Only in the case of neither setFixedLengthStreaminMode nor setChunkedStreamingMode is used, the requets can be sent simultaneously.
ERROR MESSAGES/STACK TRACES THAT OCCUR :
Client side:
java.io.IOException: Server returned HTTP response code: 500 for URL: http://localhost:8080/server/PutServlet
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
at de.wi.PutClient.runPut(PutClient.java:111)
at de.wi.PutClient.access$0(PutClient.java:67)
at de.wi.PutClient$1.run(PutClient.java:55)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Server side:
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:532)
at org.apache.coyote.http11.InternalInputBuffer.fill(InternalInputBuffer.java:501)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
// Client code
package de.wi;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class PutClient {
// Number of PUT requests sent simultaneously.
// Set >1 to produce the error.
final static int nbOfSimPuts = 10;
// Use setFixedLengthStreamingMode
enum EMode { InternalBuffering, FixedLengthStreamingMode, ChunkedStreamingMode };
final static EMode mode = EMode.ChunkedStreamingMode;
final static String surl = " http://localhost:8080/server/PutServlet " ;
public static void main(String[] args) {
System.out.println( " start FLSM test " );
System.out.println(System.getProperty( " java.version " ));
try {
System.setProperty( " http.maxConnections " , " 100 " );
ExecutorService tpool = Executors.newCachedThreadPool();
// Run test 1Mio times...
for (int i = 0; i < 1000 * 1000; i++) {
testSimPuts(tpool, nbOfSimPuts);
}
// Shutdown thread pool
tpool.shutdown();
tpool.awaitTermination(100, TimeUnit.SECONDS);
} catch (InterruptedException e) {e.printStackTrace(); }
System.out.println( " end FLSM test " );
}
// Start PUT requests in background, nbOfSimPuts are started at the same time
private static void testSimPuts(Executor tpool, int nbOfSimPuts) throws InterruptedException {
final CountDownLatch cdl = new CountDownLatch(nbOfSimPuts);
for (int j = 0 ; j < nbOfSimPuts; j++) {
tpool.execute(new Runnable() {
public void run() {
try {
runPut();
}
finally {
cdl.countDown();
}
}
});
}
// Wait for all PUT requests finished
cdl.await(1000, TimeUnit.SECONDS);
}
private static void runPut() {
HttpURLConnection conn = null;
OutputStream os = null;
final int contentLength = 1;
ByteArrayInputStream is = new ByteArrayInputStream(new byte[contentLength]);
try {
final URL url = new URL(surl);
conn = (HttpURLConnection)url.openConnection();
conn.setConnectTimeout(100 * 1000);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestMethod( " PUT " );
switch (mode) {
case FixedLengthStreamingMode:
conn.setFixedLengthStreamingMode(contentLength);
// conn.setInstanceFollowRedirects( false ); does not help
break;
case ChunkedStreamingMode:
conn.setChunkedStreamingMode(0);
break;
default:
// Internal buffering
}
conn.setRequestProperty( " Content-Type " , " application/octet-stream " );
os = conn.getOutputStream();
byte[] buf = new byte[8 * 1000];
int len = 0;
while ((len = is.read(buf)) != -1) {
os.write(buf, 0, len);
}
os.close();
os = null;
try {
InputStream isResp = conn.getInputStream();
if (isResp != null) {
while (isResp.read() != -1) {}
isResp.close();
}
}
catch (IOException e) {
InputStream errStrm = conn.getErrorStream();
if (errStrm != null) {
while (errStrm.read() != -1) {}
errStrm.close();
}
throw e;
}
}
catch (Throwable e) {
e.printStackTrace();
}
finally {
if (os != null) try { os.close(); } catch (IOException ignored) {}
if (conn != null) conn.disconnect();
}
}
}
// Server code
package de.wi;
import java.io.IOException;
import java.io.InputStream;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet( " /PutServlet " )
public class PutServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
InputStream is = request.getInputStream();
while (is.read() != -1) {}
is.close();
}
}
---------- END SOURCE ----------