go net/http: ServeFile 在 StripPrefix 过度剥离并导致路径为空时出现 panic,

disho6za  于 6个月前  发布在  Go
关注(0)|答案(8)|浏览(53)

你正在使用的Go版本是什么( go version )?

$ go version
go version go1.11.4 darwin/amd64

这个问题在最新版本中是否重现?

是的

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/Users/ggicci/Library/Caches/go-build"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="darwin"
GOOS="darwin"
GOPATH="/Users/ggicci/workspace"
GOPROXY=""
GORACE=""
GOROOT="/usr/local/Cellar/go/1.11.4/libexec"
GOTMPDIR=""
GOTOOLDIR="/usr/local/Cellar/go/1.11.4/libexec/pkg/tool/darwin_amd64"
GCCGO="gccgo"
CC="clang"
CXX="clang++"
CGO_ENABLED="1"
GOMOD=""
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/ht/hdwl47w16m10r45w89drkkph0000gn/T/go-build233590303=/tmp/go-build -gno-record-gcc-switches -fno-common"

你做了什么?

我使用了 http.StripPrefixhttp.ServeFile 来去除URL前缀并提供文件夹。如果我打开了 http://localhost:8080/download/ ,HTTP服务器会崩溃,网页将无法接收到任何内容。
以下是重现问题的代码片段:

package main

import "net/http"

var myHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
	http.ServeFile(rw, r, "./files")
})

func main() {
	http.Handle("/download/", http.StripPrefix("/download/", myHandler))
	http.ListenAndServe(":8080", nil)
}

你期望看到什么?

我应该能看到来自我的 files 文件夹的内容。文件列表或索引页面内容。

你看到了什么?

没有HTTP响应,但从stderr中可以看到恐慌信息。

nhhxz33t

nhhxz33t1#

https://golang.org/cl/161738提到了这个问题:net/http: StipPrefix clean URL path

uoifb46i

uoifb46i2#

https://golang.org/cl/180498提到了这个问题:net/http: roll back "clean the path of the stripped URL by StripPrefix"

gz5pxeao

gz5pxeao3#

我调查了这个问题,这里是一些关于为什么会出现这种情况的更多信息。
对于一个 GET /download/ 请求,在 http.StripPrefix("/download/", myHandler) 去除前缀后,URL路径将变为空字符串。
http.serveFile 中,对一个 *http.Request 调用 http.ServeFile 并传入空的 URL 路径会引发恐慌:

// redirect if the directory name doesn't end in a slash
if d.IsDir() {
	url := r.URL.Path
	if url[len(url)-1] != '/' { // panic here, since url is empty string
		localRedirect(w, r, path.Base(url)+"/")
		return
	}
}

/cc @bradfitz

8nuwlpux

8nuwlpux4#

https://golang.org/cl/180499提到了这个问题:net/http: don't panic serving dir in ServeFile with empty Request.URL.Path

edqdpe6u

edqdpe6u5#

重新开放此问题,因为在 CL 180498 中回滚了修复。
供参考,在 CL 20128 中添加了发生 panic 的代码以修复 #13996 。它没有考虑到当 http.StripPrefix 以一种过度剥离前缀的方式使用时,r.URL.Path 可能为空字符串。
修复此问题时,需要确保不会引入无限或其他不需要的重定向。第13996条注解中的分析很好,应该予以考虑。

nhhxz33t

nhhxz33t6#

我看到这个问题已经移动到了Go1.14,但由于它可能是Go1.13的一个回归问题,而且Brad的CL https://golang.org/cl/180499 LGTM,只是我没有权限使用代码审查评论更新他的CL,请求使用strings.HasPrefix而不是与""进行简单的比较。
@dmitshur@andybons,我们能否实现这一点并提交这个CL?谢谢。

xmjla07d

xmjla07d7#

@odeke-em 到目前为止,将这个内容纳入1.13版本已经太晚了。抱歉。

42fyovps

42fyovps8#

明白了!我们可以等到Go.1.14再更新。

相关问题