Update On Sun Mar 29 20:57:20 CEST 2026

This commit is contained in:
github-action[bot]
2026-03-29 20:57:20 +02:00
parent 638453a1b5
commit fb046ce894
428 changed files with 30064 additions and 26782 deletions
+8 -8
View File
@@ -378,7 +378,7 @@ jobs:
EOF
- name: Upload Prerelease
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
if: ${{ success() }}
with:
tag_name: Prerelease-${{ github.ref_name }}
@@ -468,10 +468,10 @@ jobs:
working-directory: bin
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
uses: docker/setup-qemu-action@v4
- name: Setup Docker buildx
uses: docker/setup-buildx-action@v3
uses: docker/setup-buildx-action@v4
with:
version: latest
@@ -480,7 +480,7 @@ jobs:
- name: Extract Docker metadata
if: ${{ github.event_name != 'workflow_dispatch' }}
id: meta_alpha
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: '${{ env.REGISTRY }}/${{ github.repository }}'
@@ -489,7 +489,7 @@ jobs:
- name: Extract Docker metadata
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' }}
id: meta_release
uses: docker/metadata-action@v5
uses: docker/metadata-action@v6
with:
images: '${{ env.REGISTRY }}/${{ github.repository }}'
tags: |
@@ -504,7 +504,7 @@ jobs:
ls bin/
- name: login to docker REGISTRY
uses: docker/login-action@v3
uses: docker/login-action@v4
with:
registry: ${{ env.REGISTRY }}
username: ${{ secrets.DOCKER_HUB_USER }}
@@ -514,7 +514,7 @@ jobs:
# https://github.com/docker/build-push-action
- name: Build and push Docker image
if: ${{ github.event_name != 'workflow_dispatch' }}
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
@@ -529,7 +529,7 @@ jobs:
- name: Build and push Docker image
if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' }}
uses: docker/build-push-action@v5
uses: docker/build-push-action@v7
with:
context: .
file: ./Dockerfile
+4 -3
View File
@@ -16,11 +16,12 @@ jobs:
trigger-CMFA-update:
runs-on: ubuntu-latest
steps:
- uses: tibdex/github-app-token@v1
- uses: actions/create-github-app-token@v3
id: generate-token
with:
app_id: ${{ secrets.MAINTAINER_APPID }}
private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }}
app-id: ${{ secrets.MAINTAINER_APPID }}
private-key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
- name: Trigger update-dependencies
run: |
-4
View File
@@ -267,8 +267,6 @@ func (v *Vless) dialXHTTPConn(ctx context.Context) (net.Conn, error) {
case "stream-one":
return xhttp.DialStreamOne(
ctx,
v.option.Server,
v.option.Port,
cfg,
func(ctx context.Context) (net.Conn, error) {
return v.dialer.DialContext(ctx, "tcp", v.addr)
@@ -280,8 +278,6 @@ func (v *Vless) dialXHTTPConn(ctx context.Context) (net.Conn, error) {
case "packet-up":
return xhttp.DialPacketUp(
ctx,
v.option.Server,
v.option.Port,
cfg,
func(ctx context.Context) (net.Conn, error) {
return v.dialer.DialContext(ctx, "tcp", v.addr)
@@ -1,31 +1,15 @@
package gun
package httputils
import (
"context"
"net"
"sync"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/http"
"github.com/metacubex/http/httptrace"
)
type Transport struct {
transport *http.Http2Transport
cfg *Config
ctx context.Context
cancel context.CancelFunc
closeOnce sync.Once
}
func (t *Transport) Close() error {
t.closeOnce.Do(func() {
t.cancel()
CloseHttp2Transport(t.transport)
})
return nil
}
type NetAddr struct {
remoteAddr net.Addr
localAddr net.Addr
@@ -39,7 +23,7 @@ func (addr NetAddr) LocalAddr() net.Addr {
return addr.localAddr
}
func (addr *NetAddr) SetAddrFromRequest(request *http.Request) {
func SetAddrFromRequest(addr *NetAddr, request *http.Request) {
if request.RemoteAddr != "" {
metadata := C.Metadata{}
if err := metadata.SetRemoteAddress(request.RemoteAddr); err == nil {
@@ -51,10 +35,11 @@ func (addr *NetAddr) SetAddrFromRequest(request *http.Request) {
}
}
func (addr *NetAddr) SetRemoteAddr(remoteAddr net.Addr) {
addr.remoteAddr = remoteAddr
}
func (addr *NetAddr) SetLocalAddr(localAddr net.Addr) {
addr.localAddr = localAddr
func NewAddrContext(addr *NetAddr, ctx context.Context) context.Context {
return httptrace.WithClientTrace(ctx, &httptrace.ClientTrace{
GotConn: func(connInfo httptrace.GotConnInfo) {
addr.localAddr = connInfo.Conn.LocalAddr()
addr.remoteAddr = connInfo.Conn.RemoteAddr()
},
})
}
@@ -0,0 +1,23 @@
package httputils
import (
"io"
"github.com/metacubex/http"
)
type closeIdleTransport interface {
CloseIdleConnections()
}
func CloseTransport(roundTripper http.RoundTripper) {
if tr, ok := roundTripper.(closeIdleTransport); ok {
tr.CloseIdleConnections() // for *http.Transport
}
if tr, ok := roundTripper.(*http.Http2Transport); ok {
closeHttp2Transport(tr) // for *http2.Transport
}
if tr, ok := roundTripper.(io.Closer); ok {
_ = tr.Close() // for *http3.Transport
}
}
@@ -1,4 +1,4 @@
package gun
package httputils
import (
"net"
@@ -44,7 +44,7 @@ func closeClientConn(cc *http.Http2ClientConn) { // like forceCloseConn() in htt
_ = cc.Close()
}
func CloseHttp2Transport(tr *http.Http2Transport) {
func closeHttp2Transport(tr *http.Http2Transport) {
connPool := transportConnPool(tr)
p := (*clientConnPool)((*efaceWords)(unsafe.Pointer(&connPool)).data)
p.mu.Lock()
+39 -24
View File
@@ -17,13 +17,13 @@ import (
"time"
"github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/common/httputils"
"github.com/metacubex/mihomo/common/pool"
tlsC "github.com/metacubex/mihomo/component/tls"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/vmess"
"github.com/metacubex/http"
"github.com/metacubex/http/httptrace"
"github.com/metacubex/tls"
)
@@ -40,10 +40,10 @@ var defaultHeader = http.Header{
type DialFn = func(ctx context.Context, network, addr string) (net.Conn, error)
type Conn struct {
initFn func() (io.ReadCloser, NetAddr, error)
initFn func(addr *httputils.NetAddr) (io.ReadCloser, error)
writer io.Writer // writer must not nil
closer io.Closer
NetAddr
httputils.NetAddr
initOnce sync.Once
initErr error
@@ -66,7 +66,7 @@ type Config struct {
}
func (g *Conn) initReader() {
reader, addr, err := g.initFn()
reader, err := g.initFn(&g.NetAddr)
if err != nil {
g.initErr = err
if closer, ok := g.writer.(io.Closer); ok {
@@ -74,7 +74,6 @@ func (g *Conn) initReader() {
}
return
}
g.NetAddr = addr
g.closeMutex.Lock()
defer g.closeMutex.Unlock()
@@ -152,8 +151,10 @@ func (g *Conn) Write(b []byte) (n int, err error) {
buf.Write(b)
_, err = g.writer.Write(buf.Bytes())
if err == io.ErrClosedPipe && g.initErr != nil {
err = g.initErr
if err == io.ErrClosedPipe {
if initErr := g.Init(); initErr != nil {
err = initErr
}
}
if flusher, ok := g.writer.(http.Flusher); ok {
@@ -175,8 +176,10 @@ func (g *Conn) WriteBuffer(buffer *buf.Buffer) error {
binary.PutUvarint(header[6:], uint64(dataLen))
_, err := g.writer.Write(buffer.Bytes())
if err == io.ErrClosedPipe && g.initErr != nil {
err = g.initErr
if err == io.ErrClosedPipe {
if initErr := g.Init(); initErr != nil {
err = initErr
}
}
if flusher, ok := g.writer.(http.Flusher); ok {
@@ -191,10 +194,6 @@ func (g *Conn) FrontHeadroom() int {
}
func (g *Conn) Close() error {
g.initOnce.Do(func() { // if initReader not called, it should not be run anymore
g.initErr = net.ErrClosed
})
g.closeMutex.Lock()
defer g.closeMutex.Unlock()
if g.closed {
@@ -247,6 +246,22 @@ func (g *Conn) SetDeadline(t time.Time) error {
return nil
}
type Transport struct {
transport *http.Http2Transport
cfg *Config
ctx context.Context
cancel context.CancelFunc
closeOnce sync.Once
}
func (t *Transport) Close() error {
t.closeOnce.Do(func() {
t.cancel()
httputils.CloseTransport(t.transport)
})
return nil
}
func NewTransport(dialFn DialFn, tlsConfig *vmess.TLSConfig, gunCfg *Config) *Transport {
dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) {
ctx, cancel := context.WithTimeout(ctx, C.DefaultTLSTimeout)
@@ -340,27 +355,27 @@ func (t *Transport) Dial() (net.Conn, error) {
Header: header,
}
request = request.WithContext(t.ctx)
initStarted := make(chan struct{})
conn := &Conn{
initFn: func() (io.ReadCloser, NetAddr, error) {
nAddr := NetAddr{}
trace := &httptrace.ClientTrace{
GotConn: func(connInfo httptrace.GotConnInfo) {
nAddr.SetLocalAddr(connInfo.Conn.LocalAddr())
nAddr.SetRemoteAddr(connInfo.Conn.RemoteAddr())
},
}
request = request.WithContext(httptrace.WithClientTrace(request.Context(), trace))
initFn: func(addr *httputils.NetAddr) (io.ReadCloser, error) {
close(initStarted)
request = request.WithContext(httputils.NewAddrContext(addr, request.Context()))
response, err := t.transport.RoundTrip(request)
if err != nil {
return nil, nAddr, err
return nil, err
}
return response.Body, nAddr, nil
return response.Body, nil
},
writer: writer,
}
go conn.Init()
// ensure conn.initOnce.Do has been called before return
// prevent the race caused by the return side immediately calling conn.Close
<-initStarted
return conn, nil
}
+4 -4
View File
@@ -8,6 +8,7 @@ import (
"time"
"github.com/metacubex/mihomo/common/buf"
"github.com/metacubex/mihomo/common/httputils"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/http"
@@ -41,10 +42,9 @@ func NewServerHandler(options ServerOption) http.Handler {
writer.WriteHeader(http.StatusOK)
conn := &Conn{
initFn: func() (io.ReadCloser, NetAddr, error) {
nAddr := NetAddr{}
nAddr.SetAddrFromRequest(request)
return request.Body, nAddr, nil
initFn: func(addr *httputils.NetAddr) (io.ReadCloser, error) {
httputils.SetAddrFromRequest(addr, request)
return request.Body, nil
},
writer: writer,
}
+5 -16
View File
@@ -11,20 +11,15 @@ import (
"sync"
"time"
"github.com/metacubex/mihomo/common/httputils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/vmess"
"github.com/metacubex/http"
"github.com/metacubex/http/httptrace"
"github.com/metacubex/tls"
"golang.org/x/exp/slices"
)
type RoundTripper interface {
http.RoundTripper
CloseIdleConnections()
}
type ResolvUDPFunc func(ctx context.Context, server string) (netip.AddrPort, error)
type ClientOptions struct {
@@ -46,7 +41,7 @@ type Client struct {
resolv ResolvUDPFunc
server string
auth string
roundTripper RoundTripper
roundTripper http.RoundTripper
startOnce sync.Once
healthCheck bool
healthCheckTimer *time.Timer
@@ -144,13 +139,7 @@ func (c *Client) roundTrip(request *http.Request, conn *httpConn) {
go func() {
timeout := time.AfterFunc(C.DefaultTCPTimeout, cancel) // only cancel when RoundTrip timeout
defer timeout.Stop() // RoundTrip already returned, stop the timer
trace := &httptrace.ClientTrace{
GotConn: func(connInfo httptrace.GotConnInfo) {
conn.SetLocalAddr(connInfo.Conn.LocalAddr())
conn.SetRemoteAddr(connInfo.Conn.RemoteAddr())
},
}
request = request.WithContext(httptrace.WithClientTrace(ctx, trace))
request = request.WithContext(httputils.NewAddrContext(&conn.NetAddr, ctx))
response, err := c.roundTripper.RoundTrip(request)
if err != nil {
_ = pipeWriter.CloseWithError(err)
@@ -221,7 +210,7 @@ func (c *Client) ListenICMP(ctx context.Context) (*IcmpConn, error) {
}
func (c *Client) Close() error {
forceCloseAllConnections(c.roundTripper)
httputils.CloseTransport(c.roundTripper)
if c.healthCheckTimer != nil {
c.healthCheckTimer.Stop()
}
@@ -229,7 +218,7 @@ func (c *Client) Close() error {
}
func (c *Client) ResetConnections() {
forceCloseAllConnections(c.roundTripper)
httputils.CloseTransport(c.roundTripper)
c.resetHealthCheckTimer()
}
@@ -1,18 +0,0 @@
package trusttunnel
import (
"github.com/metacubex/mihomo/transport/gun"
"github.com/metacubex/http"
"github.com/metacubex/quic-go/http3"
)
func forceCloseAllConnections(roundTripper RoundTripper) {
roundTripper.CloseIdleConnections()
switch tr := roundTripper.(type) {
case *http.Http2Transport:
gun.CloseHttp2Transport(tr)
case *http3.Transport:
_ = tr.Close()
}
}
+2 -2
View File
@@ -12,8 +12,8 @@ import (
"strings"
"time"
"github.com/metacubex/mihomo/common/httputils"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/transport/gun"
)
const (
@@ -98,7 +98,7 @@ type httpConn struct {
created chan struct{}
createErr error
cancelFn func()
gun.NetAddr
httputils.NetAddr
// deadlines
deadline *time.Timer
+5 -3
View File
@@ -6,6 +6,8 @@ import (
"net"
"time"
"github.com/metacubex/mihomo/common/httputils"
"github.com/metacubex/http"
"github.com/metacubex/http/h2c"
"github.com/metacubex/quic-go/http3"
@@ -160,7 +162,7 @@ func (s *Service) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
},
},
}
conn.SetAddrFromRequest(request)
httputils.SetAddrFromRequest(&conn.NetAddr, request)
conn.setUp(request.Body, nil)
firstPacket := buf.NewPacket()
destination, err := conn.ReadPacket(firstPacket)
@@ -197,7 +199,7 @@ func (s *Service) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
created: make(chan struct{}),
},
}
conn.SetAddrFromRequest(request)
httputils.SetAddrFromRequest(&conn.NetAddr, request)
conn.setUp(request.Body, nil)
s.icmpHandler.NewICMPConnection(ctx, conn)
}
@@ -220,7 +222,7 @@ func (s *Service) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
created: make(chan struct{}),
},
}
conn.SetAddrFromRequest(request)
httputils.SetAddrFromRequest(&conn.NetAddr, request)
conn.setUp(request.Body, nil)
_ = s.handler.NewConnection(ctx, conn, M.Metadata{
Protocol: "trusttunnel",
+33 -114
View File
@@ -10,47 +10,33 @@ import (
"net/url"
"strconv"
"sync"
"time"
"github.com/metacubex/mihomo/common/contextutils"
"github.com/metacubex/mihomo/transport/gun"
"github.com/metacubex/mihomo/common/httputils"
"github.com/metacubex/http"
"github.com/metacubex/http/httptrace"
"github.com/metacubex/tls"
)
type DialRawFunc func(ctx context.Context) (net.Conn, error)
type WrapTLSFunc func(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error)
type PacketUpConn struct {
type PacketUpWriter struct {
ctx context.Context
cfg *Config
address string
port int
host string
sessionID string
client *http.Client
transport http.RoundTripper
writeMu sync.Mutex
seq uint64
reader io.ReadCloser
gun.NetAddr
// deadlines
deadline *time.Timer
}
func (c *PacketUpConn) Read(b []byte) (int, error) {
return c.reader.Read(b)
}
func (c *PacketUpConn) Write(b []byte) (int, error) {
func (c *PacketUpWriter) Write(b []byte) (int, error) {
c.writeMu.Lock()
defer c.writeMu.Unlock()
u := url.URL{
Scheme: "https",
Host: c.host,
Host: c.cfg.Host,
Path: c.cfg.NormalizedPath(),
}
@@ -65,9 +51,9 @@ func (c *PacketUpConn) Write(b []byte) (int, error) {
if err := c.cfg.FillPacketRequest(req, c.sessionID, seqStr, b); err != nil {
return 0, err
}
req.Host = c.host
req.Host = c.cfg.Host
resp, err := c.client.Do(req)
resp, err := c.transport.RoundTrip(req)
if err != nil {
return 0, err
}
@@ -81,51 +67,20 @@ func (c *PacketUpConn) Write(b []byte) (int, error) {
return len(b), nil
}
func (c *PacketUpConn) Close() error {
if c.reader != nil {
return c.reader.Close()
}
return nil
}
func (c *PacketUpConn) SetReadDeadline(t time.Time) error { return c.SetDeadline(t) }
func (c *PacketUpConn) SetWriteDeadline(t time.Time) error { return c.SetDeadline(t) }
func (c *PacketUpConn) SetDeadline(t time.Time) error {
if t.IsZero() {
if c.deadline != nil {
c.deadline.Stop()
c.deadline = nil
}
return nil
}
d := time.Until(t)
if c.deadline != nil {
c.deadline.Reset(d)
return nil
}
c.deadline = time.AfterFunc(d, func() {
c.Close()
})
func (c *PacketUpWriter) Close() error {
httputils.CloseTransport(c.transport)
return nil
}
func DialStreamOne(
ctx context.Context,
address string,
port int,
cfg *Config,
dialRaw DialRawFunc,
wrapTLS WrapTLSFunc,
) (net.Conn, error) {
host := cfg.Host
if host == "" {
host = address
}
requestURL := url.URL{
Scheme: "https",
Host: host,
Host: cfg.Host,
Path: cfg.NormalizedPath(),
}
@@ -144,30 +99,19 @@ func DialStreamOne(
},
}
client := &http.Client{
Transport: transport,
}
pr, pw := io.Pipe()
conn := &Conn{
writer: pw,
}
trace := &httptrace.ClientTrace{
GotConn: func(connInfo httptrace.GotConnInfo) {
conn.SetLocalAddr(connInfo.Conn.LocalAddr())
conn.SetRemoteAddr(connInfo.Conn.RemoteAddr())
},
}
req, err := http.NewRequestWithContext(httptrace.WithClientTrace(contextutils.WithoutCancel(ctx), trace), http.MethodPost, requestURL.String(), pr)
req, err := http.NewRequestWithContext(httputils.NewAddrContext(&conn.NetAddr, contextutils.WithoutCancel(ctx)), http.MethodPost, requestURL.String(), pr)
if err != nil {
_ = pr.Close()
_ = pw.Close()
return nil, err
}
req.Host = host
req.Host = cfg.Host
if err := cfg.FillStreamRequest(req); err != nil {
_ = pr.Close()
@@ -175,34 +119,25 @@ func DialStreamOne(
return nil, err
}
type respResult struct {
resp *http.Response
err error
}
respCh := make(chan respResult, 1)
go func() {
resp, err := client.Do(req)
respCh <- respResult{resp: resp, err: err}
}()
result := <-respCh
if result.err != nil {
resp, err := transport.RoundTrip(req)
if err != nil {
_ = pr.Close()
_ = pw.Close()
return nil, result.err
httputils.CloseTransport(transport)
return nil, err
}
if result.resp.StatusCode < 200 || result.resp.StatusCode >= 300 {
_ = result.resp.Body.Close()
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
_ = resp.Body.Close()
_ = pr.Close()
_ = pw.Close()
return nil, fmt.Errorf("xhttp stream-one bad status: %s", result.resp.Status)
httputils.CloseTransport(transport)
return nil, fmt.Errorf("xhttp stream-one bad status: %s", resp.Status)
}
conn.reader = result.resp.Body
conn.reader = resp.Body
conn.onClose = func() {
_ = result.resp.Body.Close()
_ = resp.Body.Close()
_ = pr.Close()
httputils.CloseTransport(transport)
}
return conn, nil
@@ -210,17 +145,10 @@ func DialStreamOne(
func DialPacketUp(
ctx context.Context,
address string,
port int,
cfg *Config,
dialRaw DialRawFunc,
wrapTLS WrapTLSFunc,
) (net.Conn, error) {
host := cfg.Host
if host == "" {
host = address
}
transport := &http.Http2Transport{
DialTLSContext: func(ctx context.Context, network string, addr string, _ *tls.Config) (net.Conn, error) {
raw, err := dialRaw(ctx)
@@ -236,49 +164,40 @@ func DialPacketUp(
},
}
client := &http.Client{Transport: transport}
sessionID := newSessionID()
downloadURL := url.URL{
Scheme: "https",
Host: host,
Host: cfg.Host,
Path: cfg.NormalizedPath(),
}
conn := &PacketUpConn{
ctx: contextutils.WithoutCancel(ctx),
ctx = contextutils.WithoutCancel(ctx)
writer := &PacketUpWriter{
ctx: ctx,
cfg: cfg,
address: address,
port: port,
host: host,
sessionID: sessionID,
client: client,
transport: transport,
seq: 0,
}
conn := &Conn{writer: writer}
trace := &httptrace.ClientTrace{
GotConn: func(connInfo httptrace.GotConnInfo) {
conn.SetLocalAddr(connInfo.Conn.LocalAddr())
conn.SetRemoteAddr(connInfo.Conn.RemoteAddr())
},
}
req, err := http.NewRequestWithContext(httptrace.WithClientTrace(conn.ctx, trace), http.MethodGet, downloadURL.String(), nil)
req, err := http.NewRequestWithContext(httputils.NewAddrContext(&conn.NetAddr, ctx), http.MethodGet, downloadURL.String(), nil)
if err != nil {
return nil, err
}
if err := cfg.FillDownloadRequest(req, sessionID); err != nil {
return nil, err
}
req.Host = host
req.Host = cfg.Host
resp, err := client.Do(req)
resp, err := transport.RoundTrip(req)
if err != nil {
return nil, err
}
if resp.StatusCode != http.StatusOK {
_ = resp.Body.Close()
httputils.CloseTransport(transport)
return nil, fmt.Errorf("xhttp packet-up download bad status: %s", resp.Status)
}
conn.reader = resp.Body
+2 -2
View File
@@ -4,14 +4,14 @@ import (
"io"
"time"
"github.com/metacubex/mihomo/transport/gun"
"github.com/metacubex/mihomo/common/httputils"
)
type Conn struct {
writer io.WriteCloser
reader io.ReadCloser
onClose func()
gun.NetAddr
httputils.NetAddr
// deadlines
deadline *time.Timer
+3 -2
View File
@@ -8,6 +8,7 @@ import (
"sync"
"time"
"github.com/metacubex/mihomo/common/httputils"
N "github.com/metacubex/mihomo/common/net"
"github.com/metacubex/http"
@@ -194,7 +195,7 @@ func (h *requestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
writer: httpSC,
reader: httpSC,
}
conn.SetAddrFromRequest(r)
httputils.SetAddrFromRequest(&conn.NetAddr, r)
go h.connHandler(N.NewDeadlineConn(conn))
@@ -228,7 +229,7 @@ func (h *requestHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
h.deleteSession(sessionID)
},
}
conn.SetAddrFromRequest(r)
httputils.SetAddrFromRequest(&conn.NetAddr, r)
go h.connHandler(N.NewDeadlineConn(conn))