Skip to content

Commit

Permalink
feat(net/http): provide an option to access /index.html directly with…
Browse files Browse the repository at this point in the history
…out 301 redirect

For: golang#53870
BREAKING CHANGES: http.ServeFile won't redirect /index.html
  • Loading branch information
ahuigo committed Jul 16, 2022
1 parent 88a06f4 commit 665a2af
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 5 deletions.
2 changes: 1 addition & 1 deletion src/net/http/filetransport.go
Expand Up @@ -28,7 +28,7 @@ type fileTransport struct {
// res, err := c.Get("file:///etc/passwd")
// ...
func NewFileTransport(fs FileSystem) RoundTripper {
return fileTransport{fileHandler{fs}}
return fileTransport{fileHandler{fs, true}}
}

func (t fileTransport) RoundTrip(req *Request) (resp *Response, err error) {
Expand Down
20 changes: 16 additions & 4 deletions src/net/http/fs.go
Expand Up @@ -589,7 +589,7 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
// redirect .../index.html to .../
// can't use Redirect() because that would make the path absolute,
// which would be a problem running under StripPrefix
if strings.HasSuffix(r.URL.Path, indexPage) {
if redirect && strings.HasSuffix(r.URL.Path, indexPage) {
localRedirect(w, r, "./")
return
}
Expand Down Expand Up @@ -740,8 +740,10 @@ func containsDotDot(v string) bool {
func isSlashRune(r rune) bool { return r == '/' || r == '\\' }

type fileHandler struct {
root FileSystem
root FileSystem
permanentRedirect bool
}
type FileHandler = fileHandler

type ioFS struct {
fsys fs.FS
Expand Down Expand Up @@ -838,7 +840,7 @@ func FS(fsys fs.FS) FileSystem {
// http.Handle("/", http.FileServer(http.FS(fsys)))
//
func FileServer(root FileSystem) Handler {
return &fileHandler{root}
return &fileHandler{root, true}
}

func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
Expand All @@ -847,7 +849,17 @@ func (f *fileHandler) ServeHTTP(w ResponseWriter, r *Request) {
upath = "/" + upath
r.URL.Path = upath
}
serveFile(w, r, f.root, path.Clean(upath), true)
serveFile(w, r, f.root, path.Clean(upath), f.permanentRedirect)
}

// By default, fileHandler will redirect ``.../index.html`` to `.../` with 301 redirect (Refer to https://github.com/golang/go/issues/53870)
// If you don't want to redirect it, call this method.
func SkipPermanentRedirect(f *fileHandler) {
f.permanentRedirect = false
}
func (f *fileHandler) SkipPermanentRedirect() *fileHandler {
f.permanentRedirect = false
return f
}

// httpRange specifies the byte range to be sent to the client.
Expand Down
58 changes: 58 additions & 0 deletions src/net/http/httptest/fs_server_test.go
@@ -0,0 +1,58 @@
package httptest_test

import (
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"
)

func TestHttpFileServerSkipPermanentRedirect(t *testing.T) {
URL, _ := url.Parse("/index.html")
fs := http.Dir("./")
respRecorder := httptest.NewRecorder()
req := &http.Request{
Method: "GET",
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
URL: URL,
}

fileServer := http.FileServer(fs)

// skip 301 redirect
fileServer.(*http.FileHandler).SkipPermanentRedirect()

fileServer.ServeHTTP(respRecorder, req)
if respRecorder.Code != 200 {
t.Fatal("Expect code 200, result code: ", respRecorder.Code, "body response:", respRecorder.Body.String())
}

bodyString := respRecorder.Body.String()
if !strings.Contains(bodyString, "<body>") {
t.Fatalf("Unexpected body response: %s", respRecorder.Body.String())
}

}

func TestHttpFileServerPermanentRedirect(t *testing.T) {
URL, _ := url.Parse("/index.html")
fs := http.Dir("./")
respRecorder := httptest.NewRecorder()
req := &http.Request{
Method: "GET",
Proto: "HTTP/1.1",
ProtoMajor: 1,
ProtoMinor: 1,
URL: URL,
}

fileServer := http.FileServer(fs)

fileServer.ServeHTTP(respRecorder, req)
if respRecorder.Code != 301 {
t.Fatal("Expect code 301, result code: ", respRecorder.Code, "body:", respRecorder.Body.String())
}
}
1 change: 1 addition & 0 deletions src/net/http/httptest/index.html
@@ -0,0 +1 @@
<body>index.html page</body>

0 comments on commit 665a2af

Please sign in to comment.