static.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. package negroni
  2. import (
  3. "net/http"
  4. "path"
  5. "strings"
  6. )
  7. // Static is a middleware handler that serves static files in the given
  8. // directory/filesystem. If the file does not exist on the filesystem, it
  9. // passes along to the next middleware in the chain. If you desire "fileserver"
  10. // type behavior where it returns a 404 for unfound files, you should consider
  11. // using http.FileServer from the Go stdlib.
  12. type Static struct {
  13. // Dir is the directory to serve static files from
  14. Dir http.FileSystem
  15. // Prefix is the optional prefix used to serve the static directory content
  16. Prefix string
  17. // IndexFile defines which file to serve as index if it exists.
  18. IndexFile string
  19. }
  20. // NewStatic returns a new instance of Static
  21. func NewStatic(directory http.FileSystem) *Static {
  22. return &Static{
  23. Dir: directory,
  24. Prefix: "",
  25. IndexFile: "index.html",
  26. }
  27. }
  28. func (s *Static) ServeHTTP(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  29. if r.Method != "GET" && r.Method != "HEAD" {
  30. next(rw, r)
  31. return
  32. }
  33. file := r.URL.Path
  34. // if we have a prefix, filter requests by stripping the prefix
  35. if s.Prefix != "" {
  36. if !strings.HasPrefix(file, s.Prefix) {
  37. next(rw, r)
  38. return
  39. }
  40. file = file[len(s.Prefix):]
  41. if file != "" && file[0] != '/' {
  42. next(rw, r)
  43. return
  44. }
  45. }
  46. f, err := s.Dir.Open(file)
  47. if err != nil {
  48. // discard the error?
  49. next(rw, r)
  50. return
  51. }
  52. defer f.Close()
  53. fi, err := f.Stat()
  54. if err != nil {
  55. next(rw, r)
  56. return
  57. }
  58. // try to serve index file
  59. if fi.IsDir() {
  60. // redirect if missing trailing slash
  61. if !strings.HasSuffix(r.URL.Path, "/") {
  62. http.Redirect(rw, r, r.URL.Path+"/", http.StatusFound)
  63. return
  64. }
  65. file = path.Join(file, s.IndexFile)
  66. f, err = s.Dir.Open(file)
  67. if err != nil {
  68. next(rw, r)
  69. return
  70. }
  71. defer f.Close()
  72. fi, err = f.Stat()
  73. if err != nil || fi.IsDir() {
  74. next(rw, r)
  75. return
  76. }
  77. }
  78. http.ServeContent(rw, r, file, fi.ModTime(), f)
  79. }