Skip to content

chore: async xhttp RoundTrip to let some CDN/reverse proxy happy#2719

Merged
wwqgtxx merged 5 commits into
MetaCubeX:Alphafrom
kyber1024:Alpha
Apr 17, 2026
Merged

chore: async xhttp RoundTrip to let some CDN/reverse proxy happy#2719
wwqgtxx merged 5 commits into
MetaCubeX:Alphafrom
kyber1024:Alpha

Conversation

@kyber1024

Copy link
Copy Markdown

Summary

Fix xhttp client deadlock when connecting through CDNs (Cloudflare, CloudFront) or reverse proxies (Nginx).
Fixes #2709

Problem

DialStreamOne, DialStreamUp, and DialPacketUp call transport.RoundTrip() synchronously, blocking until HTTP response headers arrive. Behind CDN/reverse proxy with response header buffering, this creates a 4-way deadlock:

Client (waits for resp headers) → CDN (waits for origin body) → 
Origin/Xray (waits for request body) → Client (can't write, conn not returned yet)

Result: connection hangs until timeout. Xray-core work because it use async patterns.

Fix

Move RoundTrip into background goroutines, use httptrace.GotConn to detect TCP establishment, and return conn immediately. A new WaitReadCloser type defers response body reading to the first Read() call — matching Xray-core's splithttp async approach.

Testing

Built and tested locally against a real CloudFront + Xray-core server with packet-up mode

  • Before fix: timeout, no Nginx/CDN access logs generated (connection dead-locked)
  • After fix: connects instantly through CloudFront, response normal

…verse proxy

The xhttp client's DialStreamOne, DialStreamUp, and DialPacketUp methods called transport.RoundTrip() synchronously, blocking until the full HTTP response headers were received. This caused a deadlock when behind CDNs
(e.g. Cloudflare, CloudFront) or reverse proxies (e.g. Nginx) that buffer response headers until the origin server sends actual body data:
  1. mihomo client waits for HTTP response headers from CDN
  2. CDN waits for origin server to send response body
  3. Origin server (Xray) waits for client to send VLESS handshake in the request body
  4. Request body can't be written because conn hasn't been returned to the caller yet >> deadlock until timeout

Fix: move RoundTrip into a background goroutine and use httptrace.GotConn to detect TCP connection establishment. Return the conn immediately once TCP is connected, using a new WaitReadCloser type to defer response body reading until the first Read() call. This matches the async pattern used
by Xray-core's splithttp client implementation.

Fixes MetaCubeX#2709
@daiaji

daiaji commented Apr 17, 2026

Copy link
Copy Markdown

#2695
都异步了,顺手解决一下性能问题呗😘

@kyber1024

kyber1024 commented Apr 17, 2026

Copy link
Copy Markdown
Author

#2695 问题的RTT就是没有异步等待导致的,但是还有一个30ms的首包等待我不敢乱动怕导致特征,希望有经验的人来看一下qwq

@daiaji

daiaji commented Apr 17, 2026

Copy link
Copy Markdown

引入异步就不出意外的爆了😂

@kyber1024

Copy link
Copy Markdown
Author

确实爆了,在debug,可能是stream-one那里其实应该是要等一下才对的

…th async download

When download GET is async, upload POST may arrive at the server before GET creates the session. Using getSession (lookup-only) returns nil and responds 400. Switch to getOrCreateSession to allow either request to create the session on-demand, matching Xray-core's upsertSession behavior.
@kyber1024

Copy link
Copy Markdown
Author

@daiaji 麻烦再review一下,是异步导致服务端收到了预期之外的POST,getSession改为getOrCreateSession就可以了,我本地跑了go test都过了

@daiaji

daiaji commented Apr 17, 2026

Copy link
Copy Markdown

@daiaji 麻烦再review一下,是异步导致服务端收到了预期之外的POST,getSession改为getOrCreateSession就可以了,我本地跑了go test都过了

也没啥别的办法,只能说在actions跑个全平台的测试了。😂

各个平台都有自己的XP是这样的。

要不等主理人来看看吧。

@daiaji

daiaji commented Apr 17, 2026

Copy link
Copy Markdown

Win的小巧思这一块😂

@wwqgtxx

wwqgtxx commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator

改服务端倒是也可以,但是需要在getOrCreateSession加上类似原版upsertSession中30s超时机制,否则如果没有人调用uploadQueue.Read,会导致资源泄露

@kyber1024

Copy link
Copy Markdown
Author

改服务端倒是也可以,但是需要在getOrCreateSession加上类似原版upsertSession中30s超时机制,否则如果没有人调用uploadQueue.Read,会导致资源泄露

在改了,马上commit

@wwqgtxx

wwqgtxx commented Apr 17, 2026

Copy link
Copy Markdown
Collaborator

你的(*WaitReadCloser).Read里有race的代码,会导致panic

@kyber1024

Copy link
Copy Markdown
Author

没问题了合了?

@wwqgtxx wwqgtxx changed the title fix(transport/xhttp): async RoundTrip to fix CDN/reverse proxy deadlock chore: async xhttp RoundTrip to let some CDN/reverse proxy happy Apr 17, 2026
@wwqgtxx wwqgtxx merged commit 2247c0e into MetaCubeX:Alpha Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants