1 /* 2 * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.http; 27 28 import java.io.IOException; 29 import java.util.concurrent.CompletableFuture; 30 import java.util.concurrent.Executor; 31 import jdk.incubator.http.internal.common.MinimalFuture; 32 import static jdk.incubator.http.HttpClient.Version.HTTP_1_1; 33 34 /** 35 * Splits request so that headers and body can be sent separately with optional 36 * (multiple) responses in between (e.g. 100 Continue). Also request and 37 * response always sent/received in different calls. 38 * 39 * Synchronous and asynchronous versions of each method are provided. 40 * 41 * Separate implementations of this class exist for HTTP/1.1 and HTTP/2 42 * Http1Exchange (HTTP/1.1) 43 * Stream (HTTP/2) 44 * 45 * These implementation classes are where work is allocated to threads. 46 */ 47 abstract class ExchangeImpl<T> { 48 49 final Exchange<T> exchange; 50 51 ExchangeImpl(Exchange<T> e) { 52 // e == null means a http/2 pushed stream 53 this.exchange = e; 54 } 55 56 final Exchange<T> getExchange() { 57 return exchange; 58 } 59 60 61 /** 62 * Returns the {@link HttpConnection} instance to which this exchange is 63 * assigned. 64 */ 65 abstract HttpConnection connection(); 66 67 /** 68 * Initiates a new exchange and assigns it to a connection if one exists 69 * already. connection usually null. 70 */ 71 static <U> ExchangeImpl<U> get(Exchange<U> exchange, HttpConnection connection) 72 throws IOException, InterruptedException 73 { 74 HttpRequestImpl req = exchange.request(); 75 if (exchange.version() == HTTP_1_1) { 76 return new Http1Exchange<>(exchange, connection); 77 } else { 78 Http2ClientImpl c2 = exchange.client().client2(); // TODO: improve 79 HttpRequestImpl request = exchange.request(); 80 Http2Connection c; 81 try { 82 c = c2.getConnectionFor(request); 83 } catch (Http2Connection.ALPNException e) { 84 // failed to negotiate "h2" 85 AbstractAsyncSSLConnection as = e.getConnection(); 86 as.stopAsyncReading(); 87 HttpConnection sslc = as.downgrade(); 88 ExchangeImpl<U> ex = new Http1Exchange<>(exchange, sslc); 89 return ex; 90 } 91 if (c == null) { 92 // no existing connection. Send request with HTTP 1 and then 93 // upgrade if successful 94 ExchangeImpl<U> ex = new Http1Exchange<>(exchange, connection); 95 exchange.h2Upgrade(); 96 return ex; 97 } 98 return c.createStream(exchange); 99 } 100 } 101 102 /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */ 103 104 /** 105 * Sends the request headers only. May block until all sent. 106 */ 107 abstract void sendHeadersOnly() throws IOException, InterruptedException; 108 109 // Blocking impl but in async style 110 111 CompletableFuture<ExchangeImpl<T>> sendHeadersAsync() { 112 // this is blocking. cf will already be completed. 113 return MinimalFuture.supply(() -> { 114 sendHeadersOnly(); 115 return this; 116 }); 117 } 118 119 /** 120 * Gets response by blocking if necessary. This may be an 121 * intermediate response (like 101) or a final response 200 etc. Returns 122 * before body is read. 123 */ 124 abstract Response getResponse() throws IOException; 125 126 abstract T readBody(HttpResponse.BodyHandler<T> handler, 127 boolean returnConnectionToPool) throws IOException; 128 129 abstract CompletableFuture<T> readBodyAsync(HttpResponse.BodyHandler<T> handler, 130 boolean returnConnectionToPool, 131 Executor executor); 132 133 /** 134 * Async version of getResponse. Completes before body is read. 135 */ 136 abstract CompletableFuture<Response> getResponseAsync(Executor executor); 137 138 /** 139 * Sends a request body after request headers. 140 */ 141 abstract void sendBody() throws IOException, InterruptedException; 142 143 // Async version of sendBody(). This only used when body sent separately 144 // to headers (100 continue) 145 CompletableFuture<ExchangeImpl<T>> sendBodyAsync() { 146 return MinimalFuture.supply(() -> { 147 sendBody(); 148 return this; 149 }); 150 } 151 152 /** 153 * Cancels a request. Not currently exposed through API. 154 */ 155 abstract void cancel(); 156 157 /** 158 * Cancels a request with a cause. Not currently exposed through API. 159 */ 160 abstract void cancel(IOException cause); 161 } | 1 /* 2 * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.incubator.http; 27 28 import java.io.IOException; 29 import java.lang.System.Logger.Level; 30 import java.util.concurrent.CompletableFuture; 31 import java.util.concurrent.Executor; 32 import java.util.function.Function; 33 import jdk.incubator.http.internal.common.MinimalFuture; 34 import static jdk.incubator.http.HttpClient.Version.HTTP_1_1; 35 import jdk.incubator.http.internal.common.Utils; 36 37 /** 38 * Splits request so that headers and body can be sent separately with optional 39 * (multiple) responses in between (e.g. 100 Continue). Also request and 40 * response always sent/received in different calls. 41 * 42 * Synchronous and asynchronous versions of each method are provided. 43 * 44 * Separate implementations of this class exist for HTTP/1.1 and HTTP/2 45 * Http1Exchange (HTTP/1.1) 46 * Stream (HTTP/2) 47 * 48 * These implementation classes are where work is allocated to threads. 49 */ 50 abstract class ExchangeImpl<T> { 51 52 static final boolean DEBUG = Utils.DEBUG; // Revisit: temporary dev flag. 53 private static final System.Logger DEBUG_LOGGER = 54 Utils.getDebugLogger("ExchangeImpl"::toString, DEBUG); 55 56 final Exchange<T> exchange; 57 58 ExchangeImpl(Exchange<T> e) { 59 // e == null means a http/2 pushed stream 60 this.exchange = e; 61 } 62 63 final Exchange<T> getExchange() { 64 return exchange; 65 } 66 67 68 /** 69 * Returns the {@link HttpConnection} instance to which this exchange is 70 * assigned. 71 */ 72 abstract HttpConnection connection(); 73 74 /** 75 * Initiates a new exchange and assigns it to a connection if one exists 76 * already. connection usually null. 77 */ 78 static <U> CompletableFuture<? extends ExchangeImpl<U>> 79 get(Exchange<U> exchange, HttpConnection connection) 80 { 81 if (exchange.version() == HTTP_1_1) { 82 DEBUG_LOGGER.log(Level.DEBUG, "get: HTTP/1.1: new Http1Exchange"); 83 return createHttp1Exchange(exchange, connection); 84 } else { 85 Http2ClientImpl c2 = exchange.client().client2(); // TODO: improve 86 HttpRequestImpl request = exchange.request(); 87 CompletableFuture<Http2Connection> c2f = c2.getConnectionFor(request); 88 DEBUG_LOGGER.log(Level.DEBUG, "get: Trying to get HTTP/2 connection"); 89 return c2f.handle((h2c, t) -> createExchangeImpl(h2c, t, exchange, connection)) 90 .thenCompose(Function.identity()); 91 } 92 } 93 94 private static <U> CompletableFuture<? extends ExchangeImpl<U>> 95 createExchangeImpl(Http2Connection c, 96 Throwable t, 97 Exchange<U> exchange, 98 HttpConnection connection) 99 { 100 DEBUG_LOGGER.log(Level.DEBUG, "handling HTTP/2 connection creation result"); 101 if (t != null) { 102 DEBUG_LOGGER.log(Level.DEBUG, 103 "handling HTTP/2 connection creation failed: %s", 104 (Object)t); 105 t = Utils.getCompletionCause(t); 106 if (t instanceof Http2Connection.ALPNException) { 107 Http2Connection.ALPNException ee = (Http2Connection.ALPNException)t; 108 AbstractAsyncSSLConnection as = ee.getConnection(); 109 DEBUG_LOGGER.log(Level.DEBUG, "downgrading to HTTP/1.1 with: %s", as); 110 CompletableFuture<? extends ExchangeImpl<U>> ex = 111 createHttp1Exchange(exchange, as); 112 return ex; 113 } else { 114 DEBUG_LOGGER.log(Level.DEBUG, "HTTP/2 connection creation failed " 115 + "with unexpected exception: %s", (Object)t); 116 return CompletableFuture.failedFuture(t); 117 } 118 } 119 if (c == null) { 120 // no existing connection. Send request with HTTP 1 and then 121 // upgrade if successful 122 DEBUG_LOGGER.log(Level.DEBUG, "new Http1Exchange, try to upgrade"); 123 return createHttp1Exchange(exchange, connection) 124 .thenApply((e) -> { 125 exchange.h2Upgrade(); 126 return e; 127 }); 128 } else { 129 DEBUG_LOGGER.log(Level.DEBUG, "creating HTTP/2 streams"); 130 Stream<U> s = c.createStream(exchange); 131 CompletableFuture<? extends ExchangeImpl<U>> ex = MinimalFuture.completedFuture(s); 132 return ex; 133 } 134 } 135 136 private static <T> CompletableFuture<Http1Exchange<T>> 137 createHttp1Exchange(Exchange<T> ex, HttpConnection as) 138 { 139 try { 140 return MinimalFuture.completedFuture(new Http1Exchange<>(ex, as)); 141 } catch (Throwable e) { 142 return MinimalFuture.failedFuture(e); 143 } 144 } 145 146 /* The following methods have separate HTTP/1.1 and HTTP/2 implementations */ 147 148 abstract CompletableFuture<ExchangeImpl<T>> sendHeadersAsync(); 149 150 /** Sends a request body, after request headers have been sent. */ 151 abstract CompletableFuture<ExchangeImpl<T>> sendBodyAsync(); 152 153 abstract CompletableFuture<T> readBodyAsync(HttpResponse.BodyHandler<T> handler, 154 boolean returnConnectionToPool, 155 Executor executor); 156 157 /** 158 * Ignore/consume the body. 159 */ 160 abstract CompletableFuture<Void> ignoreBody(); 161 162 /** Gets the response headers. Completes before body is read. */ 163 abstract CompletableFuture<Response> getResponseAsync(Executor executor); 164 165 166 /** Cancels a request. Not currently exposed through API. */ 167 abstract void cancel(); 168 169 /** 170 * Cancels a request with a cause. Not currently exposed through API. 171 */ 172 abstract void cancel(IOException cause); 173 174 /** 175 * Called when the exchange is released, so that cleanup actions may be 176 * performed - such as deregistering callbacks. 177 * Typically released is called during upgrade, when an HTTP/2 stream 178 * takes over from an Http1Exchange, or when a new exchange is created 179 * during a multi exchange before the final response body was received. 180 */ 181 abstract void released(); 182 183 /** 184 * Called when the exchange is completed, so that cleanup actions may be 185 * performed - such as deregistering callbacks. 186 * Typically, completed is called at the end of the exchange, when the 187 * final response body has been received (or an error has caused the 188 * completion of the exchange). 189 */ 190 abstract void completed(); 191 192 /** 193 * Returns true if this exchange was canceled. 194 * @return true if this exchange was canceled. 195 */ 196 abstract boolean isCanceled(); 197 198 /** 199 * Returns the cause for which this exchange was canceled, if available. 200 * @return the cause for which this exchange was canceled, if available. 201 */ 202 abstract Throwable getCancelCause(); 203 } |