You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by "Oleg Kalnichevski (Jira)" <ji...@apache.org> on 2021/09/01 20:43:00 UTC

[jira] [Resolved] (HTTPCORE-683) H2ConnPool bug (stuck poolEntry)

     [ https://issues.apache.org/jira/browse/HTTPCORE-683?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Oleg Kalnichevski resolved HTTPCORE-683.
----------------------------------------
    Resolution: Fixed

> H2ConnPool bug (stuck poolEntry)
> --------------------------------
>
>                 Key: HTTPCORE-683
>                 URL: https://issues.apache.org/jira/browse/HTTPCORE-683
>             Project: HttpComponents HttpCore
>          Issue Type: Bug
>          Components: HttpCore
>    Affects Versions: 5.1.1
>         Environment: Linux / Ubuntu / openjdk version "1.8.0_292"
>            Reporter: Sylvain POGNANT
>            Priority: Major
>             Fix For: 5.1.2, 5.2-alpha1
>
>
> There is an implementation problem in *AbstractIOSessionPool.getSessionInternal()*
> Wrong pattern (starting line 190 in httpcore5-5.1.1) :
> if (poolEntry.sessionFuture == null) {
>                      *poolEntry.sessionFuture =* connectSession(
>                              namedEndpoint,
>                              connectTimeout,
>                              new FutureCallback<IOSession>() {
>  
>                                 ...
>  
>                                  @Override
>                                  public void failed(final Exception ex) {
>                                      synchronized (poolEntry) {
>                                          poolEntry.session = null;
>                                          *poolEntry.sessionFuture = null;*
>                                          ...
>                                      }
>                                  }
>                               ...
>                             });
> In case of a synchronous failure during connectSession (for example : UnknownHostException), the sessionFuture cleanup in the failed() callback (line 216) is executed +before+ poolEntry.sessionFuture is assigned with the return value of connectSession (line 191)
> Thus, after the failure, a cancelled future is assigned to poolEntry.sessionFuture and never cleaned up !
> This result in a stalled entry in the pool because the _if (poolEntry.sessionFuture == null)_ condition will no longer return true.
>  
> *Quick Reproducer*
>        H2AsyncClientBuilder httpClientBuilder = HttpAsyncClients.customHttp2()
>                          .setDefaultRequestConfig(RequestConfig.custom()
>                                          .setConnectTimeout(5000, TimeUnit.MILLISECONDS)
>                                          .setResponseTimeout(5000, TimeUnit.MILLISECONDS)
>                                          .build())
>                          .setH2Config(H2Config.custom()
>                                          .setPushEnabled(false)
>                                          .build());
>                  
>          CloseableHttpAsyncClient client = httpClientBuilder.build();
>          client.start();
>          
>          for(int n=1;n<=2;n++) 
>          {
>              System.out.println("Try #"+n);    
>              
>              HttpHost targetHost = new HttpHost(URIScheme.HTTPS.getId(), "invalidhost-gfhsgfxyzd.com", 443);
>              SimpleHttpRequest request = new SimpleHttpRequest("GET", targetHost, "/");
>      
>              Future<SimpleHttpResponse> responseFuture = client.execute(request, null);
>              try
>              {
>                  responseFuture.get();  // {color:#FF0000}*HANGS FOREVER at Try #2*{color}
>              }
>              catch (ExecutionException e)
>              {
>                  e.printStackTrace();
>              }
>          }
>  
> *Quick Fix*
> Cleaning the sessionFuture immediately after connectSession() returns in case its already done fixes the issue :
> (Line 234)
> + if (poolEntry.sessionFuture != null && poolEntry.sessionFuture.isDone())
>  +                       poolEntry.sessionFuture = null;



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org