go: net/http: DefaultServeMux incorrectly redirect (301) to path if path includes `%2F%2F`
What version of Go are you using (go version)?
go version go1.9 linux/amd64
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env)?
GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/home/kalbasit/code/personal/base"
GORACE=""
GOROOT="/usr/lib/go"
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build643957992=/tmp/go-build -gno-record-gcc-switches"
CXX="g++"
CGO_ENABLED="1"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
What did you do?
package main
import "net/http"
func main() {
http.ListenAndServe(":8878", nil)
}
curl 'http://localhost:8878/path:a%2F%2Fgoogle.com%2F'
What did you expect to see?
404 page not found
What did you see instead?
<a href="/path:a/google.com/">Moved Permanently</a>.
NOTE: this does not happen if alice was used instead of the http.DefaultServeMux
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 5
- Comments: 17 (11 by maintainers)
Commits related to this issue
- Implement workaround for https://github.com/golang/go/issues/21955 — committed to alexmt/argo-cd by deleted user 6 years ago
- Implement workaround for https://github.com/golang/go/issues/21955 (#256) — committed to argoproj/argo-cd by alexmt 6 years ago
- net/http: prevent incorrect redirections when the path contains %2F%2F The current implementation of ServeMux incorrectly returns a 301 status code when the path contains URL-encoded data, and especi... — committed to dunglas/go by dunglas 4 years ago
- override mux: golang/go/issues/21955 — committed to frizinak/gotls by frizinak 3 years ago
This is clearly a bug.
The encoding method can encode arbitrary data in a Uniform Resource Identifier (URI), which is the point of the encoding.
“/” is the reserved character slash. “%2f” is an arbitrary string. “/” and “%2f” are two different things.
Is “%2f” is a slash? No, of course it is not a slash. and “%25” is not a percent sign Otherwise “https://www.google.com/” will be equivalent to “https:%252f%252525252fwww.google.com%2f”.
@tombergan @bradfitz
As a countermeasure against this similar problem, there is nginx
merge_slashessyntax. Even with nginx, the above options are used for cases where you do not want to integrate encoded duplicate slashes into one.And then, I have take a look at RFC-3986 for confirming the encoded double slashes validity. According to it, the encoded string pchar is considered valid.
Therefore, I think, if we follow RFC-3986, the current behavior is buggy.
Just faced this issue in the latest go 1.18.3
curl http://localhost/%2Fhellois decoded internally to//hello(r.URL.Path) and the decision for a 301 redirect based onr.URL.Pathinstead ofr.URL.RawPath.A dirty hack that fixed useless 301 redirect issue for me:
To expand on @tombergan’s comment (https://github.com/golang/go/issues/21955#issuecomment-379057478), the
ServeMuxdocumentation states:The documentation is not explicit on whether
%2fis considered a slash, but the implementation consistently treats it as such.ServeMux.Handle("/foo/", f)matches the request/foo%2fbar.I believe the current behavior is consistent with the documentation and probably can’t be changed without violating compatibility. Perhaps the documentation should explicitly mention the treatment of escaped path components.
Redirecting
http://localhost:8878//tohttp://localhost:8878/is correct. But redirectinghttp://localhost:8878/%2Ftohttp://localhost:8878/is not correct. I think this is a bug to be fixed.