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