mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-07-10 01:57:17 +03:00
Add new admin panel, failover, dns fallback, providers, limiters. Update XHTTP
This commit is contained in:
150
transport/v2rayxhttp/utils.go
Normal file
150
transport/v2rayxhttp/utils.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package xhttp
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/sagernet/sing-box/common/xray/buf"
|
||||
"github.com/sagernet/sing-box/common/xray/utils"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
)
|
||||
|
||||
func FillStreamRequest(request *http.Request, sessionId string, seqStr string, options *option.V2RayXHTTPBaseOptions) {
|
||||
request.Header = options.GetRequestHeader()
|
||||
length := int(options.GetNormalizedXPaddingBytes().Rand())
|
||||
config := XPaddingConfig{Length: length}
|
||||
if options.XPaddingObfsMode {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: options.XPaddingPlacement,
|
||||
Key: options.XPaddingKey,
|
||||
Header: options.XPaddingHeader,
|
||||
RawURL: request.URL.String(),
|
||||
}
|
||||
config.Method = PaddingMethod(options.XPaddingMethod)
|
||||
} else {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: option.PlacementQueryInHeader,
|
||||
Key: "x_padding",
|
||||
Header: "Referer",
|
||||
RawURL: request.URL.String(),
|
||||
}
|
||||
}
|
||||
ApplyXPaddingToRequest(request, config)
|
||||
ApplyMetaToRequest(options, request, sessionId, "")
|
||||
if request.Body != nil && !options.NoGRPCHeader { // stream-up/one
|
||||
request.Header.Set("Content-Type", "application/grpc")
|
||||
}
|
||||
}
|
||||
|
||||
func FillPacketRequest(request *http.Request, sessionId string, seqStr string, payload buf.MultiBuffer, options *option.V2RayXHTTPBaseOptions) error {
|
||||
dataPlacement := options.GetNormalizedUplinkDataPlacement()
|
||||
if dataPlacement == option.PlacementBody || dataPlacement == option.PlacementAuto {
|
||||
request.Header = options.GetRequestHeader()
|
||||
request.Body = io.NopCloser(&buf.MultiBufferContainer{MultiBuffer: payload})
|
||||
request.ContentLength = int64(payload.Len())
|
||||
} else {
|
||||
data := make([]byte, payload.Len())
|
||||
payload.Copy(data)
|
||||
buf.ReleaseMulti(payload)
|
||||
switch dataPlacement {
|
||||
case option.PlacementHeader:
|
||||
request.Header = GetRequestHeaderWithPayload(data, options)
|
||||
case option.PlacementCookie:
|
||||
request.Header = options.GetRequestHeader()
|
||||
for _, cookie := range GetRequestCookiesWithPayload(data, options) {
|
||||
request.AddCookie(cookie)
|
||||
}
|
||||
}
|
||||
}
|
||||
length := int(options.GetNormalizedXPaddingBytes().Rand())
|
||||
config := XPaddingConfig{Length: length}
|
||||
if options.XPaddingObfsMode {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: options.XPaddingPlacement,
|
||||
Key: options.XPaddingKey,
|
||||
Header: options.XPaddingHeader,
|
||||
RawURL: request.URL.String(),
|
||||
}
|
||||
config.Method = PaddingMethod(options.XPaddingMethod)
|
||||
} else {
|
||||
config.Placement = XPaddingPlacement{
|
||||
Placement: option.PlacementQueryInHeader,
|
||||
Key: "x_padding",
|
||||
Header: "Referer",
|
||||
RawURL: request.URL.String(),
|
||||
}
|
||||
}
|
||||
ApplyXPaddingToRequest(request, config)
|
||||
ApplyMetaToRequest(options, request, sessionId, seqStr)
|
||||
return nil
|
||||
}
|
||||
|
||||
func WriteResponseHeader(writer http.ResponseWriter, requestMethod string, requestHeader http.Header, options *option.V2RayXHTTPOptions) {
|
||||
// CORS headers for the browser dialer
|
||||
if origin := requestHeader.Get("Origin"); origin == "" {
|
||||
writer.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
} else {
|
||||
// Chrome says: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
|
||||
writer.Header().Set("Access-Control-Allow-Origin", origin)
|
||||
}
|
||||
if options.GetNormalizedSessionPlacement() == option.PlacementCookie ||
|
||||
options.GetNormalizedSeqPlacement() == option.PlacementCookie ||
|
||||
options.XPaddingPlacement == option.PlacementCookie ||
|
||||
options.GetNormalizedUplinkDataPlacement() == option.PlacementCookie {
|
||||
writer.Header().Set("Access-Control-Allow-Credentials", "true")
|
||||
}
|
||||
if requestMethod == "OPTIONS" {
|
||||
requestedMethod := requestHeader.Get("Access-Control-Request-Method")
|
||||
if requestedMethod != "" {
|
||||
writer.Header().Set("Access-Control-Allow-Methods", requestedMethod)
|
||||
} else {
|
||||
writer.Header().Set("Access-Control-Allow-Methods", "*")
|
||||
}
|
||||
requestedHeaders := requestHeader.Get("Access-Control-Request-Headers")
|
||||
if requestedHeaders == "" {
|
||||
writer.Header().Set("Access-Control-Allow-Headers", "*")
|
||||
} else {
|
||||
writer.Header().Set("Access-Control-Allow-Headers", requestedHeaders)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func GetRequestHeader(options *option.V2RayXHTTPBaseOptions) http.Header {
|
||||
header := http.Header{}
|
||||
for k, v := range options.Headers {
|
||||
header.Add(k, v)
|
||||
}
|
||||
utils.TryDefaultHeadersWith(header, "fetch")
|
||||
return header
|
||||
}
|
||||
|
||||
func GetRequestHeaderWithPayload(payload []byte, options *option.V2RayXHTTPBaseOptions) http.Header {
|
||||
header := GetRequestHeader(options)
|
||||
key := options.UplinkDataKey
|
||||
encodedData := base64.RawURLEncoding.EncodeToString(payload)
|
||||
for i := 0; len(encodedData) > 0; i++ {
|
||||
chunkSize := min(int(options.GetNormalizedUplinkChunkSize().Rand()), len(encodedData))
|
||||
chunk := encodedData[:chunkSize]
|
||||
encodedData = encodedData[chunkSize:]
|
||||
headerKey := fmt.Sprintf("%s-%d", key, i)
|
||||
header.Set(headerKey, chunk)
|
||||
}
|
||||
|
||||
return header
|
||||
}
|
||||
|
||||
func GetRequestCookiesWithPayload(payload []byte, options *option.V2RayXHTTPBaseOptions) []*http.Cookie {
|
||||
cookies := []*http.Cookie{}
|
||||
key := options.UplinkDataKey
|
||||
encodedData := base64.RawURLEncoding.EncodeToString(payload)
|
||||
for i := 0; len(encodedData) > 0; i++ {
|
||||
chunkSize := min(int(options.GetNormalizedUplinkChunkSize().Rand()), len(encodedData))
|
||||
chunk := encodedData[:chunkSize]
|
||||
encodedData = encodedData[chunkSize:]
|
||||
cookieName := fmt.Sprintf("%s_%d", key, i)
|
||||
cookies = append(cookies, &http.Cookie{Name: cookieName, Value: chunk})
|
||||
}
|
||||
return cookies
|
||||
}
|
||||
Reference in New Issue
Block a user