Class ProtocolPolicy
FlowContext.getHttpVersion()). Configured on the bootstrap per protocol (HttpProxyServerBootstrap.onHttp1(java.util.function.Consumer<org.microproxy.Http1PolicyBuilder>), HttpProxyServerBootstrap.onHttp2(java.util.function.Consumer<org.microproxy.ProtocolPolicy.Builder>), HttpProxyServerBootstrap.onHttp3(java.util.function.Consumer<org.microproxy.ProtocolPolicy.Builder>)) and for all of them (HttpProxyServerBootstrap.onAllProtocols(java.util.function.Consumer<org.microproxy.ProtocolPolicy.Builder>)), so that a proxy can, say, keep LittleProxy's order
of events for its HTTP/1.1 clients while serving HTTP/2 and HTTP/3 clients natively:
MicroProxy.bootstrap()
.onHttp1(p -> p.preset(ProtocolPolicy.littleProxy()))
.onHttp3(p -> p.tlsRetryWithoutSni(true))
.start();
A policy sets some of its fields and leaves the others to whatever applies below it. For an
exchange the proxy takes each field from, in order: the request's own filters, where a hook
decides that field for one request; the policy of the client's protocol; the policy for all
protocols (onAllProtocols and the bootstrap's own setters, such as HttpProxyServerBootstrap.withTlsRetryWithoutSni(boolean)); and last the protocol's defaults, which are
defaults() except for HTTP/1 with HttpProxyServerBootstrap.withLittleProxyCompatibility(), which makes them littleProxy().
Which policy applies: an HTTP/1.x connection's exchanges (its CONNECTs included)
take HTTP/1's; an HTTP/2 connection's streams (their CONNECTs and extended
CONNECTs included) HTTP/2's; an HTTP/3 connection's streams HTTP/3's. The requests a client
sends inside a tunnel the proxy intercepts take the policy of what the client speaks inside it,
which may differ from that of the CONNECT that opened it (HTTP/1.1 inside a
CONNECT stream of an HTTP/2 connection, say). SOCKS clients and transparent TLS connections,
whose CONNECT the proxy makes up, are HTTP/1 connections until what they carry says
otherwise (HTTP/2 negotiated inside the intercepted TLS); a reverse proxy's clients take the
policy of the protocol they speak to it; transparent QUIC and the QUIC inside a CONNECT-UDP
flow are HTTP/3.
Instances are immutable and thread-safe, and equal when they set the same fields alike.
-
Nested Class Summary
Nested Classes -
Method Summary
Modifier and TypeMethodDescriptionHTTP/1 only: whether an HTTP/1.1 request with bothTransfer-EncodingandContent-Lengthis accepted (seeHttpProxyServerBootstrap.withAllowChunkedLength(boolean)).static ProtocolPolicy.Builderbuilder()A builder for a policy for all protocols, HTTP/2 or HTTP/3; HTTP/1's is anHttp1PolicyBuilder.The configuration namesProtocolPolicy.Builder.set(java.lang.String, java.lang.String)takes,presetfirst;Http1PolicyBuilder.set(java.lang.String, java.lang.String)takesallow_chunked_lengthtoo.static ProtocolPolicydefaults()MicroProxy's defaults, every field set (but the HTTP/1-onlyallowChunkedLength(), whichHttpProxyServerBootstrap.withAllowChunkedLength(boolean)decides):resolveBeforeProxyToServerRequest():false, soHttpFilters.proxyToServerRequest(org.microproxy.http.HttpObject)can answer or redirect a request without a DNS lookup;filterConnectAnswer():true, so response filters see the200that opens aCONNECTtunnel and can turn it into a refusal;servePlainHttpAfterConnect():true, so plain HTTP sent after aCONNECTthat could be intercepted (aws://WebSocket, say) is served as HTTP, its requests seen by filters;proxyProtocolDestination():ProxyProtocolDestination.LOCAL_ADDRESS;tlsRetryWithoutSni():false;requestHeadTimeout(): 30 seconds for HTTP/1 request heads, with zero disabling the deadline;generatedResponses():GeneratedResponses.REPLACEABLE, so a filter can brand the proxy's own responses;mitmServerHandshake():MitmServerHandshake.DEFERRED, so the server's handshake can mirror the client's ClientHello.static ProtocolPolicyempty()A policy that sets nothing: every field is left to what applies below it.booleanWhether the proxy's200 Connection establishedanswer to a client'sCONNECTgoes throughHttpFilters.serverToProxyResponse(org.microproxy.http.HttpObject)andHttpFilters.proxyToClientResponse(org.microproxy.http.HttpObject), so that filters can see it or turn it into a refusal (MicroProxy's default), rather than straight to the client (as LittleProxy writes it).HowHttpFilters.proxyToClientResponse(org.microproxy.http.HttpObject)treats the responses the proxy answers with itself: its error responses and the short-circuit responses filters returned from earlier hooks (GeneratedResponses): it may replace them (GeneratedResponses.REPLACEABLE), change them in place only (GeneratedResponses.IN_PLACE), or never see them (GeneratedResponses.SKIP).inthashCode()static ProtocolPolicyLittleProxy's behaviour, as of LittleProxy 2.9.1, every field set (but the HTTP/1-onlyallowChunkedLength(): LittleProxy rejects such requests, through Netty'sHttpObjectDecoder, as MicroProxy does by default).When the proxy runs its TLS handshake with the server for an interceptedCONNECT: after answering it and reading the client's ClientHello, which it can then mirror (MitmServerHandshake.DEFERRED), or before answering, so that a failure answers theCONNECTitself (MitmServerHandshake.EAGER).orElse(ProtocolPolicy fallback) This policy with the fields it leaves unset taken fromfallback.static ProtocolPolicyA preset policy by its configuration name:littleproxyforlittleProxy(),microproxyordefaultsfordefaults()(any case).Which address a PROXY protocol header the proxy sends to a server names as its destination (ProxyProtocolDestination).How long an HTTP/1 request head may take, from its first byte to its end; zero disables the deadline.Whether the server's name is resolved beforeHttpFilters.proxyToServerRequest(org.microproxy.http.HttpObject)runs, so that a name that does not resolve is answered502without that hook being called (as LittleProxy does), rather than after it, so that the hook can answer or redirect the request without a DNS lookup (MicroProxy's default).Whether plain HTTP that a client sends after aCONNECTthat could be intercepted (aws://WebSocket through the proxy, say) is served as HTTP, its requests going through the filters to theCONNECT's target (MicroProxy's default), rather than relayed to the target as raw bytes (as LittleProxy does).Whether a TLS handshake with a server that rejects the server name the proxy sends with anunrecognized_namealert is tried once more without SNI (seeHttpProxyServerBootstrap.withTlsRetryWithoutSni(boolean)).toString()Returns the fields this policy sets, by their configuration names, such asProtocolPolicy[tls_retry_without_sni=true].
-
Method Details
-
empty
A policy that sets nothing: every field is left to what applies below it.- Returns:
- the empty policy
-
defaults
MicroProxy's defaults, every field set (but the HTTP/1-onlyallowChunkedLength(), whichHttpProxyServerBootstrap.withAllowChunkedLength(boolean)decides):resolveBeforeProxyToServerRequest():false, soHttpFilters.proxyToServerRequest(org.microproxy.http.HttpObject)can answer or redirect a request without a DNS lookup;filterConnectAnswer():true, so response filters see the200that opens aCONNECTtunnel and can turn it into a refusal;servePlainHttpAfterConnect():true, so plain HTTP sent after aCONNECTthat could be intercepted (aws://WebSocket, say) is served as HTTP, its requests seen by filters;proxyProtocolDestination():ProxyProtocolDestination.LOCAL_ADDRESS;tlsRetryWithoutSni():false;requestHeadTimeout(): 30 seconds for HTTP/1 request heads, with zero disabling the deadline;generatedResponses():GeneratedResponses.REPLACEABLE, so a filter can brand the proxy's own responses;mitmServerHandshake():MitmServerHandshake.DEFERRED, so the server's handshake can mirror the client's ClientHello.
- Returns:
- MicroProxy's default policy
-
littleProxy
LittleProxy's behaviour, as of LittleProxy 2.9.1, every field set (but the HTTP/1-onlyallowChunkedLength(): LittleProxy rejects such requests, through Netty'sHttpObjectDecoder, as MicroProxy does by default).HttpProxyServerBootstrap.withLittleProxyCompatibility()makes it HTTP/1's defaults; LittleProxy never spoke HTTP/2 or HTTP/3. Field by field:resolveBeforeProxyToServerRequest():true.ClientToProxyConnection.doReadHTTPInitialcreates the server connection (ProxyToServerConnection.create, whosesetupConnectionParametersresolves the server) before it callsproxyToServerRequest, and answers502without calling it when the name does not resolve.filterConnectAnswer():false.ClientToProxyConnection.RespondCONNECTSuccessfulwrites the200 Connection establishedstraight to the client: no response filter sees it.servePlainHttpAfterConnect():false. With interception on, aCONNECTto a server that does not speak TLS is answered and relayed as it is (ProxyToServerConnection.initializeConnectionFlow, aftershouldRetryWithoutSsl); what the client sends then is only looked at for a TLS handshake (checkAndPerformTlsDetection).proxyProtocolDestination():ProxyProtocolDestination.SERVER_ADDRESS(ProxyToServerConnection.SendProxyProtocolHeader).tlsRetryWithoutSni():true.ProxyToServerConnection.connectionFailedconnects again without SNI after anunrecognized_namehandshake failure.requestHeadTimeout(): 30 seconds, MicroProxy's default protection against clients that trickle an HTTP/1 request head indefinitely.generatedResponses():GeneratedResponses.REPLACEABLE.ClientToProxyConnection.respondWithShortCircuitResponse, which writes the proxy's error responses (writeBadGateway,writeBadRequest,writeGatewayTimeout) and filters' short-circuit responses, runsproxyToClientResponseand writes the response it returns. (LittleProxy 1.x wrote the response it was given instead, which forks of it kept:GeneratedResponses.IN_PLACE.)mitmServerHandshake():MitmServerHandshake.EAGER.ProxyToServerConnection.initializeConnectionFlowruns the server'sEncryptChannelstep beforeRespondCONNECTSuccessful, so a server TLS failure answers theCONNECTwith502, after the next chained proxy was tried as for any connection failure (connectionFailed).
- Returns:
- LittleProxy's policy
-
preset
A preset policy by its configuration name:littleproxyforlittleProxy(),microproxyordefaultsfordefaults()(any case).- Parameters:
name- the preset's name- Returns:
- the preset
- Throws:
IllegalArgumentException- for any other name
-
builder
A builder for a policy for all protocols, HTTP/2 or HTTP/3; HTTP/1's is anHttp1PolicyBuilder.- Returns:
- an empty builder
-
resolveBeforeProxyToServerRequest
Whether the server's name is resolved beforeHttpFilters.proxyToServerRequest(org.microproxy.http.HttpObject)runs, so that a name that does not resolve is answered502without that hook being called (as LittleProxy does), rather than after it, so that the hook can answer or redirect the request without a DNS lookup (MicroProxy's default). Applies to direct connections; a request through a chained proxy is never resolved by the proxy.- Returns:
- the field's value, or empty when this policy leaves it unset
-
filterConnectAnswer
Whether the proxy's200 Connection establishedanswer to a client'sCONNECTgoes throughHttpFilters.serverToProxyResponse(org.microproxy.http.HttpObject)andHttpFilters.proxyToClientResponse(org.microproxy.http.HttpObject), so that filters can see it or turn it into a refusal (MicroProxy's default), rather than straight to the client (as LittleProxy writes it). Either way trackers are told (ActivityTracker.responseSentToClient(org.microproxy.FlowContext, org.microproxy.http.HttpResponse)), andHttpFilters.proxyToClientResponseSent(org.microproxy.http.HttpResponse, org.microproxy.ResponseSource)andHttpFilters.exchangeEnded(boolean)run. TheCONNECTs the proxy makes up itself (transparent TLS, SOCKS, raw TCP reverse proxying) always go through the filters.- Returns:
- the field's value, or empty when this policy leaves it unset
-
servePlainHttpAfterConnect
Whether plain HTTP that a client sends after aCONNECTthat could be intercepted (aws://WebSocket through the proxy, say) is served as HTTP, its requests going through the filters to theCONNECT's target (MicroProxy's default), rather than relayed to the target as raw bytes (as LittleProxy does).- Returns:
- the field's value, or empty when this policy leaves it unset
-
proxyProtocolDestination
Which address a PROXY protocol header the proxy sends to a server names as its destination (ProxyProtocolDestination).- Returns:
- the field's value, or empty when this policy leaves it unset
-
tlsRetryWithoutSni
Whether a TLS handshake with a server that rejects the server name the proxy sends with anunrecognized_namealert is tried once more without SNI (seeHttpProxyServerBootstrap.withTlsRetryWithoutSni(boolean)).- Returns:
- the field's value, or empty when this policy leaves it unset
-
requestHeadTimeout
How long an HTTP/1 request head may take, from its first byte to its end; zero disables the deadline. HTTP/2 and HTTP/3 ignore this field.- Returns:
- the field's value, or empty when this policy leaves it unset
-
generatedResponses
HowHttpFilters.proxyToClientResponse(org.microproxy.http.HttpObject)treats the responses the proxy answers with itself: its error responses and the short-circuit responses filters returned from earlier hooks (GeneratedResponses): it may replace them (GeneratedResponses.REPLACEABLE), change them in place only (GeneratedResponses.IN_PLACE), or never see them (GeneratedResponses.SKIP).- Returns:
- the field's value, or empty when this policy leaves it unset
-
mitmServerHandshake
When the proxy runs its TLS handshake with the server for an interceptedCONNECT: after answering it and reading the client's ClientHello, which it can then mirror (MitmServerHandshake.DEFERRED), or before answering, so that a failure answers theCONNECTitself (MitmServerHandshake.EAGER). A request's filters can choose for it (HttpFilters.proxyToServerMitmHandshake()). Transparent TLS connections, whose ClientHello the proxy has read before it routes them, and which get no answer in HTTP, are always deferred.- Returns:
- the field's value, or empty when this policy leaves it unset
-
allowChunkedLength
HTTP/1 only: whether an HTTP/1.1 request with bothTransfer-EncodingandContent-Lengthis accepted (seeHttpProxyServerBootstrap.withAllowChunkedLength(boolean)). Set withHttp1PolicyBuilder.allowChunkedLength(boolean); a policy for other protocols ignores it.- Returns:
- the field's value, or empty when this policy leaves it unset
-
orElse
This policy with the fields it leaves unset taken fromfallback.- Parameters:
fallback- the policy whose fields fill this one's gaps- Returns:
- the merged policy
-
equals
-
hashCode
public int hashCode() -
toString
Returns the fields this policy sets, by their configuration names, such asProtocolPolicy[tls_retry_without_sni=true]. -
configurationNames
The configuration namesProtocolPolicy.Builder.set(java.lang.String, java.lang.String)takes,presetfirst;Http1PolicyBuilder.set(java.lang.String, java.lang.String)takesallow_chunked_lengthtoo.- Returns:
- the names, in a fixed order
-