headers.go 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. package internal
  2. import (
  3. "log/slog"
  4. "net"
  5. "net/http"
  6. "strings"
  7. "github.com/TecharoHQ/anubis"
  8. "github.com/sebest/xff"
  9. )
  10. // UnchangingCache sets the Cache-Control header to cache a response for 1 year if
  11. // and only if the application is compiled in "release" mode by Docker.
  12. func UnchangingCache(next http.Handler) http.Handler {
  13. if anubis.Version == "devel" {
  14. return next
  15. }
  16. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  17. w.Header().Set("Cache-Control", "public, max-age=31536000")
  18. next.ServeHTTP(w, r)
  19. })
  20. }
  21. // RemoteXRealIP sets the X-Real-Ip header to the request's real IP if
  22. // the setting is enabled by the user.
  23. func RemoteXRealIP(useRemoteAddress bool, bindNetwork string, next http.Handler) http.Handler {
  24. if useRemoteAddress == false {
  25. slog.Debug("skipping middleware, useRemoteAddress is empty")
  26. return next
  27. }
  28. if bindNetwork == "unix" {
  29. // For local sockets there is no real remote address but the localhost
  30. // address should be sensible.
  31. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  32. r.Header.Set("X-Real-Ip", "127.0.0.1")
  33. next.ServeHTTP(w, r)
  34. })
  35. }
  36. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  37. host, _, err := net.SplitHostPort(r.RemoteAddr)
  38. if err != nil {
  39. panic(err) // this should never happen
  40. }
  41. r.Header.Set("X-Real-Ip", host)
  42. next.ServeHTTP(w, r)
  43. })
  44. }
  45. // XForwardedForToXRealIP sets the X-Real-Ip header based on the contents
  46. // of the X-Forwarded-For header.
  47. func XForwardedForToXRealIP(next http.Handler) http.Handler {
  48. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  49. if xffHeader := r.Header.Get("X-Forwarded-For"); r.Header.Get("X-Real-Ip") == "" && xffHeader != "" {
  50. ip := xff.Parse(xffHeader)
  51. slog.Debug("setting x-real-ip", "val", ip)
  52. r.Header.Set("X-Real-Ip", ip)
  53. }
  54. next.ServeHTTP(w, r)
  55. })
  56. }
  57. // Do not allow browsing directory listings in paths that end with /
  58. func NoBrowsing(next http.Handler) http.Handler {
  59. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  60. if strings.HasSuffix(r.URL.Path, "/") {
  61. http.NotFound(w, r)
  62. return
  63. }
  64. next.ServeHTTP(w, r)
  65. })
  66. }