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

Concurrent POSTs can cause socket read timeout on server

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Cannot Reproduce
    • Icon: P3 P3
    • None
    • 7u25
    • core-libs

      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 ----------

            robm Robert Mckenna
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: