session.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package session
  2. import (
  3. "crypto/sha1"
  4. "encoding/json"
  5. "fmt"
  6. "math/rand"
  7. "net/http"
  8. "os"
  9. "strings"
  10. "time"
  11. )
  12. type vars struct {
  13. Bool map[string]bool
  14. Int map[string]int
  15. String map[string]string
  16. }
  17. type Session struct {
  18. w http.ResponseWriter
  19. r *http.Request
  20. d string
  21. v *vars
  22. c bool
  23. i string
  24. }
  25. func New(w http.ResponseWriter, r *http.Request, tmpdir string) *Session {
  26. sess := Session{w: w, r: r, d: tmpdir, v: &vars{}, c: false, i: ""}
  27. cookie, err := r.Cookie("session")
  28. if err == nil && len(cookie.Value) == 40 {
  29. // Load from file
  30. sess.i = cookie.Value
  31. fname := sess.d + string(os.PathSeparator) + sess.i
  32. f, err := os.Open(fname)
  33. if err == nil {
  34. defer f.Close()
  35. dec := json.NewDecoder(f)
  36. err = dec.Decode(&sess.v)
  37. if err == nil {
  38. return &sess
  39. }
  40. // Update file last modify time if needs
  41. if info, err := os.Stat(fname); err == nil {
  42. if time.Now().Sub(info.ModTime()) > 30*time.Minute {
  43. _ = os.Chtimes(fname, time.Now(), time.Now())
  44. }
  45. }
  46. }
  47. } else {
  48. // Create new
  49. rand.Seed(time.Now().Unix())
  50. // Real remote IP for proxy servers
  51. rRemoteAddr := r.RemoteAddr
  52. if r.Header.Get("X-Real-IP") != "" && len(r.Header.Get("X-Real-IP")) <= 25 {
  53. rRemoteAddr = rRemoteAddr + ", " + strings.TrimSpace(r.Header.Get("X-Real-IP"))
  54. } else if r.Header.Get("X-Forwarded-For") != "" && len(r.Header.Get("X-Forwarded-For")) <= 25 {
  55. rRemoteAddr = rRemoteAddr + ", " + strings.TrimSpace(r.Header.Get("X-Forwarded-For"))
  56. }
  57. sign := rRemoteAddr + r.Header.Get("User-Agent") + fmt.Sprintf("%d", int64(time.Now().Unix())) + fmt.Sprintf("%d", int64(rand.Intn(9999999-99)+99))
  58. sess.i = fmt.Sprintf("%x", sha1.Sum([]byte(sign)))
  59. http.SetCookie(w, &http.Cookie{
  60. Name: "session",
  61. Value: sess.i,
  62. Path: "/",
  63. Expires: time.Now().Add(7 * 24 * time.Hour),
  64. HttpOnly: true,
  65. })
  66. }
  67. // Init empty
  68. sess.v = &vars{
  69. Bool: map[string]bool{},
  70. Int: map[string]int{},
  71. String: map[string]string{},
  72. }
  73. return &sess
  74. }
  75. func (this *Session) Close() bool {
  76. if !this.c {
  77. return false
  78. }
  79. r, err := json.Marshal(this.v)
  80. if err == nil {
  81. f, err := os.Create(this.d + string(os.PathSeparator) + this.i)
  82. if err == nil {
  83. defer f.Close()
  84. _, err = f.Write(r)
  85. if err == nil {
  86. this.c = false
  87. return true
  88. }
  89. }
  90. }
  91. return false
  92. }
  93. func (this *Session) Destroy() error {
  94. if this.d == "" || this.i == "" {
  95. return nil
  96. }
  97. err := os.Remove(this.d + string(os.PathSeparator) + this.i)
  98. if err == nil {
  99. this.c = false
  100. }
  101. return err
  102. }