From c25db4a8d6f1c18f3221cb5bcd4ec933553f2dfc Mon Sep 17 00:00:00 2001 From: AlmogBaku Date: Mon, 4 Jul 2016 18:44:51 +0300 Subject: [PATCH 1/7] Custom ConnectionFlow allowed --- .../java/org/littleshoot/proxy/ChainedProxy.java | 7 +++++++ .../org/littleshoot/proxy/ChainedProxyAdapter.java | 13 +++++++++++++ .../org/littleshoot/proxy/impl/ConnectionFlow.java | 6 +++--- .../littleshoot/proxy/impl/ConnectionFlowStep.java | 6 +++--- .../org/littleshoot/proxy/impl/ConnectionState.java | 2 +- .../org/littleshoot/proxy/impl/ProxyConnection.java | 4 ++-- .../proxy/impl/ProxyToServerConnection.java | 6 ++++++ 7 files changed, 35 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/littleshoot/proxy/ChainedProxy.java b/src/main/java/org/littleshoot/proxy/ChainedProxy.java index 3292c4253..82f514fdd 100644 --- a/src/main/java/org/littleshoot/proxy/ChainedProxy.java +++ b/src/main/java/org/littleshoot/proxy/ChainedProxy.java @@ -1,5 +1,8 @@ package org.littleshoot.proxy; +import org.littleshoot.proxy.impl.ConnectionFlowStep; +import org.littleshoot.proxy.impl.ProxyConnection; + import io.netty.handler.codec.http.HttpObject; import java.net.InetSocketAddress; @@ -49,6 +52,10 @@ public interface ChainedProxy extends SslEngineSource { */ boolean requiresEncryption(); + boolean requiresCustomConnectionFlow(); + + ConnectionFlowStep customConnectionFlow(ProxyConnection connection); + /** * Filters requests on their way to the chained proxy. * diff --git a/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java b/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java index 61f42881f..7b80abdde 100644 --- a/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java +++ b/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java @@ -1,5 +1,8 @@ package org.littleshoot.proxy; +import org.littleshoot.proxy.impl.ConnectionFlowStep; +import org.littleshoot.proxy.impl.ProxyConnection; + import io.netty.handler.codec.http.HttpObject; import java.net.InetSocketAddress; @@ -36,6 +39,16 @@ public boolean requiresEncryption() { return false; } + @Override + public boolean requiresCustomConnectionFlow() { + return false; + } + + @Override + public ConnectionFlowStep customConnectionFlow(ProxyConnection connection) { + return null; + } + @Override public SSLEngine newSslEngine() { return null; diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java index 23a65f08e..fe9f89976 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java @@ -11,7 +11,7 @@ * establishing a socket connection, SSL handshaking, HTTP CONNECT request * processing, and so on. */ -class ConnectionFlow { +public class ConnectionFlow { private Queue steps = new ConcurrentLinkedQueue(); private final ClientToProxyConnection clientConnection; @@ -82,7 +82,7 @@ void start() { * out of steps, or a step has failed. *

*/ - void advance() { + public void advance() { currentStep = steps.poll(); if (currentStep == null) { succeed(); @@ -204,7 +204,7 @@ public void operationComplete(Future future) /** * Like {@link #fail(Throwable)} but with no cause. */ - void fail() { + public void fail() { fail(null); } diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java index c60910d59..bdb8ba25b 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java @@ -5,7 +5,7 @@ /** * Represents a phase in a {@link ConnectionFlow}. */ -abstract class ConnectionFlowStep { +public abstract class ConnectionFlowStep { private final ProxyConnectionLogger LOG; private final ProxyConnection connection; private final ConnectionState state; @@ -19,8 +19,8 @@ abstract class ConnectionFlowStep { * the state that the connection will show while we're processing * this step */ - ConnectionFlowStep(ProxyConnection connection, - ConnectionState state) { + protected ConnectionFlowStep(ProxyConnection connection, + ConnectionState state) { super(); this.connection = connection; this.state = state; diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java index 371fcd586..919ea01b0 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java @@ -1,6 +1,6 @@ package org.littleshoot.proxy.impl; -enum ConnectionState { +public enum ConnectionState { /** * Connection attempting to connect. */ diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java index 58c3eb240..4cd681427 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java @@ -60,7 +60,7 @@ * the type of "initial" message. This will be either * {@link HttpResponse} or {@link HttpRequest}. */ -abstract class ProxyConnection extends +public abstract class ProxyConnection extends SimpleChannelInboundHandler { protected final ProxyConnectionLogger LOG = new ProxyConnectionLogger(this); @@ -262,7 +262,7 @@ protected void writeRaw(ByteBuf buf) { writeToChannel(buf); } - protected ChannelFuture writeToChannel(final Object msg) { + public ChannelFuture writeToChannel(final Object msg) { return channel.writeAndFlush(msg); } diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index c9cd0f2d4..26dddc9fc 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -559,6 +559,12 @@ private void initializeConnectionFlow() { connectLock) .then(ConnectChannel); + if (chainedProxy != null && chainedProxy.requiresCustomConnectionFlow()) { + connectionFlow.then(chainedProxy.customConnectionFlow(this)); + } else { + LOG.debug("wtf?"); + } + if (chainedProxy != null && chainedProxy.requiresEncryption()) { connectionFlow.then(serverConnection.EncryptChannel(chainedProxy .newSslEngine())); From 6ccaf7293594257d0e2ea748ed0962619bbde7ac Mon Sep 17 00:00:00 2001 From: AlmogBaku Date: Mon, 4 Jul 2016 18:52:09 +0300 Subject: [PATCH 2/7] comments --- .../java/org/littleshoot/proxy/ChainedProxy.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/org/littleshoot/proxy/ChainedProxy.java b/src/main/java/org/littleshoot/proxy/ChainedProxy.java index 82f514fdd..57f9b59b8 100644 --- a/src/main/java/org/littleshoot/proxy/ChainedProxy.java +++ b/src/main/java/org/littleshoot/proxy/ChainedProxy.java @@ -7,6 +7,8 @@ import java.net.InetSocketAddress; +import javax.net.ssl.SSLEngine; + /** *

* Encapsulates information needed to connect to a chained proxy. @@ -52,8 +54,22 @@ public interface ChainedProxy extends SslEngineSource { */ boolean requiresEncryption(); + /** + * Implement this method to tell LittleProxy whether or not to use custom ConnectionFlow + * to the chained proxy for the given request. If true, + * LittleProxy will call {@link ChainedProxy#customConnectionFlow(ProxyConnection)} to obtain a + * ConnectionFlow. + * + * @return true of the connection to the chained proxy should be used a custom ConnectionFlow + */ boolean requiresCustomConnectionFlow(); + /** + * Returns an {@link ConnectionFlowStep} to use for a server connection from + * LittleProxy to the client. + * + * @return + */ ConnectionFlowStep customConnectionFlow(ProxyConnection connection); /** From 07f58ef6718b8cee59cb8eaf837108db120fd600 Mon Sep 17 00:00:00 2001 From: AlmogBaku Date: Tue, 5 Jul 2016 09:41:30 +0300 Subject: [PATCH 3/7] specify changes --- src/main/java/org/littleshoot/proxy/ChainedProxy.java | 8 ++++---- .../java/org/littleshoot/proxy/ChainedProxyAdapter.java | 6 ++++-- .../java/org/littleshoot/proxy/impl/ConnectionFlow.java | 3 +++ .../org/littleshoot/proxy/impl/ConnectionFlowStep.java | 2 ++ .../java/org/littleshoot/proxy/impl/ConnectionState.java | 1 + .../java/org/littleshoot/proxy/impl/ProxyConnection.java | 2 ++ .../littleshoot/proxy/impl/ProxyToServerConnection.java | 3 +-- 7 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/littleshoot/proxy/ChainedProxy.java b/src/main/java/org/littleshoot/proxy/ChainedProxy.java index 57f9b59b8..97caa7aa8 100644 --- a/src/main/java/org/littleshoot/proxy/ChainedProxy.java +++ b/src/main/java/org/littleshoot/proxy/ChainedProxy.java @@ -1,14 +1,12 @@ package org.littleshoot.proxy; -import org.littleshoot.proxy.impl.ConnectionFlowStep; -import org.littleshoot.proxy.impl.ProxyConnection; +import org.littleshoot.proxy.impl.ConnectionFlowStep; //Change: @AlmogBaku +import org.littleshoot.proxy.impl.ProxyConnection; //Change: @AlmogBaku import io.netty.handler.codec.http.HttpObject; import java.net.InetSocketAddress; -import javax.net.ssl.SSLEngine; - /** *

* Encapsulates information needed to connect to a chained proxy. @@ -55,6 +53,7 @@ public interface ChainedProxy extends SslEngineSource { boolean requiresEncryption(); /** + * //Change: @AlmogBaku * Implement this method to tell LittleProxy whether or not to use custom ConnectionFlow * to the chained proxy for the given request. If true, * LittleProxy will call {@link ChainedProxy#customConnectionFlow(ProxyConnection)} to obtain a @@ -65,6 +64,7 @@ public interface ChainedProxy extends SslEngineSource { boolean requiresCustomConnectionFlow(); /** + * //Change: @AlmogBaku * Returns an {@link ConnectionFlowStep} to use for a server connection from * LittleProxy to the client. * diff --git a/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java b/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java index 7b80abdde..0eca7370c 100644 --- a/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java +++ b/src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java @@ -1,7 +1,7 @@ package org.littleshoot.proxy; -import org.littleshoot.proxy.impl.ConnectionFlowStep; -import org.littleshoot.proxy.impl.ProxyConnection; +import org.littleshoot.proxy.impl.ConnectionFlowStep;//Change: @AlmogBaku +import org.littleshoot.proxy.impl.ProxyConnection;//Change: @AlmogBaku import io.netty.handler.codec.http.HttpObject; @@ -39,11 +39,13 @@ public boolean requiresEncryption() { return false; } + //Change: @AlmogBaku @Override public boolean requiresCustomConnectionFlow() { return false; } + //Change: @AlmogBaku @Override public ConnectionFlowStep customConnectionFlow(ProxyConnection connection) { return null; diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java index fe9f89976..8975bfd70 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java @@ -11,6 +11,7 @@ * establishing a socket connection, SSL handshaking, HTTP CONNECT request * processing, and so on. */ +//Change(expose to public): @AlmogBaku public class ConnectionFlow { private Queue steps = new ConcurrentLinkedQueue(); @@ -77,6 +78,7 @@ void start() { } /** + * //Change(expose to public): @AlmogBaku *

* Advances the flow. {@link #advance()} will be called until we're either * out of steps, or a step has failed. @@ -202,6 +204,7 @@ public void operationComplete(Future future) } /** + * //Change(expose to public): @AlmogBaku * Like {@link #fail(Throwable)} but with no cause. */ public void fail() { diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java index bdb8ba25b..043d6e885 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java @@ -3,6 +3,7 @@ import io.netty.util.concurrent.Future; /** + * //Change(expose to public): @AlmogBaku * Represents a phase in a {@link ConnectionFlow}. */ public abstract class ConnectionFlowStep { @@ -11,6 +12,7 @@ public abstract class ConnectionFlowStep { private final ConnectionState state; /** + * //Change(expose to protected): @AlmogBaku * Construct a new step in a connection flow. * * @param connection diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java index 919ea01b0..f3598c7f6 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionState.java @@ -1,5 +1,6 @@ package org.littleshoot.proxy.impl; +//Change(expose to public): @AlmogBaku public enum ConnectionState { /** * Connection attempting to connect. diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java index 4cd681427..b3db3c7dd 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java @@ -60,6 +60,7 @@ * the type of "initial" message. This will be either * {@link HttpResponse} or {@link HttpRequest}. */ +//Change(expose to public): @AlmogBaku public abstract class ProxyConnection extends SimpleChannelInboundHandler { protected final ProxyConnectionLogger LOG = new ProxyConnectionLogger(this); @@ -262,6 +263,7 @@ protected void writeRaw(ByteBuf buf) { writeToChannel(buf); } + //Change(expose to public): @AlmogBaku public ChannelFuture writeToChannel(final Object msg) { return channel.writeAndFlush(msg); } diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index 26dddc9fc..bb71d335c 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -559,10 +559,9 @@ private void initializeConnectionFlow() { connectLock) .then(ConnectChannel); + //Change: @AlmogBaku if (chainedProxy != null && chainedProxy.requiresCustomConnectionFlow()) { connectionFlow.then(chainedProxy.customConnectionFlow(this)); - } else { - LOG.debug("wtf?"); } if (chainedProxy != null && chainedProxy.requiresEncryption()) { From e09ab799e92216c82b350c85eed18ce09004fcda Mon Sep 17 00:00:00 2001 From: AlmogBaku Date: Thu, 4 Aug 2016 16:03:45 +0300 Subject: [PATCH 4/7] expose fail with reason --- src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java index 8975bfd70..ad3e41a72 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java @@ -173,12 +173,13 @@ void succeed() { } /** + * //Change(expose to public): @AlmogBaku * Called when the flow fails at some {@link ConnectionFlowStep}. * Disconnects the {@link ProxyToServerConnection} and informs the * {@link ClientToProxyConnection} that our connection failed. */ @SuppressWarnings("unchecked") - void fail(final Throwable cause) { + public void fail(final Throwable cause) { final ConnectionState lastStateBeforeFailure = serverConnection .getCurrentState(); serverConnection.disconnect().addListener( From 3d576f86ace545c0bc10d667aff3617c98dea4a5 Mon Sep 17 00:00:00 2001 From: AlmogBaku Date: Fri, 5 Aug 2016 08:12:45 +0300 Subject: [PATCH 5/7] support multiple reads for ConnectionFlow --- .../org/littleshoot/proxy/impl/ProxyToServerConnection.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index bb71d335c..72df65a7c 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -697,6 +697,11 @@ void onSuccess(ConnectionFlow flow) { } void read(ConnectionFlow flow, Object msg) { + //@AlmogBaku: Ignore previous reads + if (msg == LastHttpContent.EMPTY_LAST_CONTENT) { + return; + } + // Here we're handling the response from a chained proxy to our // earlier CONNECT request boolean connectOk = false; From ba7d99657b120dcbdd5ed510377e00ed88690929 Mon Sep 17 00:00:00 2001 From: AlmogBaku Date: Mon, 8 Aug 2016 19:35:29 +0300 Subject: [PATCH 6/7] expose methods as protected --- .../java/org/littleshoot/proxy/impl/ConnectionFlowStep.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java index 043d6e885..caaf355b4 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java +++ b/src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java @@ -74,6 +74,7 @@ boolean shouldExecuteOnEventLoop() { protected abstract Future execute(); /** + * //Change(expose to protected): @AlmogBaku * When the flow determines that this step was successful, it calls into * this method. The default implementation simply continues with the flow. * Other implementations may choose to not continue and instead wait for a @@ -81,11 +82,12 @@ boolean shouldExecuteOnEventLoop() { * * @param flow */ - void onSuccess(ConnectionFlow flow) { + protected void onSuccess(ConnectionFlow flow) { flow.advance(); } /** + * //Change(expose to protected): @AlmogBaku *

* Any messages that are read from the underlying connection while we're at * this step of the connection flow are passed to this method. @@ -106,7 +108,7 @@ void onSuccess(ConnectionFlow flow) { * @param msg * the message read from the underlying connection */ - void read(ConnectionFlow flow, Object msg) { + protected void read(ConnectionFlow flow, Object msg) { LOG.debug("Received message while in the middle of connecting: {}", msg); } From d654500c7a11cd8de0704488ab70a9897c736b0a Mon Sep 17 00:00:00 2001 From: AlmogBaku Date: Mon, 8 Aug 2016 19:39:46 +0300 Subject: [PATCH 7/7] expose the methods.. --- .../org/littleshoot/proxy/impl/ProxyToServerConnection.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index 72df65a7c..8645cdba2 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -691,12 +691,13 @@ public void operationComplete(ChannelFuture arg0) throws Exception { } } - void onSuccess(ConnectionFlow flow) { + //Change(expose to protected): @AlmogBaku + protected void onSuccess(ConnectionFlow flow) { // Do nothing, since we want to wait for the CONNECT response to // come back } - void read(ConnectionFlow flow, Object msg) { + protected void read(ConnectionFlow flow, Object msg) { //@AlmogBaku: Ignore previous reads if (msg == LastHttpContent.EMPTY_LAST_CONTENT) { return;