Skip to content

Commit d6c31a0

Browse files
its-hammer-timedaveshanley
authored andcommitted
Cleanup And Support Disabling
1 parent eff5410 commit d6c31a0

7 files changed

Lines changed: 41 additions & 621 deletions

File tree

config/config.go

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ type ValidationOptions struct {
3131
AllowScalarCoercion bool // Enable string->boolean/number coercion
3232
Formats map[string]func(v any) error
3333
SchemaCache cache.SchemaCache // Optional cache for compiled schemas
34-
PathLookup radix.PathLookup // O(k) path lookup via radix tree (built automatically)
34+
PathTree radix.PathLookup // O(k) path lookup via radix tree (built automatically)
35+
pathTreeSet bool // Internal: true if PathTree was explicitly set via WithPathTree
3536
Logger *slog.Logger // Logger for debug/error output (nil = silent)
3637
AllowXMLBodyValidation bool // Allows to convert XML to JSON for validating a request/response body.
3738
AllowURLEncodedBodyValidation bool // Allows to convert URL Encoded to JSON for validating a request/response body.
@@ -78,7 +79,8 @@ func WithExistingOpts(options *ValidationOptions) Option {
7879
o.AllowScalarCoercion = options.AllowScalarCoercion
7980
o.Formats = options.Formats
8081
o.SchemaCache = options.SchemaCache
81-
o.PathLookup = options.PathLookup
82+
o.PathTree = options.PathTree
83+
o.pathTreeSet = options.pathTreeSet
8284
o.Logger = options.Logger
8385
o.AllowXMLBodyValidation = options.AllowXMLBodyValidation
8486
o.AllowURLEncodedBodyValidation = options.AllowURLEncodedBodyValidation
@@ -193,11 +195,13 @@ func WithSchemaCache(schemaCache cache.SchemaCache) Option {
193195
}
194196
}
195197

196-
// WithPathLookup sets a custom path lookup implementation.
197-
// The default is a radix tree built from the OpenAPI specification.
198-
func WithPathLookup(pathLookup radix.PathLookup) Option {
198+
// WithPathTree sets a custom radix tree for path matching.
199+
// The default is built automatically from the OpenAPI specification.
200+
// Pass nil to disable the radix tree and use regex-based matching only.
201+
func WithPathTree(pathTree radix.PathLookup) Option {
199202
return func(o *ValidationOptions) {
200-
o.PathLookup = pathLookup
203+
o.PathTree = pathTree
204+
o.pathTreeSet = true
201205
}
202206
}
203207

@@ -264,6 +268,11 @@ var defaultIgnoredHeaders = []string{
264268
"request-start-time", // Added by some API clients for timing
265269
}
266270

271+
// IsPathTreeSet returns true if PathTree was explicitly configured via WithPathTree.
272+
func (o *ValidationOptions) IsPathTreeSet() bool {
273+
return o.pathTreeSet
274+
}
275+
267276
// GetEffectiveStrictIgnoredHeaders returns the list of headers to ignore
268277
// based on configuration. Returns defaults if not configured, merged list
269278
// if extra headers were added, or replaced list if headers were fully replaced.

parameters/path_parameters_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/pb33f/libopenapi-validator/config"
1717
"github.com/pb33f/libopenapi-validator/helpers"
1818
"github.com/pb33f/libopenapi-validator/paths"
19+
"github.com/pb33f/libopenapi-validator/radix"
1920
)
2021

2122
func TestNewValidator_SimpleArrayEncodedPath(t *testing.T) {
@@ -2321,7 +2322,7 @@ paths:
23212322
m, _ := doc.BuildV3Model()
23222323

23232324
cache := &regexCacheWatcher{inner: &sync.Map{}}
2324-
opts := &config.ValidationOptions{RegexCache: cache}
2325+
opts := &config.ValidationOptions{RegexCache: cache, PathTree: radix.BuildPathTree(&m.Model)}
23252326

23262327
// Simple path - should NOT use regex cache (handled by radix tree)
23272328
simpleRequest, _ := http.NewRequest(http.MethodGet, "https://things.com/simple/123", nil)

paths/paths.go

Lines changed: 19 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"github.com/pb33f/libopenapi-validator/config"
1919
"github.com/pb33f/libopenapi-validator/errors"
2020
"github.com/pb33f/libopenapi-validator/helpers"
21-
"github.com/pb33f/libopenapi-validator/radix"
2221
)
2322

2423
// FindPath will find the path in the document that matches the request path. If a successful match was found, then
@@ -37,26 +36,13 @@ func FindPath(request *http.Request, document *v3.Document, options *config.Vali
3736
stripped := StripRequestPath(request, document)
3837

3938
// Fast path: try radix tree first (O(k) where k = path depth)
40-
tree := pathLookupFrom(options, document)
41-
if tree != nil {
42-
if pathItem, matchedPath, found := tree.Lookup(stripped); found {
43-
// Verify the path has the requested method
39+
// If no path lookup is provided, we will fall back to regex-based matching.
40+
if options != nil && options.PathTree != nil {
41+
if pathItem, matchedPath, found := options.PathTree.Lookup(stripped); found {
4442
if pathHasMethod(pathItem, request.Method) {
4543
return pathItem, nil, matchedPath
4644
}
47-
// Path found but method doesn't exist
48-
validationErrors := []*errors.ValidationError{{
49-
ValidationType: helpers.ParameterValidationPath,
50-
ValidationSubType: "missingOperation",
51-
Message: fmt.Sprintf("%s Path '%s' not found", request.Method, request.URL.Path),
52-
Reason: fmt.Sprintf("The %s method for that path does not exist in the specification",
53-
request.Method),
54-
SpecLine: -1,
55-
SpecCol: -1,
56-
HowToFix: errors.HowToFixPath,
57-
}}
58-
errors.PopulateValidationErrors(validationErrors, request, matchedPath)
59-
return pathItem, validationErrors, matchedPath
45+
return pathItem, missingOperationError(request, matchedPath), matchedPath
6046
}
6147
}
6248

@@ -128,18 +114,7 @@ func FindPath(request *http.Request, document *v3.Document, options *config.Vali
128114
}
129115

130116
// path matches exist but none have the required method
131-
validationErrors := []*errors.ValidationError{{
132-
ValidationType: helpers.PathValidation,
133-
ValidationSubType: helpers.ValidationMissingOperation,
134-
Message: fmt.Sprintf("%s Path '%s' not found", request.Method, request.URL.Path),
135-
Reason: fmt.Sprintf("The %s method for that path does not exist in the specification",
136-
request.Method),
137-
SpecLine: -1,
138-
SpecCol: -1,
139-
HowToFix: errors.HowToFixPath,
140-
}}
141-
errors.PopulateValidationErrors(validationErrors, request, bestOverall.path)
142-
return bestOverall.pathItem, validationErrors, bestOverall.path
117+
return bestOverall.pathItem, missingOperationError(request, bestOverall.path), bestOverall.path
143118
}
144119

145120
// normalizePathForMatching removes the fragment from a path template unless
@@ -257,13 +232,18 @@ func comparePaths(mapped, requested, basePaths []string, regexCache config.Regex
257232
return checkPathAgainstBase(l, r, basePaths)
258233
}
259234

260-
// pathLookupFrom returns the PathLookup from options, or builds one from the document.
261-
func pathLookupFrom(options *config.ValidationOptions, document *v3.Document) radix.PathLookup {
262-
if options != nil && options.PathLookup != nil {
263-
return options.PathLookup
264-
}
265-
if document != nil && document.Paths != nil {
266-
return radix.BuildPathTree(document)
267-
}
268-
return nil
235+
// missingOperationError returns a validation error for when a path was found but the HTTP method doesn't exist.
236+
func missingOperationError(request *http.Request, matchedPath string) []*errors.ValidationError {
237+
validationErrors := []*errors.ValidationError{{
238+
ValidationType: helpers.PathValidation,
239+
ValidationSubType: helpers.ValidationMissingOperation,
240+
Message: fmt.Sprintf("%s Path '%s' not found", request.Method, request.URL.Path),
241+
Reason: fmt.Sprintf("The %s method for that path does not exist in the specification",
242+
request.Method),
243+
SpecLine: -1,
244+
SpecCol: -1,
245+
HowToFix: errors.HowToFixPath,
246+
}}
247+
errors.PopulateValidationErrors(validationErrors, request, matchedPath)
248+
return validationErrors
269249
}

paths/radix_tree.go

Lines changed: 0 additions & 87 deletions
This file was deleted.

0 commit comments

Comments
 (0)