add v2ray extra options

This commit is contained in:
Mobin 2025-09-07 20:23:53 +03:30
parent d57183a218
commit 80bf1f838e
5 changed files with 69 additions and 7 deletions

View File

@ -2,12 +2,25 @@ package adapter
import (
"context"
"encoding/base64"
"net"
"net/http"
"net/url"
E "github.com/sagernet/sing/common/exceptions"
N "github.com/sagernet/sing/common/network"
)
type V2RayExtraOptionsKeyType int
var V2RayExtraOptionsKey V2RayExtraOptionsKeyType = 1
type V2RayExtraOptions struct {
URL *url.URL
QueryParams url.Values
Headers http.Header
}
type V2RayServerTransport interface {
Network() []string
Serve(listener net.Listener) error
@ -24,3 +37,32 @@ type V2RayClientTransport interface {
DialContext(ctx context.Context) (net.Conn, error)
Close() error
}
func (options *V2RayExtraOptions) Apply(requestURL *url.URL, headers http.Header) (*url.URL, http.Header) {
copyURL := *requestURL
copyHeaders := headers.Clone()
if options.URL != nil {
copyURL = *options.URL
}
if options.QueryParams != nil {
rQuery := copyURL.Query()
for key, values := range options.QueryParams {
for _, value := range values {
if rQuery.Has(key) {
rQuery.Add(key, value)
} else {
rQuery.Set(key, value)
}
}
}
copyURL.RawQuery = base64.RawURLEncoding.EncodeToString([]byte(rQuery.Encode()))
}
if options.Headers != nil {
for key, values := range options.Headers {
for _, value := range values {
copyHeaders.Add(key, value)
}
}
}
return &copyURL, copyHeaders
}

View File

@ -104,10 +104,16 @@ func (c *Client) dialHTTP(ctx context.Context) (net.Conn, error) {
return nil, err
}
requestURL, headers := &c.requestURL, c.headers.Clone()
options, ok := ctx.Value(adapter.V2RayExtraOptionsKey).(adapter.V2RayExtraOptions)
if ok {
requestURL, headers = options.Apply(requestURL, headers)
}
request := &http.Request{
Method: c.method,
URL: &c.requestURL,
Header: c.headers.Clone(),
URL: requestURL,
Header: headers,
}
switch hostLen := len(c.host); hostLen {
case 0:
@ -122,12 +128,17 @@ func (c *Client) dialHTTP(ctx context.Context) (net.Conn, error) {
}
func (c *Client) dialHTTP2(ctx context.Context) (net.Conn, error) {
requestURL, headers := &c.requestURL, c.headers.Clone()
options, ok := ctx.Value(adapter.V2RayExtraOptionsKey).(adapter.V2RayExtraOptions)
if ok {
requestURL, headers = options.Apply(requestURL, headers)
}
pipeInReader, pipeInWriter := io.Pipe()
request := &http.Request{
Method: c.method,
Body: pipeInReader,
URL: &c.requestURL,
Header: c.headers.Clone(),
URL: requestURL,
Header: headers,
}
request = request.WithContext(ctx)
switch hostLen := len(c.host); hostLen {

View File

@ -74,6 +74,11 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
}
func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
requestURL, headers := &c.requestURL, c.headers.Clone()
options, ok := ctx.Value(adapter.V2RayExtraOptionsKey).(adapter.V2RayExtraOptions)
if ok {
requestURL, headers = options.Apply(requestURL, headers)
}
conn, err := c.dialer.DialContext(ctx, N.NetworkTCP, c.serverAddr)
if err != nil {
return nil, err
@ -86,8 +91,8 @@ func (c *Client) DialContext(ctx context.Context) (net.Conn, error) {
}
request := &http.Request{
Method: http.MethodGet,
URL: &c.requestURL,
Header: c.headers.Clone(),
URL: requestURL,
Header: headers,
Host: c.host,
}
request.Header.Set("Connection", "Upgrade")

View File

@ -75,6 +75,10 @@ func NewClient(ctx context.Context, dialer N.Dialer, serverAddr M.Socksaddr, opt
}
func (c *Client) dialContext(ctx context.Context, requestURL *url.URL, headers http.Header) (*WebsocketConn, error) {
options, ok := ctx.Value(adapter.V2RayExtraOptionsKey).(adapter.V2RayExtraOptions)
if ok {
requestURL, headers = options.Apply(requestURL, headers)
}
conn, err := c.dialer.DialContext(ctx, N.NetworkTCP, c.serverAddr)
if err != nil {
return nil, err

View File

@ -77,7 +77,7 @@ func (s *Server) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
)
if s.earlyDataHeaderName == "" {
if strings.HasPrefix(request.URL.RequestURI(), s.path) {
earlyDataStr := request.URL.RequestURI()[len(s.path):]
earlyDataStr := request.URL.RequestURI()[len(s.path)+len("?"):]
earlyData, err = base64.RawURLEncoding.DecodeString(earlyDataStr)
} else {
s.invalidRequest(writer, request, http.StatusNotFound, E.New("bad path: ", request.URL.Path))