diff --git a/openapi3/schema.go b/openapi3/schema.go index c7041b58e..f941a1114 100644 --- a/openapi3/schema.go +++ b/openapi3/schema.go @@ -2011,22 +2011,6 @@ func (schema *Schema) expectedType(settings *schemaValidationSettings, value int } } -// NOTE: racey WRT [writes to schema.Pattern] vs [reads schema.Pattern then writes to compiledPatterns] -func (schema *Schema) compilePattern() (cp *regexp.Regexp, err error) { - pattern := schema.Pattern - if cp, err = regexp.Compile(pattern); err != nil { - err = &SchemaError{ - Schema: schema, - SchemaField: "pattern", - Origin: err, - Reason: fmt.Sprintf("cannot compile pattern %q: %v", pattern, err), - } - return - } - var _ bool = compiledPatterns.CompareAndSwap(pattern, nil, cp) - return -} - // SchemaError is an error that occurs during schema validation. type SchemaError struct { // Value is the value that failed validation. diff --git a/openapi3/schema_pattern.go b/openapi3/schema_pattern.go new file mode 100644 index 000000000..ceb4ad159 --- /dev/null +++ b/openapi3/schema_pattern.go @@ -0,0 +1,29 @@ +package openapi3 + +import ( + "fmt" + "regexp" +) + +var patRewriteCodepoints = regexp.MustCompile(`[\][u]([0-9A-F]{4})`) + +// See https://pkg.go.dev/regexp/syntax +func intoGoRegexp(re string) string { + return patRewriteCodepoints.ReplaceAllString(re, `x{$1}`) +} + +// NOTE: racey WRT [writes to schema.Pattern] vs [reads schema.Pattern then writes to compiledPatterns] +func (schema *Schema) compilePattern() (cp *regexp.Regexp, err error) { + pattern := schema.Pattern + if cp, err = regexp.Compile(intoGoRegexp(pattern)); err != nil { + err = &SchemaError{ + Schema: schema, + SchemaField: "pattern", + Origin: err, + Reason: fmt.Sprintf("cannot compile pattern %q: %v", pattern, err), + } + return + } + var _ bool = compiledPatterns.CompareAndSwap(pattern, nil, cp) + return +} diff --git a/openapi3/schema_pattern_test.go b/openapi3/schema_pattern_test.go new file mode 100644 index 000000000..865a21969 --- /dev/null +++ b/openapi3/schema_pattern_test.go @@ -0,0 +1,18 @@ +package openapi3 + +import ( + "regexp" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestPattern(t *testing.T) { + _, err := regexp.Compile("^[a-zA-Z\\u0080-\\u024F\\s\\/\\-\\)\\(\\`\\.\\\"\\']+$") + require.EqualError(t, err, "error parsing regexp: invalid escape sequence: `\\u`") + + _, err = regexp.Compile(`^[a-zA-Z\x{0080}-\x{024F}]+$`) + require.NoError(t, err) + + require.Equal(t, `^[a-zA-Z\x{0080}-\x{024F}]+$`, intoGoRegexp(`^[a-zA-Z\u0080-\u024F]+$`)) +}