Michael Leith created HTTPCORE-530:
--------------------------------------

             Summary: NullPointerException in HttpCore >= 4.4.5
                 Key: HTTPCORE-530
                 URL: https://issues.apache.org/jira/browse/HTTPCORE-530
             Project: HttpComponents HttpCore
          Issue Type: Bug
          Components: HttpCore
    Affects Versions: 4.4.9
            Reporter: Michael Leith


h2. Details

We're getting a NullPointerException exception in versions >= 4.4.5. The 
exception occurs ~20 times per 10m requests in DefaultConnectionReuseStrategy 
when calling request.headerIterator. The change that introduced it was swapping 
to checking the request for keepAlive instead of just the response [1] in 
version 4.4.5. From looking at the source in github, this change is still in 
version 5.0, so the NullPointerException may be in versions > 4.4.9, but that's 
the latest version I have tested on so far.

>From testing the source of the exception is multiple threads accessing the 
>HeaderGroup, with one thread calling setHeader & the other calling 
>iterator(name). The HeaderGroup is backed by a thread-unsafe ArrayList, which 
>is the source of the exception. I have a fix for this, is there somewhere I 
>can submit a pull request?

The fix is to swap to a thread safe CopyOnWriteArrayList. This will have a 
performance impact, but it should be minor since the list is small (16 indices) 
and headers don't appear to be modified frequently.

[1] 
[https://github.com/apache/httpcomponents-core/blob/ff381e315a165047e6c2db9b1e749b47cad31405/httpcore5/src/main/java/org/apache/hc/core5/http/impl/DefaultConnectionReuseStrategy.java#L84]
h2. Client details

Here's a simplified version of our client. From comparing it to the examples 
provided in the docs there isn't anything that appears to be thread-unsafe 
aside from the shared HttpClientContext, which I've confirmed is not the root 
cause by making it thread local.

// single threaded
 // Isn't necessarily thread safe, I've tried moving it into the "post" method 
to see if it is the cause, but the exceptions persist.
 private final HttpClientContext context = HttpClientContext.adapt(new 
BasicHttpContext());

final RegistryBuilder<ConnectionSocketFactory> registryBuilder = 
RegistryBuilder.<ConnectionSocketFactory>create().register("https", 
sslSocketFactory.get());.

final PoolingHttpClientConnectionManager connectionManager = new 
PoolingHttpClientConnectionManager(registryBuilder.build())
 connectionManager.setMaxTotal(connectionPoolSize);
 connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
 connectionManager.setValidateAfterInactivity(duration);

final CloseableHttpClient client = HttpClients.custom()
   .setConnectionManager(connectionManager)
   .setKeepAliveStrategy((response, context) -> keepAliveDuration.toMillis())
   .setUserAgent(userAgent)
   .build();

// removing this does not fix the NullPointerException
 executorService.scheduleAtFixedRate(
   () -> 
connectionManager.closeIdleConnections(idleConnectionExpiry.toMillis(), 
 TimeUnit.MILLISECONDS),
 Duration.ofSeconds(30).toMillis(),
 Duration.ofSeconds(30).toMillis(),
 TimeUnit.MILLISECONDS);

// Called from multiple threads
 Result post(uri, config, entity, hostName) {
 final HttpPost req = new HttpPost(uri);
 req.setConfig(config);
 req.setEntity(entity);
 req.addHeader(HttpHeaders.HOST, hostName);
 try (CloseableHttpResponse response = client.execute(req, context))

{   // handle response }

catch(...)

{   // handle exception }

}



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to