Details
-
Bug
-
Status: Closed
-
Minor
-
Resolution: Fixed
-
4.3.1
-
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)
Socket socket = server.accept();
System.out.println(
System.currentTimeMillis() + " Accepted");
Thread.sleep(100);
for (int i = 0; i < 3; ++i)
for (Future<HttpResponse> request: requests)
{ System.out.println("Response: " + request.get()); } }
}
}