1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
| func ServeMyFile(w http.ResponseWriter, r *http.Request, name string) { dir, baseName := filepath.Split(name) serveFile(w, r, http.Dir(dir), baseName) }
func toHTTPError(err error) (msg string, httpStatus int) { if os.IsNotExist(err) { return "404 page not found", http.StatusNotFound } if os.IsPermission(err) { return "403 Forbidden", http.StatusForbidden } return "500 Internal Server Error", http.StatusInternalServerError }
func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name string) { f, err := fs.Open(name) if err != nil { msg, code := toHTTPError(err) http.Error(w, msg, code) return } defer f.Close()
d, err := f.Stat() if err != nil { msg, code := toHTTPError(err) http.Error(w, msg, code) return }
buffer := bytes.NewBuffer(make([]byte, 0)) bw := bufio.NewWriter(buffer) var size int64
sizeFunc := func() (int64, error) { return size, nil }
if d.IsDir() {
dirs, err := f.Readdir(-1) if err != nil { http.Error(w, "Error reading directory", http.StatusInternalServerError) return }
sort.Slice(dirs, func(i, j int) bool { return dirs[i].Name() < dirs[j].Name() })
for _, ff := range dirs { if !ff.IsDir() { fi, err := fs.Open(path.Join(name, ff.Name())) if err != nil { msg, code := toHTTPError(err) http.Error(w, msg, code) return }
io.Copy(bw, fi) size += ff.Size() } }
serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, bytes.NewReader(buffer.Bytes())) } else { size = d.Size()
serveContent(w, r, d.Name(), d.ModTime(), sizeFunc, f) } }
var unixEpochTime = time.Unix(0, 0)
func isZeroTime(t time.Time) bool { return t.IsZero() || t.Equal(unixEpochTime) }
func setLastModified(w http.ResponseWriter, modtime time.Time) { if !isZeroTime(modtime) { w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat)) } }
func serveContent(w http.ResponseWriter, r *http.Request, name string, modtime time.Time, sizeFunc func() (int64, error), content io.ReadSeeker) { setLastModified(w, modtime)
size, err := sizeFunc() if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return }
sendSize := size var sendContent io.Reader = content if size >= 0 { w.Header().Set("Accept-Ranges", "bytes") if w.Header().Get("Content-Encoding") == "" { w.Header().Set("Content-Length", strconv.FormatInt(sendSize, 10)) } }
w.WriteHeader(http.StatusOK) if r.Method != "HEAD" { io.CopyN(w, sendContent, sendSize) } }
|