public class ClientToProxyConnection extends ProxyConnection<io.netty.handler.codec.http.HttpRequest>
Represents a connection from a client to our proxy. Each
ClientToProxyConnection can have multiple ProxyToServerConnection
s,
at most one per outbound host:port.
Once a ProxyToServerConnection has been created for a given server, it is
continually reused. The ProxyToServerConnection goes through its own
lifecycle of connects and disconnects, with different underlying
Channel
s, but only a single ProxyToServerConnection object is used
per server. The one exception to this is CONNECT tunneling - if a connection
has been used for CONNECT tunneling, that connection will never be reused.
As the ProxyToServerConnections receive responses from their servers, they
feed these back to the client by calling
respond(ProxyToServerConnection, HttpFilters, HttpRequest, HttpResponse, HttpObject)
.
ProxyConnection.BytesReadMonitor, ProxyConnection.BytesWrittenMonitor, ProxyConnection.RequestReadMonitor, ProxyConnection.RequestWrittenMonitor, ProxyConnection.ResponseReadMonitor, ProxyConnection.ResponseWrittenMonitor
Modifier and Type | Field and Description |
---|---|
private AtomicBoolean |
authenticated |
private ProxyConnection.BytesReadMonitor |
bytesReadMonitor
Activity Tracking/Statistics
We track statistics on bytes, requests and responses by adding handlers
at the appropriate parts of the pipeline (see initChannelPipeline()).
|
private ProxyConnection.BytesWrittenMonitor |
bytesWrittenMonitor |
private SSLSession |
clientSslSession |
private static io.netty.handler.codec.http.HttpResponseStatus |
CONNECTION_ESTABLISHED |
private HttpFilters |
currentFilters
The current filters to apply to incoming requests/chunks.
|
private io.netty.handler.codec.http.HttpRequest |
currentRequest
The current HTTP request that this connection is currently servicing.
|
private ProxyToServerConnection |
currentServerConnection
This is the current server connection that we're using while transferring
chunked data.
|
private io.netty.handler.traffic.GlobalTrafficShapingHandler |
globalTrafficShapingHandler |
private static Pattern |
HTTP_SCHEME
Used for case-insensitive comparisons when checking direct proxy request.
|
private static String |
LOWERCASE_TRANSFER_ENCODING_HEADER
Used for case-insensitive comparisons when parsing Connection header values.
|
private boolean |
mitming
Tracks whether or not this ClientToProxyConnection is current doing MITM.
|
private AtomicInteger |
numberOfCurrentlyConnectedServers
Keep track of how many servers are currently connected.
|
private AtomicInteger |
numberOfCurrentlyConnectingServers
Keep track of how many servers are currently in the process of
connecting.
|
private AtomicInteger |
numberOfReusedServerConnections
Keep track of how many times we were able to reuse a connection.
|
private ProxyConnection.RequestReadMonitor |
requestReadMonitor |
(package private) ConnectionFlowStep |
RespondCONNECTSuccessful
Tells the Client that its HTTP CONNECT request was successful.
|
private ProxyConnection.ResponseWrittenMonitor |
responseWrittenMonitor |
private Map<String,ProxyToServerConnection> |
serverConnectionsByHostAndPort
Keep track of all ProxyToServerConnections by host+port.
|
channel, ctx, lastReadTime, LOG, proxyServer, runsAsSslClient, sslEngine, StartTunneling
Constructor and Description |
---|
ClientToProxyConnection(DefaultHttpProxyServer proxyServer,
SslEngineSource sslEngineSource,
boolean authenticateClients,
io.netty.channel.ChannelPipeline pipeline,
io.netty.handler.traffic.GlobalTrafficShapingHandler globalTrafficShapingHandler) |
Modifier and Type | Method and Description |
---|---|
private boolean |
authenticationRequired(io.netty.handler.codec.http.HttpRequest request)
Checks whether the given HttpRequest requires authentication.
|
protected void |
becameSaturated()
When the ClientToProxyConnection becomes saturated, stop reading on all
associated ProxyToServerConnections.
|
protected void |
becameWritable()
When the ClientToProxyConnection becomes writable, resume reading on all
associated ProxyToServerConnections.
|
private void |
closeConnectionsAfterWriteIfNecessary(ProxyToServerConnection serverConnection,
io.netty.handler.codec.http.HttpRequest currentHttpRequest,
io.netty.handler.codec.http.HttpResponse currentHttpResponse,
io.netty.handler.codec.http.HttpObject httpObject)
This method takes care of closing client to proxy and/or proxy to server
connections after finishing a write.
|
protected void |
connected()
On connect of the client, start waiting for an initial
HttpRequest . |
private void |
connectionFailedUnrecoverably(io.netty.handler.codec.http.HttpRequest initialRequest,
ProxyToServerConnection serverConnection) |
private io.netty.handler.codec.http.HttpRequest |
copy(io.netty.handler.codec.http.HttpRequest original)
Copy the given
HttpRequest verbatim. |
protected void |
disconnected()
On disconnect of the client, disconnect all server connections.
|
private ConnectionState |
doReadHTTPInitial(io.netty.handler.codec.http.HttpRequest httpRequest)
Reads an
HttpRequest . |
protected void |
exceptionCaught(Throwable cause)
Override this to handle exceptions that occurred during asynchronous
processing on the
Channel . |
private void |
fixHttpVersionHeaderIfNecessary(io.netty.handler.codec.http.HttpResponse httpResponse)
Chunked encoding is an HTTP 1.1 feature, but sometimes we get a chunked
response that reports its HTTP version as 1.0.
|
private FlowContext |
flowContext() |
private void |
forceDisconnect(ProxyToServerConnection serverConnection) |
InetSocketAddress |
getClientAddress() |
private String |
identifyHostAndPort(io.netty.handler.codec.http.HttpRequest httpRequest)
Identify the host and port for a request.
|
private void |
initChannelPipeline(io.netty.channel.ChannelPipeline pipeline)
Initialize the for the client to
proxy channel.
|
boolean |
isMitming() |
private boolean |
isRequestToOriginServer(io.netty.handler.codec.http.HttpRequest httpRequest)
Returns true if the specified request is a request to an origin server, rather than to a proxy server.
|
private void |
modifyRequestHeadersToReflectProxying(io.netty.handler.codec.http.HttpRequest httpRequest)
If and only if our proxy is not running in transparent mode, modify the
request headers to reflect that it was proxied.
|
private void |
modifyResponseHeadersToReflectProxying(io.netty.handler.codec.http.HttpResponse httpResponse)
If and only if our proxy is not running in transparent mode, modify the
response headers to reflect that it was proxied.
|
protected void |
readHTTPChunk(io.netty.handler.codec.http.HttpContent chunk)
Implement this to handle reading a chunk in a chunked transfer.
|
protected ConnectionState |
readHTTPInitial(io.netty.handler.codec.http.HttpRequest httpRequest)
Reading
|
protected void |
readRaw(io.netty.buffer.ByteBuf buf)
Implement this to handle reading a raw buffer as they are used in HTTP
tunneling.
|
private void |
recordClientConnected() |
private void |
recordClientDisconnected() |
private void |
recordClientSSLHandshakeSucceeded() |
private void |
removeSDCHEncoding(io.netty.handler.codec.http.HttpHeaders headers)
Remove sdch from encodings we accept since we can't decode it.
|
(package private) void |
respond(ProxyToServerConnection serverConnection,
HttpFilters filters,
io.netty.handler.codec.http.HttpRequest currentHttpRequest,
io.netty.handler.codec.http.HttpResponse currentHttpResponse,
io.netty.handler.codec.http.HttpObject httpObject)
Send a response to the client.
|
private boolean |
respondWithShortCircuitResponse(io.netty.handler.codec.http.HttpResponse httpResponse)
Responds to the client with the specified "short-circuit" response.
|
private io.netty.handler.codec.http.DefaultFullHttpResponse |
responseFor(io.netty.handler.codec.http.HttpVersion httpVersion,
io.netty.handler.codec.http.HttpResponseStatus status)
Factory for
DefaultFullHttpResponse s. |
private io.netty.handler.codec.http.DefaultFullHttpResponse |
responseFor(io.netty.handler.codec.http.HttpVersion httpVersion,
io.netty.handler.codec.http.HttpResponseStatus status,
io.netty.buffer.ByteBuf body,
int contentLength)
Factory for
DefaultFullHttpResponse s. |
private io.netty.handler.codec.http.DefaultFullHttpResponse |
responseFor(io.netty.handler.codec.http.HttpVersion httpVersion,
io.netty.handler.codec.http.HttpResponseStatus status,
String body)
Factory for
DefaultFullHttpResponse s. |
private void |
resumeReadingIfNecessary() |
protected void |
serverBecameSaturated(ProxyToServerConnection serverConnection)
When a server becomes saturated, we stop reading from the client.
|
protected void |
serverBecameWriteable(ProxyToServerConnection serverConnection)
When a server becomes writeable, we check to see if all servers are
writeable and if they are, we resume reading.
|
protected boolean |
serverConnectionFailed(ProxyToServerConnection serverConnection,
ConnectionState lastStateBeforeFailure,
Throwable cause)
If the
ProxyToServerConnection fails to complete its connection
lifecycle successfully, this method is called to let us know about it. |
protected void |
serverConnectionFlowStarted(ProxyToServerConnection serverConnection)
Called when
ProxyToServerConnection starts its connection flow. |
protected void |
serverConnectionSucceeded(ProxyToServerConnection serverConnection,
boolean shouldForwardInitialRequest)
If the
ProxyToServerConnection completes its connection lifecycle
successfully, this method is called to let us know about it. |
protected void |
serverDisconnected(ProxyToServerConnection serverConnection)
On disconnect of the server, track that we have one fewer connected
servers and then disconnect the client if necessary.
|
protected void |
setMitming(boolean isMitming) |
private boolean |
shouldCloseClientConnection(io.netty.handler.codec.http.HttpRequest req,
io.netty.handler.codec.http.HttpResponse res,
io.netty.handler.codec.http.HttpObject httpObject)
Determine whether or not the client connection should be closed.
|
private boolean |
shouldCloseServerConnection(io.netty.handler.codec.http.HttpRequest req,
io.netty.handler.codec.http.HttpResponse res,
io.netty.handler.codec.http.HttpObject msg)
Determines if the remote connection should be closed based on the request
and response pair.
|
private void |
stripConnectionTokens(io.netty.handler.codec.http.HttpHeaders headers)
RFC2616 Section 14.10
HTTP/1.1 proxies MUST parse the Connection header field before a message
is forwarded and, for each connection-token in this field, remove any
header field(s) from the message with the same name as the
connection-token.
|
private void |
stripHopByHopHeaders(io.netty.handler.codec.http.HttpHeaders headers)
Removes all headers that should not be forwarded.
|
private void |
switchProxyConnectionHeader(io.netty.handler.codec.http.HttpHeaders headers)
Switch the de-facto standard "Proxy-Connection" header to "Connection"
when we pass it along to the remote host.
|
protected void |
timedOut()
This method is called when the underlying
Channel times out due
to an idle timeout. |
private void |
writeAuthenticationRequired(String realm) |
private boolean |
writeBadGateway(io.netty.handler.codec.http.HttpRequest httpRequest)
Tells the client that something went wrong trying to proxy its request.
|
private boolean |
writeBadRequest(io.netty.handler.codec.http.HttpRequest httpRequest)
Tells the client that the request was malformed or erroneous.
|
private void |
writeEmptyBuffer()
Write an empty buffer at the end of a chunked transfer.
|
private boolean |
writeGatewayTimeout(io.netty.handler.codec.http.HttpRequest httpRequest)
Tells the client that the connection to the server, or possibly to some intermediary service (such as DNS), timed out.
|
aggregateContentForFiltering, become, channelActive, channelInactive, channelRead0, channelRegistered, channelWritabilityChanged, disconnect, doWrite, encrypt, encrypt, EncryptChannel, exceptionCaught, getCurrentState, getHttpFiltersFromProxyServer, getLOG, getSslEngine, is, isConnecting, isSaturated, isTunneling, read, resumeReading, stopReading, userEventTriggered, write, writeHttp, writeRaw, writeToChannel
acceptInboundMessage, channelRead
channelReadComplete, channelUnregistered
handlerAdded, handlerRemoved, isSharable
private static final io.netty.handler.codec.http.HttpResponseStatus CONNECTION_ESTABLISHED
private static final String LOWERCASE_TRANSFER_ENCODING_HEADER
private static final Pattern HTTP_SCHEME
private final Map<String,ProxyToServerConnection> serverConnectionsByHostAndPort
private final AtomicInteger numberOfCurrentlyConnectingServers
private final AtomicInteger numberOfCurrentlyConnectedServers
private final AtomicInteger numberOfReusedServerConnections
private volatile ProxyToServerConnection currentServerConnection
private volatile HttpFilters currentFilters
private volatile SSLSession clientSslSession
private volatile boolean mitming
private AtomicBoolean authenticated
private final io.netty.handler.traffic.GlobalTrafficShapingHandler globalTrafficShapingHandler
private volatile io.netty.handler.codec.http.HttpRequest currentRequest
ConnectionFlowStep RespondCONNECTSuccessful
private final ProxyConnection.BytesReadMonitor bytesReadMonitor
private ProxyConnection.RequestReadMonitor requestReadMonitor
private ProxyConnection.BytesWrittenMonitor bytesWrittenMonitor
private ProxyConnection.ResponseWrittenMonitor responseWrittenMonitor
ClientToProxyConnection(DefaultHttpProxyServer proxyServer, SslEngineSource sslEngineSource, boolean authenticateClients, io.netty.channel.ChannelPipeline pipeline, io.netty.handler.traffic.GlobalTrafficShapingHandler globalTrafficShapingHandler)
protected ConnectionState readHTTPInitial(io.netty.handler.codec.http.HttpRequest httpRequest)
readHTTPInitial
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
private ConnectionState doReadHTTPInitial(io.netty.handler.codec.http.HttpRequest httpRequest)
Reads an HttpRequest
.
If we don't yet have a ProxyToServerConnection
for the desired
server, this takes care of creating it.
Note - the "server" could be a chained proxy, not the final endpoint for the request.
httpRequest
- private boolean isRequestToOriginServer(io.netty.handler.codec.http.HttpRequest httpRequest)
When making a request to a proxy, other than a CONNECT or server-wide OPTIONS request (as detailed below), a client MUST send the target URI in absolute-form as the request-target. [...] An example absolute-form of request-line would be: GET http://www.example.org/pub/WWW/TheProject.html HTTP/1.1 To allow for transition to the absolute-form for all requests in some future version of HTTP, a server MUST accept the absolute-form in requests, even though HTTP/1.1 clients will only send them in requests to proxies.
httpRequest
- the request to evaluateprotected void readHTTPChunk(io.netty.handler.codec.http.HttpContent chunk)
ProxyConnection
readHTTPChunk
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
protected void readRaw(io.netty.buffer.ByteBuf buf)
ProxyConnection
readRaw
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
void respond(ProxyToServerConnection serverConnection, HttpFilters filters, io.netty.handler.codec.http.HttpRequest currentHttpRequest, io.netty.handler.codec.http.HttpResponse currentHttpResponse, io.netty.handler.codec.http.HttpObject httpObject)
serverConnection
- the ProxyToServerConnection that's respondingfilters
- the filters to apply to the responsecurrentHttpRequest
- the HttpRequest that prompted this responsecurrentHttpResponse
- the HttpResponse corresponding to this data (when doing
chunked transfers, this is the initial HttpResponse object
that came in before the other chunks)httpObject
- the data with which to respondprotected void connected()
HttpRequest
.connected
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
protected void timedOut()
ProxyConnection
Channel
times out due
to an idle timeout.timedOut
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
protected void disconnected()
disconnected
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
protected void serverConnectionFlowStarted(ProxyToServerConnection serverConnection)
ProxyToServerConnection
starts its connection flow.serverConnection
- protected void serverConnectionSucceeded(ProxyToServerConnection serverConnection, boolean shouldForwardInitialRequest)
ProxyToServerConnection
completes its connection lifecycle
successfully, this method is called to let us know about it.serverConnection
- shouldForwardInitialRequest
- protected boolean serverConnectionFailed(ProxyToServerConnection serverConnection, ConnectionState lastStateBeforeFailure, Throwable cause)
ProxyToServerConnection
fails to complete its connection
lifecycle successfully, this method is called to let us know about it.
After failing to connect to the server, one of two things can happen:
serverConnection
- lastStateBeforeFailure
- cause
- what caused the failureprivate void connectionFailedUnrecoverably(io.netty.handler.codec.http.HttpRequest initialRequest, ProxyToServerConnection serverConnection)
private void resumeReadingIfNecessary()
protected void serverDisconnected(ProxyToServerConnection serverConnection)
serverConnection
- protected void becameSaturated()
becameSaturated
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
protected void becameWritable()
becameWritable
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
protected void serverBecameSaturated(ProxyToServerConnection serverConnection)
serverConnection
- protected void serverBecameWriteable(ProxyToServerConnection serverConnection)
serverConnection
- protected void exceptionCaught(Throwable cause)
ProxyConnection
Channel
.exceptionCaught
in class ProxyConnection<io.netty.handler.codec.http.HttpRequest>
private void initChannelPipeline(io.netty.channel.ChannelPipeline pipeline)
pipeline
- private void closeConnectionsAfterWriteIfNecessary(ProxyToServerConnection serverConnection, io.netty.handler.codec.http.HttpRequest currentHttpRequest, io.netty.handler.codec.http.HttpResponse currentHttpResponse, io.netty.handler.codec.http.HttpObject httpObject)
private void forceDisconnect(ProxyToServerConnection serverConnection)
private boolean shouldCloseClientConnection(io.netty.handler.codec.http.HttpRequest req, io.netty.handler.codec.http.HttpResponse res, io.netty.handler.codec.http.HttpObject httpObject)
req
- res
- httpObject
- private boolean shouldCloseServerConnection(io.netty.handler.codec.http.HttpRequest req, io.netty.handler.codec.http.HttpResponse res, io.netty.handler.codec.http.HttpObject msg)
req
- The request.res
- The response.msg
- The message.private boolean authenticationRequired(io.netty.handler.codec.http.HttpRequest request)
Checks whether the given HttpRequest requires authentication.
If the request contains credentials, these are checked.
If authentication is still required, either because no credentials were provided or the credentials were wrong, this writes a 407 response to the client.
request
- private void writeAuthenticationRequired(String realm)
private io.netty.handler.codec.http.HttpRequest copy(io.netty.handler.codec.http.HttpRequest original)
HttpRequest
verbatim.original
- private void fixHttpVersionHeaderIfNecessary(io.netty.handler.codec.http.HttpResponse httpResponse)
httpResponse
- private void modifyRequestHeadersToReflectProxying(io.netty.handler.codec.http.HttpRequest httpRequest)
httpRequest
- private void modifyResponseHeadersToReflectProxying(io.netty.handler.codec.http.HttpResponse httpResponse)
httpResponse
- private void removeSDCHEncoding(io.netty.handler.codec.http.HttpHeaders headers)
headers
- The headers to modifyprivate void switchProxyConnectionHeader(io.netty.handler.codec.http.HttpHeaders headers)
headers
- The headers to modifyprivate void stripConnectionTokens(io.netty.handler.codec.http.HttpHeaders headers)
headers
- The headers to modifyprivate void stripHopByHopHeaders(io.netty.handler.codec.http.HttpHeaders headers)
headers
- The headers to modifyprivate boolean writeBadGateway(io.netty.handler.codec.http.HttpRequest httpRequest)
httpRequest
- the HttpRequest that is resulting in the Bad Gateway responseprivate boolean writeBadRequest(io.netty.handler.codec.http.HttpRequest httpRequest)
private boolean writeGatewayTimeout(io.netty.handler.codec.http.HttpRequest httpRequest)
httpRequest
- the HttpRequest that is resulting in the Gateway Timeout responseprivate boolean respondWithShortCircuitResponse(io.netty.handler.codec.http.HttpResponse httpResponse)
HttpFilters.proxyToClientResponse(HttpObject)
filter method before writing it to the client. The client
will not be disconnected, unless the response includes a "Connection: close" header, or the filter returns
a null HttpResponse (in which case no response will be written to the client and the connection will be
disconnected immediately). If the response is not a Bad Gateway or Gateway Timeout response, the response's headers
will be modified to reflect proxying, including adding a Via header, Date header, etc.httpResponse
- the response to return to the clientprivate io.netty.handler.codec.http.DefaultFullHttpResponse responseFor(io.netty.handler.codec.http.HttpVersion httpVersion, io.netty.handler.codec.http.HttpResponseStatus status, String body)
DefaultFullHttpResponse
s.httpVersion
- status
- body
- private io.netty.handler.codec.http.DefaultFullHttpResponse responseFor(io.netty.handler.codec.http.HttpVersion httpVersion, io.netty.handler.codec.http.HttpResponseStatus status, io.netty.buffer.ByteBuf body, int contentLength)
DefaultFullHttpResponse
s.httpVersion
- status
- body
- contentLength
- private io.netty.handler.codec.http.DefaultFullHttpResponse responseFor(io.netty.handler.codec.http.HttpVersion httpVersion, io.netty.handler.codec.http.HttpResponseStatus status)
DefaultFullHttpResponse
s.httpVersion
- status
- private String identifyHostAndPort(io.netty.handler.codec.http.HttpRequest httpRequest)
httpRequest
- private void writeEmptyBuffer()
public boolean isMitming()
protected void setMitming(boolean isMitming)
private void recordClientConnected()
private void recordClientSSLHandshakeSucceeded()
private void recordClientDisconnected()
public InetSocketAddress getClientAddress()
private FlowContext flowContext()
Copyright © 2009–2017 LittleShoot. All rights reserved.