-
Notifications
You must be signed in to change notification settings - Fork 18.6k
Description
Summary
I would like to propose adding new interfaces to net/url to allow users to have control over url query string parsing and encoding implementations.
This can be done in a backwards compatible manner by
- introducing the interface
- providing a default implementation of the interface that implements current behavior
- exposing the default implementations as package level variables
- updating call sites in the standard library to accept interface values to prefer over the default implementation
With the DefaultQueryParser and DefaultQueryEncoder being package level variables, a user can set the implementations once in main or init. This allows the user to have confidence that their chosen implementation will be used, even if some usages have not yet been updated to accept a custom implementation.
This approach allows users to gradually widen their API to accept a QueryParser or QueryEncoder, allowing for implementation to be spread over multiple releases if necessary.
Proposed Interface Addition
var (
DefaultQueryParser QueryParser = qsParser{}
DefaultQueryEncoder QueryEncoder = qsParser{}
)
type QueryParser interface {
Parse(string) (Values, error)
}
type QueryEncoder interface {
Encode(Values) (string, error)
}
type qsParser struct{}
func (qsParser) Parse(s string) (Values, error) {
// body would be the current body of ParseQuery
}
func (qsParser) Encode(v Values) (string, error) {
// body would be the current body of Values.Encode
}
// update existing apis to use the DefaultQueryParser
// and DefaultQueryEncoder
func ParseQuery(s string) (Values, error) {
return DefaultQueryParser.Parse(s)
}
func (v Values) Encode() string {
s, _ := DefaultQueryEncoder.Encode()
return s
}
Rationale
Other systems have their own interpretations of the url RFCs, which are often at odds with how go interprets them. This creates situations where a behavior can be a security issue for one user, but an intentional and relied upon behavior for others. There is no single implementation that can serve all users.
By allowing custom implementations to be supplied, we're able to provide a safe default that covers the majority of use cases, but still allow users with very specific needs the flexibility to provide their own implementations.
Users of the package include http.Server and httputil.ReverseProxy`. Both are too large to reasonably expect users to fork in order to call their own parsing and encoding implementations.
Historical Issues
There have been a number of issues surrounding query string parsing and encoding. Security issues have caused a number of backwards incompatible changes, which then motivated other changes to allow prior behavior to be restored.
For users sensitive to these changes, some of the above issues caused operational disruption. In other cases, the backwards compatibility breakages were in point releases.
- net/http/httputil: ReverseProxy should not forward unparseable query parameters #54663
- net/url: don't parse ';' as a separator in query string [freeze exception] #25192
- net/http: remove semicolon warning #49399
- Issues parsing urls containing semicolons #49683
- net/http: add AllowQuerySemicolons [freeze exception] #45973
Issues since proposal
edit: forgot interface keyword on QueryParser and QueryEncoder
2022/11/21 edit: added Issues since proposal
Metadata
Metadata
Assignees
Labels
Type
Projects
Status