mirror of
https://github.com/fatedier/frp.git
synced 2026-03-08 10:59:11 +08:00
pkg/config: fix line numbers shown incorrectly for TOML type mismatch errors (#5195)
This commit is contained in:
@@ -180,24 +180,26 @@ func LoadConfigure(b []byte, c any, strict bool, formats ...string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
originalBytes := b
|
originalBytes := b
|
||||||
|
parsedFromTOML := false
|
||||||
|
|
||||||
var tomlObj any
|
var tomlObj any
|
||||||
tomlErr := toml.Unmarshal(b, &tomlObj)
|
tomlErr := toml.Unmarshal(b, &tomlObj)
|
||||||
if tomlErr == nil {
|
if tomlErr == nil {
|
||||||
|
parsedFromTOML = true
|
||||||
var err error
|
var err error
|
||||||
b, err = jsonx.Marshal(&tomlObj)
|
b, err = jsonx.Marshal(&tomlObj)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if format == "toml" {
|
} else if format == "toml" {
|
||||||
// File is known to be TOML but has syntax errors — report with line/column info.
|
// File is known to be TOML but has syntax errors.
|
||||||
return formatTOMLError(tomlErr)
|
return formatTOMLError(tomlErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the buffer smells like JSON (first non-whitespace character is '{'), unmarshal as JSON directly.
|
// If the buffer smells like JSON (first non-whitespace character is '{'), unmarshal as JSON directly.
|
||||||
if yaml.IsJSONBuffer(b) {
|
if yaml.IsJSONBuffer(b) {
|
||||||
if err := decodeJSONContent(b, c, strict); err != nil {
|
if err := decodeJSONContent(b, c, strict); err != nil {
|
||||||
return enhanceDecodeError(err, originalBytes)
|
return enhanceDecodeError(err, originalBytes, !parsedFromTOML)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -206,7 +208,7 @@ func LoadConfigure(b []byte, c any, strict bool, formats ...string) error {
|
|||||||
if strict {
|
if strict {
|
||||||
// In strict mode, always use our custom handler to support YAML merge
|
// In strict mode, always use our custom handler to support YAML merge
|
||||||
if err := parseYAMLWithDotFieldsHandling(b, c); err != nil {
|
if err := parseYAMLWithDotFieldsHandling(b, c); err != nil {
|
||||||
return enhanceDecodeError(err, originalBytes)
|
return enhanceDecodeError(err, originalBytes, !parsedFromTOML)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -223,18 +225,20 @@ func formatTOMLError(err error) error {
|
|||||||
}
|
}
|
||||||
var strictErr *toml.StrictMissingError
|
var strictErr *toml.StrictMissingError
|
||||||
if errors.As(err, &strictErr) {
|
if errors.As(err, &strictErr) {
|
||||||
return fmt.Errorf("toml: %s", strictErr.Error())
|
return strictErr
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// enhanceDecodeError tries to add field path and line number information to JSON/YAML decode errors.
|
// enhanceDecodeError tries to add field path and line number information to JSON/YAML decode errors.
|
||||||
func enhanceDecodeError(err error, originalContent []byte) error {
|
func enhanceDecodeError(err error, originalContent []byte, includeLine bool) error {
|
||||||
var typeErr *json.UnmarshalTypeError
|
var typeErr *json.UnmarshalTypeError
|
||||||
if errors.As(err, &typeErr) && typeErr.Field != "" {
|
if errors.As(err, &typeErr) && typeErr.Field != "" {
|
||||||
line := findFieldLineInContent(originalContent, typeErr.Field)
|
if includeLine {
|
||||||
if line > 0 {
|
line := findFieldLineInContent(originalContent, typeErr.Field)
|
||||||
return fmt.Errorf("line %d: field \"%s\": cannot unmarshal %s into %s", line, typeErr.Field, typeErr.Value, typeErr.Type)
|
if line > 0 {
|
||||||
|
return fmt.Errorf("line %d: field \"%s\": cannot unmarshal %s into %s", line, typeErr.Field, typeErr.Value, typeErr.Type)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return fmt.Errorf("field \"%s\": cannot unmarshal %s into %s", typeErr.Field, typeErr.Value, typeErr.Type)
|
return fmt.Errorf("field \"%s\": cannot unmarshal %s into %s", typeErr.Field, typeErr.Value, typeErr.Type)
|
||||||
}
|
}
|
||||||
@@ -244,6 +248,10 @@ func enhanceDecodeError(err error, originalContent []byte) error {
|
|||||||
// findFieldLineInContent searches the original config content for a field name
|
// findFieldLineInContent searches the original config content for a field name
|
||||||
// and returns the 1-indexed line number where it appears, or 0 if not found.
|
// and returns the 1-indexed line number where it appears, or 0 if not found.
|
||||||
func findFieldLineInContent(content []byte, fieldPath string) int {
|
func findFieldLineInContent(content []byte, fieldPath string) int {
|
||||||
|
if fieldPath == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// Use the last component of the field path (e.g. "proxies" from "proxies" or
|
// Use the last component of the field path (e.g. "proxies" from "proxies" or
|
||||||
// "protocol" from "transport.protocol").
|
// "protocol" from "transport.protocol").
|
||||||
parts := strings.Split(fieldPath, ".")
|
parts := strings.Split(fieldPath, ".")
|
||||||
|
|||||||
@@ -496,7 +496,7 @@ serverPort: 7000
|
|||||||
require.Equal(7000, clientCfg.ServerPort)
|
require.Equal(7000, clientCfg.ServerPort)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTOMLSyntaxErrorWithLineNumber(t *testing.T) {
|
func TestTOMLSyntaxErrorWithPosition(t *testing.T) {
|
||||||
require := require.New(t)
|
require := require.New(t)
|
||||||
|
|
||||||
// TOML with syntax error (unclosed table array header)
|
// TOML with syntax error (unclosed table array header)
|
||||||
@@ -510,8 +510,9 @@ name = "test"
|
|||||||
clientCfg := v1.ClientConfig{}
|
clientCfg := v1.ClientConfig{}
|
||||||
err := LoadConfigure([]byte(content), &clientCfg, false, "toml")
|
err := LoadConfigure([]byte(content), &clientCfg, false, "toml")
|
||||||
require.Error(err)
|
require.Error(err)
|
||||||
require.Contains(err.Error(), "line")
|
|
||||||
require.Contains(err.Error(), "toml")
|
require.Contains(err.Error(), "toml")
|
||||||
|
require.Contains(err.Error(), "line")
|
||||||
|
require.Contains(err.Error(), "column")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTOMLTypeMismatchErrorWithFieldInfo(t *testing.T) {
|
func TestTOMLTypeMismatchErrorWithFieldInfo(t *testing.T) {
|
||||||
@@ -529,6 +530,7 @@ proxies = "this should be a table array"
|
|||||||
// The error should contain field info
|
// The error should contain field info
|
||||||
errMsg := err.Error()
|
errMsg := err.Error()
|
||||||
require.Contains(errMsg, "proxies")
|
require.Contains(errMsg, "proxies")
|
||||||
|
require.NotContains(errMsg, "line")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFindFieldLineInContent(t *testing.T) {
|
func TestFindFieldLineInContent(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user