summaryrefslogtreecommitdiff
path: root/libgo/go/net/http/fs.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/net/http/fs.go')
-rw-r--r--libgo/go/net/http/fs.go53
1 files changed, 42 insertions, 11 deletions
diff --git a/libgo/go/net/http/fs.go b/libgo/go/net/http/fs.go
index e322f710a5d..75720234c25 100644
--- a/libgo/go/net/http/fs.go
+++ b/libgo/go/net/http/fs.go
@@ -102,10 +102,10 @@ func dirList(w ResponseWriter, f File) {
// The name is otherwise unused; in particular it can be empty and is
// never sent in the response.
//
-// If modtime is not the zero time, ServeContent includes it in a
-// Last-Modified header in the response. If the request includes an
-// If-Modified-Since header, ServeContent uses modtime to decide
-// whether the content needs to be sent at all.
+// If modtime is not the zero time or Unix epoch, ServeContent
+// includes it in a Last-Modified header in the response. If the
+// request includes an If-Modified-Since header, ServeContent uses
+// modtime to decide whether the content needs to be sent at all.
//
// The content's Seek method must work: ServeContent uses
// a seek to the end of the content to determine its size.
@@ -258,10 +258,15 @@ func serveContent(w ResponseWriter, r *Request, name string, modtime time.Time,
}
}
+var unixEpochTime = time.Unix(0, 0)
+
// modtime is the modification time of the resource to be served, or IsZero().
// return value is whether this request is now complete.
func checkLastModified(w ResponseWriter, r *Request, modtime time.Time) bool {
- if modtime.IsZero() {
+ if modtime.IsZero() || modtime.Equal(unixEpochTime) {
+ // If the file doesn't have a modtime (IsZero), or the modtime
+ // is obviously garbage (Unix time == 0), then ignore modtimes
+ // and don't process the If-Modified-Since header.
return false
}
@@ -353,16 +358,16 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
f, err := fs.Open(name)
if err != nil {
- // TODO expose actual error?
- NotFound(w, r)
+ msg, code := toHTTPError(err)
+ Error(w, msg, code)
return
}
defer f.Close()
d, err1 := f.Stat()
if err1 != nil {
- // TODO expose actual error?
- NotFound(w, r)
+ msg, code := toHTTPError(err)
+ Error(w, msg, code)
return
}
@@ -412,6 +417,22 @@ func serveFile(w ResponseWriter, r *Request, fs FileSystem, name string, redirec
serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f)
}
+// toHTTPError returns a non-specific HTTP error message and status code
+// for a given non-nil error value. It's important that toHTTPError does not
+// actually return err.Error(), since msg and httpStatus are returned to users,
+// and historically Go's ServeContent always returned just "404 Not Found" for
+// all errors. We don't want to start leaking information in error messages.
+func toHTTPError(err error) (msg string, httpStatus int) {
+ if os.IsNotExist(err) {
+ return "404 page not found", StatusNotFound
+ }
+ if os.IsPermission(err) {
+ return "403 Forbidden", StatusForbidden
+ }
+ // Default:
+ return "500 Internal Server Error", StatusInternalServerError
+}
+
// localRedirect gives a Moved Permanently response.
// It does not convert relative paths to absolute paths like Redirect does.
func localRedirect(w ResponseWriter, r *Request, newPath string) {
@@ -422,7 +443,13 @@ func localRedirect(w ResponseWriter, r *Request, newPath string) {
w.WriteHeader(StatusMovedPermanently)
}
-// ServeFile replies to the request with the contents of the named file or directory.
+// ServeFile replies to the request with the contents of the named
+// file or directory.
+//
+// As a special case, ServeFile redirects any request where r.URL.Path
+// ends in "/index.html" to the same path, without the final
+// "index.html". To avoid such redirects either modify the path or
+// use ServeContent.
func ServeFile(w ResponseWriter, r *Request, name string) {
dir, file := filepath.Split(name)
serveFile(w, r, Dir(dir), file, false)
@@ -439,6 +466,10 @@ type fileHandler struct {
// use http.Dir:
//
// http.Handle("/", http.FileServer(http.Dir("/tmp")))
+//
+// As a special case, the returned file server redirects any request
+// ending in "/index.html" to the same path, without the final
+// "index.html".
func FileServer(root FileSystem) Handler {
return &fileHandler{root}
}
@@ -503,7 +534,7 @@ func parseRange(s string, size int64) ([]httpRange, error) {
r.length = size - r.start
} else {
i, err := strconv.ParseInt(start, 10, 64)
- if err != nil || i > size || i < 0 {
+ if err != nil || i >= size || i < 0 {
return nil, errors.New("invalid range")
}
r.start = i