Class ProxyServer
Translates an HTTP/1.1 client connection onto an h2-only origin (Http2
with AllowHttpProtocolTranslation enabled - see ResolveHttp2ForClientAsync(SessionEventArgsBase, bool, string, int, string, int?, UpstreamHttpProtocol, bool, bool, CancellationToken, bool)), leasing
one h2 stream per HTTP/1.1 request from a shared Titanium.Web.Proxy.Http2.Http2OriginConnection via
Titanium.Web.Proxy.ProxyServer.Http2OriginConnectionPool rather than opening a new TCP/TLS connection for every request.
Implements
Inherited Members
Namespace: Titanium.Web.Proxy
Assembly: Titanium.Web.Proxy.dll
Syntax
public class ProxyServer : IDisposable
Remarks
This re-implements the HTTP/1.1 client read loop (request line, headers, BeforeRequest,
authorization, header preparation, CancelRequest/replaced-response handling) rather than reusing
the private HandleHttpSessionRequest/HandleHttpSessionResponse methods, because those
methods send/receive over TcpServerConnection.Stream using the raw HTTP/1.1 wire format, which an
h2 origin connection cannot speak. This mirrors the precedent set by the h2-to-HTTP/1.1 bridge
(Http2ToHttp11BridgeHandler), which similarly bypasses the wire-format-specific machinery for the
leg that does not match it.
Origin connections are multiplexed across independent HTTP/1.1 clients through Titanium.Web.Proxy.ProxyServer.Http2OriginConnectionPool (fan-in share). Response bodies are delivered via Titanium.Web.Proxy.Http2.Http2OriginConnection streaming writers where available.
Constructors
| Edit this page View SourceProxyServer(bool, bool, bool)
Initializes a new instance of ProxyServer class with provided parameters.
Declaration
public ProxyServer(bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false)
Parameters
| Type | Name | Description |
|---|---|---|
| bool | userTrustRootCertificate | When true (the default), EnsureRootCertificate() installs the MITM root into the current-user Personal and Trusted Root stores. Prefer user-only trust for interactive apps; pass false when trust must be fully opt-in. |
| bool | machineTrustRootCertificate | When true, also trust in the local-machine stores (needs elevation). Defaults to false — machine trust is opt-in for services/admin installs, not for normal desktop use. |
| bool | trustRootCertificateAsAdmin | When true, attempt elevated trust via UAC (Windows only). Defaults to false. |
ProxyServer(string?, string?, bool, bool, bool)
Initializes a new instance of ProxyServer class with provided parameters.
Declaration
public ProxyServer(string? rootCertificateName, string? rootCertificateIssuerName, bool userTrustRootCertificate = true, bool machineTrustRootCertificate = false, bool trustRootCertificateAsAdmin = false)
Parameters
| Type | Name | Description |
|---|---|---|
| string | rootCertificateName | Name of the root certificate. |
| string | rootCertificateIssuerName | Name of the root certificate issuer. |
| bool | userTrustRootCertificate | When true (the default), EnsureRootCertificate() installs the MITM root into the current-user Personal and Trusted Root stores. Prefer user-only trust for interactive apps; pass false when trust must be fully opt-in. |
| bool | machineTrustRootCertificate | When true, also trust in the local-machine stores (needs elevation). Defaults to false — machine trust is opt-in for services/admin installs, not for normal desktop use. |
| bool | trustRootCertificateAsAdmin | When true, attempt elevated trust via UAC (Windows only). Defaults to false. |
Properties
| Edit this page View SourceAdmittedClientConnectionCount
Number of client connections currently admitted (accepted and past the admission gate, not yet finished being handled), across all TCP-based endpoints. Unlike ClientConnectionCount, this drops to zero as soon as the handler returns, without the trailing TIME_WAIT delay.
Declaration
public int AdmittedClientConnectionCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
BlockPrivateNetworkDestinations
Outbound destination policy hook: when true, every resolved destination IP address is checked against loopback, private (RFC 1918/4193), link-local (which subsumes the 169.254.169.254 cloud metadata endpoint), and other non-globally-routable ranges before connecting, and the connection attempt is rejected with an OutboundDestinationBlockedException if it matches.
Off by default: blocking private destinations would break this library's most common
configurations, including upstream-proxy chaining to localhost and interception of
local development servers. Only enable this when the proxy accepts requests from
untrusted clients (an SSRF-relevant deployment), where those same destinations become an
attacker-reachable pivot into the host's private network instead of an operator's own
intentional configuration.
An explicitly configured upstream proxy address (UpStreamHttpProxy,
UpStreamHttpsProxy, or a per-session external proxy) is always exempt -
that address is operator intent, not attacker-controlled. Checked against the resolved
address actually used to connect (no re-resolution afterward, which would make the check
a TOCTOU no-op against DNS rebinding). Not currently enforced for a SOCKS upstream with
ProxyDnsRequests enabled, since the proxy never resolves the origin itself in that
mode and has no address of its own to validate.
Declaration
public bool BlockPrivateNetworkDestinations { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
BufferPool
The buffer pool used throughout this proxy instance. Set custom implementations by implementing this interface. By default this uses DefaultBufferPool implementation available in StreamExtended library package. Buffer size should be at least 10 bytes.
Declaration
public IBufferPool BufferPool { get; set; }
Property Value
| Type | Description |
|---|---|
| IBufferPool |
CertificateManager
Manages certificates used by this proxy.
Declaration
public CertificateManager CertificateManager { get; }
Property Value
| Type | Description |
|---|---|
| CertificateManager |
CheckCertificateRevocation
Should we check for certificate revocation during SSL authentication to servers Note: If enabled can reduce performance. Defaults to false.
Declaration
public X509RevocationMode CheckCertificateRevocation { get; set; }
Property Value
| Type | Description |
|---|---|
| X509RevocationMode |
ClientConnectionCount
Total number of active TCP client connections. Does not include inbound HTTP/3 (QUIC) clients; see Http3ClientConnectionCount.
Declaration
public int ClientConnectionCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
ClientHeaderTimeoutSeconds
Seconds to wait for a client to finish sending the request line and headers, from the moment
this proxy starts reading a new request on the connection. Enforced with a linked
CancellationTokenSource around the request-line and header
read, not Socket.ReceiveTimeout: that property only bounds a single blocking
Receive call, not the asynchronous reads this proxy actually issues, so without this
deadline a client that opens a connection and trickles bytes arbitrarily slowly (or stops
sending entirely) after the first byte ties up a read loop indefinitely.
Default is 0 (disabled), matching every other deadline in this class - no per-session
override exists because there is no SessionEventArgs for this
request yet at the point this deadline applies.
Declaration
public int ClientHeaderTimeoutSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
CompatibilityMode100Continue
When true, the proxy immediately responds with a synthetic
100 Continue to any client request carrying Expect: 100-continue,
before forwarding the headers to the origin and without waiting for the origin
to respond. This breaks the strict handshake (client → proxy 100 → client body
→ origin body) but prevents the deadlock that occurs with strict clients when
Enable100ContinueBehaviour is false (the default).
Has no effect when Enable100ContinueBehaviour is true.
Default: false.
Declaration
public bool CompatibilityMode100Continue { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
ConnectTimeOutSeconds
Seconds server connection are to wait for connection to be established. Default value is 20 seconds.
Declaration
public int ConnectTimeOutSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
ConnectionTimeOutSeconds
Seconds client/server connection are to be kept alive when waiting for read/write to complete. This will also determine the pool eviction time when connection pool is enabled. Default value is 60 seconds.
Declaration
public int ConnectionTimeOutSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
CustomUpStreamProxyFailureFunc
A callback to provide a chance for an upstream proxy failure to be handled by a new upstream proxy. User should return the ExternalProxy object with valid credentials or null.
Declaration
public Func<SessionEventArgsBase, Task<IExternalProxy?>>? CustomUpStreamProxyFailureFunc { get; set; }
Property Value
| Type | Description |
|---|---|
| Func<SessionEventArgsBase, Task<IExternalProxy>> |
DnsServerEndPoint
DNS server endpoint used by Titanium.Web.Proxy.Http3.Dns.UdpSvcbDnsResolver for HTTPS/SVCB queries. Defaults to the first usable OS-configured plain-UDP DNS server discovered via NetworkInterface. This is a best-effort default and does not honor Windows NRPT, DoH, or VPN split-DNS policy.
When no OS-configured DNS server can be discovered, the property reports
0.0.0.0:0 and proactive SVCB discovery is skipped (never falls back to a public
third-party resolver). Assign an explicit endpoint to override discovery.
Declaration
[Experimental("TWP001")]
public IPEndPoint DnsServerEndPoint { get; set; }
Property Value
| Type | Description |
|---|---|
| IPEndPoint |
Enable100ContinueBehaviour
Does this proxy uses the HTTP protocol 100 continue behaviour strictly? Broken 100 continue implementations on server/client may cause problems if enabled. Defaults to false.
Declaration
public bool Enable100ContinueBehaviour { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableConnectionPool
Should we enable the server connection pool. Defaults to true. When connection pooling is enabled, instead of creating a new TCP connection to the server for each client TCP connection, we check if an idle server connection is available in our cached pool. If a compatible connection (same destination, scheme, upstream proxy, credentials and negotiated protocol) created from an earlier request is available, we reuse it. Only connections that are safe to reuse under the HTTP protocol are pooled: the response body must be fully received and the connection must be persistent (HTTP/1.1 keep-alive, or an HTTP/1.0 connection that explicitly opted in via "Connection: keep-alive"). Connections whose response asked to close, that failed, or that carry connection-oriented authentication state (WinAuth NTLM/Negotiate) or a per-session client certificate are never returned to the shared pool. The ConnectionTimeOutSeconds parameter determines the eviction time for inactive server connections. This reduces TCP (and TLS) connection establishment cost, both in wall clock time and CPU cycles. Set to false to force a fresh server connection for every client connection.
Declaration
public bool EnableConnectionPool { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableHttp2
Enable disable HTTP/2 support.
Client-facing HTTP/2 is negotiated via TLS ALPN, or as prior-knowledge cleartext h2c on a
transparent reverse endpoint (DecryptSsl: false). No Upgrade: h2c.
Origin-facing HTTP/2 uses TLS ALPN h2 by default; with
ForwardCleartext and
Http2, the origin speaks cleartext HTTP/2
prior-knowledge (outbound h2c).
A client/server that does not support HTTP/2 transparently falls back to HTTP/1.1 when policy allows.
Request/response header and body modification in BeforeRequest/BeforeResponse, chunked trailers,
interim (1xx) responses, and the synthetic-response APIs (Ok/Respond/Redirect/GenericResponse/
RespondStreaming) are all supported over HTTP/2, the same as over HTTP/1.x.
Not supported: HTTP/2 server push (the wire frames are transcoded but there is no public API to
originate a push) and Upgrade: h2c. Explicit-proxy inbound h2c is not implemented.
See the protocol support matrix on the wiki for exact, up-to-date HTTP/1.x/HTTP/2 feature coverage.
Declaration
public bool EnableHttp2 { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableHttp3
Enable HTTP/3 (QUIC) support. When true:
-
Any
TransparentQuicProxyEndPointis started as a UDP-only QUIC listener for transparent/NAT HTTP/3 interception. -
Any
TransparentProxyEndPointwithEnableHttp3also listens for HTTP/3 on the same IP:port (TCP H1/H2 + UDP H3) and injects client-facingAlt-Svc. - With Auto (default), a cached Alt-Svc / HTTPS/SVCB capability only arms background QUIC warm-up. Outbound HTTP/3 is used once that origin is warm; until then the request stays on HTTP/2 or HTTP/1.1. Forced Http3 skips warm-up gating and fails closed with no TCP fallback.
Requires MsQuic native library and a supported operating-system version (IsSupported). Setting to true with no inbound HTTP/3 endpoint configured emits a warning and skips QUIC initialization. Default: false (opt-in).
Experimental: HTTP/3 support has not yet completed the full interop/soak/fuzz gate
process. Suppress TWP001 to opt in; the attribute is removed when the feature
graduates to stable.
Declaration
[Experimental("TWP001")]
public bool EnableHttp3 { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableHttpInterception
Forces the full interception path (SessionEventArgs, BeforeRequest, etc.) even when no event handlers are subscribed. Set this when consuming SessionEventArgs for timing or metrics without subscribing to any event. Default: false.
Declaration
public bool EnableHttpInterception { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableHttpsSvcbDnsDiscovery
When true, the proxy queues a background HTTPS/SVCB RR (DNS type 65) lookup
after an Auto-mode capability-cache miss. A positive result (ALPN h3 found) warms
Titanium.Web.Proxy.Http3.Http3OriginCapabilityCache for subsequent connections; the CONNECT /
request path itself never awaits DNS. Negative results are cached for 1 minute; transient
failures use a short backoff.
Defaults to true whenever EnableHttp3 is
true. Set explicitly to false to disable discovery
even when HTTP/3 is enabled — for example, when the configured DNS server is untrusted
or unreachable. First-connection HTTP/3 adoption then comes from Alt-Svc.
Declaration
[Experimental("TWP001")]
public bool EnableHttpsSvcbDnsDiscovery { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableIpv6UnreachableSoftSkip
When true (default), after one IPv6 connect failure with NetworkUnreachable (or equivalent), temporarily omit IPv6 addresses from the Happy Eyeballs race for 30 seconds. Reduces first-chance SocketException noise on dual-stack hosts with a broken IPv6 path. Disable if operators require strict IPv6 preference even when the path is unreachable.
Declaration
public bool EnableIpv6UnreachableSoftSkip { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableQpackDynamicTable
When true, enables RFC 9204 QPACK dynamic table encoding and decoding for inbound HTTP/3 connections. Each connection gets its own Titanium.Web.Proxy.Http3.Qpack.QpackContext with two independent 4096-byte tables (one inbound, one outbound). Defaults to false (static-table-only); existing deployments are unaffected.
Declaration
[Experimental("TWP001")]
public bool EnableQpackDynamicTable { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableRequestTimingCapture
Enables structured request/connection timing capture. When false (the default) no timing objects are allocated and no UtcNow calls are made for timing purposes anywhere in the proxy, so there is zero overhead on the hot path.
When enabled, every SessionEventArgsBase exposes a populated
Timing (per-request phases: client header read,
connection wait, request send, time-to-first-byte, response delivery, total), every
upstream connection exposes a populated UpstreamConnectionTiming (reachable from a
session via UpstreamConnectionTiming, describing DNS,
TCP connect, optional upstream-proxy CONNECT, and TLS handshake durations), and a decrypted
TunnelConnectSessionEventArgs exposes the client-facing TLS
handshake duration via ClientTlsTiming.
Can be toggled at any time; it only affects sessions/connections created after the change, never mutating timing objects already handed out. Defaults to false.
Declaration
public bool EnableRequestTimingCapture { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableRfc8441
When true, the proxy enables RFC 8441 WebSocket-over-HTTP/2:
-
Accepts extended CONNECT (
:protocol = websocket) from h2 clients and advertisesSETTINGS_ENABLE_CONNECT_PROTOCOL=1to them. Per origin: if the origin is HTTP/2 and advertises RFC 8441 support, DATA frames are relayed directly; if the origin is HTTP/2 and does not, the stream is reset withREFUSED_STREAM; if the origin is HTTP/1.1, the h2→h1 WebSocket upgrade bridge is used. -
On the HTTP/1.1-client-to-h2-origin translation bridge, translates
Upgrade: websocketinto extended CONNECT when the origin advertises the setting; otherwise falls back to a dedicated HTTP/1.1 origin connection for that WebSocket. When this property is false, that bridge still returns synthetic501 Not Implementedfor WebSocket upgrades (historical default).
Default: false (must opt-in).
Declaration
public bool EnableRfc8441 { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableTcpKeepAlive
Enable TCP KeepAlive on client and server sockets so NAT/firewall mappings for long-lived CONNECT tunnels are refreshed. Default: true.
Declaration
public bool EnableTcpKeepAlive { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableTcpServerConnectionPrefetch
Should we enable tcp server connection prefetching? When enabled, as soon as we receive a client connection we concurrently initiate corresponding server connection process using CONNECT hostname or SNI hostname on a separate task so that after parsing client request we will have the server connection immediately ready or in the process of getting ready. If a server connection is available in cache then this prefetch task will immediately return with the available connection from cache. Defaults to true.
Declaration
public bool EnableTcpServerConnectionPrefetch { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EnableWinAuth
Enable disable Windows Authentication (NTLM/Kerberos). By default SSPI uses the process identity. To authenticate as another user, set WinAuthCredentialsProvider (issue #461). Defaults to false.
Declaration
public bool EnableWinAuth { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
EndpointAdmissionRejectionCount
Total number of client connections rejected by any endpoint's MaxConcurrentClients since this instance was created.
Declaration
public long EndpointAdmissionRejectionCount { get; }
Property Value
| Type | Description |
|---|---|
| long |
ForwardToUpstreamGateway
Gets or sets a value indicating whether requests will be chained to upstream gateway. Defaults to false.
Declaration
public bool ForwardToUpstreamGateway { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
GetCustomUpStreamProxyFunc
A callback to provide authentication credentials for up stream proxy this proxy is using for HTTP(S) requests. User should return the ExternalProxy object with valid credentials.
Declaration
public Func<SessionEventArgsBase, Task<IExternalProxy?>>? GetCustomUpStreamProxyFunc { get; set; }
Property Value
| Type | Description |
|---|---|
| Func<SessionEventArgsBase, Task<IExternalProxy>> |
GlobalAdmissionRejectionCount
Total number of client connections rejected by MaxConcurrentClientConnections since this instance was created.
Declaration
public long GlobalAdmissionRejectionCount { get; }
Property Value
| Type | Description |
|---|---|
| long |
Http3ClientConnectionCount
Total number of active inbound HTTP/3 (QUIC) client connections.
Declaration
public int Http3ClientConnectionCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
Http3ServerConnectionCount
Total number of active upstream HTTP/3 (QUIC) server connections. These are also included in ServerConnectionCount.
Declaration
public int Http3ServerConnectionCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
IdleReadTimeoutSeconds
Seconds of idle time allowed while reading from the origin (stalled header/body waits).
Applied via CancelAfter on the active read operation. Default is 0 (disabled).
Per-session override: IdleReadTimeout.
Declaration
public int IdleReadTimeoutSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
IdleWriteTimeoutSeconds
Seconds of idle time allowed while writing to the origin (stalled header/body waits).
Applied via CancelAfter on the active write operation. Default is 0 (disabled).
Per-session override: IdleWriteTimeout.
Declaration
public int IdleWriteTimeoutSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
ListenerBackLog
TCP listener accept backlog. Default: 1024 for burst connection handling.
Declaration
public int ListenerBackLog { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
Logger
The live, shared logger used throughout this proxy instance. Reflects the most recent call to ApplyLoggingConfiguration().
Declaration
public ILogger Logger { get; }
Property Value
| Type | Description |
|---|---|
| ILogger |
Logging
Configuration for this proxy instance's built-in diagnostic logging - the replacement for the
removed ExceptionFunc callback. Every exception the proxy catches (even when handled
internally and never surfaced to user code) is reported through this logger at an appropriate
severity; see ProxyLoggingOptions for the console/file sinks, enable/disable
switch, and minimum level.
Mutate the returned instance (or assign a new one) at any point; each assignment/mutation you
want to take effect must be followed by ApplyLoggingConfiguration() (which
Start(bool) also calls automatically, so the configuration active at the moment the
proxy starts running is picked up for the run even if you never call it yourself). Calling it
again later - including while the proxy is already running - immediately swaps in the new
configuration; this is safe because logging never blocks or otherwise affects proxy traffic.
Declaration
public ProxyLoggingOptions Logging { get; set; }
Property Value
| Type | Description |
|---|---|
| ProxyLoggingOptions |
MaxBufferedBodyBytes
Maximum bytes the proxy will buffer for a single request or response body when body buffering is required (body-read hooks, authentication retry, etc.). Bodies larger than this limit are rejected with 413 (upstream request) or connection teardown (upstream response). Set to 0 to disable the limit (not recommended). Default: 4,194,304 (4 MiB).
Declaration
public int MaxBufferedBodyBytes { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
MaxCachedConnections
Maximum number of concurrent connections per remote host in cache. Only meaningful when EnableConnectionPool is true; to disable pooling, set EnableConnectionPool to false rather than setting this to 0 - the pool eviction loop treats a value below 1 as "evict without limit while holding the pool-wide lock", which spins indefinitely once the cache for that host is empty and would stall every other connection acquire/release in the process. Rejected outright at assignment so that state cannot be reached. Default value is 128.
Declaration
public int MaxCachedConnections { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | The assigned value is less than 1. |
MaxConcurrentClientConnections
Maximum number of client connections admitted across all TCP-based endpoints at once. null (the default) disables the global admission gate, preserving today's unbounded behavior. When set, a connection beyond this limit is rejected and disposed immediately after accept, before a handler task is even started.
Enforced independently of ClientConnectionCount: see Titanium.Web.Proxy.ProxyServer.admittedClientConnectionCount for why. See also MaxConcurrentClients for a per-endpoint cap layered on top of this global one.
Declaration
public int? MaxConcurrentClientConnections { get; set; }
Property Value
| Type | Description |
|---|---|
| int? |
MaxConcurrentHttp11HttpsOriginCreates
Caps concurrent new HTTPS origin TCP/TLS opens on the H2→H1 bridge only
(MITM / re-encrypt). Pool hits (warm keep-alive) are uncapped. Cleartext H1 origins
are not gated. Default is Clamp(ProcessorCount, 4, 32). Set before the first
H2→H1 HTTPS origin open (typically before Start(bool)); changing the value
after the create gate has been used has no effect on the live semaphore.
Declaration
public int MaxConcurrentHttp11HttpsOriginCreates { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
Exceptions
| Type | Condition |
|---|---|
| ArgumentOutOfRangeException | The assigned value is less than 1. |
MaxDecodedHeaderListBytes
Maximum decoded HTTP/2 header list size in bytes, using RFC 7541 accounting (name.Length + value.Length + 32 per field). Requests or responses with a decoded header list exceeding this limit will be refused with RST_STREAM(ENHANCE_YOUR_CALM) (code 0xb). Set to 0 to disable the limit (not recommended). Default: 65,536 (64 KiB). Advertised via SETTINGS_MAX_HEADER_LIST_SIZE.
Declaration
public int MaxDecodedHeaderListBytes { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
MaxWebSocketFramePayloadBytes
Maximum WebSocket frame payload size in bytes that the proxy will accept during
frame-level interception (i.e. when BeforeWebSocketFrame has at least one
subscriber). Frames whose decoded payload exceeds this limit cause the WebSocket
connection to be closed with Close code 1009 (Message Too Big).
Raw-relay sessions (no BeforeWebSocketFrame subscriber) bypass this check
entirely and pass all frames through unvalidated.
Default: 16,777,216 (16 MiB).
Declaration
public int MaxWebSocketFramePayloadBytes { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
NetworkFailureRetryAttempts
Number of times to retry upon network failures when connection pool is enabled.
Declaration
public int NetworkFailureRetryAttempts { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
NoDelay
Gets or sets a Boolean value that specifies whether server and client stream Sockets are using the Nagle algorithm. Defaults to true, no nagle algorithm is used.
Declaration
public bool NoDelay { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
OriginHttpVersionPolicy
Controls which HTTP version is declared to the origin server on the request line, independently of the version the client declared to the proxy. Defaults to PreserveClientVersion, which matches the proxy's historical pass-through behavior exactly. Set to NormalizeToHttp11 to let HTTP/1.0 clients share pooled, persistent origin connections the same way HTTP/1.1 clients already do. This only changes the wire version written to the origin request line - it never changes the client-facing Http.Request.HttpVersion that event handlers observe, nor the version/persistence used to write the response back to the client.
Declaration
public OriginHttpVersionPolicy OriginHttpVersionPolicy { get; set; }
Property Value
| Type | Description |
|---|---|
| OriginHttpVersionPolicy |
PolicyModes
Which resource-bound PolicyFamily is enforced, observed, or disabled, per the plan's rollout section. Read live by each family's enforcement call site - not baked into a per-request snapshot at connection accept time - so assigning a new value here (a whole-object replacement, never a mutation of the previous instance) takes effect for the next check any in-flight or new request makes, without restarting the proxy. This is the "runtime switch to drop to Observe without redeploying" the plan requires; see WithAllObservedExceptDisabled() for the one-call way to do that.
Defaults to AllEnforce, matching Balanced. Assigning Profile also replaces this value with that profile's bundle; assign PolicyModes afterward to deviate from the selected profile's modes without changing anything else the profile set.
Declaration
public ProxyPolicyModes PolicyModes { get; set; }
Property Value
| Type | Description |
|---|---|
| ProxyPolicyModes |
Profile
The last profile applied via this property's setter, defaulting to
Balanced - the profile every field on this instance already
starts at, so a fresh new ProxyServer() reports Balanced
without needing its setter to run once at construction time.
Assigning this property applies its entire ProxyProfileSettings bundle - ResourceLimits, PolicyModes, SupportedSslProtocols, BlockPrivateNetworkDestinations, MaxConcurrentClientConnections and the deadline-seconds properties - as a single atomic assignment, so a reader can never observe a half-applied profile. Assigning any of those properties individually afterward overrides just that one, without reverting the rest of the profile's bundle.
Logged once per Start(bool) call, by name only - never with hosts, URLs or secrets, per the plan's rollout section.
Declaration
public ProxyProfile Profile { get; set; }
Property Value
| Type | Description |
|---|---|
| ProxyProfile |
ProxyAuthenticationRealm
Realm used during Proxy Basic Authentication.
Declaration
public string ProxyAuthenticationRealm { get; set; }
Property Value
| Type | Description |
|---|---|
| string |
ProxyAuthenticationSchemes
A collection of scheme types, e.g. basic, NTLM, Kerberos, Negotiate, to return if scheme authentication is required. Works in relation with ProxySchemeAuthenticateFunc.
Declaration
public IEnumerable<string> ProxyAuthenticationSchemes { get; set; }
Property Value
| Type | Description |
|---|---|
| IEnumerable<string> |
ProxyBasicAuthenticateFunc
A callback to authenticate proxy clients via basic authentication. Parameters are username and password as provided by client. Should return true for successful authentication.
Declaration
public Func<SessionEventArgsBase?, string, string, Task<bool>>? ProxyBasicAuthenticateFunc { get; set; }
Property Value
| Type | Description |
|---|---|
| Func<SessionEventArgsBase, string, string, Task<bool>> |
ProxyEndPoints
A list of IpAddress and port this proxy is listening to.
Declaration
public List<ProxyEndPoint> ProxyEndPoints { get; set; }
Property Value
| Type | Description |
|---|---|
| List<ProxyEndPoint> |
ProxyRunning
Is the proxy currently running?
Declaration
public bool ProxyRunning { get; }
Property Value
| Type | Description |
|---|---|
| bool |
ProxySchemeAuthenticateFunc
A pluggable callback to authenticate clients by scheme instead of requiring basic authentication through ProxyBasicAuthenticateFunc. Parameters are current working session, schemeType, and token as provided by a calling client. Should return success for successful authentication, continuation if the package requests, or failure.
Declaration
public Func<SessionEventArgsBase, string, string, Task<ProxyAuthenticationContext>>? ProxySchemeAuthenticateFunc { get; set; }
Property Value
| Type | Description |
|---|---|
| Func<SessionEventArgsBase, string, string, Task<ProxyAuthenticationContext>> |
RequestTimeoutSeconds
Total seconds allowed for a single request/response exchange after BeforeRequest returns (connect, send, wait for headers, and body copy). Default is 0 (disabled). Per-session override: RequestTimeout.
Declaration
public int RequestTimeoutSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
ResourceLimits
The shared, immutable resource-bound snapshot (concurrent-stream cap, CONTINUATION
frame-count/wall-clock bounds, peer-initiated incomplete-stream-reset budget, and the
other limits described in ProxyResourceLimits) consulted by the HTTP/2
relay so a single proxy-owned value governs both what is enforced and what is advertised
to each peer, rather than admitting purely against whatever the origin advertised.
Assign a new ProxyResourceLimits (constructed via
Create(long, int, long, long?, long?, double?, int?, int, int?, int, TimeSpan, bool, int, int?)) to override the Default
snapshot. There is no artificial upper clamp: high-CPU/RAM hosts may pass larger
maxCachedConnectionsPerHost, maxConcurrentStreamsPerConnection, etc. as needed.
The live TCP pool depth knob MaxCachedConnections remains independently settable
and should usually be kept in sync with MaxCachedConnectionsPerHost.
Declaration
public ProxyResourceLimits ResourceLimits { get; set; }
Property Value
| Type | Description |
|---|---|
| ProxyResourceLimits |
ResponseHeaderTimeoutSeconds
Seconds to wait for the origin to send the response status line and headers after the request has been sent. Enforced with a linked CancellationTokenSource (not Socket receive timeout alone). When the deadline elapses a ProxyTimeoutException with ResponseHeader is raised (and may be converted to HTTP 504 before any response bytes have been committed to the client). Default is 0 (disabled). WebSocket upgrades, Server-Sent Events, raw tunnels, and sessions that already wrote a response status to the client are exempt; those waits use IdleReadTimeoutSeconds when configured. Per-session override: ResponseHeaderTimeout.
Declaration
public int ResponseHeaderTimeoutSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
ReuseSocket
When true (default), SO_REUSEADDR is requested where Titanium.Web.Proxy.Helpers.RunTime.IsSocketReuseAvailable() reports support (always on Windows; on non-Windows, .NET Core 3+ / compatible runtimes).
Declaration
public bool ReuseSocket { get; set; }
Property Value
| Type | Description |
|---|---|
| bool |
ServerConnectionCount
Total number of active server connections (TCP plus upstream QUIC). For HTTP/3-only upstreams see Http3ServerConnectionCount.
Declaration
public int ServerConnectionCount { get; }
Property Value
| Type | Description |
|---|---|
| int |
ShouldInterceptHttp
Optional per-request/stream predicate consulted only when the global interception gate is active. Return true to use the full SessionEventArgs path; return false to use the fast-forward path. null (the default) intercepts every request — preserving today's behavior.
Declaration
public Func<HttpInterceptionContext, bool>? ShouldInterceptHttp { get; set; }
Property Value
| Type | Description |
|---|---|
| Func<HttpInterceptionContext, bool> |
SupportedServerSslProtocols
List of supported Server Ssl versions. Using SslProtocol.None means to require the same SSL protocol as the proxy client.
Declaration
public SslProtocols SupportedServerSslProtocols { get; set; }
Property Value
| Type | Description |
|---|---|
| SslProtocols |
SupportedSslProtocols
List of supported Ssl versions.
Defaults to TLS 1.2/1.3 only as of 5.0 - a breaking change from 4.x, which also enabled
SSL 3.0/TLS 1.0/1.1. Those legacy, broken-by-design protocols require an explicit opt-in
by assigning this property directly (e.g. SslProtocols.Tls | SslProtocols.Tls11 |
SslProtocols.Tls12 | SslProtocols.Tls13) if a legacy client/server genuinely requires
them.
Declaration
public SslProtocols SupportedSslProtocols { get; set; }
Property Value
| Type | Description |
|---|---|
| SslProtocols |
TcpTimeWaitSeconds
SO_LINGER timeout in seconds applied to client and upstream sockets via
LingerOption (enabled with this timeout).
This is not the kernel TCP TIME_WAIT duration — TIME_WAIT is controlled by the OS.
A positive value means Close may block up to that many seconds flushing send buffers;
use 0 for an abortive close (RST). Default is 0 so high-churn proxies avoid TIME_WAIT
accumulation; the 1-second connection disposal delay already prefers peer-first close.
Declaration
public int TcpTimeWaitSeconds { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
ThreadPoolWorkerThread
Customize the minimum ThreadPool size (increase it on a server).
Defaults to max(ProcessorCount * 2, 16) so short loopback/proxy workloads are not
starved while the pool is still ramping workers.
Declaration
public int ThreadPoolWorkerThread { get; set; }
Property Value
| Type | Description |
|---|---|
| int |
UpStreamEndPoint
Local adapter/NIC endpoint where proxy makes request via. Defaults via any IP addresses of this machine. When the resolved destination address family does not match this endpoint, it is ignored so dual-stack destinations can still connect (see UpStreamEndPointIPv4 / UpStreamEndPointIPv6).
Declaration
public IPEndPoint? UpStreamEndPoint { get; set; }
Property Value
| Type | Description |
|---|---|
| IPEndPoint |
UpStreamEndPointIPv4
Local bind endpoint used when the resolved upstream destination is IPv4. Takes precedence over UpStreamEndPoint for IPv4 destinations.
Declaration
public IPEndPoint? UpStreamEndPointIPv4 { get; set; }
Property Value
| Type | Description |
|---|---|
| IPEndPoint |
UpStreamEndPointIPv6
Local bind endpoint used when the resolved upstream destination is IPv6. Takes precedence over UpStreamEndPoint for IPv6 destinations.
Declaration
public IPEndPoint? UpStreamEndPointIPv6 { get; set; }
Property Value
| Type | Description |
|---|---|
| IPEndPoint |
UpStreamHttpProxy
External proxy used for Http requests.
Declaration
public IExternalProxy? UpStreamHttpProxy { get; set; }
Property Value
| Type | Description |
|---|---|
| IExternalProxy |
UpStreamHttpsProxy
External proxy used for Https requests.
Declaration
public IExternalProxy? UpStreamHttpsProxy { get; set; }
Property Value
| Type | Description |
|---|---|
| IExternalProxy |
UpstreamProxyConfigurationScript
If set, the upstream proxy will be detected by a script that will be loaded from the provided Uri
Declaration
public Uri? UpstreamProxyConfigurationScript { get; set; }
Property Value
| Type | Description |
|---|---|
| Uri |
ViaHeaderPseudonym
Pseudonym used in Via header fields appended to forwarded requests and responses
(RFC 9110 §7.6.3). Defaults to "titanium-web-proxy". Set to an empty string
to disable Via header injection entirely. Loop detection uses this value: a request
arriving with this pseudonym already present in Via is refused with 508 Loop Detected.
Declaration
public string ViaHeaderPseudonym { get; set; }
Property Value
| Type | Description |
|---|---|
| string |
WinAuthCredentialsProvider
Optional per-session credential provider for server 401 WinAuth (NTLM/Negotiate/Kerberos). Return null to use the current process identity (legacy behavior). Do not put plaintext passwords on SessionEventArgs — use this callback instead. Windows SSPI only; ignored on non-Windows platforms.
Declaration
public Func<SessionEventArgs, Task<WinAuthCredentials?>>? WinAuthCredentialsProvider { get; set; }
Property Value
| Type | Description |
|---|---|
| Func<SessionEventArgs, Task<WinAuthCredentials>> |
Methods
| Edit this page View SourceAddEndPoint(ProxyEndPoint)
Add a proxy end point.
Declaration
public void AddEndPoint(ProxyEndPoint endPoint)
Parameters
| Type | Name | Description |
|---|---|---|
| ProxyEndPoint | endPoint | The proxy endpoint. |
ApplyLoggingConfiguration()
Rebuilds the active logger/logger factory from the current Logging configuration, disposing any previously owned built-in providers. Called automatically from the constructor (with the default configuration) and from Start(bool). Call this explicitly any time after changing Logging and you want the change to take effect immediately - whether the proxy is stopped (e.g. before using CertificateManager directly) or already running.
Declaration
public void ApplyLoggingConfiguration()
DisableAllSystemProxies()
Clear all proxy settings for current machine.
Declaration
public void DisableAllSystemProxies()
DisableSystemHttpProxy()
Clear HTTP proxy settings of current machine.
Declaration
public void DisableSystemHttpProxy()
DisableSystemHttpsProxy()
Clear HTTPS proxy settings of current machine.
Declaration
public void DisableSystemHttpsProxy()
DisableSystemProxy(ProxyProtocolType)
Clear the specified proxy setting for current machine.
Declaration
public void DisableSystemProxy(ProxyProtocolType protocolType)
Parameters
| Type | Name | Description |
|---|---|---|
| ProxyProtocolType | protocolType |
Dispose()
Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
Declaration
public void Dispose()
Dispose(bool)
Declaration
[SuppressMessage("ApiDesign", "RS0016:Add public types and members to the declared API", Justification = "Protected Dispose(bool) is required by the standard IDisposable pattern but is not public API.")]
protected virtual void Dispose(bool disposing)
Parameters
| Type | Name | Description |
|---|---|---|
| bool | disposing |
RemoveEndPoint(ProxyEndPoint)
Remove a proxy end point. Will throw error if the end point doesn't exist.
Declaration
public void RemoveEndPoint(ProxyEndPoint endPoint)
Parameters
| Type | Name | Description |
|---|---|---|
| ProxyEndPoint | endPoint | The existing endpoint to remove. |
RestoreOriginalProxySettings()
Restores the original proxy settings.
Declaration
public void RestoreOriginalProxySettings()
SetAsSystemHttpProxy(ExplicitProxyEndPoint)
Set the given explicit end point as the default proxy server for current machine.
Declaration
public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint)
Parameters
| Type | Name | Description |
|---|---|---|
| ExplicitProxyEndPoint | endPoint | The explicit endpoint. |
SetAsSystemHttpProxy(ExplicitProxyEndPoint, SystemProxySettings)
Set the given explicit end point as the default HTTP proxy server for current machine.
Declaration
public void SetAsSystemHttpProxy(ExplicitProxyEndPoint endPoint, SystemProxySettings settings)
Parameters
| Type | Name | Description |
|---|---|---|
| ExplicitProxyEndPoint | endPoint | The explicit endpoint. |
| SystemProxySettings | settings | The Windows system proxy settings. |
SetAsSystemHttpsProxy(ExplicitProxyEndPoint)
Set the given explicit end point as the default proxy server for current machine.
Declaration
public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint)
Parameters
| Type | Name | Description |
|---|---|---|
| ExplicitProxyEndPoint | endPoint | The explicit endpoint. |
SetAsSystemHttpsProxy(ExplicitProxyEndPoint, SystemProxySettings)
Set the given explicit end point as the default HTTPS proxy server for current machine.
Declaration
public void SetAsSystemHttpsProxy(ExplicitProxyEndPoint endPoint, SystemProxySettings settings)
Parameters
| Type | Name | Description |
|---|---|---|
| ExplicitProxyEndPoint | endPoint | The explicit endpoint. |
| SystemProxySettings | settings | The Windows system proxy settings. |
SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType)
Set the given explicit end point as the default proxy server for current machine.
Declaration
public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType)
Parameters
| Type | Name | Description |
|---|---|---|
| ExplicitProxyEndPoint | endPoint | The explicit endpoint. |
| ProxyProtocolType | protocolType | The proxy protocol type. |
SetAsSystemProxy(ExplicitProxyEndPoint, ProxyProtocolType, SystemProxySettings?)
Set the given explicit end point as the default proxy server for current machine.
Declaration
public void SetAsSystemProxy(ExplicitProxyEndPoint endPoint, ProxyProtocolType protocolType, SystemProxySettings? settings)
Parameters
| Type | Name | Description |
|---|---|---|
| ExplicitProxyEndPoint | endPoint | The explicit endpoint. |
| ProxyProtocolType | protocolType | The proxy protocol type. |
| SystemProxySettings | settings | The Windows system proxy settings, or null to preserve the current bypass list. |
Start(bool)
Start this proxy server instance.
Transactional: if any endpoint fails to start, every listener this call already started is stopped, the system-upstream-proxy resolver (if this call created one) is disposed, and ProxyRunning is left false before the exception propagates. A caller that catches the exception is left with an instance in exactly the same state as before calling Start(bool), not a partially-bound proxy with some endpoints silently listening.
Declaration
public void Start(bool changeSystemProxySettings = true)
Parameters
| Type | Name | Description |
|---|---|---|
| bool | changeSystemProxySettings | Whether or not clear any system proxy settings which is pointing to our own endpoint (causing a cycle). E.g due to ungracious proxy shutdown before. |
Stop()
Stop this proxy server instance. Endpoints remain registered so Start(bool) can re-listen on the same ports. In-flight sessions are cancelled; pooled upstream connections are cleared. The connection factory itself stays usable for a subsequent Start (it is only disposed with the proxy).
Declaration
public void Stop()
StopAsync(TimeSpan?)
Asynchronously stop this proxy server, cancel in-flight sessions, and wait briefly for client connection count to drain before clearing the upstream pool.
Declaration
public Task StopAsync(TimeSpan? drainTimeout = null)
Parameters
| Type | Name | Description |
|---|---|---|
| TimeSpan? | drainTimeout | Maximum time to wait for active client handlers to exit after cancellation. Defaults to 5 seconds. |
Returns
| Type | Description |
|---|---|
| Task |
Events
| Edit this page View SourceAfterResponse
Intercept after response event from server.
Declaration
public event AsyncEventHandler<SessionEventArgs>? AfterResponse
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<SessionEventArgs> |
BeforeRequest
Intercept request event to server.
Declaration
public event AsyncEventHandler<SessionEventArgs>? BeforeRequest
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<SessionEventArgs> |
BeforeResponse
Intercept response event from server.
Declaration
public event AsyncEventHandler<SessionEventArgs>? BeforeResponse
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<SessionEventArgs> |
BeforeUpStreamConnectRequest
Intercept connect request sent to upstream proxy.
Declaration
public event AsyncEventHandler<ConnectRequest>? BeforeUpStreamConnectRequest
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<ConnectRequest> |
ClientCertificateSelectionCallback
Event to override client certificate selection during mutual SSL authentication.
Declaration
public event AsyncEventHandler<CertificateSelectionEventArgs>? ClientCertificateSelectionCallback
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<CertificateSelectionEventArgs> |
ClientConnectionCountChanged
Event occurs when client connection count changed.
Declaration
public event EventHandler? ClientConnectionCountChanged
Event Type
| Type | Description |
|---|---|
| EventHandler |
Http3ClientConnectionCountChanged
Event occurs when inbound HTTP/3 client connection count changed.
Declaration
public event EventHandler? Http3ClientConnectionCountChanged
Event Type
| Type | Description |
|---|---|
| EventHandler |
Http3ServerConnectionCountChanged
Event occurs when upstream HTTP/3 server connection count changed.
Declaration
public event EventHandler? Http3ServerConnectionCountChanged
Event Type
| Type | Description |
|---|---|
| EventHandler |
OnClientConnectionCreate
Customize TcpClient used for client connection upon create.
Declaration
public event AsyncEventHandler<Socket>? OnClientConnectionCreate
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<Socket> |
OnRequestBodyWrite
Intercept request body send event to server. Subscribe to inspect or modify the request body chunk-by-chunk as it streams to the server, without buffering the whole body. Do not combine with SessionEventArgs.GetRequestBody (which buffers).
Declaration
public event AsyncEventHandler<BeforeBodyWriteEventArgs>? OnRequestBodyWrite
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<BeforeBodyWriteEventArgs> |
OnResponseBodyWrite
Intercept response body send event to client. Subscribe to inspect or modify the response body chunk-by-chunk as it streams to the client, without buffering the whole body. Do not combine with SessionEventArgs.GetResponseBody (which buffers).
Declaration
public event AsyncEventHandler<BeforeBodyWriteEventArgs>? OnResponseBodyWrite
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<BeforeBodyWriteEventArgs> |
OnServerConnectionCreate
Customize TcpClient used for server connection upon create.
Declaration
public event AsyncEventHandler<Socket>? OnServerConnectionCreate
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<Socket> |
ServerCertificateValidationCallback
Event to override the default verification logic of remote SSL certificate received during authentication.
Declaration
public event AsyncEventHandler<CertificateValidationEventArgs>? ServerCertificateValidationCallback
Event Type
| Type | Description |
|---|---|
| AsyncEventHandler<CertificateValidationEventArgs> |
ServerConnectionCountChanged
Event occurs when server connection count changed.
Declaration
public event EventHandler? ServerConnectionCountChanged
Event Type
| Type | Description |
|---|---|
| EventHandler |