Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Validate URI query string encoding #183

Merged
merged 7 commits into from
Feb 3, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions cel/library.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,8 +232,7 @@ func (l library) CompileOptions() []cel.EnvOption {
if !ok {
return types.Bool(false)
}
uri, err := url.Parse(s)
return types.Bool(err == nil && uri.IsAbs())
return types.Bool(l.validateURI(s, true))
}),
),
),
Expand All @@ -247,8 +246,7 @@ func (l library) CompileOptions() []cel.EnvOption {
if !ok {
return types.Bool(false)
}
_, err := url.Parse(s)
return types.Bool(err == nil)
return types.Bool(l.validateURI(s, false))
}),
),
),
Expand Down Expand Up @@ -479,6 +477,20 @@ func (l library) validateIPPrefix(p string, ver int64, strict bool) bool {
}
}

func (l library) validateURI(val string, checkAbs bool) bool {
uri, err := url.Parse(val)
if err != nil {
return false
}
if checkAbs && !uri.IsAbs() {
return false
}

// Parse the query string to validate it is formed and encoded properly
_, err = url.ParseQuery(uri.RawQuery)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the intent here, but this does an awful lot of work just to check the validity of the encoding. It parses out the query components and constructs a map with them, which we don't need.

It's a bit less succinct, but we can get the exact same validation while doing a lot less work:

	// (Not sure if we want to disallow unescaped semicolons, but ParseQuery does.)
	if strings.Contains(uri.RawQuery, ";") {
		return false
	}
	_, err = url.QueryUnescape(uri.RawQuery)
	return err == nil

It'd be even better if we could just validate without parsing and decoding everything, but I argue we at least should avoid building the map if we can.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @jchadwick-buf i merged before i saw your comments. @rodaine wdyt? I can open up another PR to incorporate John's suggestions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually in talking to @timostamm today, we may want to discuss this deeper once his validation is done for protovalidate-ts. We can then make sure all the implementations are behaving the same way since he's following the RFC. We could then add additional conformance checks and formally define the grammar for what we validate.

return err == nil
}

func (l library) isHostAndPort(val string, portRequired bool) bool {
if len(val) == 0 {
return false
Expand Down