From 15ee24585e8cf34e7e56f72ba02218545cb9ccee Mon Sep 17 00:00:00 2001 From: Joakim Erdfelt Date: Thu, 15 Oct 2015 09:15:50 -0700 Subject: [PATCH] 479678 - Support HTTP/1.1 Upgrade in HttpClient + Adding Connection.UpgradeFrom support to HttpConnectionOverHTTP + (Soft) Closing HttpConnectionOverHTTP on upgrade + Removing 'extends Connection' from Connection.UpgradeFrom and Connection.UpgradeTo to allow for use from components that delegate bytebuffer handling away from raw Connection --- .../eclipse/jetty/client/HttpDestination.java | 2 +- .../client/http/HttpChannelOverHTTP.java | 24 ++++++++++++------- .../client/http/HttpConnectionOverHTTP.java | 19 +++++++++++++-- .../client/http/HttpReceiverOverHTTP.java | 11 +++++++++ .../java/org/eclipse/jetty/io/Connection.java | 4 ++-- 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java index d678a11ab69..ff24d7b3b13 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpDestination.java @@ -76,7 +76,7 @@ public abstract class HttpDestination extends ContainerLifeCycle implements Dest } else { - if (HttpScheme.HTTPS.is(getScheme())||HttpScheme.WSS.is(getScheme())) + if (HttpScheme.HTTPS.is(getScheme()) || HttpScheme.WSS.is(getScheme())) connectionFactory = newSslClientConnectionFactory(connectionFactory); } this.connectionFactory = connectionFactory; diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java index 969c6f15f74..0ca65b109cc 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpChannelOverHTTP.java @@ -18,12 +18,13 @@ package org.eclipse.jetty.client.http; +import java.util.Locale; + import org.eclipse.jetty.client.HttpChannel; import org.eclipse.jetty.client.HttpExchange; -import org.eclipse.jetty.client.HttpReceiver; import org.eclipse.jetty.client.HttpRequest; import org.eclipse.jetty.client.HttpResponse; -import org.eclipse.jetty.client.HttpSender; +import org.eclipse.jetty.client.HttpResponseException; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.http.HttpFields; @@ -58,13 +59,13 @@ public class HttpChannelOverHTTP extends HttpChannel } @Override - protected HttpSender getHttpSender() + protected HttpSenderOverHTTP getHttpSender() { return sender; } @Override - protected HttpReceiver getHttpReceiver() + protected HttpReceiverOverHTTP getHttpReceiver() { return receiver; } @@ -96,10 +97,15 @@ public class HttpChannelOverHTTP extends HttpChannel HttpResponse response = exchange.getResponse(); - if ( (response.getVersion() == HttpVersion.HTTP_1_1) && - (response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101) && - (response.getHeaders().get("Connection").equalsIgnoreCase("upgrade")) ) + if ((response.getVersion() == HttpVersion.HTTP_1_1) && + (response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101)) { + String connection = response.getHeaders().get(HttpHeader.CONNECTION); + if ((connection == null) || !connection.toLowerCase(Locale.US).contains("upgrade")) + { + return new Result(result,new HttpResponseException("101 Switching Protocols without Connection: Upgrade not supported",response)); + } + // Upgrade Response HttpRequest request = exchange.getRequest(); if (request instanceof HttpConnectionUpgrader) @@ -107,11 +113,11 @@ public class HttpChannelOverHTTP extends HttpChannel HttpConnectionUpgrader listener = (HttpConnectionUpgrader)request; try { - listener.upgrade(response, getHttpConnection()); + listener.upgrade(response,getHttpConnection()); } catch (Throwable x) { - return new Result(result, x); + return new Result(result,x); } } } diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java index 59e152acf4b..5b592f6ce12 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpConnectionOverHTTP.java @@ -18,6 +18,7 @@ package org.eclipse.jetty.client.http; +import java.nio.ByteBuffer; import java.nio.channels.AsynchronousCloseException; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicBoolean; @@ -36,7 +37,7 @@ import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Sweeper; -public class HttpConnectionOverHTTP extends AbstractConnection implements Connection, Sweeper.Sweepable +public class HttpConnectionOverHTTP extends AbstractConnection implements Connection, org.eclipse.jetty.io.Connection.UpgradeFrom, Sweeper.Sweepable { private static final Logger LOG = Log.getLogger(HttpConnectionOverHTTP.class); @@ -88,7 +89,14 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec fillInterested(); promise.succeeded(this); } - + + @Override + public void onClose() + { + softClose(); + super.onClose(); + } + public boolean isClosed() { return closed.get(); @@ -119,6 +127,13 @@ public class HttpConnectionOverHTTP extends AbstractConnection implements Connec } } + @Override + public ByteBuffer onUpgradeFrom() + { + HttpReceiverOverHTTP receiver = channel.getHttpReceiver(); + return receiver.onUpgradeFrom(); + } + public void release() { // Restore idle timeout diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index b9b2709a92f..3503706d069 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -88,6 +88,17 @@ public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.Res buffer = null; } + protected ByteBuffer onUpgradeFrom() + { + if (BufferUtil.hasContent(buffer)) + { + ByteBuffer upgradeBuffer = buffer; + releaseBuffer(); // TODO: right place to do this? + return upgradeBuffer; + } + return null; + } + private void process() { try diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java index a0f7a5d29df..b47c59058e8 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/Connection.java @@ -63,7 +63,7 @@ public interface Connection extends Closeable public long getBytesOut(); public long getCreatedTimeStamp(); - public interface UpgradeFrom extends Connection + public interface UpgradeFrom { /* ------------------------------------------------------------ */ /** Take the input buffer from the connection on upgrade. @@ -75,7 +75,7 @@ public interface Connection extends Closeable ByteBuffer onUpgradeFrom(); } - public interface UpgradeTo extends Connection + public interface UpgradeTo { /** *

Callback method invoked when this {@link Connection} is upgraded.