From af01397ebed6c6737d553c4fad6f1248c7135964 Mon Sep 17 00:00:00 2001 From: Marshall Jones Date: Fri, 3 Mar 2017 10:56:12 -0800 Subject: [PATCH 01/21] VGS Specific Deploy Config --- circle.yml | 16 ++++++++++++++++ pom.xml | 38 +++++++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 circle.yml diff --git a/circle.yml b/circle.yml new file mode 100644 index 000000000..acaf6f159 --- /dev/null +++ b/circle.yml @@ -0,0 +1,16 @@ +--- +machine: + java: + version: oraclejdk8 +dependencies: + override: + - mvn clean dependency:go-offline install -Dmaven.test.skip=true --fail-never --threads 5 -B +test: + override: + - mvn test -T2C +deployment: + snapshot: + branch: vgs-edition + owner: verygoodsecurity + commands: + - mvn deploy -DskipTests=true diff --git a/pom.xml b/pom.xml index a81bd358f..20399816b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.3-SNAPSHOT + 1.1.3-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. @@ -54,17 +54,32 @@ - - ossrh - https://oss.sonatype.org/content/repositories/snapshots - - ossrh - https://oss.sonatype.org/service/local/staging/deploy/maven2/ + vg-release + VG Release Repository + s3://very-good/software/release/ + + + vg-snapshot + VG Snapshot Repository + s3://very-good/software/snapshot/ + + + + + yle-public + Yle public repository + http://maven.c4.yle.fi/release + + false + + + + 2009 @@ -550,6 +565,15 @@ + + + + fi.yle.tools + aws-maven + 1.4.0 + + + From 859246f6c1c09fe7ec0f7b8b3a6f0e1667501a3b Mon Sep 17 00:00:00 2001 From: Marshall Jones Date: Fri, 3 Mar 2017 11:15:29 -0800 Subject: [PATCH 02/21] Add Circle CI Badge --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d512855e6..ded0c47ab 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ [![Build Status](https://travis-ci.org/adamfisk/LittleProxy.png?branch=master)](https://travis-ci.org/adamfisk/LittleProxy) +[![CircleCI](https://circleci.com/gh/verygoodsecurity/LittleProxy.svg?style=svg)](https://circleci.com/gh/verygoodsecurity/LittleProxy) LittleProxy is a high performance HTTP proxy written in Java atop Trustin Lee's excellent [Netty](http://netty.io) event-based networking library. It's quite stable, performs well, and is easy to integrate into your projects. From f4027693a38e4e8a3b323e67d757407cffc0e206 Mon Sep 17 00:00:00 2001 From: Kostiantyn Severynov Date: Fri, 14 Apr 2017 16:56:39 +0300 Subject: [PATCH 03/21] Verify that request is not null (#9) --- .../org/littleshoot/proxy/impl/ClientToProxyConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java index 964858fbf..32d8d01ec 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java @@ -443,7 +443,7 @@ void respond(ProxyToServerConnection serverConnection, HttpFilters filters, // if this HttpResponse does not have any means of signaling the end of the message body other than closing // the connection, convert the message to a "Transfer-Encoding: chunked" HTTP response. This avoids the need // to close the client connection to indicate the end of the message. (Responses to HEAD requests "must be" empty.) - if (!ProxyUtils.isHEAD(currentHttpRequest) && !ProxyUtils.isResponseSelfTerminating(httpResponse)) { + if (currentHttpRequest != null && !ProxyUtils.isHEAD(currentHttpRequest) && !ProxyUtils.isResponseSelfTerminating(httpResponse)) { // if this is not a FullHttpResponse, duplicate the HttpResponse from the server before sending it to // the client. this allows us to set the Transfer-Encoding to chunked without interfering with netty's // handling of the response from the server. if we modify the original HttpResponse from the server, From 981e55f02ecfd6a143deca6da05aff223e946b8c Mon Sep 17 00:00:00 2001 From: Marshall Jones Date: Mon, 17 Apr 2017 11:53:44 -0400 Subject: [PATCH 04/21] Move to new AWS distribution --- pom.xml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 20399816b..09c407e29 100644 --- a/pom.xml +++ b/pom.xml @@ -58,24 +58,24 @@ vg-release VG Release Repository - s3://very-good/software/release/ + s3://vault-dev-01-audits-01-artifact-19k6160zpr44j/software/release/ vg-snapshot VG Snapshot Repository - s3://very-good/software/snapshot/ + s3://vault-dev-01-audits-01-artifact-19k6160zpr44j/software/snapshot/ - yle-public - Yle public repository - http://maven.c4.yle.fi/release + jfog + jfrog + https://dl.bintray.com/vg/vgs-misc - false + true @@ -568,9 +568,9 @@ - fi.yle.tools + io.vgs.tools aws-maven - 1.4.0 + 1.4.2 From 63cef1e40c7b83f93846310805dda96c1e3b0e0e Mon Sep 17 00:00:00 2001 From: Marshall Jones Date: Mon, 17 Apr 2017 12:17:58 -0400 Subject: [PATCH 05/21] Set Environment Variables for Deploy --- circle.yml | 1 + env.sh | 14 ++++++++++++++ 2 files changed, 15 insertions(+) create mode 100755 env.sh diff --git a/circle.yml b/circle.yml index acaf6f159..e5dc3b71e 100644 --- a/circle.yml +++ b/circle.yml @@ -4,6 +4,7 @@ machine: version: oraclejdk8 dependencies: override: + - ./env.sh - mvn clean dependency:go-offline install -Dmaven.test.skip=true --fail-never --threads 5 -B test: override: diff --git a/env.sh b/env.sh new file mode 100755 index 000000000..c5f147a03 --- /dev/null +++ b/env.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +set -x + +mkdir -p ~/.aws +touch ~/.aws/credentials + +echo " +[vgs-dev] +region = us-west-2 +role_arn = arn:aws:iam::883127560329:role/StageDeploy +source_profile = default +" | tee -a ~/.aws/credentials + From b8edde90b1a4fd7163256837a2aa6f3c9952d46a Mon Sep 17 00:00:00 2001 From: Marshall Jones Date: Mon, 17 Apr 2017 12:28:30 -0400 Subject: [PATCH 06/21] Set Deployment Profile --- circle.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/circle.yml b/circle.yml index e5dc3b71e..a8e11d782 100644 --- a/circle.yml +++ b/circle.yml @@ -2,6 +2,8 @@ machine: java: version: oraclejdk8 + environment: + AWS_PROFILE: vgs-dev dependencies: override: - ./env.sh From 24f8ac95691dd6448107b83978083a165275fa2c Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Thu, 1 Jun 2017 19:37:42 +0300 Subject: [PATCH 07/21] Customize handling of http 502 (#12) * Adds custom message when there is a problem with upstream server certificate * Makes the implementation generic. * Renamed interface * Removes unnecesssary if statement * Adds tests * Addresses code review comments * trigger build * trigger build 2 * Adds clear content on head request test * Added minor version --- pom.xml | 2 +- ...BadGatewayFailureHttpResponseComposer.java | 42 +++++++++++ .../proxy/FailureHttpResponseComposer.java | 18 +++++ .../proxy/HttpProxyServerBootstrap.java | 16 ++++ .../proxy/impl/ClientToProxyConnection.java | 24 +++--- .../proxy/impl/DefaultHttpProxyServer.java | 21 +++++- ...atewayFailureHttpResponseComposerTest.java | 74 +++++++++++++++++++ .../impl/DefaultHttpProxyServerTest.java | 38 ++++++++++ 8 files changed, 220 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposer.java create mode 100644 src/main/java/org/littleshoot/proxy/FailureHttpResponseComposer.java create mode 100644 src/test/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposerTest.java create mode 100644 src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java diff --git a/pom.xml b/pom.xml index 09c407e29..52691c1c9 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.3-VGS-SNAPSHOT + 1.1.3.1-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. diff --git a/src/main/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposer.java b/src/main/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposer.java new file mode 100644 index 000000000..f115332cb --- /dev/null +++ b/src/main/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposer.java @@ -0,0 +1,42 @@ +package org.littleshoot.proxy; + +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; +import io.netty.handler.codec.http.HttpVersion; +import org.littleshoot.proxy.impl.ProxyUtils; + +public class BadGatewayFailureHttpResponseComposer implements FailureHttpResponseComposer { + + /** + * Tells the client that something went wrong trying to proxy its request. If the Bad Gateway is a response to + * an HTTP HEAD request, the response will contain no body, but the Content-Length header will be set to the + * value it would have been if this 502 Bad Gateway were in response to a GET. + * + * @param httpRequest the HttpRequest that is resulting in the Bad Gateway response + * @param cause raised exception + * @return true if the connection will be kept open, or false if it will be disconnected + */ + @Override + public FullHttpResponse compose(HttpRequest httpRequest, Throwable cause) { + String body = provideCustomMessage(httpRequest, cause); + + FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_GATEWAY, body); + + if (ProxyUtils.isHEAD(httpRequest)) { + // don't allow any body content in response to a HEAD request + response.content().clear(); + } + return response; + } + + /** + * The method can be overridden to provide a custom message along with 502 code + * @param httpRequest initial request + * @param cause an exception thrown on a failure + * @return custom message + */ + protected String provideCustomMessage(HttpRequest httpRequest, Throwable cause) { + return "Bad Gateway: " + httpRequest.getUri(); + } +} diff --git a/src/main/java/org/littleshoot/proxy/FailureHttpResponseComposer.java b/src/main/java/org/littleshoot/proxy/FailureHttpResponseComposer.java new file mode 100644 index 000000000..54e1e40fa --- /dev/null +++ b/src/main/java/org/littleshoot/proxy/FailureHttpResponseComposer.java @@ -0,0 +1,18 @@ +package org.littleshoot.proxy; + +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpRequest; + +/** + * Interface for objects that can provide a custom http response on a specific failure. + */ +public interface FailureHttpResponseComposer { + + /** + * Creates an {@link FullHttpResponse} based on initial request and failure cause + * @param httpRequest initial request + * @param cause an exception thrown during a failure + * @return failure http response + */ + FullHttpResponse compose(HttpRequest httpRequest, Throwable cause); +} diff --git a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java index 367dc8dd1..3993d420d 100644 --- a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java +++ b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java @@ -197,6 +197,22 @@ HttpProxyServerBootstrap withManInTheMiddle( HttpProxyServerBootstrap withFiltersSource( HttpFiltersSource filtersSource); + /** + *

+ * Specify a {@link FailureHttpResponseComposer} to use for composing + * custom response message on unrecoverable failure + *

+ * + *

+ * Default = {@link BadGatewayFailureHttpResponseComposer} + *

+ * + * @param unrecoverableFailureHttpResponseComposer custom response message composer + * @return + */ + HttpProxyServerBootstrap withUnrecoverableFailureHttpResponseComposer( + FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer); + /** *

* Specify whether or not to use secure DNS lookups for outbound diff --git a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java index 32d8d01ec..8bf49b107 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java @@ -25,6 +25,8 @@ import io.netty.util.concurrent.GenericFutureListener; import org.apache.commons.lang3.StringUtils; import org.littleshoot.proxy.ActivityTracker; +import org.littleshoot.proxy.BadGatewayFailureHttpResponseComposer; +import org.littleshoot.proxy.FailureHttpResponseComposer; import org.littleshoot.proxy.FlowContext; import org.littleshoot.proxy.FullFlowContext; import org.littleshoot.proxy.HttpFilters; @@ -616,22 +618,25 @@ protected boolean serverConnectionFailed( serverConnection.getRemoteAddress(), lastStateBeforeFailure, cause); - connectionFailedUnrecoverably(initialRequest, serverConnection); + connectionFailedUnrecoverably(initialRequest, serverConnection, cause); return false; } } catch (UnknownHostException uhe) { - connectionFailedUnrecoverably(initialRequest, serverConnection); + connectionFailedUnrecoverably(initialRequest, serverConnection, cause); return false; } } - private void connectionFailedUnrecoverably(HttpRequest initialRequest, ProxyToServerConnection serverConnection) { + private void connectionFailedUnrecoverably(HttpRequest initialRequest, ProxyToServerConnection serverConnection, Throwable cause) { // the connection to the server failed, so disconnect the server and remove the ProxyToServerConnection from the // map of open server connections serverConnection.disconnect(); this.serverConnectionsByHostAndPort.remove(serverConnection.getServerHostAndPort()); - boolean keepAlive = writeBadGateway(initialRequest); + FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = proxyServer.getUnrecoverableFailureHttpResponseComposer(); + FullHttpResponse failureResponse = unrecoverableFailureHttpResponseComposer.compose(initialRequest, cause); + + boolean keepAlive = respondWithShortCircuitResponse(failureResponse); if (keepAlive) { become(AWAITING_INITIAL); } else { @@ -1203,15 +1208,8 @@ private void stripHopByHopHeaders(HttpHeaders headers) { * @return true if the connection will be kept open, or false if it will be disconnected */ private boolean writeBadGateway(HttpRequest httpRequest) { - String body = "Bad Gateway: " + httpRequest.getUri(); - FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_GATEWAY, body); - - if (ProxyUtils.isHEAD(httpRequest)) { - // don't allow any body content in response to a HEAD request - response.content().clear(); - } - - return respondWithShortCircuitResponse(response); + FullHttpResponse badGatewayResponse = new BadGatewayFailureHttpResponseComposer().compose(httpRequest, null); + return respondWithShortCircuitResponse(badGatewayResponse); } /** diff --git a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java index 1891532e4..72d3c4a26 100644 --- a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java +++ b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java @@ -17,6 +17,7 @@ import io.netty.handler.traffic.GlobalTrafficShapingHandler; import io.netty.util.concurrent.GlobalEventExecutor; import org.littleshoot.proxy.ActivityTracker; +import org.littleshoot.proxy.BadGatewayFailureHttpResponseComposer; import org.littleshoot.proxy.ChainedProxyManager; import org.littleshoot.proxy.DefaultHostResolver; import org.littleshoot.proxy.DnsSecServerResolver; @@ -26,6 +27,7 @@ import org.littleshoot.proxy.HttpFiltersSourceAdapter; import org.littleshoot.proxy.HttpProxyServer; import org.littleshoot.proxy.HttpProxyServerBootstrap; +import org.littleshoot.proxy.FailureHttpResponseComposer; import org.littleshoot.proxy.MitmManager; import org.littleshoot.proxy.ProxyAuthenticator; import org.littleshoot.proxy.SslEngineSource; @@ -108,6 +110,7 @@ public class DefaultHttpProxyServer implements HttpProxyServer { private final ChainedProxyManager chainProxyManager; private final MitmManager mitmManager; private final HttpFiltersSource filtersSource; + private final FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer; private final boolean transparent; private volatile int connectTimeout; private volatile int idleConnectionTimeout; @@ -240,6 +243,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, ChainedProxyManager chainProxyManager, MitmManager mitmManager, HttpFiltersSource filtersSource, + FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, int idleConnectionTimeout, Collection activityTrackers, @@ -262,6 +266,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, this.chainProxyManager = chainProxyManager; this.mitmManager = mitmManager; this.filtersSource = filtersSource; + this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; this.idleConnectionTimeout = idleConnectionTimeout; if (activityTrackers != null) { @@ -396,6 +401,7 @@ public HttpProxyServerBootstrap clone() { chainProxyManager, mitmManager, filtersSource, + unrecoverableFailureHttpResponseComposer, transparent, idleConnectionTimeout, activityTrackers, @@ -581,6 +587,10 @@ public HttpFiltersSource getFiltersSource() { return filtersSource; } + public FailureHttpResponseComposer getUnrecoverableFailureHttpResponseComposer() { + return unrecoverableFailureHttpResponseComposer; + } + protected Collection getActivityTrackers() { return activityTrackers; } @@ -608,6 +618,7 @@ private static class DefaultHttpProxyServerBootstrap implements HttpProxyServerB private ChainedProxyManager chainProxyManager = null; private MitmManager mitmManager = null; private HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter(); + private FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = new BadGatewayFailureHttpResponseComposer(); private boolean transparent = false; private int idleConnectionTimeout = 70; private Collection activityTrackers = new ConcurrentLinkedQueue(); @@ -638,6 +649,7 @@ private DefaultHttpProxyServerBootstrap( ChainedProxyManager chainProxyManager, MitmManager mitmManager, HttpFiltersSource filtersSource, + FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, int idleConnectionTimeout, Collection activityTrackers, int connectTimeout, HostResolver serverResolver, @@ -659,6 +671,7 @@ private DefaultHttpProxyServerBootstrap( this.chainProxyManager = chainProxyManager; this.mitmManager = mitmManager; this.filtersSource = filtersSource; + this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; this.idleConnectionTimeout = idleConnectionTimeout; if (activityTrackers != null) { @@ -797,6 +810,12 @@ public HttpProxyServerBootstrap withFiltersSource( return this; } + public HttpProxyServerBootstrap withUnrecoverableFailureHttpResponseComposer( + FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer) { + this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; + return this; + } + @Override public HttpProxyServerBootstrap withUseDnsSec(boolean useDnsSec) { if (useDnsSec) { @@ -900,7 +919,7 @@ private DefaultHttpProxyServer build() { transportProtocol, determineListenAddress(), sslEngineSource, authenticateSslClients, proxyAuthenticator, chainProxyManager, mitmManager, - filtersSource, transparent, + filtersSource, unrecoverableFailureHttpResponseComposer, transparent, idleConnectionTimeout, activityTrackers, connectTimeout, serverResolver, readThrottleBytesPerSecond, writeThrottleBytesPerSecond, localAddress, proxyAlias, maxInitialLineLength, maxHeaderSize, maxChunkSize, diff --git a/src/test/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposerTest.java b/src/test/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposerTest.java new file mode 100644 index 000000000..8a7333e0c --- /dev/null +++ b/src/test/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposerTest.java @@ -0,0 +1,74 @@ +package org.littleshoot.proxy; + +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import org.junit.Test; + +import java.io.IOException; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +public class BadGatewayFailureHttpResponseComposerTest { + + private static final String REQUEST_URI = "https://localhost/hi"; + + @Test + public void testDefault() throws IOException { + FailureHttpResponseComposer badGatewayResponseComposer = new BadGatewayFailureHttpResponseComposer(); + + HttpRequest initialRequest = mock(HttpRequest.class); + when(initialRequest.getUri()).thenReturn(REQUEST_URI); + + FullHttpResponse response = badGatewayResponseComposer.compose(initialRequest, new RuntimeException()); + + assertEquals(502, response.getStatus().code()); + assertEquals("Bad Gateway", response.getStatus().reasonPhrase()); + assertEquals("Bad Gateway: " + REQUEST_URI, new String(response.content().array())); + } + + @Test + public void testCustomMessage() throws IOException { + FailureHttpResponseComposer badGatewayResponseComposer = new BadGatewayFailureHttpResponseComposer() { + @Override + protected String provideCustomMessage(HttpRequest httpRequest, Throwable cause) { + return "Invalid certificate: " + httpRequest.getUri(); + } + }; + + HttpRequest initialRequest = mock(HttpRequest.class); + when(initialRequest.getUri()).thenReturn(REQUEST_URI); + + FullHttpResponse response = badGatewayResponseComposer.compose(initialRequest, new RuntimeException()); + + assertEquals(502, response.getStatus().code()); + assertEquals("Bad Gateway", response.getStatus().reasonPhrase()); + assertEquals("Invalid certificate: " + REQUEST_URI, new String(response.content().array())); + } + + @Test + public void testClearedContent() throws IOException { + FailureHttpResponseComposer badGatewayResponseComposer = new BadGatewayFailureHttpResponseComposer(); + + HttpRequest initialRequest = mock(HttpRequest.class); + when(initialRequest.getUri()).thenReturn(REQUEST_URI); + + FullHttpResponse response = badGatewayResponseComposer.compose(initialRequest, new RuntimeException()); + + assertEquals(502, response.getStatus().code()); + + assertEquals(0, response.content().readerIndex()); + assertNotEquals(0, response.content().writerIndex()); + + when(initialRequest.getMethod()).thenReturn(HttpMethod.HEAD); + + response = badGatewayResponseComposer.compose(initialRequest, new RuntimeException()); + + assertEquals(502, response.getStatus().code()); + + assertEquals(0, response.content().readerIndex()); + assertEquals(0, response.content().writerIndex()); + } + +} \ No newline at end of file diff --git a/src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java b/src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java new file mode 100644 index 000000000..eb370fc51 --- /dev/null +++ b/src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java @@ -0,0 +1,38 @@ +package org.littleshoot.proxy.impl; + +import io.netty.handler.codec.http.FullHttpResponse; +import io.netty.handler.codec.http.HttpRequest; +import org.junit.Test; +import org.littleshoot.proxy.BadGatewayFailureHttpResponseComposer; +import org.littleshoot.proxy.FailureHttpResponseComposer; + +import static org.junit.Assert.assertTrue; + +public class DefaultHttpProxyServerTest { + + @Test + public void testDefaultUnrecoverableFailureHttpResponseComposer() { + DefaultHttpProxyServer httpProxyServer = (DefaultHttpProxyServer) DefaultHttpProxyServer.bootstrap().start(); + assertTrue(httpProxyServer.getUnrecoverableFailureHttpResponseComposer() instanceof BadGatewayFailureHttpResponseComposer); + httpProxyServer.stop(); + } + + @Test + public void testCustomUnrecoverableFailureHttpResponseComposer() { + + class CustomUnrecoverableFailureHttpResponseComposer implements FailureHttpResponseComposer { + @Override + public FullHttpResponse compose(HttpRequest httpRequest, Throwable cause) { + return null; + } + } + + DefaultHttpProxyServer httpProxyServer = (DefaultHttpProxyServer) DefaultHttpProxyServer + .bootstrap() + .withUnrecoverableFailureHttpResponseComposer(new CustomUnrecoverableFailureHttpResponseComposer()) + .start(); + assertTrue(httpProxyServer.getUnrecoverableFailureHttpResponseComposer() instanceof CustomUnrecoverableFailureHttpResponseComposer); + httpProxyServer.stop(); + } + +} \ No newline at end of file From 36d654b16a826279e06c3018ae1f2c4d7127a861 Mon Sep 17 00:00:00 2001 From: Igor Dmitriev Date: Thu, 1 Jun 2017 22:23:05 +0300 Subject: [PATCH 08/21] Fix - NPE in ClientToProxyConnection while closing the client connection (#13) --- .../org/littleshoot/proxy/impl/ClientToProxyConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java index 8bf49b107..f5e6a908b 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java @@ -871,7 +871,7 @@ private boolean shouldCloseClientConnection(HttpRequest req, } } - if (!HttpHeaders.isKeepAlive(req)) { + if (req != null && !HttpHeaders.isKeepAlive(req)) { LOG.debug("Closing client connection since request is not keep alive: {}", req); // Here we simply want to close the connection because the // client itself has requested it be closed in the request. From 800aa8ffa4221767b46bd698accbf95d9ae7a180 Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Fri, 9 Jun 2017 00:20:15 +0300 Subject: [PATCH 09/21] Mitm manager factory (#15) * Introduces mitm manager factory which can create a defferent mitm manager based on attributes from channel * Extracted self figned mitm manager factory * Import cleanup * Refactors (rename) mitmManager --- pom.xml | 2 +- .../proxy/HttpProxyServerBootstrap.java | 4 +-- .../java/org/littleshoot/proxy/Launcher.java | 4 +-- .../littleshoot/proxy/MitmManagerFactory.java | 14 ++++++++ .../extras/SelfSignedMitmManagerFactory.java | 15 ++++++++ .../proxy/impl/DefaultHttpProxyServer.java | 34 +++++++++++-------- .../proxy/impl/ProxyToServerConnection.java | 10 +++--- ...ernamePasswordAuthenticatingProxyTest.java | 4 +-- .../org/littleshoot/proxy/MitmProxyTest.java | 5 ++- .../proxy/MitmWithChainedProxyTest.java | 5 ++- 10 files changed, 64 insertions(+), 33 deletions(-) create mode 100644 src/main/java/org/littleshoot/proxy/MitmManagerFactory.java create mode 100644 src/main/java/org/littleshoot/proxy/extras/SelfSignedMitmManagerFactory.java diff --git a/pom.xml b/pom.xml index 52691c1c9..e895f4e6c 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.3.1-VGS-SNAPSHOT + 1.1.3.2-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. diff --git a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java index 3993d420d..118205a5e 100644 --- a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java +++ b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java @@ -102,7 +102,7 @@ HttpProxyServerBootstrap withTransportProtocol( *

* *

- * Note - This and {@link #withManInTheMiddle(MitmManager)} are + * Note - This and {@link #withManInTheMiddle(MitmManagerFactory)} are * mutually exclusive. *

* @@ -179,7 +179,7 @@ HttpProxyServerBootstrap withChainProxyManager( * @return */ HttpProxyServerBootstrap withManInTheMiddle( - MitmManager mitmManager); + MitmManagerFactory mitmManager); /** *

diff --git a/src/main/java/org/littleshoot/proxy/Launcher.java b/src/main/java/org/littleshoot/proxy/Launcher.java index f9b654a0e..79a558689 100755 --- a/src/main/java/org/littleshoot/proxy/Launcher.java +++ b/src/main/java/org/littleshoot/proxy/Launcher.java @@ -9,7 +9,7 @@ import org.apache.commons.cli.UnrecognizedOptionException; import org.apache.commons.lang3.StringUtils; import org.apache.log4j.xml.DOMConfigurator; -import org.littleshoot.proxy.extras.SelfSignedMitmManager; +import org.littleshoot.proxy.extras.SelfSignedMitmManagerFactory; import org.littleshoot.proxy.impl.DefaultHttpProxyServer; import org.littleshoot.proxy.impl.ProxyUtils; import org.slf4j.Logger; @@ -100,7 +100,7 @@ public static void main(final String... args) { if (cmd.hasOption(OPTION_MITM)) { LOG.info("Running as Man in the Middle"); - bootstrap.withManInTheMiddle(new SelfSignedMitmManager()); + bootstrap.withManInTheMiddle(new SelfSignedMitmManagerFactory()); } if (cmd.hasOption(OPTION_DNSSEC)) { diff --git a/src/main/java/org/littleshoot/proxy/MitmManagerFactory.java b/src/main/java/org/littleshoot/proxy/MitmManagerFactory.java new file mode 100644 index 000000000..21d0ff5e0 --- /dev/null +++ b/src/main/java/org/littleshoot/proxy/MitmManagerFactory.java @@ -0,0 +1,14 @@ +package org.littleshoot.proxy; + +import io.netty.channel.Channel; + +public interface MitmManagerFactory { + + /** + * Retrieves an instance of {@link MitmManager} based on specific attributes from cxt channel + * + * @param channel current channel from cxt + * @return concrete instance of {@link MitmManager} + */ + MitmManager getInstance(Channel channel); +} diff --git a/src/main/java/org/littleshoot/proxy/extras/SelfSignedMitmManagerFactory.java b/src/main/java/org/littleshoot/proxy/extras/SelfSignedMitmManagerFactory.java new file mode 100644 index 000000000..02a651596 --- /dev/null +++ b/src/main/java/org/littleshoot/proxy/extras/SelfSignedMitmManagerFactory.java @@ -0,0 +1,15 @@ +package org.littleshoot.proxy.extras; + +import io.netty.channel.Channel; +import org.littleshoot.proxy.MitmManager; +import org.littleshoot.proxy.MitmManagerFactory; + +/** + * The factory for self signed mitm manager + */ +public class SelfSignedMitmManagerFactory implements MitmManagerFactory { + @Override + public MitmManager getInstance(Channel channel) { + return new SelfSignedMitmManager(); + } +} diff --git a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java index 72d3c4a26..64bb78cbe 100644 --- a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java +++ b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java @@ -29,6 +29,7 @@ import org.littleshoot.proxy.HttpProxyServerBootstrap; import org.littleshoot.proxy.FailureHttpResponseComposer; import org.littleshoot.proxy.MitmManager; +import org.littleshoot.proxy.MitmManagerFactory; import org.littleshoot.proxy.ProxyAuthenticator; import org.littleshoot.proxy.SslEngineSource; import org.littleshoot.proxy.TransportProtocol; @@ -108,7 +109,7 @@ public class DefaultHttpProxyServer implements HttpProxyServer { private final boolean authenticateSslClients; private final ProxyAuthenticator proxyAuthenticator; private final ChainedProxyManager chainProxyManager; - private final MitmManager mitmManager; + private final MitmManagerFactory mitmManagerFactory; private final HttpFiltersSource filtersSource; private final FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer; private final boolean transparent; @@ -205,7 +206,7 @@ public static HttpProxyServerBootstrap bootstrapFromFile(String path) { * @param chainProxyManager * The proxy to send requests to if chaining proxies. Typically * null. - * @param mitmManager + * @param mitmManagerFactory * The {@link MitmManager} to use for man in the middle'ing * CONNECT requests * @param filtersSource @@ -241,7 +242,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, boolean authenticateSslClients, ProxyAuthenticator proxyAuthenticator, ChainedProxyManager chainProxyManager, - MitmManager mitmManager, + MitmManagerFactory mitmManagerFactory, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, @@ -264,7 +265,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, this.authenticateSslClients = authenticateSslClients; this.proxyAuthenticator = proxyAuthenticator; this.chainProxyManager = chainProxyManager; - this.mitmManager = mitmManager; + this.mitmManagerFactory = mitmManagerFactory; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; @@ -399,7 +400,7 @@ public HttpProxyServerBootstrap clone() { authenticateSslClients, proxyAuthenticator, chainProxyManager, - mitmManager, + mitmManagerFactory, filtersSource, unrecoverableFailureHttpResponseComposer, transparent, @@ -571,8 +572,11 @@ protected ChainedProxyManager getChainProxyManager() { return chainProxyManager; } - protected MitmManager getMitmManager() { - return mitmManager; + protected MitmManager getMitmManager(Channel channel) { + if (mitmManagerFactory != null) { + return mitmManagerFactory.getInstance(channel); + } + return null; } protected SslEngineSource getSslEngineSource() { @@ -616,7 +620,7 @@ private static class DefaultHttpProxyServerBootstrap implements HttpProxyServerB private boolean authenticateSslClients = true; private ProxyAuthenticator proxyAuthenticator = null; private ChainedProxyManager chainProxyManager = null; - private MitmManager mitmManager = null; + private MitmManagerFactory mitmManagerFactory = null; private HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter(); private FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = new BadGatewayFailureHttpResponseComposer(); private boolean transparent = false; @@ -647,7 +651,7 @@ private DefaultHttpProxyServerBootstrap( boolean authenticateSslClients, ProxyAuthenticator proxyAuthenticator, ChainedProxyManager chainProxyManager, - MitmManager mitmManager, + MitmManagerFactory mitmManagerFactory, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, int idleConnectionTimeout, @@ -669,7 +673,7 @@ private DefaultHttpProxyServerBootstrap( this.authenticateSslClients = authenticateSslClients; this.proxyAuthenticator = proxyAuthenticator; this.chainProxyManager = chainProxyManager; - this.mitmManager = mitmManager; + this.mitmManagerFactory = mitmManagerFactory; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; @@ -762,10 +766,10 @@ public HttpProxyServerBootstrap withListenOnAllAddresses(boolean listenOnAllAddr public HttpProxyServerBootstrap withSslEngineSource( SslEngineSource sslEngineSource) { this.sslEngineSource = sslEngineSource; - if (this.mitmManager != null) { + if (this.mitmManagerFactory != null) { LOG.warn("Enabled encrypted inbound connections with man in the middle. " + "These are mutually exclusive - man in the middle will be disabled."); - this.mitmManager = null; + this.mitmManagerFactory = null; } return this; } @@ -793,8 +797,8 @@ public HttpProxyServerBootstrap withChainProxyManager( @Override public HttpProxyServerBootstrap withManInTheMiddle( - MitmManager mitmManager) { - this.mitmManager = mitmManager; + MitmManagerFactory mitmManagerFactory) { + this.mitmManagerFactory = mitmManagerFactory; if (this.sslEngineSource != null) { LOG.warn("Enabled man in the middle with encrypted inbound connections. " + "These are mutually exclusive - encrypted inbound connections will be disabled."); @@ -918,7 +922,7 @@ private DefaultHttpProxyServer build() { return new DefaultHttpProxyServer(serverGroup, transportProtocol, determineListenAddress(), sslEngineSource, authenticateSslClients, - proxyAuthenticator, chainProxyManager, mitmManager, + proxyAuthenticator, chainProxyManager, mitmManagerFactory, filtersSource, unrecoverableFailureHttpResponseComposer, transparent, idleConnectionTimeout, activityTrackers, connectTimeout, serverResolver, readThrottleBytesPerSecond, writeThrottleBytesPerSecond, diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index 2c9cece42..bb5e09d5e 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -556,7 +556,7 @@ private void initializeConnectionFlow() { serverConnection.HTTPCONNECTWithChainedProxy); } - MitmManager mitmManager = proxyServer.getMitmManager(); + MitmManager mitmManager = proxyServer.getMitmManager(clientConnection.channel); boolean isMitmEnabled = mitmManager != null; if (isMitmEnabled) { @@ -568,10 +568,10 @@ private void initializeConnectionFlow() { // SNI may be disabled for this request due to a previous failed attempt to connect to the server // with SNI enabled. if (disableSni) { - connectionFlow.then(serverConnection.EncryptChannel(proxyServer.getMitmManager() + connectionFlow.then(serverConnection.EncryptChannel(proxyServer.getMitmManager(clientConnection.channel) .serverSslEngine())); } else { - connectionFlow.then(serverConnection.EncryptChannel(proxyServer.getMitmManager() + connectionFlow.then(serverConnection.EncryptChannel(proxyServer.getMitmManager(clientConnection.channel) .serverSslEngine(parsedHostAndPort.getHostText(), parsedHostAndPort.getPort()))); } @@ -643,7 +643,7 @@ protected void initChannel(Channel ch) throws Exception { protected Future execute() { LOG.debug("Handling CONNECT request through Chained Proxy"); chainedProxy.filterRequest(initialRequest); - MitmManager mitmManager = proxyServer.getMitmManager(); + MitmManager mitmManager = proxyServer.getMitmManager(clientConnection.channel); boolean isMitmEnabled = mitmManager != null; /* * We ignore the LastHttpContent which we read from the client @@ -720,7 +720,7 @@ boolean shouldSuppressInitialRequest() { @Override protected Future execute() { return clientConnection - .encrypt(proxyServer.getMitmManager() + .encrypt(proxyServer.getMitmManager(clientConnection.channel) .clientSslEngineFor(initialRequest, sslEngine.getSession()), false) .addListener( new GenericFutureListener>() { diff --git a/src/test/java/org/littleshoot/proxy/MITMUsernamePasswordAuthenticatingProxyTest.java b/src/test/java/org/littleshoot/proxy/MITMUsernamePasswordAuthenticatingProxyTest.java index 48369cdd0..3de5877b8 100644 --- a/src/test/java/org/littleshoot/proxy/MITMUsernamePasswordAuthenticatingProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MITMUsernamePasswordAuthenticatingProxyTest.java @@ -1,6 +1,6 @@ package org.littleshoot.proxy; -import org.littleshoot.proxy.extras.SelfSignedMitmManager; +import org.littleshoot.proxy.extras.SelfSignedMitmManagerFactory; /** * Tests a single proxy that requires username/password authentication and that @@ -14,7 +14,7 @@ protected void setUp() { this.proxyServer = bootstrapProxy() .withPort(0) .withProxyAuthenticator(this) - .withManInTheMiddle(new SelfSignedMitmManager()) + .withManInTheMiddle(new SelfSignedMitmManagerFactory()) .start(); } diff --git a/src/test/java/org/littleshoot/proxy/MitmProxyTest.java b/src/test/java/org/littleshoot/proxy/MitmProxyTest.java index 7b2853a19..2a2dda413 100644 --- a/src/test/java/org/littleshoot/proxy/MitmProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MitmProxyTest.java @@ -5,11 +5,10 @@ import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; -import org.littleshoot.proxy.extras.SelfSignedMitmManager; +import org.littleshoot.proxy.extras.SelfSignedMitmManagerFactory; import java.nio.charset.Charset; import java.util.HashSet; -import java.util.Queue; import java.util.Set; import static org.hamcrest.Matchers.hasItem; @@ -31,7 +30,7 @@ public class MitmProxyTest extends BaseProxyTest { protected void setUp() { this.proxyServer = bootstrapProxy() .withPort(0) - .withManInTheMiddle(new SelfSignedMitmManager()) + .withManInTheMiddle(new SelfSignedMitmManagerFactory()) .withFiltersSource(new HttpFiltersSourceAdapter() { @Override public HttpFilters filterRequest(HttpRequest originalRequest) { diff --git a/src/test/java/org/littleshoot/proxy/MitmWithChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/MitmWithChainedProxyTest.java index a29873eb6..07025de2d 100644 --- a/src/test/java/org/littleshoot/proxy/MitmWithChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MitmWithChainedProxyTest.java @@ -8,13 +8,12 @@ import java.util.HashSet; import java.util.Set; -import org.littleshoot.proxy.extras.SelfSignedMitmManager; - import io.netty.handler.codec.http.HttpContent; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpObject; import io.netty.handler.codec.http.HttpRequest; import io.netty.handler.codec.http.HttpResponse; +import org.littleshoot.proxy.extras.SelfSignedMitmManagerFactory; /** * Tests a proxy that runs as a MITM and which is chained with @@ -40,7 +39,7 @@ protected void setUp() { .withPort(0) .withChainProxyManager(chainedProxyManager()) .plusActivityTracker(DOWNSTREAM_TRACKER) - .withManInTheMiddle(new SelfSignedMitmManager()) + .withManInTheMiddle(new SelfSignedMitmManagerFactory()) .withFiltersSource(new HttpFiltersSourceAdapter() { @Override public HttpFilters filterRequest(HttpRequest originalRequest) { From ee36707b1449355839f16d441489c6852de850cd Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Wed, 21 Jun 2017 20:32:32 +0300 Subject: [PATCH 10/21] Custom Error Handler (#18) * Implements custom proxy to server error handler * Adds unit test * Adds client to proxy exception handler * Fixes java docs * Fixes after code review --- pom.xml | 2 +- .../littleshoot/proxy/ExceptionHandler.java | 11 ++++ .../proxy/HttpProxyServerBootstrap.java | 30 +++++++++++ .../proxy/impl/ClientToProxyConnection.java | 9 +++- .../proxy/impl/DefaultHttpProxyServer.java | 38 ++++++++++++++ .../proxy/impl/ProxyToServerConnection.java | 9 +++- .../CustomClientToProxyExHandlerTest.java | 51 +++++++++++++++++++ .../CustomProxyToServerExHandlerTest.java | 44 ++++++++++++++++ 8 files changed, 191 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/littleshoot/proxy/ExceptionHandler.java create mode 100644 src/test/java/org/littleshoot/proxy/CustomClientToProxyExHandlerTest.java create mode 100644 src/test/java/org/littleshoot/proxy/CustomProxyToServerExHandlerTest.java diff --git a/pom.xml b/pom.xml index e895f4e6c..69eb55325 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.3.2-VGS-SNAPSHOT + 1.1.3.3-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. diff --git a/src/main/java/org/littleshoot/proxy/ExceptionHandler.java b/src/main/java/org/littleshoot/proxy/ExceptionHandler.java new file mode 100644 index 000000000..41fc38bdd --- /dev/null +++ b/src/main/java/org/littleshoot/proxy/ExceptionHandler.java @@ -0,0 +1,11 @@ +package org.littleshoot.proxy; + +public interface ExceptionHandler { + + /** + * Handles proxy exceptions + * + * @param cause error cause + */ + void handle(Throwable cause); +} diff --git a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java index 118205a5e..7eb838673 100644 --- a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java +++ b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java @@ -181,6 +181,36 @@ HttpProxyServerBootstrap withChainProxyManager( HttpProxyServerBootstrap withManInTheMiddle( MitmManagerFactory mitmManager); + /** + *

+ * Specify an {@link ExceptionHandler} to handle client to proxy errors + *

+ * + *

+ * Default = null + *

+ * + * @param clientToProxyExHandler + * @return exception handler + */ + HttpProxyServerBootstrap withClientToProxyExHandler( + ExceptionHandler clientToProxyExHandler); + + /** + *

+ * Specify an {@link ExceptionHandler} to handle proxy to server errors + *

+ * + *

+ * Default = null + *

+ * + * @param proxyToServerExHandler + * @return exception handler + */ + HttpProxyServerBootstrap withProxyToServerExHandler( + ExceptionHandler proxyToServerExHandler); + /** *

* Specify a {@link HttpFiltersSource} to use for filtering requests and/or diff --git a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java index f5e6a908b..afef50a11 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java @@ -26,6 +26,7 @@ import org.apache.commons.lang3.StringUtils; import org.littleshoot.proxy.ActivityTracker; import org.littleshoot.proxy.BadGatewayFailureHttpResponseComposer; +import org.littleshoot.proxy.ExceptionHandler; import org.littleshoot.proxy.FailureHttpResponseComposer; import org.littleshoot.proxy.FlowContext; import org.littleshoot.proxy.FullFlowContext; @@ -755,7 +756,13 @@ protected void exceptionCaught(Throwable cause) { LOG.info("An executor rejected a read or write operation on the ClientToProxyConnection (this is normal if the proxy is shutting down). Message: " + cause.getMessage()); LOG.debug("A RejectedExecutionException occurred on ClientToProxyConnection", cause); } else { - LOG.error("Caught an exception on ClientToProxyConnection", cause); + ExceptionHandler exHandler = proxyServer.getClientToProxyExHandler(); + if (exHandler != null) { + LOG.debug("Custom exception handler '" + exHandler.toString() + "' invoked", cause); + exHandler.handle(cause); + } else { + LOG.error("Caught an exception on ClientToProxyConnection", cause); + } } } finally { // always disconnect the client when an exception occurs on the channel diff --git a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java index 64bb78cbe..91a2b710e 100644 --- a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java +++ b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java @@ -31,6 +31,7 @@ import org.littleshoot.proxy.MitmManager; import org.littleshoot.proxy.MitmManagerFactory; import org.littleshoot.proxy.ProxyAuthenticator; +import org.littleshoot.proxy.ExceptionHandler; import org.littleshoot.proxy.SslEngineSource; import org.littleshoot.proxy.TransportProtocol; import org.littleshoot.proxy.UnknownTransportProtocolException; @@ -110,6 +111,8 @@ public class DefaultHttpProxyServer implements HttpProxyServer { private final ProxyAuthenticator proxyAuthenticator; private final ChainedProxyManager chainProxyManager; private final MitmManagerFactory mitmManagerFactory; + private final ExceptionHandler clientToProxyExHandler; + private final ExceptionHandler proxyToServerExHandler; private final HttpFiltersSource filtersSource; private final FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer; private final boolean transparent; @@ -243,6 +246,8 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, ProxyAuthenticator proxyAuthenticator, ChainedProxyManager chainProxyManager, MitmManagerFactory mitmManagerFactory, + ExceptionHandler clientToProxyExHandler, + ExceptionHandler proxyToServerExHandler, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, @@ -266,6 +271,8 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, this.proxyAuthenticator = proxyAuthenticator; this.chainProxyManager = chainProxyManager; this.mitmManagerFactory = mitmManagerFactory; + this.clientToProxyExHandler = clientToProxyExHandler; + this.proxyToServerExHandler = proxyToServerExHandler; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; @@ -401,6 +408,8 @@ public HttpProxyServerBootstrap clone() { proxyAuthenticator, chainProxyManager, mitmManagerFactory, + clientToProxyExHandler, + proxyToServerExHandler, filtersSource, unrecoverableFailureHttpResponseComposer, transparent, @@ -579,6 +588,14 @@ protected MitmManager getMitmManager(Channel channel) { return null; } + protected ExceptionHandler getClientToProxyExHandler() { + return clientToProxyExHandler; + } + + protected ExceptionHandler getProxyToServerExHandler() { + return proxyToServerExHandler; + } + protected SslEngineSource getSslEngineSource() { return sslEngineSource; } @@ -621,6 +638,8 @@ private static class DefaultHttpProxyServerBootstrap implements HttpProxyServerB private ProxyAuthenticator proxyAuthenticator = null; private ChainedProxyManager chainProxyManager = null; private MitmManagerFactory mitmManagerFactory = null; + private ExceptionHandler clientToProxyExHandler = null; + private ExceptionHandler proxyToServerExHandler = null; private HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter(); private FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = new BadGatewayFailureHttpResponseComposer(); private boolean transparent = false; @@ -652,6 +671,8 @@ private DefaultHttpProxyServerBootstrap( ProxyAuthenticator proxyAuthenticator, ChainedProxyManager chainProxyManager, MitmManagerFactory mitmManagerFactory, + ExceptionHandler clientToProxyExHandler, + ExceptionHandler proxyToServerExHandler, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, int idleConnectionTimeout, @@ -674,6 +695,8 @@ private DefaultHttpProxyServerBootstrap( this.proxyAuthenticator = proxyAuthenticator; this.chainProxyManager = chainProxyManager; this.mitmManagerFactory = mitmManagerFactory; + this.clientToProxyExHandler = clientToProxyExHandler; + this.proxyToServerExHandler = proxyToServerExHandler; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; @@ -807,6 +830,20 @@ public HttpProxyServerBootstrap withManInTheMiddle( return this; } + @Override + public HttpProxyServerBootstrap withProxyToServerExHandler( + ExceptionHandler proxyToServerExHandler) { + this.proxyToServerExHandler = proxyToServerExHandler; + return this; + } + + @Override + public HttpProxyServerBootstrap withClientToProxyExHandler( + ExceptionHandler clientToProxyExHandler) { + this.clientToProxyExHandler = clientToProxyExHandler; + return this; + } + @Override public HttpProxyServerBootstrap withFiltersSource( HttpFiltersSource filtersSource) { @@ -923,6 +960,7 @@ private DefaultHttpProxyServer build() { transportProtocol, determineListenAddress(), sslEngineSource, authenticateSslClients, proxyAuthenticator, chainProxyManager, mitmManagerFactory, + clientToProxyExHandler, proxyToServerExHandler, filtersSource, unrecoverableFailureHttpResponseComposer, transparent, idleConnectionTimeout, activityTrackers, connectTimeout, serverResolver, readThrottleBytesPerSecond, writeThrottleBytesPerSecond, diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index bb5e09d5e..3bd22224a 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -39,6 +39,7 @@ import org.littleshoot.proxy.FullFlowContext; import org.littleshoot.proxy.HttpFilters; import org.littleshoot.proxy.MitmManager; +import org.littleshoot.proxy.ExceptionHandler; import org.littleshoot.proxy.TransportProtocol; import org.littleshoot.proxy.UnknownTransportProtocolException; @@ -439,7 +440,13 @@ protected void exceptionCaught(Throwable cause) { LOG.info("An executor rejected a read or write operation on the ProxyToServerConnection (this is normal if the proxy is shutting down). Message: " + cause.getMessage()); LOG.debug("A RejectedExecutionException occurred on ProxyToServerConnection", cause); } else { - LOG.error("Caught an exception on ProxyToServerConnection", cause); + ExceptionHandler exHandler = proxyServer.getProxyToServerExHandler(); + if (exHandler != null) { + LOG.debug("Custom exception handler '" + exHandler.toString() + "' invoked", cause); + exHandler.handle(cause); + } else { + LOG.error("Caught an exception on ProxyToServerConnection", cause); + } } } finally { if (!is(DISCONNECTED)) { diff --git a/src/test/java/org/littleshoot/proxy/CustomClientToProxyExHandlerTest.java b/src/test/java/org/littleshoot/proxy/CustomClientToProxyExHandlerTest.java new file mode 100644 index 000000000..3f07896b8 --- /dev/null +++ b/src/test/java/org/littleshoot/proxy/CustomClientToProxyExHandlerTest.java @@ -0,0 +1,51 @@ +package org.littleshoot.proxy; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.http.HttpRequest; +import org.apache.http.NoHttpResponseException; +import org.junit.Assert; +import org.junit.Test; +import org.littleshoot.proxy.extras.SelfSignedMitmManagerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class CustomClientToProxyExHandlerTest extends AbstractProxyTest { + + private final List customExHandlerEntered = new ArrayList<>(); + + private static final String EXCEPTION_MESSAGE = "Error occurred in client to proxy connection"; + + @Override + protected void setUp() { + this.proxyServer = bootstrapProxy() + .withPort(0) + .withManInTheMiddle(new SelfSignedMitmManagerFactory()) + .withClientToProxyExHandler(new ExceptionHandler() { + @Override + public void handle(Throwable cause) { + customExHandlerEntered.add(cause); + } + }) + .withFiltersSource(new HttpFiltersSourceAdapter() { + @Override + public HttpFilters filterRequest(HttpRequest originalRequest, + ChannelHandlerContext ctx) { + throw new RuntimeException(EXCEPTION_MESSAGE); + } + }) + .start(); + } + + @Test + public void testCustomClientToProxyExHandler() throws Exception { + try { + httpGetWithApacheClient(webHost, DEFAULT_RESOURCE, true, true); + } catch (NoHttpResponseException e) { + // expected + } + Assert.assertFalse("Custom ex handler was not called", customExHandlerEntered.isEmpty()); + Assert.assertEquals("Incorrect exception was passed to custom ex handles", + customExHandlerEntered.get(0).getMessage(), EXCEPTION_MESSAGE); + } +} diff --git a/src/test/java/org/littleshoot/proxy/CustomProxyToServerExHandlerTest.java b/src/test/java/org/littleshoot/proxy/CustomProxyToServerExHandlerTest.java new file mode 100644 index 000000000..0a791acda --- /dev/null +++ b/src/test/java/org/littleshoot/proxy/CustomProxyToServerExHandlerTest.java @@ -0,0 +1,44 @@ +package org.littleshoot.proxy; + +import org.junit.Assert; +import org.junit.Test; +import org.littleshoot.proxy.extras.SelfSignedMitmManagerFactory; + +import java.util.ArrayList; +import java.util.List; + +public class CustomProxyToServerExHandlerTest extends MitmWithBadServerAuthenticationTCPChainedProxyTest { + + private final List customExHandlerEntered = new ArrayList<>(); + + @Override + protected void setUp() { + this.upstreamProxy = upstreamProxy().start(); + + this.proxyServer = bootstrapProxy() + .withPort(0) + .withChainProxyManager(chainedProxyManager()) + .plusActivityTracker(DOWNSTREAM_TRACKER) + .withManInTheMiddle(new SelfSignedMitmManagerFactory()) + .withProxyToServerExHandler(new ExceptionHandler() { + @Override + public void handle(Throwable cause) { + customExHandlerEntered.add(cause); + } + }) + .start(); + } + + @Override + protected void tearDown() throws Exception { + this.upstreamProxy.abort(); + } + + @Test + public void testCustomProxyToServerExHandler() throws Exception { + super.testSimpleGetRequestOverHTTPS(); + Assert.assertFalse("Custom ex handler was not called", customExHandlerEntered.isEmpty()); + Assert.assertEquals("Incorrect exception was passed to custom ex handles", + customExHandlerEntered.get(0).getMessage(), "javax.net.ssl.SSLHandshakeException: General SSLEngine problem"); + } +} From 26018b2f486077c68738042828615d00329db5f5 Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Wed, 21 Jun 2017 21:00:21 +0300 Subject: [PATCH 11/21] Store Remote Address in Client Channel (#17) * Adds remote address to client to proxy channel on proxy to server connection * Bumps up version * Renames remoteAddressAttrKey * Camel case remote address att key vaule --- .../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 3bd22224a..d7345b59a 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -29,6 +29,7 @@ import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.timeout.IdleStateHandler; import io.netty.handler.traffic.GlobalTrafficShapingHandler; +import io.netty.util.AttributeKey; import io.netty.util.ReferenceCounted; import io.netty.util.concurrent.Future; import io.netty.util.concurrent.GenericFutureListener; @@ -138,6 +139,8 @@ public class ProxyToServerConnection extends ProxyConnection { * Minimum size of the adaptive recv buffer when throttling is enabled. */ private static final int MINIMUM_RECV_BUFFER_SIZE_BYTES = 64; + + public static final AttributeKey REMOTE_ADDRESS_ATTR_KEY = AttributeKey.valueOf("remoteAddressAttrKey"); /** * Create a new ProxyToServerConnection. @@ -535,6 +538,8 @@ private void respondWith(HttpObject httpObject) { private void connectAndWrite(HttpRequest initialRequest) { LOG.debug("Starting new connection to: {}", remoteAddress); + this.clientConnection.channel.attr(REMOTE_ADDRESS_ATTR_KEY).set(remoteAddress); + // Remember our initial request so that we can write it after connecting this.initialRequest = initialRequest; initializeConnectionFlow(); From d39d5de8a74dad4e5225af4a51a928ab901dfe8a Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Wed, 21 Jun 2017 22:15:23 +0300 Subject: [PATCH 12/21] Custom reason phrase on unrecoverable error (#16) * Adds custom status to bad request response composer * bumps up version * Renames BadGatewayFailureHttpResponseComposer * Removes unused import --- ...> DefaultFailureHttpResponseComposer.java} | 9 +++++++-- .../proxy/HttpProxyServerBootstrap.java | 2 +- .../proxy/impl/ClientToProxyConnection.java | 4 ++-- .../proxy/impl/DefaultHttpProxyServer.java | 4 ++-- ...faultFailureHttpResponseComposerTest.java} | 20 ++++++++++++------- .../impl/DefaultHttpProxyServerTest.java | 4 ++-- 6 files changed, 27 insertions(+), 16 deletions(-) rename src/main/java/org/littleshoot/proxy/{BadGatewayFailureHttpResponseComposer.java => DefaultFailureHttpResponseComposer.java} (81%) rename src/test/java/org/littleshoot/proxy/{BadGatewayFailureHttpResponseComposerTest.java => DefaultFailureHttpResponseComposerTest.java} (78%) diff --git a/src/main/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposer.java b/src/main/java/org/littleshoot/proxy/DefaultFailureHttpResponseComposer.java similarity index 81% rename from src/main/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposer.java rename to src/main/java/org/littleshoot/proxy/DefaultFailureHttpResponseComposer.java index f115332cb..15b8c2572 100644 --- a/src/main/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposer.java +++ b/src/main/java/org/littleshoot/proxy/DefaultFailureHttpResponseComposer.java @@ -6,7 +6,7 @@ import io.netty.handler.codec.http.HttpVersion; import org.littleshoot.proxy.impl.ProxyUtils; -public class BadGatewayFailureHttpResponseComposer implements FailureHttpResponseComposer { +public class DefaultFailureHttpResponseComposer implements FailureHttpResponseComposer { /** * Tells the client that something went wrong trying to proxy its request. If the Bad Gateway is a response to @@ -20,8 +20,9 @@ public class BadGatewayFailureHttpResponseComposer implements FailureHttpRespons @Override public FullHttpResponse compose(HttpRequest httpRequest, Throwable cause) { String body = provideCustomMessage(httpRequest, cause); + HttpResponseStatus status = provideCustomStatus(httpRequest, cause); - FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_GATEWAY, body); + FullHttpResponse response = ProxyUtils.createFullHttpResponse(HttpVersion.HTTP_1_1, status, body); if (ProxyUtils.isHEAD(httpRequest)) { // don't allow any body content in response to a HEAD request @@ -39,4 +40,8 @@ public FullHttpResponse compose(HttpRequest httpRequest, Throwable cause) { protected String provideCustomMessage(HttpRequest httpRequest, Throwable cause) { return "Bad Gateway: " + httpRequest.getUri(); } + + protected HttpResponseStatus provideCustomStatus(HttpRequest httpRequest, Throwable cause) { + return HttpResponseStatus.BAD_GATEWAY; + } } diff --git a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java index 7eb838673..3b5d82031 100644 --- a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java +++ b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java @@ -234,7 +234,7 @@ HttpProxyServerBootstrap withFiltersSource( *

* *

- * Default = {@link BadGatewayFailureHttpResponseComposer} + * Default = {@link DefaultFailureHttpResponseComposer} *

* * @param unrecoverableFailureHttpResponseComposer custom response message composer diff --git a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java index afef50a11..dca696d4b 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java @@ -25,7 +25,7 @@ import io.netty.util.concurrent.GenericFutureListener; import org.apache.commons.lang3.StringUtils; import org.littleshoot.proxy.ActivityTracker; -import org.littleshoot.proxy.BadGatewayFailureHttpResponseComposer; +import org.littleshoot.proxy.DefaultFailureHttpResponseComposer; import org.littleshoot.proxy.ExceptionHandler; import org.littleshoot.proxy.FailureHttpResponseComposer; import org.littleshoot.proxy.FlowContext; @@ -1215,7 +1215,7 @@ private void stripHopByHopHeaders(HttpHeaders headers) { * @return true if the connection will be kept open, or false if it will be disconnected */ private boolean writeBadGateway(HttpRequest httpRequest) { - FullHttpResponse badGatewayResponse = new BadGatewayFailureHttpResponseComposer().compose(httpRequest, null); + FullHttpResponse badGatewayResponse = new DefaultFailureHttpResponseComposer().compose(httpRequest, null); return respondWithShortCircuitResponse(badGatewayResponse); } diff --git a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java index 91a2b710e..e42457213 100644 --- a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java +++ b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java @@ -17,7 +17,7 @@ import io.netty.handler.traffic.GlobalTrafficShapingHandler; import io.netty.util.concurrent.GlobalEventExecutor; import org.littleshoot.proxy.ActivityTracker; -import org.littleshoot.proxy.BadGatewayFailureHttpResponseComposer; +import org.littleshoot.proxy.DefaultFailureHttpResponseComposer; import org.littleshoot.proxy.ChainedProxyManager; import org.littleshoot.proxy.DefaultHostResolver; import org.littleshoot.proxy.DnsSecServerResolver; @@ -641,7 +641,7 @@ private static class DefaultHttpProxyServerBootstrap implements HttpProxyServerB private ExceptionHandler clientToProxyExHandler = null; private ExceptionHandler proxyToServerExHandler = null; private HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter(); - private FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = new BadGatewayFailureHttpResponseComposer(); + private FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = new DefaultFailureHttpResponseComposer(); private boolean transparent = false; private int idleConnectionTimeout = 70; private Collection activityTrackers = new ConcurrentLinkedQueue(); diff --git a/src/test/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposerTest.java b/src/test/java/org/littleshoot/proxy/DefaultFailureHttpResponseComposerTest.java similarity index 78% rename from src/test/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposerTest.java rename to src/test/java/org/littleshoot/proxy/DefaultFailureHttpResponseComposerTest.java index 8a7333e0c..1c8466c14 100644 --- a/src/test/java/org/littleshoot/proxy/BadGatewayFailureHttpResponseComposerTest.java +++ b/src/test/java/org/littleshoot/proxy/DefaultFailureHttpResponseComposerTest.java @@ -3,6 +3,7 @@ import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpResponseStatus; import org.junit.Test; import java.io.IOException; @@ -10,13 +11,13 @@ import static org.junit.Assert.*; import static org.mockito.Mockito.*; -public class BadGatewayFailureHttpResponseComposerTest { +public class DefaultFailureHttpResponseComposerTest { private static final String REQUEST_URI = "https://localhost/hi"; @Test public void testDefault() throws IOException { - FailureHttpResponseComposer badGatewayResponseComposer = new BadGatewayFailureHttpResponseComposer(); + FailureHttpResponseComposer badGatewayResponseComposer = new DefaultFailureHttpResponseComposer(); HttpRequest initialRequest = mock(HttpRequest.class); when(initialRequest.getUri()).thenReturn(REQUEST_URI); @@ -29,12 +30,17 @@ public void testDefault() throws IOException { } @Test - public void testCustomMessage() throws IOException { - FailureHttpResponseComposer badGatewayResponseComposer = new BadGatewayFailureHttpResponseComposer() { + public void testCustomMessageAndStatus() throws IOException { + FailureHttpResponseComposer badGatewayResponseComposer = new DefaultFailureHttpResponseComposer() { @Override protected String provideCustomMessage(HttpRequest httpRequest, Throwable cause) { return "Invalid certificate: " + httpRequest.getUri(); } + + @Override + protected HttpResponseStatus provideCustomStatus(HttpRequest httpRequest, Throwable cause) { + return new HttpResponseStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR.code(), "Something is wrong"); + } }; HttpRequest initialRequest = mock(HttpRequest.class); @@ -42,14 +48,14 @@ protected String provideCustomMessage(HttpRequest httpRequest, Throwable cause) FullHttpResponse response = badGatewayResponseComposer.compose(initialRequest, new RuntimeException()); - assertEquals(502, response.getStatus().code()); - assertEquals("Bad Gateway", response.getStatus().reasonPhrase()); + assertEquals(500, response.getStatus().code()); + assertEquals("Something is wrong", response.getStatus().reasonPhrase()); assertEquals("Invalid certificate: " + REQUEST_URI, new String(response.content().array())); } @Test public void testClearedContent() throws IOException { - FailureHttpResponseComposer badGatewayResponseComposer = new BadGatewayFailureHttpResponseComposer(); + FailureHttpResponseComposer badGatewayResponseComposer = new DefaultFailureHttpResponseComposer(); HttpRequest initialRequest = mock(HttpRequest.class); when(initialRequest.getUri()).thenReturn(REQUEST_URI); diff --git a/src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java b/src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java index eb370fc51..ba3148d26 100644 --- a/src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java +++ b/src/test/java/org/littleshoot/proxy/impl/DefaultHttpProxyServerTest.java @@ -3,7 +3,7 @@ import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpRequest; import org.junit.Test; -import org.littleshoot.proxy.BadGatewayFailureHttpResponseComposer; +import org.littleshoot.proxy.DefaultFailureHttpResponseComposer; import org.littleshoot.proxy.FailureHttpResponseComposer; import static org.junit.Assert.assertTrue; @@ -13,7 +13,7 @@ public class DefaultHttpProxyServerTest { @Test public void testDefaultUnrecoverableFailureHttpResponseComposer() { DefaultHttpProxyServer httpProxyServer = (DefaultHttpProxyServer) DefaultHttpProxyServer.bootstrap().start(); - assertTrue(httpProxyServer.getUnrecoverableFailureHttpResponseComposer() instanceof BadGatewayFailureHttpResponseComposer); + assertTrue(httpProxyServer.getUnrecoverableFailureHttpResponseComposer() instanceof DefaultFailureHttpResponseComposer); httpProxyServer.stop(); } From e4384b8559f8e3001aee6053a11cd55c1eb90b22 Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Thu, 5 Oct 2017 14:43:47 +0300 Subject: [PATCH 13/21] Global state handler (#19) * Adds global state customizer * Clear global state * Use spans instead of MDC values * Fixes the code so logging context test passes * javadoc update * build fix * Clear global context in finally bloack --- pom.xml | 2 +- .../littleshoot/proxy/GlobalStateHandler.java | 35 ++++++++++++++ .../proxy/HttpProxyServerBootstrap.java | 15 ++++++ .../proxy/impl/ClientToProxyConnection.java | 21 +++++++++ .../proxy/impl/DefaultHttpProxyServer.java | 22 ++++++++- .../proxy/impl/ProxyConnection.java | 47 +++++++++++++++++++ .../proxy/impl/ProxyToServerConnection.java | 8 ++++ 7 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/main/java/org/littleshoot/proxy/GlobalStateHandler.java diff --git a/pom.xml b/pom.xml index 69eb55325..a8f4df3df 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.3.3-VGS-SNAPSHOT + 1.1.4.0-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. diff --git a/src/main/java/org/littleshoot/proxy/GlobalStateHandler.java b/src/main/java/org/littleshoot/proxy/GlobalStateHandler.java new file mode 100644 index 000000000..3c04ffd70 --- /dev/null +++ b/src/main/java/org/littleshoot/proxy/GlobalStateHandler.java @@ -0,0 +1,35 @@ +package org.littleshoot.proxy; + +import io.netty.channel.Channel; + +/** + * Netty is not designed for thread local or global state usage. + * It guarantees that a channel is handled by only one thread + * but that thread is constantly reused by other channels so + * the state can be messed up. + * + * This handler lets serialize the state to a channel so it + * can be deserialized when needed. + */ +public interface GlobalStateHandler { + + /** + * Serializes global state to channel. + * + * @param channel client connection channel + */ + void persistToChannel(Channel channel); + + /** + * Deserializes global state from channel. + * + * @param channel client connection channel + */ + void restoreFromChannel(Channel channel); + + /** + * Clears global state. + */ + void clear(); + +} diff --git a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java index 3b5d82031..94a5ec9dc 100644 --- a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java +++ b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java @@ -211,6 +211,21 @@ HttpProxyServerBootstrap withClientToProxyExHandler( HttpProxyServerBootstrap withProxyToServerExHandler( ExceptionHandler proxyToServerExHandler); + /** + *

+ * Specify an {@link GlobalStateHandler} to customize a global state based on channel attributes + *

+ * + *

+ * Default = null + *

+ * + * @param globalStateHandler + * @return proxy server bootstrap + */ + HttpProxyServerBootstrap withCustomGlobalState( + GlobalStateHandler globalStateHandler); + /** *

* Specify a {@link HttpFiltersSource} to use for filtering requests and/or diff --git a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java index dca696d4b..26161cfa2 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java @@ -4,6 +4,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; +import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; @@ -770,6 +771,17 @@ protected void exceptionCaught(Throwable cause) { } } + @Override + public void channelRegistered(ChannelHandlerContext ctx) throws Exception { + try { + if (this.proxyServer.getGlobalStateHandler() != null) { + this.proxyServer.getGlobalStateHandler().persistToChannel(ctx.channel()); + } + } finally { + super.channelRegistered(ctx); + } + } + /*************************************************************************** * Connection Management **************************************************************************/ @@ -791,6 +803,10 @@ protected void exceptionCaught(Throwable cause) { private void initChannelPipeline(ChannelPipeline pipeline) { LOG.debug("Configuring ChannelPipeline"); + if (proxyServer.getGlobalStateHandler() != null) { + pipeline.addLast("inboundGlobalStateHandler", new InboundGlobalStateHandler(this)); + } + pipeline.addLast("bytesReadMonitor", bytesReadMonitor); pipeline.addLast("bytesWrittenMonitor", bytesWrittenMonitor); @@ -817,7 +833,12 @@ private void initChannelPipeline(ChannelPipeline pipeline) { new IdleStateHandler(0, 0, proxyServer .getIdleConnectionTimeout())); + if (proxyServer.getGlobalStateHandler() != null) { + pipeline.addLast("outboundGlobalStateHandler", new OutboundGlobalStateHandler(this)); + } + pipeline.addLast("handler", this); + } /** diff --git a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java index e42457213..cc618d48d 100644 --- a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java +++ b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java @@ -17,6 +17,7 @@ import io.netty.handler.traffic.GlobalTrafficShapingHandler; import io.netty.util.concurrent.GlobalEventExecutor; import org.littleshoot.proxy.ActivityTracker; +import org.littleshoot.proxy.GlobalStateHandler; import org.littleshoot.proxy.DefaultFailureHttpResponseComposer; import org.littleshoot.proxy.ChainedProxyManager; import org.littleshoot.proxy.DefaultHostResolver; @@ -113,6 +114,7 @@ public class DefaultHttpProxyServer implements HttpProxyServer { private final MitmManagerFactory mitmManagerFactory; private final ExceptionHandler clientToProxyExHandler; private final ExceptionHandler proxyToServerExHandler; + private final GlobalStateHandler globalStateHandler; private final HttpFiltersSource filtersSource; private final FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer; private final boolean transparent; @@ -248,6 +250,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, MitmManagerFactory mitmManagerFactory, ExceptionHandler clientToProxyExHandler, ExceptionHandler proxyToServerExHandler, + GlobalStateHandler globalStateHandler, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, @@ -273,6 +276,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, this.mitmManagerFactory = mitmManagerFactory; this.clientToProxyExHandler = clientToProxyExHandler; this.proxyToServerExHandler = proxyToServerExHandler; + this.globalStateHandler = globalStateHandler; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; @@ -410,6 +414,7 @@ public HttpProxyServerBootstrap clone() { mitmManagerFactory, clientToProxyExHandler, proxyToServerExHandler, + globalStateHandler, filtersSource, unrecoverableFailureHttpResponseComposer, transparent, @@ -596,6 +601,10 @@ protected ExceptionHandler getProxyToServerExHandler() { return proxyToServerExHandler; } + protected GlobalStateHandler getGlobalStateHandler() { + return globalStateHandler; + } + protected SslEngineSource getSslEngineSource() { return sslEngineSource; } @@ -640,6 +649,7 @@ private static class DefaultHttpProxyServerBootstrap implements HttpProxyServerB private MitmManagerFactory mitmManagerFactory = null; private ExceptionHandler clientToProxyExHandler = null; private ExceptionHandler proxyToServerExHandler = null; + private GlobalStateHandler globalStateHandler = null; private HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter(); private FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = new DefaultFailureHttpResponseComposer(); private boolean transparent = false; @@ -673,6 +683,7 @@ private DefaultHttpProxyServerBootstrap( MitmManagerFactory mitmManagerFactory, ExceptionHandler clientToProxyExHandler, ExceptionHandler proxyToServerExHandler, + GlobalStateHandler globalStateHandler, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, boolean transparent, int idleConnectionTimeout, @@ -697,6 +708,7 @@ private DefaultHttpProxyServerBootstrap( this.mitmManagerFactory = mitmManagerFactory; this.clientToProxyExHandler = clientToProxyExHandler; this.proxyToServerExHandler = proxyToServerExHandler; + this.globalStateHandler = globalStateHandler; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; this.transparent = transparent; @@ -844,6 +856,14 @@ public HttpProxyServerBootstrap withClientToProxyExHandler( return this; } + @Override + public HttpProxyServerBootstrap withCustomGlobalState( + GlobalStateHandler globalStateHandler) { + this.globalStateHandler = globalStateHandler; + return this; + } + + @Override public HttpProxyServerBootstrap withFiltersSource( HttpFiltersSource filtersSource) { @@ -960,7 +980,7 @@ private DefaultHttpProxyServer build() { transportProtocol, determineListenAddress(), sslEngineSource, authenticateSslClients, proxyAuthenticator, chainProxyManager, mitmManagerFactory, - clientToProxyExHandler, proxyToServerExHandler, + clientToProxyExHandler, proxyToServerExHandler, globalStateHandler, filtersSource, unrecoverableFailureHttpResponseComposer, transparent, idleConnectionTimeout, activityTrackers, connectTimeout, serverResolver, readThrottleBytesPerSecond, writeThrottleBytesPerSecond, diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java index 58c3eb240..5c68a8d96 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java @@ -62,6 +62,7 @@ */ abstract class ProxyConnection extends SimpleChannelInboundHandler { + protected final ProxyConnectionLogger LOG = new ProxyConnectionLogger(this); protected final DefaultHttpProxyServer proxyServer; @@ -742,6 +743,52 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) protected abstract void responseRead(HttpResponse httpResponse); } + @Sharable + protected class InboundGlobalStateHandler extends + ChannelInboundHandlerAdapter { + + private final ProxyConnection clientToProxyConnection; + + InboundGlobalStateHandler(ProxyConnection clientToProxyConnection) { + this.clientToProxyConnection = clientToProxyConnection; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) + throws Exception { + try { + proxyServer.getGlobalStateHandler().restoreFromChannel(clientToProxyConnection.channel); + super.channelRead(ctx, msg); + } finally { + proxyServer.getGlobalStateHandler().clear(); + } + } + } + + @Sharable + protected class OutboundGlobalStateHandler extends + ChannelOutboundHandlerAdapter { + + private final ProxyConnection clientToProxyConnection; + + OutboundGlobalStateHandler(ProxyConnection clientToProxyConnection) { + this.clientToProxyConnection = clientToProxyConnection; + } + + @Override + public void write(ChannelHandlerContext ctx, + Object msg, ChannelPromise promise) + throws Exception { + try { + proxyServer.getGlobalStateHandler().restoreFromChannel(clientToProxyConnection.channel); + super.write(ctx, msg, promise); + } finally { + proxyServer.getGlobalStateHandler().clear(); + } + } + } + + /** * Utility handler for monitoring bytes written on this connection. */ diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index d7345b59a..c4a7ba1c3 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -881,6 +881,10 @@ private void setupConnectionParameters() throws UnknownHostException { private void initChannelPipeline(ChannelPipeline pipeline, HttpRequest httpRequest) { + if (proxyServer.getGlobalStateHandler() != null) { + pipeline.addLast("inboundGlobalStateHandler", new InboundGlobalStateHandler(clientConnection)); + } + if (trafficHandler != null) { pipeline.addLast("global-traffic-shaping", trafficHandler); } @@ -910,6 +914,10 @@ private void initChannelPipeline(ChannelPipeline pipeline, new IdleStateHandler(0, 0, proxyServer .getIdleConnectionTimeout())); + if (proxyServer.getGlobalStateHandler() != null) { + pipeline.addLast("outboundGlobalStateHandler", new OutboundGlobalStateHandler(clientConnection)); + } + pipeline.addLast("handler", this); } From d1c4cedc54d7681b20b1640bf6a8d22881281c97 Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Wed, 15 Nov 2017 00:46:57 +0200 Subject: [PATCH 14/21] SNI Support (#23) * Bump guava to version 23 * adamfisk#337 - SNI headers not being sent for outbound proxies. * Adds NULL check * Fixes repo --- pom.xml | 6 +++--- .../proxy/impl/ProxyToServerConnection.java | 16 ++++++++++------ ...dClientAuthenticationTCPChainedProxyTest.java | 5 +++++ ...dServerAuthenticationTCPChainedProxyTest.java | 5 +++++ ...hFallbackToOtherChainedProxyDueToSSLTest.java | 5 +++++ ...enticationNotRequiredTCPChainedProxyTest.java | 5 +++++ .../proxy/EncryptedTCPChainedProxyTest.java | 5 +++++ .../proxy/EncryptedUDTChainedProxyTest.java | 5 +++++ .../org/littleshoot/proxy/HttpFilterTest.java | 5 +++++ ...dClientAuthenticationTCPChainedProxyTest.java | 5 +++++ ...dServerAuthenticationTCPChainedProxyTest.java | 5 +++++ ...enticationNotRequiredTCPChainedProxyTest.java | 5 +++++ .../MitmWithEncryptedTCPChainedProxyTest.java | 5 +++++ .../MitmWithEncryptedUDTChainedProxyTest.java | 5 +++++ 14 files changed, 73 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index a8f4df3df..b25a7d883 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ jfog jfrog - https://dl.bintray.com/vg/vgs-misc + https://dl.bintray.com/vg/vgs-oss true @@ -201,7 +201,7 @@ com.google.guava guava - 20.0 + 23.0 @@ -570,7 +570,7 @@ io.vgs.tools aws-maven - 1.4.2 + 1.4.3 diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java index c4a7ba1c3..c0ea3390b 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyToServerConnection.java @@ -44,6 +44,7 @@ import org.littleshoot.proxy.TransportProtocol; import org.littleshoot.proxy.UnknownTransportProtocolException; +import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLProtocolException; import javax.net.ssl.SSLSession; import java.io.IOException; @@ -141,7 +142,7 @@ public class ProxyToServerConnection extends ProxyConnection { private static final int MINIMUM_RECV_BUFFER_SIZE_BYTES = 64; public static final AttributeKey REMOTE_ADDRESS_ATTR_KEY = AttributeKey.valueOf("remoteAddressAttrKey"); - + /** * Create a new ProxyToServerConnection. * @@ -557,8 +558,11 @@ private void initializeConnectionFlow() { .then(ConnectChannel); if (chainedProxy != null && chainedProxy.requiresEncryption()) { - connectionFlow.then(serverConnection.EncryptChannel(chainedProxy - .newSslEngine())); + InetSocketAddress proxyAddress = chainedProxy.getChainedProxyAddress(); + + SSLEngine engine = proxyAddress == null || proxyAddress.isUnresolved() ? chainedProxy.newSslEngine() : + chainedProxy.newSslEngine(proxyAddress.getHostName(), proxyAddress.getPort()); + connectionFlow.then(serverConnection.EncryptChannel(engine)); } if (ProxyUtils.isCONNECT(initialRequest)) { @@ -566,7 +570,7 @@ private void initializeConnectionFlow() { if (hasUpstreamChainedProxy()) { connectionFlow.then( serverConnection.HTTPCONNECTWithChainedProxy); - } + } MitmManager mitmManager = proxyServer.getMitmManager(clientConnection.channel); boolean isMitmEnabled = mitmManager != null; @@ -584,7 +588,7 @@ private void initializeConnectionFlow() { .serverSslEngine())); } else { connectionFlow.then(serverConnection.EncryptChannel(proxyServer.getMitmManager(clientConnection.channel) - .serverSslEngine(parsedHostAndPort.getHostText(), parsedHostAndPort.getPort()))); + .serverSslEngine(parsedHostAndPort.getHost(), parsedHostAndPort.getPort()))); } connectionFlow @@ -978,7 +982,7 @@ public static InetSocketAddress addressFor(String hostAndPort, DefaultHttpProxyS throw new UnknownHostException(hostAndPort); } - String host = parsedHostAndPort.getHostText(); + String host = parsedHostAndPort.getHost(); int port = parsedHostAndPort.getPortOrDefault(80); return proxyServer.getServerResolver().resolve(host, port); diff --git a/src/test/java/org/littleshoot/proxy/BadClientAuthenticationTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/BadClientAuthenticationTCPChainedProxyTest.java index 1ef321f95..e19aaa55b 100644 --- a/src/test/java/org/littleshoot/proxy/BadClientAuthenticationTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/BadClientAuthenticationTCPChainedProxyTest.java @@ -47,6 +47,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return clientSslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return clientSslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/BadServerAuthenticationTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/BadServerAuthenticationTCPChainedProxyTest.java index e75c87d12..12a6a324e 100644 --- a/src/test/java/org/littleshoot/proxy/BadServerAuthenticationTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/BadServerAuthenticationTCPChainedProxyTest.java @@ -47,6 +47,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return clientSslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return clientSslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/ChainedProxyWithFallbackToOtherChainedProxyDueToSSLTest.java b/src/test/java/org/littleshoot/proxy/ChainedProxyWithFallbackToOtherChainedProxyDueToSSLTest.java index c16ffa9d1..48665d968 100644 --- a/src/test/java/org/littleshoot/proxy/ChainedProxyWithFallbackToOtherChainedProxyDueToSSLTest.java +++ b/src/test/java/org/littleshoot/proxy/ChainedProxyWithFallbackToOtherChainedProxyDueToSSLTest.java @@ -41,6 +41,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return serverSslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return serverSslEngineSource.newSslEngine(peerHost, peerPort); + } }); } }; diff --git a/src/test/java/org/littleshoot/proxy/ClientAuthenticationNotRequiredTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/ClientAuthenticationNotRequiredTCPChainedProxyTest.java index 7a881311b..a05a540a1 100644 --- a/src/test/java/org/littleshoot/proxy/ClientAuthenticationNotRequiredTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/ClientAuthenticationNotRequiredTCPChainedProxyTest.java @@ -43,6 +43,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return clientSslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return clientSslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/EncryptedTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/EncryptedTCPChainedProxyTest.java index 32261035b..ea5aad723 100644 --- a/src/test/java/org/littleshoot/proxy/EncryptedTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/EncryptedTCPChainedProxyTest.java @@ -34,6 +34,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return sslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return sslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/EncryptedUDTChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/EncryptedUDTChainedProxyTest.java index b5728caca..086da00b2 100644 --- a/src/test/java/org/littleshoot/proxy/EncryptedUDTChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/EncryptedUDTChainedProxyTest.java @@ -34,6 +34,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return sslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return sslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/HttpFilterTest.java b/src/test/java/org/littleshoot/proxy/HttpFilterTest.java index 56e3a229e..ca786aa3c 100644 --- a/src/test/java/org/littleshoot/proxy/HttpFilterTest.java +++ b/src/test/java/org/littleshoot/proxy/HttpFilterTest.java @@ -633,6 +633,11 @@ public SSLEngine newSslEngine() { // use the same "bad" keystore as BadServerAuthenticationTCPChainedProxyTest return new SelfSignedSslEngineSource("chain_proxy_keystore_2.jks").newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return new SelfSignedSslEngineSource("chain_proxy_keystore_2.jks").newSslEngine(peerHost, peerPort); + } }); } }) diff --git a/src/test/java/org/littleshoot/proxy/MitmWithBadClientAuthenticationTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/MitmWithBadClientAuthenticationTCPChainedProxyTest.java index e3b724c60..8789ce553 100644 --- a/src/test/java/org/littleshoot/proxy/MitmWithBadClientAuthenticationTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MitmWithBadClientAuthenticationTCPChainedProxyTest.java @@ -48,6 +48,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return clientSslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return clientSslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/MitmWithBadServerAuthenticationTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/MitmWithBadServerAuthenticationTCPChainedProxyTest.java index bc192db8a..342af1a6f 100644 --- a/src/test/java/org/littleshoot/proxy/MitmWithBadServerAuthenticationTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MitmWithBadServerAuthenticationTCPChainedProxyTest.java @@ -48,6 +48,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return clientSslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return clientSslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/MitmWithClientAuthenticationNotRequiredTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/MitmWithClientAuthenticationNotRequiredTCPChainedProxyTest.java index f748dddb7..3a17b25fa 100644 --- a/src/test/java/org/littleshoot/proxy/MitmWithClientAuthenticationNotRequiredTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MitmWithClientAuthenticationNotRequiredTCPChainedProxyTest.java @@ -43,6 +43,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return clientSslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return clientSslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/MitmWithEncryptedTCPChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/MitmWithEncryptedTCPChainedProxyTest.java index 418e7e8d6..0625e9af6 100644 --- a/src/test/java/org/littleshoot/proxy/MitmWithEncryptedTCPChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MitmWithEncryptedTCPChainedProxyTest.java @@ -34,6 +34,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return sslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return sslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } diff --git a/src/test/java/org/littleshoot/proxy/MitmWithEncryptedUDTChainedProxyTest.java b/src/test/java/org/littleshoot/proxy/MitmWithEncryptedUDTChainedProxyTest.java index 0630149d6..4955a784e 100644 --- a/src/test/java/org/littleshoot/proxy/MitmWithEncryptedUDTChainedProxyTest.java +++ b/src/test/java/org/littleshoot/proxy/MitmWithEncryptedUDTChainedProxyTest.java @@ -34,6 +34,11 @@ public boolean requiresEncryption() { public SSLEngine newSslEngine() { return sslEngineSource.newSslEngine(); } + + @Override + public SSLEngine newSslEngine(String peerHost, int peerPort) { + return sslEngineSource.newSslEngine(peerHost, peerPort); + } }; } } From 21ac651753a2d6a1a7b698ca0c0dfc8942a593ba Mon Sep 17 00:00:00 2001 From: Slava Fomin Date: Thu, 23 Nov 2017 12:49:56 +0200 Subject: [PATCH 15/21] Separate global state handler from request tracing (#25) * Separate global state handler from request tracing * Wraps channel read into finally section * Formatting * Adds catch block to request tracer * Adds try catch to trace finish method --- pom.xml | 2 +- .../littleshoot/proxy/GlobalStateHandler.java | 7 ---- .../proxy/HttpProxyServerBootstrap.java | 15 ++++++++ .../org/littleshoot/proxy/RequestTracer.java | 18 ++++++++++ .../proxy/impl/ClientToProxyConnection.java | 16 +++------ .../proxy/impl/DefaultHttpProxyServer.java | 22 ++++++++++-- .../proxy/impl/ProxyConnection.java | 35 +++++++++++++++++++ 7 files changed, 93 insertions(+), 22 deletions(-) create mode 100644 src/main/java/org/littleshoot/proxy/RequestTracer.java diff --git a/pom.xml b/pom.xml index b25a7d883..2b1eddfe8 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.4.0-VGS-SNAPSHOT + 1.1.5.0-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. diff --git a/src/main/java/org/littleshoot/proxy/GlobalStateHandler.java b/src/main/java/org/littleshoot/proxy/GlobalStateHandler.java index 3c04ffd70..2949f1ffb 100644 --- a/src/main/java/org/littleshoot/proxy/GlobalStateHandler.java +++ b/src/main/java/org/littleshoot/proxy/GlobalStateHandler.java @@ -13,13 +13,6 @@ */ public interface GlobalStateHandler { - /** - * Serializes global state to channel. - * - * @param channel client connection channel - */ - void persistToChannel(Channel channel); - /** * Deserializes global state from channel. * diff --git a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java index 94a5ec9dc..1c064a140 100644 --- a/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java +++ b/src/main/java/org/littleshoot/proxy/HttpProxyServerBootstrap.java @@ -211,6 +211,21 @@ HttpProxyServerBootstrap withClientToProxyExHandler( HttpProxyServerBootstrap withProxyToServerExHandler( ExceptionHandler proxyToServerExHandler); + + /** + *

+ * Specify a {@link RequestTracer} to trace proxy requests + *

+ * + *

+ * Default = null + *

+ * + * @param requestTracer + * @return proxy server bootstrap + */ + HttpProxyServerBootstrap withRequestTracer(RequestTracer requestTracer); + /** *

* Specify an {@link GlobalStateHandler} to customize a global state based on channel attributes diff --git a/src/main/java/org/littleshoot/proxy/RequestTracer.java b/src/main/java/org/littleshoot/proxy/RequestTracer.java new file mode 100644 index 000000000..68505e293 --- /dev/null +++ b/src/main/java/org/littleshoot/proxy/RequestTracer.java @@ -0,0 +1,18 @@ +package org.littleshoot.proxy; + +import io.netty.channel.Channel; + +public interface RequestTracer { + + /** + * Start tracing proxy request + * @param channel + */ + void start(Channel channel); + + /** + * Request is served. Finish tracing. + * @param channel + */ + void finish(Channel channel); +} diff --git a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java index 26161cfa2..a4347e9c7 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ClientToProxyConnection.java @@ -4,7 +4,6 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; -import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.http.DefaultHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; @@ -771,17 +770,6 @@ protected void exceptionCaught(Throwable cause) { } } - @Override - public void channelRegistered(ChannelHandlerContext ctx) throws Exception { - try { - if (this.proxyServer.getGlobalStateHandler() != null) { - this.proxyServer.getGlobalStateHandler().persistToChannel(ctx.channel()); - } - } finally { - super.channelRegistered(ctx); - } - } - /*************************************************************************** * Connection Management **************************************************************************/ @@ -803,6 +791,10 @@ public void channelRegistered(ChannelHandlerContext ctx) throws Exception { private void initChannelPipeline(ChannelPipeline pipeline) { LOG.debug("Configuring ChannelPipeline"); + if (proxyServer.getRequestTracer() != null) { + pipeline.addLast("requestTracerHandler", new RequestTracerHandler(this)); + } + if (proxyServer.getGlobalStateHandler() != null) { pipeline.addLast("inboundGlobalStateHandler", new InboundGlobalStateHandler(this)); } diff --git a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java index cc618d48d..32ad0195f 100644 --- a/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java +++ b/src/main/java/org/littleshoot/proxy/impl/DefaultHttpProxyServer.java @@ -33,6 +33,7 @@ import org.littleshoot.proxy.MitmManagerFactory; import org.littleshoot.proxy.ProxyAuthenticator; import org.littleshoot.proxy.ExceptionHandler; +import org.littleshoot.proxy.RequestTracer; import org.littleshoot.proxy.SslEngineSource; import org.littleshoot.proxy.TransportProtocol; import org.littleshoot.proxy.UnknownTransportProtocolException; @@ -114,6 +115,7 @@ public class DefaultHttpProxyServer implements HttpProxyServer { private final MitmManagerFactory mitmManagerFactory; private final ExceptionHandler clientToProxyExHandler; private final ExceptionHandler proxyToServerExHandler; + private final RequestTracer requestTracer; private final GlobalStateHandler globalStateHandler; private final HttpFiltersSource filtersSource; private final FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer; @@ -250,6 +252,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, MitmManagerFactory mitmManagerFactory, ExceptionHandler clientToProxyExHandler, ExceptionHandler proxyToServerExHandler, + RequestTracer requestTracer, GlobalStateHandler globalStateHandler, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, @@ -276,6 +279,7 @@ private DefaultHttpProxyServer(ServerGroup serverGroup, this.mitmManagerFactory = mitmManagerFactory; this.clientToProxyExHandler = clientToProxyExHandler; this.proxyToServerExHandler = proxyToServerExHandler; + this.requestTracer = requestTracer; this.globalStateHandler = globalStateHandler; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; @@ -414,6 +418,7 @@ public HttpProxyServerBootstrap clone() { mitmManagerFactory, clientToProxyExHandler, proxyToServerExHandler, + requestTracer, globalStateHandler, filtersSource, unrecoverableFailureHttpResponseComposer, @@ -605,6 +610,10 @@ protected GlobalStateHandler getGlobalStateHandler() { return globalStateHandler; } + protected RequestTracer getRequestTracer() { + return requestTracer; + } + protected SslEngineSource getSslEngineSource() { return sslEngineSource; } @@ -649,6 +658,7 @@ private static class DefaultHttpProxyServerBootstrap implements HttpProxyServerB private MitmManagerFactory mitmManagerFactory = null; private ExceptionHandler clientToProxyExHandler = null; private ExceptionHandler proxyToServerExHandler = null; + private RequestTracer requestTracer = null; private GlobalStateHandler globalStateHandler = null; private HttpFiltersSource filtersSource = new HttpFiltersSourceAdapter(); private FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer = new DefaultFailureHttpResponseComposer(); @@ -683,6 +693,7 @@ private DefaultHttpProxyServerBootstrap( MitmManagerFactory mitmManagerFactory, ExceptionHandler clientToProxyExHandler, ExceptionHandler proxyToServerExHandler, + RequestTracer requestTracer, GlobalStateHandler globalStateHandler, HttpFiltersSource filtersSource, FailureHttpResponseComposer unrecoverableFailureHttpResponseComposer, @@ -708,6 +719,7 @@ private DefaultHttpProxyServerBootstrap( this.mitmManagerFactory = mitmManagerFactory; this.clientToProxyExHandler = clientToProxyExHandler; this.proxyToServerExHandler = proxyToServerExHandler; + this.requestTracer = requestTracer; this.globalStateHandler = globalStateHandler; this.filtersSource = filtersSource; this.unrecoverableFailureHttpResponseComposer = unrecoverableFailureHttpResponseComposer; @@ -856,6 +868,13 @@ public HttpProxyServerBootstrap withClientToProxyExHandler( return this; } + @Override + public HttpProxyServerBootstrap withRequestTracer( + RequestTracer requestTracer) { + this.requestTracer = requestTracer; + return this; + } + @Override public HttpProxyServerBootstrap withCustomGlobalState( GlobalStateHandler globalStateHandler) { @@ -863,7 +882,6 @@ public HttpProxyServerBootstrap withCustomGlobalState( return this; } - @Override public HttpProxyServerBootstrap withFiltersSource( HttpFiltersSource filtersSource) { @@ -980,7 +998,7 @@ private DefaultHttpProxyServer build() { transportProtocol, determineListenAddress(), sslEngineSource, authenticateSslClients, proxyAuthenticator, chainProxyManager, mitmManagerFactory, - clientToProxyExHandler, proxyToServerExHandler, globalStateHandler, + clientToProxyExHandler, proxyToServerExHandler, requestTracer, globalStateHandler, filtersSource, unrecoverableFailureHttpResponseComposer, transparent, idleConnectionTimeout, activityTrackers, connectTimeout, serverResolver, readThrottleBytesPerSecond, writeThrottleBytesPerSecond, diff --git a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java index 5c68a8d96..fc2d89b6e 100644 --- a/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java +++ b/src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java @@ -743,6 +743,41 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) protected abstract void responseRead(HttpResponse httpResponse); } + @Sharable + protected class RequestTracerHandler extends ChannelDuplexHandler { + + private final ProxyConnection clientToProxyConnection; + + RequestTracerHandler(ProxyConnection clientToProxyConnection) { + this.clientToProxyConnection = clientToProxyConnection; + } + + @Override + public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { + try { + proxyServer.getRequestTracer().start(clientToProxyConnection.channel); + } catch (Throwable t) { + LOG.warn("Unable to start tracing request", t); + } finally { + super.channelRead(ctx, msg); + } + } + + @Override + public void write(ChannelHandlerContext ctx, + Object msg, ChannelPromise promise) throws Exception { + try { + super.write(ctx, msg, promise); + } finally { + try { + proxyServer.getRequestTracer().finish(clientToProxyConnection.channel); + } catch (Throwable t) { + LOG.warn("Unable to finish request tracing", t); + } + } + } + } + @Sharable protected class InboundGlobalStateHandler extends ChannelInboundHandlerAdapter { From 5c96b457ddb2e06093792bb4ead0106e57dde2c1 Mon Sep 17 00:00:00 2001 From: Yuriy Shafranyuk Date: Tue, 2 Jan 2018 23:19:31 +0200 Subject: [PATCH 16/21] Add gitflow versioning (#35) * Versioning test jgitflow (#27) * Added jgitflow plugin * Added release section * Versioning test jgitflow (#28) * Added jgitflow plugin * Added custom version and remove ssh agent * Added maven plugin and circle code that make release (#29) * Fix gitflow plugin dependency (#30) * test code * test code * test code * deploy any branch * Added plugin to dependency management * comment code * trigger build * skip tests * skip tests * try to fix dependencies * full name of plugin * remove gitflow from report section * removed gitfloe from dependency management * added gitflow from dependency management * added gitflow to release * added gitflow configs to command * remove dependency * remove no needed commands * possible fix * fix gitflow release (#31) * test code * test code * test code * deploy any branch * comment code * trigger build * skip tests * skip tests * try to fix dependencies * full name of plugin * remove gitflow from report section * removed gitfloe from dependency management * added gitflow from dependency management * added gitflow to release * added gitflow configs to command * remove dependency * remove no needed commands * possible fix * Ignore some commands. Added configs in all gitflow declaration * release any branch * Test no needed configs * Test no needed configs * Test no needed configs * revert changes for test * Fix gitflow release (#32) * test code * test code * test code * deploy any branch * comment code * trigger build * skip tests * skip tests * try to fix dependencies * full name of plugin * remove gitflow from report section * removed gitfloe from dependency management * added gitflow from dependency management * added gitflow to release * added gitflow configs to command * remove dependency * remove no needed commands * possible fix * Ignore some commands. Added configs in all gitflow declaration * release any branch * Test no needed configs * Test no needed configs * Test no needed configs * revert changes for test * Another try to release * pull branch * revert formatting * update versions for 1.1.5.0-vgs-test release * Fix gitflow release (#33) * test code * test code * test code * deploy any branch * comment code * trigger build * skip tests * skip tests * try to fix dependencies * full name of plugin * remove gitflow from report section * removed gitfloe from dependency management * added gitflow from dependency management * added gitflow configs to command * remove dependency * remove no needed commands * possible fix * Ignore some commands. Added configs in all gitflow declaration * release any branch * Test no needed configs * Test no needed configs * Test no needed configs * revert changes for test * Another try to release * pull branch * revert formatting * change version. skip tests * Fix gitflow release (#34) * test code * test code * test code * deploy any branch * comment code * trigger build * skip tests * skip tests * try to fix dependencies * full name of plugin * remove gitflow from report section * removed gitfloe from dependency management * added gitflow from dependency management * added gitflow configs to command * remove dependency * remove no needed commands * possible fix * Ignore some commands. Added configs in all gitflow declaration * release any branch * Test no needed configs * Test no needed configs * Test no needed configs * revert changes for test * Another try to release * pull branch * revert formatting * change version. skip tests * reset uncommited * fiz * update versions for 1.1.5.0-vgs-test release * update for next development version 1.1.6.0-vgs-test-SNAPSHOT * test code * test code * test code * deploy any branch * comment code * trigger build * skip tests * skip tests * try to fix dependencies * remove gitflow from report section * removed gitfloe from dependency management * added gitflow from dependency management * added gitflow configs to command * remove dependency * remove no needed commands * possible fix * Ignore some commands. Added configs in all gitflow declaration * release any branch * Test no needed configs * Test no needed configs * Test no needed configs * revert changes for test * Another try to release * pull branch * revert formatting * change version. skip tests * fiz * revert version * change release branch * change branch name --- circle.yml | 12 +++++++++ pom.xml | 78 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 80 insertions(+), 10 deletions(-) diff --git a/circle.yml b/circle.yml index a8e11d782..246276f8e 100644 --- a/circle.yml +++ b/circle.yml @@ -4,6 +4,7 @@ machine: version: oraclejdk8 environment: AWS_PROFILE: vgs-dev + RELEASE_BRANCH: vgs-edition dependencies: override: - ./env.sh @@ -17,3 +18,14 @@ deployment: owner: verygoodsecurity commands: - mvn deploy -DskipTests=true + release: + tag: /.*/ + commands: + - git config user.name "circleci" + - git fetch + - git checkout $RELEASE_BRANCH + - git pull origin $RELEASE_BRANCH + - git reset --hard + - git tag -d $CIRCLE_TAG + - mvn -B -X -e gitflow:release-start gitflow:release-finish -DreleaseVersion=$CIRCLE_TAG -DpostReleaseGoals=deploy -DskipTests + - git push origin $RELEASE_BRANCH diff --git a/pom.xml b/pom.xml index 2b1eddfe8..c50945867 100644 --- a/pom.xml +++ b/pom.xml @@ -80,6 +80,40 @@ + + + + jcenter + jcenter + https://jcenter.bintray.com/ + + + + verygood-release-repo + Very Good Release Repository + s3://vault-dev-01-audits-01-artifact-19k6160zpr44j/software/release/ + + true + + + false + + + + + verygood-snapshot-repo + Very Good Snapshot Repository + s3://vault-dev-01-audits-01-artifact-19k6160zpr44j/software/snapshot/ + + false + + + true + + + + + 2009 @@ -99,7 +133,7 @@ [,1.8) - + @@ -175,15 +209,9 @@ - org.apache.maven.plugins - maven-release-plugin - 2.5.3 - - true - false - release - deploy - + com.amashchenko.maven.plugin + gitflow-maven-plugin + 1.8.0 @@ -480,6 +508,12 @@ maven-resources-plugin 3.0.2 + + + com.amashchenko.maven.plugin + gitflow-maven-plugin + 1.8.0 + @@ -519,6 +553,30 @@ + + com.amashchenko.maven.plugin + gitflow-maven-plugin + 1.8.0 + + true + 2 + true + false + true + true + + vgs-edition + vgs-edition + release- + + + + update versions for @{version} release + update for next development version @{version} + + + + org.apache.maven.plugins maven-shade-plugin From 6828b87f8d6b215d62f20c2a53b01e9b27dd7c86 Mon Sep 17 00:00:00 2001 From: circleci Date: Thu, 4 Jan 2018 13:44:12 +0000 Subject: [PATCH 17/21] update versions for 1.1.5.0-VGS release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c50945867..b53e0645e 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.5.0-VGS-SNAPSHOT + 1.1.5.0-VGS LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. From 7faaadb9598d319eb950f589a905d1c388251e4a Mon Sep 17 00:00:00 2001 From: Yuriy Shafranyuk Date: Fri, 5 Jan 2018 00:10:14 +0200 Subject: [PATCH 18/21] Gitflow release versioning (#36) * change to next snapshot version * split release goals * skip tests when tag set * change permission * add user email * revert version --- circle.yml | 6 ++++-- pom.xml | 2 +- scripts/run_circle_tests.sh | 6 ++++++ 3 files changed, 11 insertions(+), 3 deletions(-) create mode 100755 scripts/run_circle_tests.sh diff --git a/circle.yml b/circle.yml index 246276f8e..15e0d8fcc 100644 --- a/circle.yml +++ b/circle.yml @@ -11,7 +11,7 @@ dependencies: - mvn clean dependency:go-offline install -Dmaven.test.skip=true --fail-never --threads 5 -B test: override: - - mvn test -T2C + - ./scripts/run_circle_tests.sh deployment: snapshot: branch: vgs-edition @@ -22,10 +22,12 @@ deployment: tag: /.*/ commands: - git config user.name "circleci" + - git config user.email "circleci@vgs.com" - git fetch - git checkout $RELEASE_BRANCH - git pull origin $RELEASE_BRANCH - git reset --hard - git tag -d $CIRCLE_TAG - - mvn -B -X -e gitflow:release-start gitflow:release-finish -DreleaseVersion=$CIRCLE_TAG -DpostReleaseGoals=deploy -DskipTests + - mvn -B -X -e gitflow:release-start -DreleaseVersion=$CIRCLE_TAG + - mvn -B -X -e gitflow:release-finish -DreleaseVersion=$CIRCLE_TAG -DpostReleaseGoals='deploy -DskipTests' - git push origin $RELEASE_BRANCH diff --git a/pom.xml b/pom.xml index b53e0645e..c50945867 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.5.0-VGS + 1.1.5.0-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. diff --git a/scripts/run_circle_tests.sh b/scripts/run_circle_tests.sh new file mode 100755 index 000000000..21245dc4b --- /dev/null +++ b/scripts/run_circle_tests.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +if [ "$CIRCLE_TAG" == "" ] +then + mvn test -T2C +fi \ No newline at end of file From f5fe0a10de1ba09b6c135130fbe4ff854bb683fb Mon Sep 17 00:00:00 2001 From: circleci Date: Thu, 4 Jan 2018 22:37:01 +0000 Subject: [PATCH 19/21] update versions for 1.1.5.0-VGS release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c50945867..b53e0645e 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.5.0-VGS-SNAPSHOT + 1.1.5.0-VGS LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. From 516b1cd8735afa97ede18f8304503c76709e5f09 Mon Sep 17 00:00:00 2001 From: circleci Date: Thu, 4 Jan 2018 22:37:55 +0000 Subject: [PATCH 20/21] update for next development version 1.1.6.0-VGS-SNAPSHOT --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b53e0645e..345f49fbb 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.littleshoot littleproxy jar - 1.1.5.0-VGS + 1.1.6.0-VGS-SNAPSHOT LittleProxy LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework. From 1d94b43b43b2bebb440486200c70d000a99f4a74 Mon Sep 17 00:00:00 2001 From: Yuriy Shafranyuk Date: Wed, 10 Jan 2018 15:07:21 +0200 Subject: [PATCH 21/21] Add build number and version to jar (#39) * Added build number plugin * Move plugin configs from plugin management --- pom.xml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/pom.xml b/pom.xml index 345f49fbb..1008c952f 100644 --- a/pom.xml +++ b/pom.xml @@ -497,6 +497,12 @@ 2.5.2 + + org.codehaus.mojo + buildnumber-maven-plugin + 1.4 + + org.apache.maven.plugins maven-jar-plugin @@ -553,6 +559,35 @@ + + org.codehaus.mojo + buildnumber-maven-plugin + 1.4 + + + + create + + + + + + + org.apache.maven.plugins + maven-jar-plugin + 3.0.2 + + + + true + + + ${buildNumber} + + + + + com.amashchenko.maven.plugin gitflow-maven-plugin