我在 FileServer 的根目录有什么不同吗?
Does it make a difference where I root a FileServer?
在 https://www.alexedwards.net/blog/serving-static-sites-with-go,有一个静态文件服务器在单个目录中为站点提供服务的示例:static
。
File: app.go
...
func main() {
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
log.Println("Listening...")
http.ListenAndServe(":3000", nil)
}
但是,我发现我可以通过以下方式获得相同的结果。
func main() {
fs := http.FileServer(http.Dir(".")) // root at the root directory.
http.Handle("/static/", fs) //leave off the StripPrefix call.
log.Println("Listening...")
http.ListenAndServe(":3000", nil)
}
这样做有任何(性能或安全)缺点吗?我可以看到,如果我在文件系统上的文件位置与它们所服务的 URL 不匹配,我将不得不使用 StripPrefix
,但在这种情况下,似乎调用 StripPrefix
是不必要的。
编辑: 我忘了说了,不过我自己已经看过了。在性能方面,这似乎不是问题,因为对 FileServer
的调用实际上并没有将文件加载到内存中;它只是存储地址。在安全方面,这似乎完全相同:我尝试使用类似以下内容的目录遍历攻击。
$ curl -i --path-as-is 'http://localhost:3000/static/../sensitive.txt'
但是我对两个版本都得到了 301 响应,这让我有点吃惊。
当你使用http.ServeMux
处理程序时也是如此
http.ServeMux
会在匹配路径前调用 cleanPath 函数
https://github.com/golang/go/blob/master/src/net/http/server.go#L2305
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
// snip
path := cleanPath(r.URL.Path)
//snip
}
cleanPath 函数 return p 的规范路径,消除 .和 .. 元素。
https://github.com/golang/go/blob/master/src/net/http/server.go#L2174-L2193
// cleanPath returns the canonical path for p, eliminating . and .. elements.
func cleanPath(p string) string {
if p == "" {
return "/"
}
if p[0] != '/' {
p = "/" + p
}
np := path.Clean(p)
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if p[len(p)-1] == '/' && np != "/" {
// Fast path for common case of p being the string we want:
if len(p) == len(np)+1 && strings.HasPrefix(p, np) {
np = p
} else {
np += "/"
}
}
return np
}
在 https://www.alexedwards.net/blog/serving-static-sites-with-go,有一个静态文件服务器在单个目录中为站点提供服务的示例:static
。
File: app.go
...
func main() {
fs := http.FileServer(http.Dir("static"))
http.Handle("/static/", http.StripPrefix("/static/", fs))
log.Println("Listening...")
http.ListenAndServe(":3000", nil)
}
但是,我发现我可以通过以下方式获得相同的结果。
func main() {
fs := http.FileServer(http.Dir(".")) // root at the root directory.
http.Handle("/static/", fs) //leave off the StripPrefix call.
log.Println("Listening...")
http.ListenAndServe(":3000", nil)
}
这样做有任何(性能或安全)缺点吗?我可以看到,如果我在文件系统上的文件位置与它们所服务的 URL 不匹配,我将不得不使用 StripPrefix
,但在这种情况下,似乎调用 StripPrefix
是不必要的。
编辑: 我忘了说了,不过我自己已经看过了。在性能方面,这似乎不是问题,因为对 FileServer
的调用实际上并没有将文件加载到内存中;它只是存储地址。在安全方面,这似乎完全相同:我尝试使用类似以下内容的目录遍历攻击。
$ curl -i --path-as-is 'http://localhost:3000/static/../sensitive.txt'
但是我对两个版本都得到了 301 响应,这让我有点吃惊。
当你使用http.ServeMux
处理程序时也是如此
http.ServeMux
会在匹配路径前调用 cleanPath 函数
https://github.com/golang/go/blob/master/src/net/http/server.go#L2305
func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
// snip
path := cleanPath(r.URL.Path)
//snip
}
cleanPath 函数 return p 的规范路径,消除 .和 .. 元素。
https://github.com/golang/go/blob/master/src/net/http/server.go#L2174-L2193
// cleanPath returns the canonical path for p, eliminating . and .. elements.
func cleanPath(p string) string {
if p == "" {
return "/"
}
if p[0] != '/' {
p = "/" + p
}
np := path.Clean(p)
// path.Clean removes trailing slash except for root;
// put the trailing slash back if necessary.
if p[len(p)-1] == '/' && np != "/" {
// Fast path for common case of p being the string we want:
if len(p) == len(np)+1 && strings.HasPrefix(p, np) {
np = p
} else {
np += "/"
}
}
return np
}