You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

73 line
1.6KB

  1. package middleware
  2. import (
  3. "net/http"
  4. "path"
  5. "strings"
  6. )
  7. // Static serves as file server for static assets,
  8. // as convention, the given dir name will be used as the URL prefix.
  9. func Static(dir string) func(http.Handler) http.Handler {
  10. var (
  11. fs = http.Dir(dir)
  12. prefix = path.Join("/", path.Base(path.Dir(dir)))
  13. )
  14. return func(next http.Handler) http.Handler {
  15. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  16. // Accepts http GET | HEAD Only, ignores all requests not started with prefix.
  17. if r.Method != "GET" && r.Method != "HEAD" {
  18. next.ServeHTTP(w, r)
  19. return
  20. } else if !strings.HasPrefix(r.URL.Path, prefix) {
  21. next.ServeHTTP(w, r)
  22. return
  23. }
  24. filename := strings.TrimPrefix(r.URL.Path, prefix)
  25. if filename != "" && filename[0] != '/' {
  26. next.ServeHTTP(w, r)
  27. return
  28. }
  29. file, err := fs.Open(filename)
  30. if err != nil {
  31. next.ServeHTTP(w, r)
  32. return
  33. }
  34. defer file.Close()
  35. stat, err := file.Stat()
  36. if err != nil {
  37. next.ServeHTTP(w, r)
  38. return
  39. }
  40. // try to serve index filename
  41. if stat.IsDir() {
  42. // redirect if missing trailing slash
  43. if !strings.HasSuffix(r.URL.Path, "/") {
  44. http.Redirect(w, r, r.URL.Path+"/", http.StatusFound)
  45. return
  46. }
  47. filename = path.Join(filename, "index.html")
  48. file, err = fs.Open(filename)
  49. if err != nil {
  50. next.ServeHTTP(w, r)
  51. return
  52. }
  53. defer file.Close()
  54. stat, err = file.Stat()
  55. if err != nil || stat.IsDir() {
  56. next.ServeHTTP(w, r)
  57. return
  58. }
  59. }
  60. http.ServeContent(w, r, filename, stat.ModTime(), file)
  61. })
  62. }
  63. }