Uploaded image for project: 'HttpComponents HttpCore'
  1. HttpComponents HttpCore
  2. HTTPCORE-373

NPE on premature response from server

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Minor
    • Resolution: Fixed
    • 4.3.1
    • 4.3.2, 4.4-alpha1
    • HttpCore NIO
    • None
    • Linux 3.10.25-gentoo

    Description

      Steps to reproduce:
      1. Bind server socket
      2. Create CloseableHttpAsyncClient with .setDefaultMaxPerRoute(1);
      3. Send two GET requests to port, store each Future<HttpResponse> somewhere
      4. Sleep 100 ms (don't know why, but issues is not reproducible without this sleep)
      5. On server socket accept incoming connection and write "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nConnection: keep-alive\r\n\r\n" to socket three times
      6. Call .get() on both Futures from step 3.

      Expected result:
      Both .get()s returns valid HttpResponse with status code 200.
      or
      First .get() throws exception indicating protocol violation (as Content-Length is 0)

      Actual result:
      First .get() returns HttpResponse with status code 200.
      Second .get() throws java.util.concurrent.ExecutionException: java.lang.NullPointerException
      at org.apache.http.concurrent.BasicFuture.getResult(BasicFuture.java:70)
      at org.apache.http.concurrent.BasicFuture.get(BasicFuture.java:80)
      at NPETest.main(NPETest.java:46)
      Caused by: java.lang.NullPointerException
      at org.apache.http.impl.nio.client.MainClientExec.responseReceived(MainClientExec.java:318)
      at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseReceived(DefaultClientExchangeHandlerImpl.java:148)
      at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.responseReceived(HttpAsyncRequestExecutor.java:227)
      at org.apache.http.impl.nio.client.LoggingAsyncRequestExecutor.responseReceived(LoggingAsyncRequestExecutor.java:112)
      at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:256)
      at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:73)
      at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:37)
      at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:116)
      at org.apache.http.impl.nio.reactor.BaseIOReactor.validate(BaseIOReactor.java:219)
      at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:282)
      at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:106)
      at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:589)
      at java.lang.Thread.run(Thread.java:744)

      NPE is not too informative and probably there should be IOException or HttpException instead. Most probably this error occurs because no events comes to reactor after first response consumption.

      Here the simple program illustrating the issue:
      import java.net.ServerSocket;
      import java.net.Socket;

      import java.nio.charset.StandardCharsets;

      import java.util.ArrayList;
      import java.util.List;
      import java.util.concurrent.Future;

      import org.apache.http.HttpResponse;
      import org.apache.http.client.methods.HttpGet;
      import org.apache.http.impl.nio.client.CloseableHttpAsyncClient;
      import org.apache.http.impl.nio.client.HttpAsyncClients;
      import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager;
      import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor;

      public class NPETest {
      public static void main(final String... args) throws Exception {
      ServerSocket server = new ServerSocket(0, 1);
      PoolingNHttpClientConnectionManager connManager =
      new PoolingNHttpClientConnectionManager(
      new DefaultConnectingIOReactor());
      connManager.setDefaultMaxPerRoute(1);
      connManager.setMaxTotal(Integer.MAX_VALUE);
      try (CloseableHttpAsyncClient client = HttpAsyncClients.custom()
      .setConnectionManager(connManager)
      .build())
      {
      client.start();
      List<Future<HttpResponse>> requests = new ArrayList<>();
      for (int i = 0; i < 2; ++i)

      { requests.add(client.execute( new HttpGet("http://localhost:" + server.getLocalPort()), null)); }

      Socket socket = server.accept();
      System.out.println(
      System.currentTimeMillis() + " Accepted");
      Thread.sleep(100);
      for (int i = 0; i < 3; ++i)

      { socket.getOutputStream().write(("HTTP/1.1 200 OK\r\n" + "Content-Length: 0\r\nConnection: keep-alive\r\n\r\n") .getBytes(StandardCharsets.UTF_8)); }

      for (Future<HttpResponse> request: requests)

      { System.out.println("Response: " + request.get()); }

      }
      }
      }

      Attachments

        Activity

          People

            Unassigned Unassigned
            hirthwork Dmitry Potapov
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: