Pin native Xray transport params to xray-core defaults; keep only safe knobs
Remove the transport-shaping tuning footguns that could break data flow if misconfigured, and hardcode them to xray-core / Go net/http2 defaults instead: - HTTP/2: stop overriding MaxConcurrentStreams and the per-conn/per-stream upload buffers; use Go's defaults exactly like xray-core's splithttp hub does. - XHTTP reorder buffer default is now 30 (xray-core scMaxBufferedPosts), still overridable per-inbound from the generated config. - Mux per-connection session cap, mux UDP idle/read/write buffers, and the XHTTP session cap are now fixed constants rather than admin knobs. The XrayNativeTuning struct and admin UI keep only the operator-safe controls: Go GOMAXPROCS, the global mux-session DoS cap, and the packet-trace debug toggle. Old config.json files with the removed keys still load (unknown fields ignored). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,49 +29,25 @@ function toggleUdpgwFields(on) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Only operator-safe knobs remain. Transport buffers (HTTP/2 flow control, XHTTP
|
||||||
|
// reorder buffer, mux/UDP buffers) are fixed to xray-core defaults in the backend
|
||||||
|
// and are no longer exposed here, so they cannot be misconfigured.
|
||||||
const XRAY_NATIVE_TUNING_DEFAULTS = {
|
const XRAY_NATIVE_TUNING_DEFAULTS = {
|
||||||
safe: {
|
safe: {
|
||||||
runtime_gomaxprocs: 0,
|
runtime_gomaxprocs: 0,
|
||||||
mux_max_sessions: 64,
|
|
||||||
mux_global_sessions: 8192,
|
mux_global_sessions: 8192,
|
||||||
mux_udp_idle_ms: 120000,
|
|
||||||
mux_udp_read_buffer: 131072,
|
|
||||||
mux_udp_write_buffer: 131072,
|
|
||||||
xhttp_max_sessions: 4096,
|
|
||||||
xhttp_buffered_posts: 128,
|
|
||||||
h2_max_concurrent_streams: 256,
|
|
||||||
h2_upload_buffer_conn: 1048576,
|
|
||||||
h2_upload_buffer_stream: 262144,
|
|
||||||
trace_packets: false,
|
trace_packets: false,
|
||||||
},
|
},
|
||||||
"2k": {
|
"2k": {
|
||||||
runtime_gomaxprocs: 0,
|
runtime_gomaxprocs: 0,
|
||||||
mux_max_sessions: 128,
|
|
||||||
mux_global_sessions: 32768,
|
mux_global_sessions: 32768,
|
||||||
mux_udp_idle_ms: 120000,
|
|
||||||
mux_udp_read_buffer: 262144,
|
|
||||||
mux_udp_write_buffer: 262144,
|
|
||||||
xhttp_max_sessions: 16384,
|
|
||||||
xhttp_buffered_posts: 256,
|
|
||||||
h2_max_concurrent_streams: 1024,
|
|
||||||
h2_upload_buffer_conn: 1048576,
|
|
||||||
h2_upload_buffer_stream: 262144,
|
|
||||||
trace_packets: false,
|
trace_packets: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const XRAY_NATIVE_TUNING_FIELDS = {
|
const XRAY_NATIVE_TUNING_FIELDS = {
|
||||||
runtime_gomaxprocs: "cfgXrayRuntimeGomaxprocs",
|
runtime_gomaxprocs: "cfgXrayRuntimeGomaxprocs",
|
||||||
mux_max_sessions: "cfgXrayMuxMaxSessions",
|
|
||||||
mux_global_sessions: "cfgXrayMuxGlobalSessions",
|
mux_global_sessions: "cfgXrayMuxGlobalSessions",
|
||||||
mux_udp_idle_ms: "cfgXrayMuxUdpIdleMs",
|
|
||||||
mux_udp_read_buffer: "cfgXrayMuxUdpRbuf",
|
|
||||||
mux_udp_write_buffer: "cfgXrayMuxUdpWbuf",
|
|
||||||
xhttp_max_sessions: "cfgXrayXhttpMaxSessions",
|
|
||||||
xhttp_buffered_posts: "cfgXrayXhttpBufferedPosts",
|
|
||||||
h2_max_concurrent_streams: "cfgXrayH2MaxStreams",
|
|
||||||
h2_upload_buffer_conn: "cfgXrayH2UploadConn",
|
|
||||||
h2_upload_buffer_stream: "cfgXrayH2UploadStream",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function setXrayNativeTuningDefaults(profile = "2k") {
|
function setXrayNativeTuningDefaults(profile = "2k") {
|
||||||
|
|||||||
+1
-10
@@ -1192,22 +1192,13 @@
|
|||||||
<summary style="cursor:pointer;font-size:.76rem;font-weight:700;color:var(--text);">Native Xray scale tuning</summary>
|
<summary style="cursor:pointer;font-size:.76rem;font-weight:700;color:var(--text);">Native Xray scale tuning</summary>
|
||||||
<div class="grid2" style="margin-top:10px;gap:8px;">
|
<div class="grid2" style="margin-top:10px;gap:8px;">
|
||||||
<div class="field"><label>Go CPU threads (GOMAXPROCS)</label><input type="number" min="0" id="cfgXrayRuntimeGomaxprocs" placeholder="0 = all CPU cores"/></div>
|
<div class="field"><label>Go CPU threads (GOMAXPROCS)</label><input type="number" min="0" id="cfgXrayRuntimeGomaxprocs" placeholder="0 = all CPU cores"/></div>
|
||||||
<div class="field"><label>Mux sessions per connection</label><input type="number" min="1" id="cfgXrayMuxMaxSessions" placeholder="128"/></div>
|
|
||||||
<div class="field"><label>Global mux backend sessions</label><input type="number" min="1" id="cfgXrayMuxGlobalSessions" placeholder="32768"/></div>
|
<div class="field"><label>Global mux backend sessions</label><input type="number" min="1" id="cfgXrayMuxGlobalSessions" placeholder="32768"/></div>
|
||||||
<div class="field"><label>Mux UDP idle ms</label><input type="number" min="1000" id="cfgXrayMuxUdpIdleMs" placeholder="15000"/></div>
|
|
||||||
<div class="field"><label>Mux UDP read buffer bytes</label><input type="number" min="4096" id="cfgXrayMuxUdpRbuf" placeholder="262144"/></div>
|
|
||||||
<div class="field"><label>Mux UDP write buffer bytes</label><input type="number" min="4096" id="cfgXrayMuxUdpWbuf" placeholder="262144"/></div>
|
|
||||||
<div class="field"><label>XHTTP max active sessions</label><input type="number" min="1" id="cfgXrayXhttpMaxSessions" placeholder="16384"/></div>
|
|
||||||
<div class="field"><label>XHTTP buffered posts</label><input type="number" min="1" id="cfgXrayXhttpBufferedPosts" placeholder="64"/></div>
|
|
||||||
<div class="field"><label>HTTP/2 max streams</label><input type="number" min="1" id="cfgXrayH2MaxStreams" placeholder="1024"/></div>
|
|
||||||
<div class="field"><label>HTTP/2 upload buffer / conn</label><input type="number" min="65536" id="cfgXrayH2UploadConn" placeholder="1048576"/></div>
|
|
||||||
<div class="field"><label>HTTP/2 upload buffer / stream</label><input type="number" min="32768" id="cfgXrayH2UploadStream" placeholder="262144"/></div>
|
|
||||||
<label style="font-size:.73rem;display:flex;align-items:center;gap:5px;cursor:pointer;grid-column:1/-1"><input type="checkbox" id="cfgXrayTracePackets"/> Trace every XHTTP/mux packet <span class="hint">debug only, slows QUIC</span></label>
|
<label style="font-size:.73rem;display:flex;align-items:center;gap:5px;cursor:pointer;grid-column:1/-1"><input type="checkbox" id="cfgXrayTracePackets"/> Trace every XHTTP/mux packet <span class="hint">debug only, slows QUIC</span></label>
|
||||||
<div class="card-actions" style="grid-column:1/-1;">
|
<div class="card-actions" style="grid-column:1/-1;">
|
||||||
<button class="btn btn-ghost btn-sm" type="button" onclick="setXrayNativeTuningDefaults('2k')">Apply 2K defaults</button>
|
<button class="btn btn-ghost btn-sm" type="button" onclick="setXrayNativeTuningDefaults('2k')">Apply 2K defaults</button>
|
||||||
<button class="btn btn-ghost btn-sm" type="button" onclick="setXrayNativeTuningDefaults('safe')">Apply safe defaults</button>
|
<button class="btn btn-ghost btn-sm" type="button" onclick="setXrayNativeTuningDefaults('safe')">Apply safe defaults</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="hint" style="grid-column:1/-1;margin-top:-4px;">These values are saved in the panel config and applied live on restart/reload. Go CPU threads = 0 means all detected CPU cores. No systemd Environment lines are needed.</div>
|
<div class="hint" style="grid-column:1/-1;margin-top:-4px;">Transport buffers (HTTP/2 flow control, XHTTP reorder buffer, mux/UDP buffers) are fixed to xray-core defaults and no longer tunable, so they can't be misconfigured. Go CPU threads = 0 means all detected cores. Saved in the panel config and applied live on restart/reload.</div>
|
||||||
</div>
|
</div>
|
||||||
</details>
|
</details>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+42
-86
@@ -6,53 +6,45 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// XrayNativeTuning contains native-emulator performance limits that are edited
|
// XrayNativeTuning holds the few operator-facing knobs for the in-process native
|
||||||
// from the admin panel and saved in config.json under xray.native_tuning.
|
// Xray. Transport-shaping parameters (HTTP/2 flow control, the XHTTP reorder
|
||||||
// Values are process/runtime settings, not generated Xray JSON settings.
|
// buffer, mux/UDP socket buffers) are intentionally NOT exposed: they are pinned
|
||||||
|
// to xray-core / Go defaults so they cannot be misconfigured into breakage. Only
|
||||||
|
// safe operational controls remain here: CPU parallelism, a global mux-session
|
||||||
|
// DoS cap, and a packet-level trace toggle for debugging.
|
||||||
type XrayNativeTuning struct {
|
type XrayNativeTuning struct {
|
||||||
// RuntimeGOMAXPROCS controls Go CPU parallelism for the in-process native Xray.
|
// RuntimeGOMAXPROCS controls Go CPU parallelism. 0 or negative = all cores.
|
||||||
// 0 or negative means use all detected CPU cores.
|
RuntimeGOMAXPROCS int `json:"runtime_gomaxprocs,omitempty"`
|
||||||
RuntimeGOMAXPROCS int `json:"runtime_gomaxprocs,omitempty"`
|
// MuxGlobalSessions caps total concurrent mux child sessions across every
|
||||||
MuxMaxSessions int `json:"mux_max_sessions,omitempty"`
|
// client connection (a DoS guard for the multi-tenant panel). 0 = default.
|
||||||
MuxGlobalSessions int `json:"mux_global_sessions,omitempty"`
|
MuxGlobalSessions int `json:"mux_global_sessions,omitempty"`
|
||||||
MuxUDPIdleMS int `json:"mux_udp_idle_ms,omitempty"`
|
// TracePackets enables very verbose per-packet XHTTP/mux logging. Debug only.
|
||||||
MuxUDPReadBuffer int `json:"mux_udp_read_buffer,omitempty"`
|
TracePackets bool `json:"trace_packets,omitempty"`
|
||||||
MuxUDPWriteBuffer int `json:"mux_udp_write_buffer,omitempty"`
|
|
||||||
XHTTPMaxSessions int `json:"xhttp_max_sessions,omitempty"`
|
|
||||||
XHTTPBufferedPosts int `json:"xhttp_buffered_posts,omitempty"`
|
|
||||||
H2MaxConcurrentStreams int `json:"h2_max_concurrent_streams,omitempty"`
|
|
||||||
H2UploadBufferConn int `json:"h2_upload_buffer_conn,omitempty"`
|
|
||||||
H2UploadBufferStream int `json:"h2_upload_buffer_stream,omitempty"`
|
|
||||||
TracePackets bool `json:"trace_packets,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
defaultNativeRuntimeGOMAXPROCS = 0
|
defaultNativeRuntimeGOMAXPROCS = 0
|
||||||
defaultNativeMuxMaxSessions = 128
|
defaultNativeMuxGlobalSessions = 32768
|
||||||
defaultNativeMuxGlobalSessions = 32768
|
|
||||||
defaultNativeMuxUDPIdleMS = 120000
|
// Fixed transport defaults, aligned with xray-core / Go's net/http2. These are
|
||||||
defaultNativeMuxUDPReadBuffer = 256 * 1024
|
// deliberately not operator-tunable: wrong values silently break data flow.
|
||||||
defaultNativeMuxUDPWriteBuffer = 256 * 1024
|
fixedNativeMuxMaxSessions = 128 // per-connection mux child-session guard
|
||||||
defaultNativeXHTTPMaxSessions = 16384
|
fixedNativeMuxUDPIdleMS = 120000 // mux UDP backend idle cleanup (ms)
|
||||||
defaultNativeXHTTPBufferedPosts = 256
|
fixedNativeMuxUDPReadBuffer = 256 * 1024 // mux UDP socket read buffer
|
||||||
defaultNativeH2MaxConcurrentStreams = 1024
|
fixedNativeMuxUDPWriteBuffer = 256 * 1024 // mux UDP socket write buffer
|
||||||
defaultNativeH2UploadBufferConn = 1 * 1024 * 1024
|
|
||||||
defaultNativeH2UploadBufferStream = 256 * 1024
|
// XHTTP: max tracked sessions (DoS guard) and the packet-up reorder buffer.
|
||||||
|
// defaultNativeXHTTPBufferedPosts matches xray-core's scMaxBufferedPosts
|
||||||
|
// default; the per-inbound scMaxBufferedPosts from the config still overrides
|
||||||
|
// it, exactly like upstream.
|
||||||
|
defaultNativeXHTTPMaxSessions = 16384
|
||||||
|
defaultNativeXHTTPBufferedPosts = 30
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
nativeTuneRuntimeGOMAXPROCS atomic.Int64
|
nativeTuneRuntimeGOMAXPROCS atomic.Int64
|
||||||
nativeTuneMuxMaxSessions atomic.Int64
|
nativeTuneMuxGlobalSessions atomic.Int64
|
||||||
nativeTuneMuxGlobalSessions atomic.Int64
|
nativeTuneTracePackets atomic.Bool
|
||||||
nativeTuneMuxUDPIdleMS atomic.Int64
|
|
||||||
nativeTuneMuxUDPReadBuffer atomic.Int64
|
|
||||||
nativeTuneMuxUDPWriteBuffer atomic.Int64
|
|
||||||
nativeTuneXHTTPMaxSessions atomic.Int64
|
|
||||||
nativeTuneXHTTPBufferedPosts atomic.Int64
|
|
||||||
nativeTuneH2MaxConcurrentStreams atomic.Int64
|
|
||||||
nativeTuneH2UploadBufferConn atomic.Int64
|
|
||||||
nativeTuneH2UploadBufferStream atomic.Int64
|
|
||||||
nativeTuneTracePackets atomic.Bool
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -67,36 +59,9 @@ func normalizeNativeXrayTuning(t *XrayNativeTuning) XrayNativeTuning {
|
|||||||
if out.RuntimeGOMAXPROCS < 0 {
|
if out.RuntimeGOMAXPROCS < 0 {
|
||||||
out.RuntimeGOMAXPROCS = defaultNativeRuntimeGOMAXPROCS
|
out.RuntimeGOMAXPROCS = defaultNativeRuntimeGOMAXPROCS
|
||||||
}
|
}
|
||||||
if out.MuxMaxSessions <= 0 {
|
|
||||||
out.MuxMaxSessions = defaultNativeMuxMaxSessions
|
|
||||||
}
|
|
||||||
if out.MuxGlobalSessions <= 0 {
|
if out.MuxGlobalSessions <= 0 {
|
||||||
out.MuxGlobalSessions = defaultNativeMuxGlobalSessions
|
out.MuxGlobalSessions = defaultNativeMuxGlobalSessions
|
||||||
}
|
}
|
||||||
if out.MuxUDPIdleMS <= 0 {
|
|
||||||
out.MuxUDPIdleMS = defaultNativeMuxUDPIdleMS
|
|
||||||
}
|
|
||||||
if out.MuxUDPReadBuffer <= 0 {
|
|
||||||
out.MuxUDPReadBuffer = defaultNativeMuxUDPReadBuffer
|
|
||||||
}
|
|
||||||
if out.MuxUDPWriteBuffer <= 0 {
|
|
||||||
out.MuxUDPWriteBuffer = defaultNativeMuxUDPWriteBuffer
|
|
||||||
}
|
|
||||||
if out.XHTTPMaxSessions <= 0 {
|
|
||||||
out.XHTTPMaxSessions = defaultNativeXHTTPMaxSessions
|
|
||||||
}
|
|
||||||
if out.XHTTPBufferedPosts <= 0 {
|
|
||||||
out.XHTTPBufferedPosts = defaultNativeXHTTPBufferedPosts
|
|
||||||
}
|
|
||||||
if out.H2MaxConcurrentStreams <= 0 {
|
|
||||||
out.H2MaxConcurrentStreams = defaultNativeH2MaxConcurrentStreams
|
|
||||||
}
|
|
||||||
if out.H2UploadBufferConn <= 0 {
|
|
||||||
out.H2UploadBufferConn = defaultNativeH2UploadBufferConn
|
|
||||||
}
|
|
||||||
if out.H2UploadBufferStream <= 0 {
|
|
||||||
out.H2UploadBufferStream = defaultNativeH2UploadBufferStream
|
|
||||||
}
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,31 +76,22 @@ func applyNativeXrayTuning(t *XrayNativeTuning) XrayNativeTuning {
|
|||||||
}
|
}
|
||||||
runtime.GOMAXPROCS(gomax)
|
runtime.GOMAXPROCS(gomax)
|
||||||
nativeTuneRuntimeGOMAXPROCS.Store(int64(gomax))
|
nativeTuneRuntimeGOMAXPROCS.Store(int64(gomax))
|
||||||
nativeTuneMuxMaxSessions.Store(int64(out.MuxMaxSessions))
|
|
||||||
nativeTuneMuxGlobalSessions.Store(int64(out.MuxGlobalSessions))
|
nativeTuneMuxGlobalSessions.Store(int64(out.MuxGlobalSessions))
|
||||||
nativeTuneMuxUDPIdleMS.Store(int64(out.MuxUDPIdleMS))
|
|
||||||
nativeTuneMuxUDPReadBuffer.Store(int64(out.MuxUDPReadBuffer))
|
|
||||||
nativeTuneMuxUDPWriteBuffer.Store(int64(out.MuxUDPWriteBuffer))
|
|
||||||
nativeTuneXHTTPMaxSessions.Store(int64(out.XHTTPMaxSessions))
|
|
||||||
nativeTuneXHTTPBufferedPosts.Store(int64(out.XHTTPBufferedPosts))
|
|
||||||
nativeTuneH2MaxConcurrentStreams.Store(int64(out.H2MaxConcurrentStreams))
|
|
||||||
nativeTuneH2UploadBufferConn.Store(int64(out.H2UploadBufferConn))
|
|
||||||
nativeTuneH2UploadBufferStream.Store(int64(out.H2UploadBufferStream))
|
|
||||||
nativeTuneTracePackets.Store(out.TracePackets)
|
nativeTuneTracePackets.Store(out.TracePackets)
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Operator-tunable values.
|
||||||
func nativeRuntimeGOMAXPROCS() int { return int(nativeTuneRuntimeGOMAXPROCS.Load()) }
|
func nativeRuntimeGOMAXPROCS() int { return int(nativeTuneRuntimeGOMAXPROCS.Load()) }
|
||||||
func nativeMuxMaxSessionLimit() int { return int(nativeTuneMuxMaxSessions.Load()) }
|
|
||||||
func nativeMuxGlobalSessionLimit() int { return int(nativeTuneMuxGlobalSessions.Load()) }
|
func nativeMuxGlobalSessionLimit() int { return int(nativeTuneMuxGlobalSessions.Load()) }
|
||||||
|
func nativeTracePacketsEnabled() bool { return nativeTuneTracePackets.Load() }
|
||||||
|
|
||||||
|
// Fixed transport limits (see the const block for rationale).
|
||||||
|
func nativeMuxMaxSessionLimit() int { return fixedNativeMuxMaxSessions }
|
||||||
|
func nativeMuxUDPReadBufferSize() int { return fixedNativeMuxUDPReadBuffer }
|
||||||
|
func nativeMuxUDPWriteBufferSize() int { return fixedNativeMuxUDPWriteBuffer }
|
||||||
|
func nativeXHTTPMaxSessionLimit() int { return defaultNativeXHTTPMaxSessions }
|
||||||
|
func nativeXHTTPBufferedPostLimit() int { return defaultNativeXHTTPBufferedPosts }
|
||||||
func nativeMuxUDPIdleTimeout() time.Duration {
|
func nativeMuxUDPIdleTimeout() time.Duration {
|
||||||
return time.Duration(nativeTuneMuxUDPIdleMS.Load()) * time.Millisecond
|
return fixedNativeMuxUDPIdleMS * time.Millisecond
|
||||||
}
|
}
|
||||||
func nativeMuxUDPReadBufferSize() int { return int(nativeTuneMuxUDPReadBuffer.Load()) }
|
|
||||||
func nativeMuxUDPWriteBufferSize() int { return int(nativeTuneMuxUDPWriteBuffer.Load()) }
|
|
||||||
func nativeXHTTPMaxSessionLimit() int { return int(nativeTuneXHTTPMaxSessions.Load()) }
|
|
||||||
func nativeXHTTPBufferedPostLimit() int { return int(nativeTuneXHTTPBufferedPosts.Load()) }
|
|
||||||
func nativeH2MaxConcurrentStreams() int { return int(nativeTuneH2MaxConcurrentStreams.Load()) }
|
|
||||||
func nativeH2UploadBufferConn() int { return int(nativeTuneH2UploadBufferConn.Load()) }
|
|
||||||
func nativeH2UploadBufferStream() int { return int(nativeTuneH2UploadBufferStream.Load()) }
|
|
||||||
func nativeTracePacketsEnabled() bool { return nativeTuneTracePackets.Load() }
|
|
||||||
|
|||||||
+3
-5
@@ -99,11 +99,9 @@ func mergeNativeXHTTPSettings(primary, fallback nativeXHTTPSettingsJSON) nativeX
|
|||||||
|
|
||||||
func (ib *nativeInbound) serveXHTTPListener(ln net.Listener) {
|
func (ib *nativeInbound) serveXHTTPListener(ln net.Listener) {
|
||||||
defer xrayRecover(fmt.Sprintf("native xray XHTTP listener inbound=%q addr=%s", ib.tag, ln.Addr()))
|
defer xrayRecover(fmt.Sprintf("native xray XHTTP listener inbound=%q addr=%s", ib.tag, ln.Addr()))
|
||||||
h2s := &http2.Server{
|
// Match xray-core: let net/http's HTTP/2 use its own defaults for flow
|
||||||
MaxConcurrentStreams: uint32(nativeH2MaxConcurrentStreams()),
|
// control, stream limits and upload buffers instead of overriding them.
|
||||||
MaxUploadBufferPerConnection: int32(nativeH2UploadBufferConn()),
|
h2s := &http2.Server{}
|
||||||
MaxUploadBufferPerStream: int32(nativeH2UploadBufferStream()),
|
|
||||||
}
|
|
||||||
handler := http.Handler(ib)
|
handler := http.Handler(ib)
|
||||||
// Official Xray accepts plaintext HTTP/1.1 and h2c on non-TLS XHTTP
|
// Official Xray accepts plaintext HTTP/1.1 and h2c on non-TLS XHTTP
|
||||||
// listeners, and negotiates h2/http1 through ALPN on TLS listeners. Without
|
// listeners, and negotiates h2/http1 through ALPN on TLS listeners. Without
|
||||||
|
|||||||
Reference in New Issue
Block a user