Interface TcpInterceptor
- Functional Interface:
- This is a functional interface and can therefore be used as the assignment target for a lambda expression or method reference.
tcp_start,
tcp_message, tcp_end and tcp_error hooks. Configure one per proxy with
HttpProxyServerBootstrap.withTcpInterceptor(TcpInterceptor).
bootstrap.withTcpInterceptor((message, ctx) -> message.fromClient()
? message.data() // pass on
: message.text().replace("ESMTP", "ESMTP proxied").getBytes(UTF_8));
Which tunnels
Every connection the proxy relays as bytes rather than as HTTP: a CONNECT tunnel that
is not intercepted (no MITM manager, an ignored host, a declined ClientHello, a protocol other
than TLS or HTTP, a server that speaks first), on an HTTP/1 connection or as a stream of an
HTTP/2 one, and whether the server is reached directly, through a chained proxy, on a stream of
an HTTP/2 connection or through an intercepted HTTPS proxy; reverse:tcp:// connections;
and intercepted TLS sessions that do not carry HTTP (see HttpProxyServerBootstrap.withTcpInterceptor(org.microproxy.tcp.TcpInterceptor)), whose bytes the hooks see
decrypted (TcpContext.tlsIntercepted()). Hosts matched by HttpProxyServerBootstrap.withTcpHosts(java.lang.String...) are tunnels even when they speak HTTP.
Upgraded WebSocket connections are not: their frames go to the WebSocket frame hooks.
Messages
TCP has no message boundaries: a TcpMessage is whatever one read returned, so a
peer's write may be seen in pieces or joined with the next one (see TcpMessage).
Each direction is read by a thread of its own, so the hooks of one tunnel are called from two threads at once, and those of many tunnels concurrently: the interceptor must be thread-safe. Within a direction, calls come in order, and the direction waits for each one: a slow hook slows that direction down.
Every tunnel gets tcpStart(org.microproxy.tcp.TcpContext) first, then its messages and half-closes, then either
tcpEnd(org.microproxy.tcp.TcpContext) or tcpError(org.microproxy.tcp.TcpContext, java.lang.Throwable), never both. A hook that throws is logged; a throwing
tcpMessage(org.microproxy.tcp.TcpMessage, org.microproxy.tcp.TcpContext) passes the message on unchanged.
Without an interceptor, tunnels copy bytes through pooled buffers as they always did, and cost nothing extra.
-
Method Summary
Modifier and TypeMethodDescriptiondefault voidtcpEnd(TcpContext context) The tunnel ended: both directions finished, or one side closed the connection.default voidtcpError(TcpContext context, Throwable error) The tunnel failed: a read or write failed (a reset, a timeout), and the connection was closed.default voidtcpHalfClose(TcpContext context, boolean fromClient) One side finished sending (end of stream, a TCP half-close): called before the end is passed on to the other side, soTcpContext.send(boolean, byte[])with the samefromClientcan still add bytes in that direction.byte[]tcpMessage(TcpMessage message, TcpContext context) Bytes read from one side, before they are passed on.default voidtcpStart(TcpContext context) A tunnel opened: both sides are connected, nothing has been relayed yet (except the bytes the proxy read to decide what the connection is, which follow as the first message).
-
Method Details
-
tcpStart
A tunnel opened: both sides are connected, nothing has been relayed yet (except the bytes the proxy read to decide what the connection is, which follow as the first message).TcpContext.send(boolean, byte[])may already add bytes, such as a greeting.- Parameters:
context- the tunnel
-
tcpMessage
Bytes read from one side, before they are passed on.- Parameters:
message- the bytes, which side sent them and whencontext- the tunnel, andTcpContext.send(boolean, byte[])to add bytes after these- Returns:
- the bytes to pass on:
message.data()as it is or changed in place, other bytes, or null or an empty array to drop them
-
tcpHalfClose
One side finished sending (end of stream, a TCP half-close): called before the end is passed on to the other side, soTcpContext.send(boolean, byte[])with the samefromClientcan still add bytes in that direction. The other direction goes on.- Parameters:
context- the tunnelfromClient- whether the client finished sending, rather than the server
-
tcpEnd
The tunnel ended: both directions finished, or one side closed the connection.- Parameters:
context- the tunnel
-
tcpError
The tunnel failed: a read or write failed (a reset, a timeout), and the connection was closed. Called instead oftcpEnd(org.microproxy.tcp.TcpContext).- Parameters:
context- the tunnelerror- what failed
-