Skip to content
This repository was archived by the owner on Feb 21, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<groupId>org.littleshoot</groupId>
<artifactId>littleproxy</artifactId>
<packaging>jar</packaging>
<version>1.1.17-VGS-SNAPSHOT</version>
<version>1.1.2-ntlm-20200117</version>
<name>LittleProxy</name>
<description>
LittleProxy is a high performance HTTP proxy written in Java and using the Netty networking framework.
Expand All @@ -14,7 +14,7 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<github.global.server>github</github.global.server>
<netty.version>4.1.28.Final</netty.version>
<netty.version>4.1.54.Fina</netty.version>
<slf4j.version>1.7.24</slf4j.version>
<java.version>1.8</java.version>
<java.version.major>8</java.version.major>
Expand Down Expand Up @@ -225,7 +225,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
<version>30.0-jre</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -273,7 +273,7 @@
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>8.1.17.v20150415</version>
<version>9.4.34.v20201102</version>
<scope>test</scope>
</dependency>

Expand Down Expand Up @@ -329,6 +329,18 @@
<artifactId>netty-all</artifactId>
</dependency>

<dependency>
<groupId>jcifs</groupId>
<artifactId>jcifs</artifactId>
<version>1.3.17</version>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.barchart.udt</groupId>
<artifactId>barchart-udt-bundle</artifactId>
Expand Down Expand Up @@ -547,6 +559,19 @@
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/org/littleshoot/proxy/ChainedProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

import java.net.InetSocketAddress;

import org.littleshoot.proxy.ntlm.NtlmHandler;

/**
* <p>
* Encapsulates information needed to connect to a chained proxy.
Expand Down Expand Up @@ -49,6 +51,17 @@ public interface ChainedProxy extends SslEngineSource {
*/
boolean requiresEncryption();

/**
* Tell LittleProxy whether or not to do NTLM authentication to the chained
* proxy. Same instance should be returned to maintain state during NLTM
* handshake.
*
* null indicates that we won't do NTLM handshake.
*
* @return NtlmHandler
*/
NtlmHandler getNtlmHandler();

/**
* Filters requests on their way to the chained proxy.
*
Expand Down
9 changes: 8 additions & 1 deletion src/main/java/org/littleshoot/proxy/ChainedProxyAdapter.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import javax.net.ssl.SSLEngine;

import org.littleshoot.proxy.ntlm.NtlmHandler;

/**
* Convenience base class for implementations of {@link ChainedProxy}.
*/
Expand Down Expand Up @@ -40,7 +42,12 @@ public boolean requiresEncryption() {
public SSLEngine newSslEngine() {
return null;
}


@Override
public NtlmHandler getNtlmHandler() {
return null;
}

@Override
public void filterRequest(HttpObject httpObject) {
}
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/org/littleshoot/proxy/FlowContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import org.littleshoot.proxy.impl.ClientToProxyConnection;

import io.netty.channel.ChannelHandlerContext;

/**
* <p>
* Encapsulates contextual information for flow information that's being
Expand All @@ -16,15 +18,26 @@
public class FlowContext {
private final InetSocketAddress clientAddress;
private final SSLSession clientSslSession;
private final ChannelHandlerContext ctx;

public FlowContext(ClientToProxyConnection clientConnection) {
super();
this.ctx = clientConnection.getContext();
this.clientAddress = clientConnection.getClientAddress();
SSLEngine sslEngine = clientConnection.getSslEngine();
this.clientSslSession = sslEngine != null ? sslEngine.getSession()
: null;
}

/**
* The client to proxy channel context.
*
* @return
*/
public ChannelHandlerContext getClientToProxyContext() {
return ctx;
}

/**
* The address of the client.
*
Expand Down
13 changes: 13 additions & 0 deletions src/main/java/org/littleshoot/proxy/FullFlowContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,34 @@
import org.littleshoot.proxy.impl.ClientToProxyConnection;
import org.littleshoot.proxy.impl.ProxyToServerConnection;

import io.netty.channel.ChannelHandlerContext;

/**
* Extension of {@link FlowContext} that provides additional information (which
* we know after actually processing the request from the client).
*/
public class FullFlowContext extends FlowContext {
private final String serverHostAndPort;
private final ChainedProxy chainedProxy;
private final ChannelHandlerContext ctx;

public FullFlowContext(ClientToProxyConnection clientConnection,
ProxyToServerConnection serverConnection) {
super(clientConnection);
this.ctx = serverConnection.getContext();
this.serverHostAndPort = serverConnection.getServerHostAndPort();
this.chainedProxy = serverConnection.getChainedProxy();
}

/**
* The proxy to server channel context.
*
* @return
*/
public ChannelHandlerContext getProxyToServerContext() {
return ctx;
}

/**
* The host and port for the server (i.e. the ultimate endpoint).
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ protected void exceptionCaught(Throwable cause) {
private void initChannelPipeline(ChannelPipeline pipeline) {
LOG.debug("Configuring ChannelPipeline");

if (proxyServer.getRequestTracer() != null) {
if (!proxyServer.getActivityTrackers().isEmpty() && proxyServer.getRequestTracer() != null) {
pipeline.addLast("requestTracerHandler", new RequestTracerHandler(this));
}

Expand All @@ -870,8 +870,14 @@ private void initChannelPipeline(ChannelPipeline pipeline) {

EventExecutorGroup globalStateWrapperEvenLoop = new GlobalStateWrapperEvenLoop(this);

pipeline.addLast(globalStateWrapperEvenLoop, "bytesReadMonitor", bytesReadMonitor);
pipeline.addLast(globalStateWrapperEvenLoop, "bytesWrittenMonitor", bytesWrittenMonitor);
if(!proxyServer.getActivityTrackers().isEmpty()){
LOG.info("Activity Trackers are available: {}. Enabled monitoring.", proxyServer.getActivityTrackers().size());
for (final ActivityTracker activityTracker : proxyServer.getActivityTrackers()) {
LOG.debug("Activity Tracker: {}", activityTracker.getClass());
}
pipeline.addLast(globalStateWrapperEvenLoop, "bytesReadMonitor", bytesReadMonitor);
pipeline.addLast(globalStateWrapperEvenLoop, "bytesWrittenMonitor", bytesWrittenMonitor);
}

pipeline.addLast("proxyProtocolReader", new HttpProxyProtocolRequestDecoder());

Expand All @@ -890,8 +896,10 @@ private void initChannelPipeline(ChannelPipeline pipeline) {
aggregateContentForFiltering(pipeline, numberOfBytesToBuffer);
}

pipeline.addLast(globalStateWrapperEvenLoop, "requestReadMonitor", requestReadMonitor);
pipeline.addLast(globalStateWrapperEvenLoop, "responseWrittenMonitor", responseWrittenMonitor);
if(!proxyServer.getActivityTrackers().isEmpty()){
pipeline.addLast(globalStateWrapperEvenLoop, "requestReadMonitor", requestReadMonitor);
pipeline.addLast(globalStateWrapperEvenLoop, "responseWrittenMonitor", responseWrittenMonitor);
}

pipeline.addLast(
"idle",
Expand Down Expand Up @@ -1349,7 +1357,8 @@ private boolean respondWithShortCircuitResponse(HttpResponse httpResponse) {

// if the response is not a Bad Gateway or Gateway Timeout, modify the headers "as if" the short-circuit response were proxied
int statusCode = httpResponse.getStatus().code();
if (statusCode != HttpResponseStatus.BAD_GATEWAY.code() && statusCode != HttpResponseStatus.GATEWAY_TIMEOUT.code()) {
if (statusCode != HttpResponseStatus.BAD_GATEWAY.code() && statusCode != HttpResponseStatus.GATEWAY_TIMEOUT.code()
&& statusCode != HttpResponseStatus.PROXY_AUTHENTICATION_REQUIRED.code()) {
modifyResponseHeadersToReflectProxying(httpResponse);
}

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/org/littleshoot/proxy/impl/ConnectionFlow.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ ConnectionFlow then(ConnectionFlowStep step) {
return this;
}

/**
* Indicates whether the given message is relevant to the current step.
* Invoker should check this before calling read().
*
* @param msg
* the message read from the underlying connection
* @return
*/
boolean isRelevant(Object msg) {
return currentStep.isRelevant(msg);
}

/**
* While we're in the process of connecting, any messages read by the
* {@link ProxyToServerConnection} are passed to this method, which passes
Expand Down
11 changes: 11 additions & 0 deletions src/main/java/org/littleshoot/proxy/impl/ConnectionFlowStep.java
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@ void onSuccess(ConnectionFlow flow) {
flow.advance();
}

/**
* Indicates whether the given message is relevant to this step.
*
* @param msg
* the message read from the underlying connection
* @return
*/
boolean isRelevant(Object msg) {
return true;
}

/**
* <p>
* Any messages that are read from the underlying connection while we're at
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/org/littleshoot/proxy/impl/ConnectionState.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ enum ConnectionState {
*/
HANDSHAKING(true),

/**
* In the process of sending NTLM negotiate (Type-1)
* and waiting to receive NTLM challenge (Type-2).
*/
NTLM_HANDSHAKING(true),

/**
* In the process of negotiating an HTTP CONNECT from the client.
*/
Expand Down
16 changes: 9 additions & 7 deletions src/main/java/org/littleshoot/proxy/impl/ProxyConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -887,21 +887,20 @@ public void write(ChannelHandlerContext ctx,
}

/**
* Invoked immediately before an HttpRequest is written.
*/
* Invoked immediately before an HttpRequest is written.
*/
protected abstract void requestWriting(HttpRequest httpRequest);

/**
* Invoked immediately after an HttpRequest has been sent.
*/
* Invoked immediately after an HttpRequest has been sent.
*/
protected abstract void requestWritten(HttpRequest httpRequest);

/**
* Invoked immediately after an HttpContent has been sent.
*/
* Invoked immediately after an HttpContent has been sent.
*/
protected abstract void contentWritten(HttpContent httpContent);
}

/**
* Utility handler for monitoring responses written on this connection.
*/
Expand All @@ -926,4 +925,7 @@ public void write(ChannelHandlerContext ctx,
protected abstract void responseWritten(HttpResponse httpResponse);
}

public ChannelHandlerContext getContext() {
return ctx;
}
}
Loading