Package org.microproxy
package org.microproxy
-
ClassDescriptionObserves proxy activity, e.g. for metrics or access logs.An
ActivityTrackerthat ignores everything; extend it and override what you need.What aProxyAuthenticatordecided about a request.The client may use the proxy.The client may not use the proxy.An upstream proxy that requests are forwarded through.BaseChainedProxyimplementation.Chooses upstream proxies for each request.The protocol spoken to an upstream (chained) proxy.What the proxy knows about a client: its address and, once authenticated, its user name.A client's TLSClientHello, the first message of a handshake, as the proxy read it before deciding whether to intercept a connection: after aCONNECTis accepted, and first thing on a connection to a transparent listener.Resolves host names withInetAddress.getByName(java.lang.String).How a draining proxy (HttpProxyServer.drain(java.time.Duration)) tells its clients to go elsewhere, as Envoy's--drain-strategy: each new request may be answered withConnection: close(HTTP/1) or make the proxy send GOAWAY (HTTP/2, HTTP/3) on its connection.Makes the proxy's own answer when a request fails (ProxyFailure), e.g. to send branded error pages or JSON instead of the default plain-text body.Information about the client side of a proxied flow.What an access log needs to know about one finished exchange or flow, handed toActivityTracker.flowEnded(org.microproxy.FlowRecord)once it is over: an HTTP exchange once its response has been written (or it was abandoned), aCONNECTtunnel, a SOCKS client's tunnel, a WebSocket session, a tunnel seen by the TCP hooks, a CONNECT-UDP flow, and a QUIC flow the transparent QUIC listener relayed or intercepted stream by stream, each when it closes.Builds aFlowRecord; unset values are unknown.What kind of exchange or flow a record is about;%MP_FLOW%renders itsFlowRecord.Kind.label().When the phases of one request/response exchange happened, fromFlowContext.timings().The distributed trace of one exchange, made by aFlowTracerwhen the request head arrives: its trace and span ids, whichFlowContext.trace(), access logs (%TRACE_ID%,%SPAN_ID%) and scripts (ctx.trace_id) show, and the calls through which the proxy reports each attempt to reach the server and asks for the headers that carry the trace to it.A spanFlowTrace.startSpan(java.lang.String)started, used by one thread at a time.Traces the proxy's exchanges and flows: given withHttpProxyServerBootstrap.withTracer(org.microproxy.FlowTracer), it is asked for aFlowTracewhen each request head arrives, and handed each exchange's and flow'sFlowRecordwhen it is over.AFlowContextthat also knows the server side of the flow.HowHttpFilters.proxyToClientResponse(org.microproxy.http.HttpObject)treats the responses the proxy answers with itself, rather than relaying a server's: its own error responses (the502for a server it cannot reach, the504for one that does not answer, a400for a bad request, theFailureResponder's andHttpFilters.proxyToServerFailure(org.microproxy.ProxyFailure)'s answers, ...), and the short-circuit responses a filter returned from an earlier hook (HttpFilters.clientToProxyRequest(org.microproxy.http.HttpObject),HttpFilters.proxyToServerRequest(org.microproxy.http.HttpObject)), theHttpCache's answers included.Resolves server host names.Builds theProtocolPolicyof HTTP/1.x clients (HttpProxyServerBootstrap.onHttp1(java.util.function.Consumer<org.microproxy.Http1PolicyBuilder>)): the fields every protocol has, and HTTP/1-specific fields such asHttp1PolicyBuilder.requestHeadTimeout(java.time.Duration)andHttp1PolicyBuilder.allowChunkedLength(boolean).Limits for HTTP/2 client connections (HttpProxyServerBootstrap.withHttp2(boolean)).BuildsHttp2Options.Limits and timers for HTTP/3 (HttpProxyServerBootstrap.withHttp3(boolean)andHttpProxyServerBootstrap.withHttp3Upstream(boolean)).BuildsHttp3Options.The congestion controllers of the proxy's QUIC connections (seeHttp3Options.Builder.quicCongestionControl).Hooks into the life of a single request/response exchange.Convenience base class forHttpFiltersthat keeps the original request and context.BuildsHttpFiltersfrom lambdas, one per hook, instead of a class that overrides the hooks it needs:The streams a built filter inspects piece by piece.Filters made byHttpFiltersBuilder.Runs several filters sources as one, in order.The filters of several sources for one request.Creates theHttpFiltersfor each request.AHttpFiltersSourcethat applies no filtering and no buffering unless overridden.A running proxy.Configures and starts aHttpProxyServer.A certificate chain and the private key of its first certificate: what a TLS server presents.Command-line entry point.Adds command-line options toLauncher.Entry point:MicroProxy.bootstrap().withPort(8080).start().Enables man-in-the-middle interception of CONNECT tunnels.When the proxy runs its TLS handshake with the server for aCONNECTit intercepts: after answering theCONNECTand reading the client's ClientHello, or before answering.Hosts that bypass the upstream proxy, in the comma-separatedNO_PROXYsyntax used by curl and most HTTP clients:*matches every host;example.com,.example.comand*.example.commatch the domain and all its subdomains; an IP literal matches that address, and CIDR notation (10.0.0.0/8,fd00::/8) matches a range; addresses are compared only when the request names an IP literal (no DNS lookups); any entry may end in:portto apply to that port only.A snapshot of the shared server connection pool.How the proxy behaves, where it can behave in more than one way, for the exchanges of clients that speak one protocol: HTTP/1.x, HTTP/2 or HTTP/3 (the protocol the client speaks to the proxy,FlowContext.getHttpVersion()).Builds aProtocolPolicy.Decides which clients may use the proxy.Why the proxy has to answer a request itself instead of relaying the server's response.The proxy refuses the request: an origin-form request withoutHttpProxyServerBootstrap.withAllowRequestToOriginServer(boolean), anhttps://request withoutHttpProxyServerBootstrap.withTlsOrigination(boolean), or aCONNECTtarget that is nothost:port.The server's response was malformed, or the server closed the connection or failed before the response head (or a body the filters asked to buffer) was complete.No connection could be made to the server or any chained proxy offered for it: refused, unreachable, timed out, a chained proxy whose own name did not resolve, or a chained proxy that refused theCONNECTor SOCKS request.The shared connection pool had no connection to spare within the connect timeout.There is nowhere to send the request: it names no host (hostAndPortis null), or theChainedProxyManageroffered no route.The request body is larger than the filters asked to buffer (maxBytes).The server did not answer within the idle timeout.The TLS handshake with the server (when intercepting) or with a TLS chained proxy failed or did not finish withinHttpProxyServerBootstrap.withTlsHandshakeTimeout(java.time.Duration)(or the request'sHttpFilters.proxyToServerTlsHandshakeTimeout()), e.g. because its certificate is not trusted.Why a TLS handshake failed, read from the exception's cause chain: the certificate checks first, then an alert from the peer, a timeout, or anything else.The server's name did not resolve (direct connections).Which address a PROXY protocol header the proxy sends to a server (HttpProxyServerBootstrap.withSendProxyProtocol(boolean)) names as its destination, when the client's connection did not bring a header of its own (whose destination is passed on as it is).Whether client connections start with a PROXY protocol header (v1 or v2, as HAProxy defines them), which names the client a load balancer in front of the proxy connected for.Why an exchange or a flow ended the way it did, in the vocabulary of Envoy's access-log response flags: each constant has Envoy's short code (UF,UT, ...) and long name, so logs read by tools made for Envoy keep their meaning.Where a response sent to the client came from; seeActivityTracker.responseSentToClient(FlowContext, HttpResponse, ResponseSource).How long the proxy waits before trying the next route after a connection attempt failed: the next chained proxy, or the direct fallback, that theChainedProxyManageroffered.Reverse proxy mode: every request on the listener goes to one fixed upstream server, whatever its target, as a server of its own rather than a forward proxy.Sees every call into a script's hooks (with the optional Starlark module): when it starts, and how it ended, with the interpreter steps it ran, about how many bytes of values it created, how long it took and why it failed.What the calls into scripts for one exchange added up to, asFlowContext.scriptStats()gives it: how many calls, how long they took, how many interpreter steps they ran and about how many bytes of values they created (an estimate of what was made, not of what stayed in memory).Filters that say which streams they inspect piece by piece.Implementations of the shared server connection pool.Where a proxy is in its life (HttpProxyServer.state()), with the names Envoy's admin/readyanswers and the numbers itsserver.stategauge shows.Supplies TLS configuration for one side of a connection.Who the proxy expects at the other end of a TLS connection to a server, when that is not simply the request's host: the server name it sends in the ClientHello (SNI, RFC 6066 section 3) and the host name the server's certificate is verified against (HTTPS endpoint identification, RFC 9110 section 4.3.4).AChainedProxyManagerconfigured like command-line HTTP clients: an upstream proxy URL for plain HTTP, one for HTTPS (CONNECT), andNoProxyRulesfor hosts reached directly.