diff --git a/bindparam.go b/bindparam.go index 5abe5c7..b7dd324 100644 --- a/bindparam.go +++ b/bindparam.go @@ -155,16 +155,21 @@ func BindStyledParameterWithOptions(style string, paramName string, value string return bindSplitPartsToDestinationArray(parts, dest) } - // For primitive types, we still need to strip style prefixes (e.g. label's - // leading "." or matrix's ";paramName=") before binding. - parts, err := splitStyledParameter(style, opts.Explode, false, paramName, value) - if err != nil { - return fmt.Errorf("error splitting parameter '%s': %w", paramName, err) - } - if len(parts) != 1 { - return fmt.Errorf("parameter '%s': expected single value, got %d parts", paramName, len(parts)) + // For primitive types, only label and matrix styles need prefix stripping + // via splitStyledParameter. Simple and form styles can bind the raw value + // directly — splitting on commas would incorrectly reject primitive values + // that contain commas (see https://github.com/oapi-codegen/runtime/issues/114). + if style == "label" || style == "matrix" { + parts, err := splitStyledParameter(style, opts.Explode, false, paramName, value) + if err != nil { + return fmt.Errorf("error splitting parameter '%s': %w", paramName, err) + } + if len(parts) != 1 { + return fmt.Errorf("parameter '%s': expected single value, got %d parts", paramName, len(parts)) + } + value = parts[0] } - return BindStringToObject(parts[0], dest) + return BindStringToObject(value, dest) } // This is a complex set of operations, but each given parameter style can be diff --git a/bindparam_test.go b/bindparam_test.go index ef6b76e..01e825f 100644 --- a/bindparam_test.go +++ b/bindparam_test.go @@ -1284,3 +1284,54 @@ func TestBindStyledParameterWithLocation(t *testing.T) { assert.EqualValues(t, expectedMap, dstMap) }) } + +// TestBindStyledParameter_HeaderWithCommas reproduces +// https://github.com/oapi-codegen/runtime/issues/114 +// Header parameters using simple style should accept string values containing +// commas without treating them as array delimiters. +func TestBindStyledParameter_HeaderWithCommas(t *testing.T) { + t.Run("primitive string with commas", func(t *testing.T) { + var dest string + // A JSON string header value that happens to contain commas. + err := BindStyledParameterWithOptions("simple", "X-My-Header", `{"key":"value","other":"data"}`, &dest, BindStyledParameterOptions{ + ParamLocation: ParamLocationHeader, + Explode: false, + Required: true, + }) + assert.NoError(t, err) + assert.Equal(t, `{"key":"value","other":"data"}`, dest) + }) + + t.Run("primitive string with many commas", func(t *testing.T) { + var dest string + err := BindStyledParameterWithOptions("simple", "X-My-Header", "a,b,c,d,e", &dest, BindStyledParameterOptions{ + ParamLocation: ParamLocationHeader, + Explode: false, + Required: true, + }) + assert.NoError(t, err) + assert.Equal(t, "a,b,c,d,e", dest) + }) + + t.Run("primitive string without commas still works", func(t *testing.T) { + var dest string + err := BindStyledParameterWithOptions("simple", "X-My-Header", "simple-value", &dest, BindStyledParameterOptions{ + ParamLocation: ParamLocationHeader, + Explode: false, + Required: true, + }) + assert.NoError(t, err) + assert.Equal(t, "simple-value", dest) + }) + + t.Run("array of strings still splits on commas", func(t *testing.T) { + var dest []string + err := BindStyledParameterWithOptions("simple", "X-My-Header", "a,b,c", &dest, BindStyledParameterOptions{ + ParamLocation: ParamLocationHeader, + Explode: false, + Required: true, + }) + assert.NoError(t, err) + assert.Equal(t, []string{"a", "b", "c"}, dest) + }) +}