From 66dd7808b69088d847617164fbcd94254f49f8e4 Mon Sep 17 00:00:00 2001 From: nobody <59990325+vrnobody@users.noreply.github.com> Date: Fri, 17 Jan 2025 18:40:36 +0800 Subject: [PATCH] Commands: Fix dumping merged config for XHTTP (#4290) Fixes https://github.com/XTLS/Xray-core/issues/4287 --- common/reflect/marshal.go | 57 ++++++---- common/reflect/marshal_test.go | 201 +++++++++++++++++++-------------- 2 files changed, 150 insertions(+), 108 deletions(-) diff --git a/common/reflect/marshal.go b/common/reflect/marshal.go index 2b224b45..127dc8e0 100644 --- a/common/reflect/marshal.go +++ b/common/reflect/marshal.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" "reflect" - "slices" "strings" cnet "github.com/xtls/xray-core/common/net" @@ -32,6 +31,9 @@ func JSONMarshalWithoutEscape(t interface{}) ([]byte, error) { } func marshalTypedMessage(v *cserial.TypedMessage, ignoreNullValue bool, insertTypeInfo bool) interface{} { + if v == nil { + return nil + } tmsg, err := v.GetInstance() if err != nil { return nil @@ -56,7 +58,9 @@ func marshalSlice(v reflect.Value, ignoreNullValue bool, insertTypeInfo bool) in } func isNullValue(f reflect.StructField, rv reflect.Value) bool { - if rv.Kind() == reflect.String && rv.Len() == 0 { + if rv.Kind() == reflect.Struct { + return false + } else if rv.Kind() == reflect.String && rv.Len() == 0 { return true } else if !isValueKind(rv.Kind()) && rv.IsNil() { return true @@ -182,6 +186,12 @@ func marshalKnownType(v interface{}, ignoreNullValue bool, insertTypeInfo bool) case *conf.PortList: cpl := v.(*conf.PortList) return serializePortList(cpl.Build()) + case conf.Int32Range: + i32rng := v.(conf.Int32Range) + if i32rng.Left == i32rng.Right { + return i32rng.Left, true + } + return i32rng.String(), true case cnet.Address: if addr := v.(cnet.Address); addr != nil { return addr.String(), true @@ -192,28 +202,29 @@ func marshalKnownType(v interface{}, ignoreNullValue bool, insertTypeInfo bool) } } -var valueKinds = []reflect.Kind{ - reflect.Bool, - reflect.Int, - reflect.Int8, - reflect.Int16, - reflect.Int32, - reflect.Int64, - reflect.Uint, - reflect.Uint8, - reflect.Uint16, - reflect.Uint32, - reflect.Uint64, - reflect.Uintptr, - reflect.Float32, - reflect.Float64, - reflect.Complex64, - reflect.Complex128, - reflect.String, -} - func isValueKind(kind reflect.Kind) bool { - return slices.Contains(valueKinds, kind) + switch kind { + case reflect.Bool, + reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64, + reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64, + reflect.Uintptr, + reflect.Float32, + reflect.Float64, + reflect.Complex64, + reflect.Complex128, + reflect.String: + return true + default: + return false + } } func marshalInterface(v interface{}, ignoreNullValue bool, insertTypeInfo bool) interface{} { diff --git a/common/reflect/marshal_test.go b/common/reflect/marshal_test.go index 82194279..80df23f1 100644 --- a/common/reflect/marshal_test.go +++ b/common/reflect/marshal_test.go @@ -116,98 +116,129 @@ func TestMarshalConfigJson(t *testing.T) { "system", "inboundDownlink", "outboundUplink", + "XHTTP_IN", + "\"host\": \"bing.com\"", + "scMaxEachPostBytes", + "\"from\": 100", + "\"to\": 1000", + "\"from\": 1000000", + "\"to\": 1000000", } for _, kw := range keywords { if !strings.Contains(tc, kw) { - t.Error("marshaled config error") + t.Log("config.json:", tc) + t.Error("keyword not found:", kw) + break } } } func getConfig() string { return `{ - "log": { - "loglevel": "debug" - }, - "stats": {}, - "policy": { - "levels": { - "0": { - "statsUserUplink": true, - "statsUserDownlink": true - } - }, - "system": { - "statsInboundUplink": true, - "statsInboundDownlink": true, - "statsOutboundUplink": true, - "statsOutboundDownlink": true - } - }, - "inbounds": [ - { - "tag": "agentin", - "protocol": "http", - "port": 8080, - "listen": "127.0.0.1", - "settings": {} - }, - { - "listen": "127.0.0.1", - "port": 10085, - "protocol": "dokodemo-door", - "settings": { - "address": "127.0.0.1" - }, - "tag": "api-in" - } - ], - "api": { - "tag": "api", - "services": [ - "HandlerService", - "StatsService" - ] - }, - "routing": { - "rules": [ - { - "inboundTag": [ - "api-in" - ], - "outboundTag": "api", - "type": "field" - } - ], - "domainStrategy": "AsIs" - }, - "outbounds": [ - { - "protocol": "vless", - "settings": { - "vnext": [ - { - "address": "1.2.3.4", - "port": 1234, - "users": [ - { - "id": "4784f9b8-a879-4fec-9718-ebddefa47750", - "encryption": "none" - } - ] - } - ] - }, - "tag": "agentout", - "streamSettings": { - "network": "ws", - "security": "none", - "wsSettings": { - "path": "/?ed=2048", - "host": "bing.com" - } - } - } - ] - }` + "log": { + "loglevel": "debug" + }, + "stats": {}, + "policy": { + "levels": { + "0": { + "statsUserUplink": true, + "statsUserDownlink": true + } + }, + "system": { + "statsInboundUplink": true, + "statsInboundDownlink": true, + "statsOutboundUplink": true, + "statsOutboundDownlink": true + } + }, + "inbounds": [ + { + "tag": "agentin", + "protocol": "http", + "port": 18080, + "listen": "127.0.0.1", + "settings": {} + }, + { + "listen": "127.0.0.1", + "port": 10085, + "protocol": "dokodemo-door", + "settings": { + "address": "127.0.0.1" + }, + "tag": "api-in" + } + ], + "api": { + "tag": "api", + "services": [ + "HandlerService", + "StatsService" + ] + }, + "routing": { + "rules": [ + { + "inboundTag": [ + "api-in" + ], + "outboundTag": "api", + "type": "field" + } + ], + "domainStrategy": "AsIs" + }, + "outbounds": [ + { + "protocol": "vless", + "settings": { + "vnext": [ + { + "address": "1.2.3.4", + "port": 1234, + "users": [ + { + "id": "4784f9b8-a879-4fec-9718-ebddefa47750", + "encryption": "none" + } + ] + } + ] + }, + "tag": "XHTTP_IN", + "streamSettings": { + "network": "xhttp", + "xhttpSettings": { + "host": "bing.com", + "path": "/xhttp_client_upload", + "mode": "auto", + "extra": { + "noSSEHeader": false, + "scMaxEachPostBytes": 1000000, + "scMaxBufferedPosts": 30, + "xPaddingBytes": "100-1000" + } + }, + "sockopt": { + "tcpFastOpen": true, + "acceptProxyProtocol": false, + "tcpcongestion": "bbr", + "tcpMptcp": true + } + }, + "sniffing": { + "enabled": true, + "destOverride": [ + "http", + "tls", + "quic" + ], + "metadataOnly": false, + "routeOnly": true + } + } + ] +}` }