2020-11-25 19:01:53 +08:00
package conf
import (
"encoding/json"
2024-06-29 14:32:57 -04:00
"github.com/xtls/xray-core/common/errors"
2020-12-04 09:36:16 +08:00
"github.com/xtls/xray-core/common/protocol"
"github.com/xtls/xray-core/common/serial"
"github.com/xtls/xray-core/proxy/http"
2023-08-10 04:43:34 +00:00
"google.golang.org/protobuf/proto"
2020-11-25 19:01:53 +08:00
)
type HTTPAccount struct {
Username string ` json:"user" `
Password string ` json:"pass" `
}
func ( v * HTTPAccount ) Build ( ) * http . Account {
return & http . Account {
Username : v . Username ,
Password : v . Password ,
}
}
type HTTPServerConfig struct {
Accounts [ ] * HTTPAccount ` json:"accounts" `
Transparent bool ` json:"allowTransparent" `
UserLevel uint32 ` json:"userLevel" `
}
func ( c * HTTPServerConfig ) Build ( ) ( proto . Message , error ) {
config := & http . ServerConfig {
AllowTransparent : c . Transparent ,
UserLevel : c . UserLevel ,
}
if len ( c . Accounts ) > 0 {
config . Accounts = make ( map [ string ] string )
for _ , account := range c . Accounts {
config . Accounts [ account . Username ] = account . Password
}
}
return config , nil
}
type HTTPRemoteConfig struct {
Address * Address ` json:"address" `
Port uint16 ` json:"port" `
Users [ ] json . RawMessage ` json:"users" `
}
2021-10-19 12:57:14 -04:00
2020-11-25 19:01:53 +08:00
type HTTPClientConfig struct {
2025-09-11 21:48:20 +08:00
Address * Address ` json:"address" `
Port uint16 ` json:"port" `
Level uint32 ` json:"level" `
Email string ` json:"email" `
Username string ` json:"user" `
Password string ` json:"pass" `
Servers [ ] * HTTPRemoteConfig ` json:"servers" `
Headers map [ string ] string ` json:"headers" `
2020-11-25 19:01:53 +08:00
}
func ( v * HTTPClientConfig ) Build ( ) ( proto . Message , error ) {
config := new ( http . ClientConfig )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
v . Servers = [ ] * HTTPRemoteConfig {
{
Address : v . Address ,
Port : v . Port ,
} ,
}
2025-09-15 21:31:27 +08:00
if len ( v . Username ) > 0 {
v . Servers [ 0 ] . Users = [ ] json . RawMessage { { } }
}
}
if len ( v . Servers ) != 1 {
return nil , errors . New ( ` HTTP settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple HTTP outbounds and routing balancer instead ` )
2025-09-11 21:48:20 +08:00
}
2025-09-15 21:31:27 +08:00
for _ , serverConfig := range v . Servers {
if len ( serverConfig . Users ) > 1 {
return nil , errors . New ( ` HTTP servers: "users" should have one member at most. Multiple members in "users" should use multiple HTTP outbounds and routing balancer instead ` )
}
2020-11-25 19:01:53 +08:00
server := & protocol . ServerEndpoint {
Address : serverConfig . Address . Build ( ) ,
Port : uint32 ( serverConfig . Port ) ,
}
for _ , rawUser := range serverConfig . Users {
user := new ( protocol . User )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
user . Level = v . Level
user . Email = v . Email
} else {
if err := json . Unmarshal ( rawUser , user ) ; err != nil {
return nil , errors . New ( "failed to parse HTTP user" ) . Base ( err ) . AtError ( )
}
2020-11-25 19:01:53 +08:00
}
account := new ( HTTPAccount )
2025-09-11 21:48:20 +08:00
if v . Address != nil {
account . Username = v . Username
account . Password = v . Password
} else {
if err := json . Unmarshal ( rawUser , account ) ; err != nil {
return nil , errors . New ( "failed to parse HTTP account" ) . Base ( err ) . AtError ( )
}
2020-11-25 19:01:53 +08:00
}
user . Account = serial . ToTypedMessage ( account . Build ( ) )
2025-09-15 21:31:27 +08:00
server . User = user
break
2020-11-25 19:01:53 +08:00
}
2025-09-15 21:31:27 +08:00
config . Server = server
break
2020-11-25 19:01:53 +08:00
}
2022-12-15 19:15:43 +08:00
config . Header = make ( [ ] * http . Header , 0 , 32 )
for key , value := range v . Headers {
config . Header = append ( config . Header , & http . Header {
Key : key ,
Value : value ,
} )
}
2020-11-25 19:01:53 +08:00
return config , nil
}