4444import  java .util .concurrent .ExecutionException ;
4545import  java .util .concurrent .ExecutorService ;
4646import  java .util .concurrent .Executors ;
47+ import  java .util .concurrent .Future ;
4748import  java .util .concurrent .TimeUnit ;
4849import  java .util .concurrent .atomic .AtomicInteger ;
4950import  java .util .function .Supplier ;
@@ -369,9 +370,64 @@ private URI getWebSocketUri(HttpRequest request) throws URISyntaxException {
369370    return  uri ;
370371  }
371372
373+   @ Override 
374+   public  CompletableFuture <HttpResponse > executeAsync (HttpRequest  request ) {
375+     // the facade for this http request 
376+     CompletableFuture <HttpResponse > cf  = new  CompletableFuture <>();
377+ 
378+     // the actual http request 
379+     Future <?> future  =
380+         executorService .submit (
381+             () -> {
382+               try  {
383+                 HttpResponse  response  = handler .execute (request );
384+ 
385+                 cf .complete (response );
386+               } catch  (Throwable  t ) {
387+                 cf .completeExceptionally (t );
388+               }
389+             });
390+ 
391+     // try to interrupt the http request in case of a timeout, to avoid 
392+     // https://bugs.openjdk.org/browse/JDK-8258397 
393+     cf .exceptionally (
394+         (throwable ) -> {
395+           if  (throwable  instanceof  java .util .concurrent .TimeoutException ) {
396+             // interrupts the thread 
397+             future .cancel (true );
398+           }
399+ 
400+           // nobody will read this result 
401+           return  null ;
402+         });
403+ 
404+     // will complete exceptionally with a java.util.concurrent.TimeoutException 
405+     return  cf .orTimeout (readTimeout .toMillis (), TimeUnit .MILLISECONDS );
406+   }
407+ 
372408  @ Override 
373409  public  HttpResponse  execute (HttpRequest  req ) throws  UncheckedIOException  {
374-     return  handler .execute (req );
410+     try  {
411+       // executeAsync does define a timeout, no need to use a timeout here 
412+       return  executeAsync (req ).get ();
413+     } catch  (CancellationException  e ) {
414+       throw  new  WebDriverException (e .getMessage (), e );
415+     } catch  (InterruptedException  e ) {
416+       Thread .currentThread ().interrupt ();
417+       throw  new  WebDriverException (e .getMessage (), e );
418+     } catch  (ExecutionException  e ) {
419+       Throwable  cause  = e .getCause ();
420+ 
421+       if  (cause  instanceof  java .util .concurrent .TimeoutException ) {
422+         throw  new  TimeoutException (cause );
423+       } else  if  (cause  instanceof  RuntimeException ) {
424+         throw  (RuntimeException ) cause ;
425+       } else  if  (cause  instanceof  Error ) {
426+         throw  (Error ) cause ;
427+       }
428+ 
429+       throw  new  WebDriverException ((cause  != null ) ? cause  : e );
430+     }
375431  }
376432
377433  private  HttpResponse  execute0 (HttpRequest  req ) throws  UncheckedIOException  {
@@ -390,34 +446,13 @@ private HttpResponse execute0(HttpRequest req) throws UncheckedIOException {
390446      // - avoid a downgrade of POST requests, see the javadoc of j.n.h.HttpClient.Redirect 
391447      // - not run into https://bugs.openjdk.org/browse/JDK-8304701 
392448      for  (int  i  = 0 ; i  < 100 ; i ++) {
393-         java .net .http .HttpRequest  request  = messages .createRequest (req , method , rawUri );
394-         java .net .http .HttpResponse <byte []> response ;
395- 
396-         // use sendAsync to not run into https://bugs.openjdk.org/browse/JDK-8258397 
397-         CompletableFuture <java .net .http .HttpResponse <byte []>> future  =
398-             client .sendAsync (request , byteHandler );
399- 
400-         try  {
401-           response  = future .get (readTimeout .toMillis (), TimeUnit .MILLISECONDS );
402-         } catch  (CancellationException  e ) {
403-           throw  new  WebDriverException (e .getMessage (), e );
404-         } catch  (ExecutionException  e ) {
405-           Throwable  cause  = e .getCause ();
406- 
407-           if  (cause  instanceof  HttpTimeoutException ) {
408-             throw  new  TimeoutException (cause );
409-           } else  if  (cause  instanceof  IOException ) {
410-             throw  (IOException ) cause ;
411-           } else  if  (cause  instanceof  RuntimeException ) {
412-             throw  (RuntimeException ) cause ;
413-           }
414- 
415-           throw  new  WebDriverException ((cause  != null ) ? cause  : e );
416-         } catch  (java .util .concurrent .TimeoutException  e ) {
417-           future .cancel (true );
418-           throw  new  TimeoutException (e );
449+         if  (Thread .interrupted ()) {
450+           throw  new  InterruptedException ("http request has been interrupted" );
419451        }
420452
453+         java .net .http .HttpRequest  request  = messages .createRequest (req , method , rawUri );
454+         java .net .http .HttpResponse <byte []> response  = client .send (request , byteHandler );
455+ 
421456        switch  (response .statusCode ()) {
422457          case  303 :
423458            method  = HttpMethod .GET ;
@@ -454,6 +489,8 @@ private HttpResponse execute0(HttpRequest req) throws UncheckedIOException {
454489      }
455490
456491      throw  new  ProtocolException ("Too many redirects: 101" );
492+     } catch  (HttpTimeoutException  e ) {
493+       throw  new  TimeoutException (e );
457494    } catch  (IOException  e ) {
458495      throw  new  UncheckedIOException (e );
459496    } catch  (InterruptedException  e ) {
0 commit comments