Add MASQUE/CONNECT-UDP support (RFC 9298)
Implement UDP tunneling over HTTP/3 using HTTP Datagrams (RFC 9297): - Add masque handler for server-side CONNECT-UDP - Add masque connector and h3-masque dialer for client-side - Add enableDatagrams option to HTTP/3 listener - Add shared utilities for datagram connections and path parsing Resource management and connection caching: - Add deferred stream cleanup in connector on error paths - Add IsClosed() and Close() methods to Client for proper session management - Clean up stale cached clients in dialer before reuse - Close underlying stream when DatagramConn is closed - Move RequestStream opening from connector to dialer to enable dead connection detection and cache invalidation (follows QUIC dialer pattern)
This commit is contained in:
committed by
ginuerzh
parent
b3b5986b63
commit
7625973ca1
@@ -0,0 +1,60 @@
|
||||
package masque
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
// WellKnownPath is the well-known path prefix for MASQUE UDP proxying
|
||||
WellKnownPath = "/.well-known/masque/udp/"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrInvalidPath = errors.New("masque: invalid path template")
|
||||
ErrInvalidPort = errors.New("masque: invalid port number")
|
||||
)
|
||||
|
||||
// ParseMasquePath parses a MASQUE UDP proxy path template.
|
||||
// The expected format is: /.well-known/masque/udp/{host}/{port}/
|
||||
// Returns the host and port extracted from the path.
|
||||
func ParseMasquePath(path string) (host string, port int, err error) {
|
||||
if !strings.HasPrefix(path, WellKnownPath) {
|
||||
return "", 0, ErrInvalidPath
|
||||
}
|
||||
|
||||
remainder := strings.TrimPrefix(path, WellKnownPath)
|
||||
remainder = strings.TrimSuffix(remainder, "/")
|
||||
|
||||
parts := strings.Split(remainder, "/")
|
||||
if len(parts) != 2 {
|
||||
return "", 0, ErrInvalidPath
|
||||
}
|
||||
|
||||
host = parts[0]
|
||||
if host == "" {
|
||||
return "", 0, ErrInvalidPath
|
||||
}
|
||||
|
||||
// URL decode the host in case it contains percent-encoded characters
|
||||
host, err = url.PathUnescape(host)
|
||||
if err != nil {
|
||||
return "", 0, ErrInvalidPath
|
||||
}
|
||||
|
||||
port, err = strconv.Atoi(parts[1])
|
||||
if err != nil || port <= 0 || port > 65535 {
|
||||
return "", 0, ErrInvalidPort
|
||||
}
|
||||
|
||||
return host, port, nil
|
||||
}
|
||||
|
||||
// BuildMasquePath constructs a MASQUE UDP proxy path from host and port.
|
||||
func BuildMasquePath(host string, port int) string {
|
||||
// URL encode the host in case it contains special characters (like IPv6 addresses)
|
||||
encodedHost := url.PathEscape(host)
|
||||
return WellKnownPath + encodedHost + "/" + strconv.Itoa(port) + "/"
|
||||
}
|
||||
Reference in New Issue
Block a user