From e7dc48db5b046492b1c8b2ea86394e3a718bc34d Mon Sep 17 00:00:00 2001 From: Artem Smotrakov Date: Fri, 13 May 2016 11:32:41 -0700 Subject: [PATCH] 8156710: HttpTimeoutException should be thrown if server doesn't respond Reviewed-by: michaelm --- .../share/classes/java/net/http/Stream.java | 16 ++- .../java/net/httpclient/http2/Timeout.java | 114 ++++++++++++++++++ .../java/net/httpclient/http2/keystore.p12 | Bin 0 -> 2452 bytes 3 files changed, 127 insertions(+), 3 deletions(-) create mode 100644 jdk/test/java/net/httpclient/http2/Timeout.java create mode 100644 jdk/test/java/net/httpclient/http2/keystore.p12 diff --git a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java index cea95c8f2f6..91252c93b88 100644 --- a/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java +++ b/jdk/src/java.httpclient/share/classes/java/net/http/Stream.java @@ -32,6 +32,9 @@ import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.function.BiFunction; import java.util.function.LongConsumer; @@ -409,13 +412,20 @@ class Stream extends ExchangeImpl { @Override HttpResponseImpl getResponse() throws IOException { try { - return getResponseAsync(null).join(); - } catch (Throwable e) { + if (request.timeval() > 0) { + return getResponseAsync(null).get( + request.timeval(), TimeUnit.MILLISECONDS); + } else { + return getResponseAsync(null).join(); + } + } catch (TimeoutException e) { + throw new HttpTimeoutException("Response timed out"); + } catch (InterruptedException | ExecutionException e) { Throwable t = e.getCause(); if (t instanceof IOException) { throw (IOException)t; } - throw e; + throw new IOException(e); } } diff --git a/jdk/test/java/net/httpclient/http2/Timeout.java b/jdk/test/java/net/httpclient/http2/Timeout.java new file mode 100644 index 00000000000..5418d127a97 --- /dev/null +++ b/jdk/test/java/net/httpclient/http2/Timeout.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.net.http.HttpTimeoutException; +import java.util.concurrent.TimeUnit; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSocket; + +/* + * @test + * @bug 8156710 + * @summary Check if HttpTimeoutException is thrown if a server doesn't reply + * @run main/othervm Timeout + */ +public class Timeout { + + private static final int RANDOM_PORT = 0; + private static final int TIMEOUT = 3 * 1000; // in millis + private static final String KEYSTORE = System.getProperty("test.src") + + File.separator + "keystore.p12"; + private static final String PASSWORD = "password"; + + // indicates if server is ready to accept connections + private static volatile boolean ready = false; + + public static void main(String[] args) throws Exception { + System.setProperty("javax.net.ssl.keyStore", KEYSTORE); + System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD); + System.setProperty("javax.net.ssl.trustStore", KEYSTORE); + System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD); + + SSLServerSocketFactory factory = + (SSLServerSocketFactory) SSLServerSocketFactory.getDefault(); + + try (SSLServerSocket ssocket = + (SSLServerSocket) factory.createServerSocket(RANDOM_PORT)) { + + // start server + Thread server = new Thread(() -> { + while (true) { + System.out.println("server: ready"); + ready = true; + try (SSLSocket socket = (SSLSocket) ssocket.accept()) { + + // just read forever + System.out.println("server: accepted"); + while (true) { + socket.getInputStream().read(); + } + } catch (IOException e) { + // ignore exceptions on server side + System.out.println("server: exception: " + e); + } + } + }); + server.setDaemon(true); + server.start(); + + // wait for server is ready + do { + Thread.sleep(1000); + } while (!ready); + + String uri = "https://localhost:" + ssocket.getLocalPort(); + connect(uri); + } + } + + private static void connect(String server) throws Exception { + try { + HttpClient.create() + .version(HttpClient.Version.HTTP_2) + .build() + .request(new URI(server)) + .timeout(TimeUnit.MILLISECONDS, TIMEOUT) + .body(HttpRequest.fromString("body")) + .GET() + .response() + .body(HttpResponse.asString()); + + throw new RuntimeException("unexpected successful connection"); + } catch (HttpTimeoutException e) { + System.out.println("expected exception: " + e); + } + } + +} diff --git a/jdk/test/java/net/httpclient/http2/keystore.p12 b/jdk/test/java/net/httpclient/http2/keystore.p12 new file mode 100644 index 0000000000000000000000000000000000000000..a635533d086f0dd97cb3c24ac34cf35680af3774 GIT binary patch literal 2452 zcmY+Ec{CJ?7sqFq1sS}IC8BI)DUIF4GmWyPVaC2>8N0G&Yp4d3zxU4j^C9oveEj{doUmr zm`!5W0Fl_$POuV!1Sb4P0(*i;VAm6jKPfxNssBxJasXMfNuUD+3ABrlhH(5JpDY&w z!Lj;iNqx2C&_RLTC8rc!fSXHB8w(2v03v}prVW}tS zNYM{C85ap|Rec#YKrsjBJsbW_6mjIS&Y|xtiN57(*X ziUjxLSSXTt!HJE{;-l)Y+=LqO$4kmLqiX;WDQj%(Q6m4r*LY6 zNv7Rvx)|$XOWA4>OvhZxBM>V}5165XC0w(QAPH-o;6(@=oMNo;Eur$Vsmrdt=110Axm;GWv* z8&l>^OOMc1K08F{vns8sXX(0PbB3;~{MY(9484sBJ^ISHjK}AlC7SS0e*Xg&CLC7b zr9(0K87td&_-?JOs5wk+ol}sn?Sd$861>A&>b}(w?k1+PZisunTOa1~I!nj$D(r4; z)i#|y&Ebwf9+JjgjiiFO5qQUhFPY#C5$562D{1NedDX<)Q(g8=zKQl*$C#vL!odLB zkl=6epoO@r?u+E{ujo=tgLw0~i+l1CnXdr+Sa^El&w=;p=QkAhLsNDNaG48Ry^gz` zjDy}=+blh-E}QIi@!A8*K#agXOPA*a$2_6$mu(o4rm@BwQtXvf-0MmP5C1WP1ftGH z_NG)!dkXo2*7@}&Z|^iaRm*ddnu8=X9bF;L2KXe{Mc=@Eb5+XCd2tXIoZsZWJ) z-z?0b{Y^h;x&F$19||gYmBHsS7V$#GAw1F7jAtWg=0WI`Q}or;Nu9-^;i6ubFJhtx ztwV>~-w*_T)P+ojR34IUdWOp*+)gQ? zq{+5pE}aTGdH{tt{Czme-*j3qc))zBYl_TOiY5OBwo(kti|h{Aus! z)kv97gMD0PssMv{MaP67bT6b0(*bAE2`HQP^ zGLw+9g<YP`{N;?r!Ud3Px+xNmF3Ux#m=VW0Ea$v+?2n zm{!84D=b>?sRj;mb7l_O@)5$7x+1qCrtlTbqdll=~dfV&w@~5|*DdVe^8oTW@P|NI9 zyZ%kYjGVMu4$icDaYy8{^-RLEo0lHWeC?v8El6qmNbMR+OSXkS*t5RAy0*d2k=;VY zYZ<6V$b&GFQ*^RAsr?l}gE=_kFw{ic!bal~z_ z5eJs!)c^#w+TOY+%KO2yzPwYWL}08y>5D|s4*Ly#*cjTPl~bZ>Plk}qh)2Cqj~oxRCtbXGoH?9+W-zAY-7Gd9X@;JE<3n~14$^F| zVeAB`1;8sB%IMLHab;ck*OxVeAu!Jf(sx>D5eA6j--vUc^r>8zGY!>$IJg*gR!-Nq zGUE=P|Lv0-9%kHMA9-GIQEQI(IB(&V(^x1fZXk_?tnFj$tU;~jsg_*ISFm7W<}Sk| zl%sz=4h#0)f2-;CdFu}$k+k(|^)}C>(_?%T(a)Q*yl%)FebdD#J z?+u&p*xuJN-=FQ?iyoVdE26jG{lKP(H%f~PeMGu2@Q|NRAG~%n`P`F5+0Sx~H9vD4 z_t-&kL~mp2`r+~pKK-SzE2Lw$3E>al#V;!cz3^5<{ZP>=dNql%?i%$BF;5bvji*G6 zNAPp2LED6_&@=ML7K_Ut&z6x