Skip to content

Commit 9c7b620

Browse files
committed
feat(config): expose HTTP/2 server controls
1 parent 86e5d4f commit 9c7b620

10 files changed

Lines changed: 287 additions & 90 deletions

File tree

‎.env.example‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ PROXY_LOG_SENSITIVE_DATA=false
1818

1919
# Resource limits.
2020
PROXY_MAX_CONNECTIONS=1024
21-
PROXY_MAX_CONNECTIONS_PER_IP=64
21+
PROXY_MAX_CONNECTIONS_PER_IP=128
2222
PROXY_MAX_TUNNELS=256
23-
PROXY_MAX_TUNNELS_PER_IP=16
23+
PROXY_MAX_TUNNELS_PER_IP=128
24+
PROXY_HTTP2_MAX_CONCURRENT_STREAMS=0
2425
PROXY_MAX_IDLE_CONNS=100
2526
PROXY_MAX_IDLE_CONNS_PER_HOST=10
2627
PROXY_MAX_HEADER_BYTES=65536
2728
PROXY_TUNNEL_IDLE_TIMEOUT=10m
29+
PROXY_HTTP2_SEND_PING_TIMEOUT=1m
30+
PROXY_HTTP2_PING_TIMEOUT=15s
31+
PROXY_HTTP2_WRITE_BYTE_TIMEOUT=30s
2832

2933
# Failed Basic Auth attempts are counted per client IP.
3034
PROXY_AUTH_MAX_FAILURES=10

‎README.md‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ Any of these override the corresponding YAML field:
7979
| `PROXY_MAX_CONNECTIONS_PER_IP` | `max_connections_per_ip` |
8080
| `PROXY_MAX_TUNNELS` | `max_tunnels` |
8181
| `PROXY_MAX_TUNNELS_PER_IP` | `max_tunnels_per_ip` |
82+
| `PROXY_HTTP2_MAX_CONCURRENT_STREAMS` | `http2_max_concurrent_streams` (`0` derives the limit from tunnel limits) |
8283
| `PROXY_MAX_IDLE_CONNS` | `max_idle_conns` |
8384
| `PROXY_MAX_IDLE_CONNS_PER_HOST` | `max_idle_conns_per_host` |
8485
| `PROXY_MAX_HEADER_BYTES` | `max_header_bytes` |
@@ -93,6 +94,9 @@ Any of these override the corresponding YAML field:
9394
| `PROXY_READ_HEADER_TIMEOUT` | `read_header_timeout` |
9495
| `PROXY_IDLE_TIMEOUT` | `idle_timeout` |
9596
| `PROXY_TUNNEL_IDLE_TIMEOUT` | `tunnel_idle_timeout` |
97+
| `PROXY_HTTP2_SEND_PING_TIMEOUT` | `http2_send_ping_timeout` |
98+
| `PROXY_HTTP2_PING_TIMEOUT` | `http2_ping_timeout` |
99+
| `PROXY_HTTP2_WRITE_BYTE_TIMEOUT` | `http2_write_byte_timeout` |
96100
| `PROXY_AUTH_FAILURE_WINDOW` | `auth_failure_window` |
97101
| `PROXY_AUTH_BLOCK_DURATION` | `auth_block_duration` |
98102
| `PROXY_SHUTDOWN_TIMEOUT` | `shutdown_timeout` |
@@ -166,6 +170,7 @@ max_connections: 1024
166170
max_connections_per_ip: 128
167171
max_tunnels: 256
168172
max_tunnels_per_ip: 128
173+
http2_max_concurrent_streams: 0
169174
max_idle_conns: 100
170175
max_idle_conns_per_host: 10
171176
max_header_bytes: 65536
@@ -180,6 +185,9 @@ idle_conn_timeout: 90s
180185
read_header_timeout: 15s
181186
idle_timeout: 2m
182187
tunnel_idle_timeout: 10m
188+
http2_send_ping_timeout: 1m
189+
http2_ping_timeout: 15s
190+
http2_write_byte_timeout: 30s
183191
auth_failure_window: 1m
184192
auth_block_duration: 5m
185193
shutdown_timeout: 15s
@@ -204,6 +212,7 @@ The example listens on localhost. Set `proxy_addr` to `0.0.0.0:8080` only when t
204212
| `max_connections_per_ip` | Maximum simultaneous client connections per source IP |
205213
| `max_tunnels` | Maximum simultaneous CONNECT tunnels |
206214
| `max_tunnels_per_ip` | Maximum simultaneous CONNECT tunnels per source IP |
215+
| `http2_max_concurrent_streams` | Maximum streams advertised per HTTP/2 connection; `0` uses the lower of `max_tunnels` and `max_tunnels_per_ip` |
207216
| `max_idle_conns` | Maximum idle outbound HTTP connections across all destinations |
208217
| `max_idle_conns_per_host` | Maximum idle outbound HTTP connections retained per destination |
209218
| `max_header_bytes` | Maximum size of incoming HTTP request headers |
@@ -218,6 +227,9 @@ The example listens on localhost. Set `proxy_addr` to `0.0.0.0:8080` only when t
218227
| `read_header_timeout` | Incoming request-header timeout |
219228
| `idle_timeout` | Incoming keep-alive idle timeout |
220229
| `tunnel_idle_timeout` | Close a CONNECT tunnel after no traffic in either direction |
230+
| `http2_send_ping_timeout` | Send an HTTP/2 PING after no frame is received for this duration; `0s` disables health checks |
231+
| `http2_ping_timeout` | Close an HTTP/2 connection when a PING response is not received; `0s` uses Go's default |
232+
| `http2_write_byte_timeout` | Close an HTTP/2 connection when no response bytes can be written for this duration; `0s` disables the timeout |
221233
| `auth_failure_window` | Window in which failed authentication attempts are counted |
222234
| `auth_block_duration` | How long an IP is blocked after exceeding `auth_max_failures` |
223235
| `shutdown_timeout` | Graceful shutdown deadline |
@@ -228,7 +240,7 @@ By default, request URL userinfo and query parameters are removed from logs, ups
228240

229241
### Resource limits and destination policy
230242

231-
Connection and CONNECT limits are enforced globally and per source IP. Excess TCP connections are closed immediately; excess tunnels and rate-limited authentication attempts receive `429 Too Many Requests`. A tunnel is closed when no bytes flow in either direction for `tunnel_idle_timeout`.
243+
Connection and CONNECT limits are enforced globally and per source IP. Excess TCP connections are closed immediately; excess tunnels and rate-limited authentication attempts receive `429 Too Many Requests`. A tunnel is closed when no bytes flow in either direction for `tunnel_idle_timeout`. Unless explicitly overridden, the HTTP/2 SETTINGS stream limit is derived from the lower tunnel limit so clients do not open streams that the proxy would immediately reject.
232244

233245
The default destination policy rejects loopback, private, link-local, metadata, carrier-grade NAT, and other reserved addresses. It also blocks common administration, mail, database, and cache ports. To intentionally proxy internal services, set `allow_private_destinations: true`. To clear only the blocked port list, use `blocked_destination_ports: []` in YAML or `PROXY_BLOCKED_DESTINATION_PORTS=none`.
234246

‎VERSION‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.5.0
1+
0.5.1

‎config.docker.yaml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ max_connections: 1024
1010
max_connections_per_ip: 128
1111
max_tunnels: 256
1212
max_tunnels_per_ip: 128
13+
http2_max_concurrent_streams: 0
1314
max_idle_conns: 100
1415
max_idle_conns_per_host: 10
1516
max_header_bytes: 65536
@@ -24,6 +25,9 @@ idle_conn_timeout: 90s
2425
read_header_timeout: 15s
2526
idle_timeout: 2m
2627
tunnel_idle_timeout: 10m
28+
http2_send_ping_timeout: 1m
29+
http2_ping_timeout: 15s
30+
http2_write_byte_timeout: 30s
2731
auth_failure_window: 1m
2832
auth_block_duration: 5m
2933
shutdown_timeout: 15s

‎config.example.yaml‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ max_connections: 1024
1010
max_connections_per_ip: 128
1111
max_tunnels: 256
1212
max_tunnels_per_ip: 128
13+
http2_max_concurrent_streams: 0
1314
max_idle_conns: 100
1415
max_idle_conns_per_host: 10
1516
max_header_bytes: 65536
@@ -24,6 +25,9 @@ idle_conn_timeout: 90s
2425
read_header_timeout: 15s
2526
idle_timeout: 2m
2627
tunnel_idle_timeout: 10m
28+
http2_send_ping_timeout: 1m
29+
http2_ping_timeout: 15s
30+
http2_write_byte_timeout: 30s
2731
auth_failure_window: 1m
2832
auth_block_duration: 5m
2933
shutdown_timeout: 15s

‎docker-compose.yml‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,18 @@ services:
1515
PROXY_NETWORK: ${PROXY_NETWORK:-auto}
1616
PROXY_LOG_SENSITIVE_DATA: "${PROXY_LOG_SENSITIVE_DATA:-false}"
1717
PROXY_MAX_CONNECTIONS: "${PROXY_MAX_CONNECTIONS:-1024}"
18-
PROXY_MAX_CONNECTIONS_PER_IP: "${PROXY_MAX_CONNECTIONS_PER_IP:-64}"
18+
PROXY_MAX_CONNECTIONS_PER_IP: "${PROXY_MAX_CONNECTIONS_PER_IP:-128}"
1919
PROXY_MAX_TUNNELS: "${PROXY_MAX_TUNNELS:-256}"
20-
PROXY_MAX_TUNNELS_PER_IP: "${PROXY_MAX_TUNNELS_PER_IP:-16}"
20+
PROXY_MAX_TUNNELS_PER_IP: "${PROXY_MAX_TUNNELS_PER_IP:-128}"
21+
PROXY_HTTP2_MAX_CONCURRENT_STREAMS: "${PROXY_HTTP2_MAX_CONCURRENT_STREAMS:-0}"
2122
PROXY_MAX_IDLE_CONNS: "${PROXY_MAX_IDLE_CONNS:-100}"
2223
PROXY_MAX_IDLE_CONNS_PER_HOST: "${PROXY_MAX_IDLE_CONNS_PER_HOST:-10}"
2324
PROXY_MAX_HEADER_BYTES: "${PROXY_MAX_HEADER_BYTES:-65536}"
2425
PROXY_IDLE_CONN_TIMEOUT: "${PROXY_IDLE_CONN_TIMEOUT:-90s}"
2526
PROXY_TUNNEL_IDLE_TIMEOUT: "${PROXY_TUNNEL_IDLE_TIMEOUT:-10m}"
27+
PROXY_HTTP2_SEND_PING_TIMEOUT: "${PROXY_HTTP2_SEND_PING_TIMEOUT:-1m}"
28+
PROXY_HTTP2_PING_TIMEOUT: "${PROXY_HTTP2_PING_TIMEOUT:-15s}"
29+
PROXY_HTTP2_WRITE_BYTE_TIMEOUT: "${PROXY_HTTP2_WRITE_BYTE_TIMEOUT:-30s}"
2630
PROXY_AUTH_MAX_FAILURES: "${PROXY_AUTH_MAX_FAILURES:-10}"
2731
PROXY_AUTH_FAILURE_WINDOW: "${PROXY_AUTH_FAILURE_WINDOW:-1m}"
2832
PROXY_AUTH_BLOCK_DURATION: "${PROXY_AUTH_BLOCK_DURATION:-5m}"
@@ -47,14 +51,18 @@ services:
4751
PROXY_NETWORK: ${PROXY_NETWORK:-auto}
4852
PROXY_LOG_SENSITIVE_DATA: "${PROXY_LOG_SENSITIVE_DATA:-false}"
4953
PROXY_MAX_CONNECTIONS: "${PROXY_MAX_CONNECTIONS:-1024}"
50-
PROXY_MAX_CONNECTIONS_PER_IP: "${PROXY_MAX_CONNECTIONS_PER_IP:-64}"
54+
PROXY_MAX_CONNECTIONS_PER_IP: "${PROXY_MAX_CONNECTIONS_PER_IP:-128}"
5155
PROXY_MAX_TUNNELS: "${PROXY_MAX_TUNNELS:-256}"
52-
PROXY_MAX_TUNNELS_PER_IP: "${PROXY_MAX_TUNNELS_PER_IP:-16}"
56+
PROXY_MAX_TUNNELS_PER_IP: "${PROXY_MAX_TUNNELS_PER_IP:-128}"
57+
PROXY_HTTP2_MAX_CONCURRENT_STREAMS: "${PROXY_HTTP2_MAX_CONCURRENT_STREAMS:-0}"
5358
PROXY_MAX_IDLE_CONNS: "${PROXY_MAX_IDLE_CONNS:-100}"
5459
PROXY_MAX_IDLE_CONNS_PER_HOST: "${PROXY_MAX_IDLE_CONNS_PER_HOST:-10}"
5560
PROXY_MAX_HEADER_BYTES: "${PROXY_MAX_HEADER_BYTES:-65536}"
5661
PROXY_IDLE_CONN_TIMEOUT: "${PROXY_IDLE_CONN_TIMEOUT:-90s}"
5762
PROXY_TUNNEL_IDLE_TIMEOUT: "${PROXY_TUNNEL_IDLE_TIMEOUT:-10m}"
63+
PROXY_HTTP2_SEND_PING_TIMEOUT: "${PROXY_HTTP2_SEND_PING_TIMEOUT:-1m}"
64+
PROXY_HTTP2_PING_TIMEOUT: "${PROXY_HTTP2_PING_TIMEOUT:-15s}"
65+
PROXY_HTTP2_WRITE_BYTE_TIMEOUT: "${PROXY_HTTP2_WRITE_BYTE_TIMEOUT:-30s}"
5866
PROXY_AUTH_MAX_FAILURES: "${PROXY_AUTH_MAX_FAILURES:-10}"
5967
PROXY_AUTH_FAILURE_WINDOW: "${PROXY_AUTH_FAILURE_WINDOW:-1m}"
6068
PROXY_AUTH_BLOCK_DURATION: "${PROXY_AUTH_BLOCK_DURATION:-5m}"

‎internal/config/config.go‎

Lines changed: 89 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -41,36 +41,40 @@ func (d Duration) String() string {
4141

4242
// Config contains all runtime settings for the proxy server.
4343
type Config struct {
44-
ProxyAddr string `yaml:"proxy_addr"`
45-
Username string `yaml:"username"`
46-
Password string `yaml:"password"`
47-
Proto string `yaml:"proto"`
48-
CertPath string `yaml:"cert_path"`
49-
KeyPath string `yaml:"key_path"`
50-
UpstreamProxy string `yaml:"upstream_proxy"`
51-
Network string `yaml:"network"`
52-
LogSensitiveData bool `yaml:"log_sensitive_data"`
53-
MaxConnections int `yaml:"max_connections"`
54-
MaxConnectionsPerIP int `yaml:"max_connections_per_ip"`
55-
MaxTunnels int `yaml:"max_tunnels"`
56-
MaxTunnelsPerIP int `yaml:"max_tunnels_per_ip"`
57-
MaxIdleConns int `yaml:"max_idle_conns"`
58-
MaxIdleConnsPerHost int `yaml:"max_idle_conns_per_host"`
59-
MaxHeaderBytes int `yaml:"max_header_bytes"`
60-
AuthMaxFailures int `yaml:"auth_max_failures"`
61-
AllowPrivateDestinations bool `yaml:"allow_private_destinations"`
62-
BlockedDestinationPorts []int `yaml:"blocked_destination_ports"`
63-
DialTimeout Duration `yaml:"dial_timeout"`
64-
TLSHandshakeTimeout Duration `yaml:"tls_handshake_timeout"`
65-
TLSReloadInterval Duration `yaml:"tls_reload_interval"`
66-
ResponseHeaderTimeout Duration `yaml:"response_header_timeout"`
67-
IdleConnTimeout Duration `yaml:"idle_conn_timeout"`
68-
ReadHeaderTimeout Duration `yaml:"read_header_timeout"`
69-
IdleTimeout Duration `yaml:"idle_timeout"`
70-
TunnelIdleTimeout Duration `yaml:"tunnel_idle_timeout"`
71-
AuthFailureWindow Duration `yaml:"auth_failure_window"`
72-
AuthBlockDuration Duration `yaml:"auth_block_duration"`
73-
ShutdownTimeout Duration `yaml:"shutdown_timeout"`
44+
ProxyAddr string `yaml:"proxy_addr"`
45+
Username string `yaml:"username"`
46+
Password string `yaml:"password"`
47+
Proto string `yaml:"proto"`
48+
CertPath string `yaml:"cert_path"`
49+
KeyPath string `yaml:"key_path"`
50+
UpstreamProxy string `yaml:"upstream_proxy"`
51+
Network string `yaml:"network"`
52+
LogSensitiveData bool `yaml:"log_sensitive_data"`
53+
MaxConnections int `yaml:"max_connections"`
54+
MaxConnectionsPerIP int `yaml:"max_connections_per_ip"`
55+
MaxTunnels int `yaml:"max_tunnels"`
56+
MaxTunnelsPerIP int `yaml:"max_tunnels_per_ip"`
57+
HTTP2MaxConcurrentStreams int `yaml:"http2_max_concurrent_streams"`
58+
MaxIdleConns int `yaml:"max_idle_conns"`
59+
MaxIdleConnsPerHost int `yaml:"max_idle_conns_per_host"`
60+
MaxHeaderBytes int `yaml:"max_header_bytes"`
61+
AuthMaxFailures int `yaml:"auth_max_failures"`
62+
AllowPrivateDestinations bool `yaml:"allow_private_destinations"`
63+
BlockedDestinationPorts []int `yaml:"blocked_destination_ports"`
64+
DialTimeout Duration `yaml:"dial_timeout"`
65+
TLSHandshakeTimeout Duration `yaml:"tls_handshake_timeout"`
66+
TLSReloadInterval Duration `yaml:"tls_reload_interval"`
67+
ResponseHeaderTimeout Duration `yaml:"response_header_timeout"`
68+
IdleConnTimeout Duration `yaml:"idle_conn_timeout"`
69+
ReadHeaderTimeout Duration `yaml:"read_header_timeout"`
70+
IdleTimeout Duration `yaml:"idle_timeout"`
71+
TunnelIdleTimeout Duration `yaml:"tunnel_idle_timeout"`
72+
HTTP2SendPingTimeout Duration `yaml:"http2_send_ping_timeout"`
73+
HTTP2PingTimeout Duration `yaml:"http2_ping_timeout"`
74+
HTTP2WriteByteTimeout Duration `yaml:"http2_write_byte_timeout"`
75+
AuthFailureWindow Duration `yaml:"auth_failure_window"`
76+
AuthBlockDuration Duration `yaml:"auth_block_duration"`
77+
ShutdownTimeout Duration `yaml:"shutdown_timeout"`
7478
}
7579

7680
// Default returns a configuration with safe local-listener defaults.
@@ -80,29 +84,33 @@ func Default() Config {
8084

8185
func defaultConfig() Config {
8286
return Config{
83-
ProxyAddr: "127.0.0.1:8080",
84-
Proto: "http",
85-
Network: "auto",
86-
MaxConnections: 1024,
87-
MaxConnectionsPerIP: 128,
88-
MaxTunnels: 256,
89-
MaxTunnelsPerIP: 128,
90-
MaxIdleConns: 100,
91-
MaxIdleConnsPerHost: 10,
92-
MaxHeaderBytes: 64 << 10,
93-
AuthMaxFailures: 10,
94-
BlockedDestinationPorts: []int{21, 22, 23, 25, 110, 111, 135, 137, 138, 139, 445, 1433, 2049, 2375, 2376, 3306, 3389, 5432, 5900, 6379, 9200, 11211, 27017},
95-
DialTimeout: Duration(10 * time.Second),
96-
TLSHandshakeTimeout: Duration(10 * time.Second),
97-
TLSReloadInterval: Duration(time.Minute),
98-
ResponseHeaderTimeout: Duration(30 * time.Second),
99-
IdleConnTimeout: Duration(90 * time.Second),
100-
ReadHeaderTimeout: Duration(15 * time.Second),
101-
IdleTimeout: Duration(2 * time.Minute),
102-
TunnelIdleTimeout: Duration(10 * time.Minute),
103-
AuthFailureWindow: Duration(time.Minute),
104-
AuthBlockDuration: Duration(5 * time.Minute),
105-
ShutdownTimeout: Duration(15 * time.Second),
87+
ProxyAddr: "127.0.0.1:8080",
88+
Proto: "http",
89+
Network: "auto",
90+
MaxConnections: 1024,
91+
MaxConnectionsPerIP: 128,
92+
MaxTunnels: 256,
93+
MaxTunnelsPerIP: 128,
94+
HTTP2MaxConcurrentStreams: 0,
95+
MaxIdleConns: 100,
96+
MaxIdleConnsPerHost: 10,
97+
MaxHeaderBytes: 64 << 10,
98+
AuthMaxFailures: 10,
99+
BlockedDestinationPorts: []int{21, 22, 23, 25, 110, 111, 135, 137, 138, 139, 445, 1433, 2049, 2375, 2376, 3306, 3389, 5432, 5900, 6379, 9200, 11211, 27017},
100+
DialTimeout: Duration(10 * time.Second),
101+
TLSHandshakeTimeout: Duration(10 * time.Second),
102+
TLSReloadInterval: Duration(time.Minute),
103+
ResponseHeaderTimeout: Duration(30 * time.Second),
104+
IdleConnTimeout: Duration(90 * time.Second),
105+
ReadHeaderTimeout: Duration(15 * time.Second),
106+
IdleTimeout: Duration(2 * time.Minute),
107+
TunnelIdleTimeout: Duration(10 * time.Minute),
108+
HTTP2SendPingTimeout: Duration(time.Minute),
109+
HTTP2PingTimeout: Duration(15 * time.Second),
110+
HTTP2WriteByteTimeout: Duration(30 * time.Second),
111+
AuthFailureWindow: Duration(time.Minute),
112+
AuthBlockDuration: Duration(5 * time.Minute),
113+
ShutdownTimeout: Duration(15 * time.Second),
106114
}
107115
}
108116

@@ -155,7 +163,8 @@ func decodeConfig(r io.Reader) (Config, error) {
155163
// PROXY_CERT_PATH, PROXY_KEY_PATH, PROXY_UPSTREAM_PROXY, PROXY_NETWORK,
156164
// PROXY_LOG_SENSITIVE_DATA, PROXY_MAX_CONNECTIONS,
157165
// PROXY_MAX_CONNECTIONS_PER_IP, PROXY_MAX_TUNNELS,
158-
// PROXY_MAX_TUNNELS_PER_IP, PROXY_MAX_IDLE_CONNS,
166+
// PROXY_MAX_TUNNELS_PER_IP, PROXY_HTTP2_MAX_CONCURRENT_STREAMS,
167+
// PROXY_MAX_IDLE_CONNS,
159168
// PROXY_MAX_IDLE_CONNS_PER_HOST, PROXY_MAX_HEADER_BYTES,
160169
// PROXY_AUTH_MAX_FAILURES, PROXY_ALLOW_PRIVATE_DESTINATIONS,
161170
// PROXY_BLOCKED_DESTINATION_PORTS,
@@ -164,6 +173,8 @@ func decodeConfig(r io.Reader) (Config, error) {
164173
// PROXY_RESPONSE_HEADER_TIMEOUT, PROXY_IDLE_CONN_TIMEOUT,
165174
// PROXY_READ_HEADER_TIMEOUT,
166175
// PROXY_IDLE_TIMEOUT, PROXY_TUNNEL_IDLE_TIMEOUT,
176+
// PROXY_HTTP2_SEND_PING_TIMEOUT, PROXY_HTTP2_PING_TIMEOUT,
177+
// PROXY_HTTP2_WRITE_BYTE_TIMEOUT,
167178
// PROXY_AUTH_FAILURE_WINDOW, PROXY_AUTH_BLOCK_DURATION,
168179
// PROXY_SHUTDOWN_TIMEOUT.
169180
func applyEnvOverrides(c *Config) error {
@@ -218,6 +229,7 @@ func applyEnvOverrides(c *Config) error {
218229
{"PROXY_MAX_CONNECTIONS_PER_IP", &c.MaxConnectionsPerIP},
219230
{"PROXY_MAX_TUNNELS", &c.MaxTunnels},
220231
{"PROXY_MAX_TUNNELS_PER_IP", &c.MaxTunnelsPerIP},
232+
{"PROXY_HTTP2_MAX_CONCURRENT_STREAMS", &c.HTTP2MaxConcurrentStreams},
221233
{"PROXY_MAX_IDLE_CONNS", &c.MaxIdleConns},
222234
{"PROXY_MAX_IDLE_CONNS_PER_HOST", &c.MaxIdleConnsPerHost},
223235
{"PROXY_MAX_HEADER_BYTES", &c.MaxHeaderBytes},
@@ -255,6 +267,9 @@ func applyEnvOverrides(c *Config) error {
255267
{"PROXY_READ_HEADER_TIMEOUT", &c.ReadHeaderTimeout},
256268
{"PROXY_IDLE_TIMEOUT", &c.IdleTimeout},
257269
{"PROXY_TUNNEL_IDLE_TIMEOUT", &c.TunnelIdleTimeout},
270+
{"PROXY_HTTP2_SEND_PING_TIMEOUT", &c.HTTP2SendPingTimeout},
271+
{"PROXY_HTTP2_PING_TIMEOUT", &c.HTTP2PingTimeout},
272+
{"PROXY_HTTP2_WRITE_BYTE_TIMEOUT", &c.HTTP2WriteByteTimeout},
258273
{"PROXY_AUTH_FAILURE_WINDOW", &c.AuthFailureWindow},
259274
{"PROXY_AUTH_BLOCK_DURATION", &c.AuthBlockDuration},
260275
{"PROXY_SHUTDOWN_TIMEOUT", &c.ShutdownTimeout},
@@ -337,6 +352,26 @@ func validateConfig(config *Config) error {
337352
if config.MaxTunnelsPerIP > config.MaxTunnels {
338353
return errors.New("max_tunnels_per_ip cannot exceed max_tunnels")
339354
}
355+
if config.HTTP2MaxConcurrentStreams < 0 {
356+
return errors.New("http2_max_concurrent_streams must be zero or greater")
357+
}
358+
if config.HTTP2MaxConcurrentStreams > 0 &&
359+
(config.HTTP2MaxConcurrentStreams > config.MaxTunnels ||
360+
config.HTTP2MaxConcurrentStreams > config.MaxTunnelsPerIP) {
361+
return errors.New("http2_max_concurrent_streams cannot exceed tunnel limits")
362+
}
363+
for _, duration := range []struct {
364+
name string
365+
value Duration
366+
}{
367+
{"http2_send_ping_timeout", config.HTTP2SendPingTimeout},
368+
{"http2_ping_timeout", config.HTTP2PingTimeout},
369+
{"http2_write_byte_timeout", config.HTTP2WriteByteTimeout},
370+
} {
371+
if duration.value < 0 {
372+
return fmt.Errorf("%s must be zero or greater", duration.name)
373+
}
374+
}
340375
seenPorts := make(map[int]struct{}, len(config.BlockedDestinationPorts))
341376
for _, port := range config.BlockedDestinationPorts {
342377
if port < 1 || port > 65535 {

0 commit comments

Comments
 (0)