Repository: go
Issue: proposal: net/url: add QueryParser and QueryEncoder interfaces
Labels: Proposal

<!--
Our proposal process is documented here:
https://go.dev/s/proposal-process
-->

## 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
1. introducing the interface
2. providing a default implementation of the interface that implements current behavior
3. exposing the default implementations as package level variables
4. 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.

- https://github.com/golang/go/issues/54663
- https://github.com/golang/go/issues/25192
- https://github.com/golang/go/issues/49399
- https://github.com/golang/go/issues/49683
- https://github.com/golang/go/issues/45973

## Issues since proposal
 - https://github.com/golang/go/issues/56884

edit: forgot `interface` keyword on `QueryParser` and `QueryEncoder`

2022/11/21 edit: added Issues since proposal