entry.go 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package entry
  2. import (
  3. "time"
  4. "github.com/kataras/iris/cache/cfg"
  5. )
  6. // Entry is the cache entry
  7. // contains the expiration datetime and the response
  8. type Entry struct {
  9. life time.Duration
  10. // ExpiresAt is the time which this cache will not be available
  11. expiresAt time.Time
  12. // when `Reset` this value is reseting to time.Now(),
  13. // it's used to send the "Last-Modified" header,
  14. // some clients may need it.
  15. LastModified time.Time
  16. // Response the response should be served to the client
  17. response *Response
  18. // but we need the key to invalidate manually...xmm
  19. // let's see for that later, maybe we make a slice instead
  20. // of store map
  21. }
  22. // NewEntry returns a new cache entry
  23. // it doesn't sets the expiresAt & the response
  24. // because these are setting each time on Reset
  25. func NewEntry(duration time.Duration) *Entry {
  26. // if given duration is not <=0 (which means finds from the headers)
  27. // then we should check for the MinimumCacheDuration here
  28. if duration >= 0 && duration < cfg.MinimumCacheDuration {
  29. duration = cfg.MinimumCacheDuration
  30. }
  31. return &Entry{
  32. life: duration,
  33. response: &Response{},
  34. }
  35. }
  36. // Response gets the cache response contents
  37. // if it's valid returns them with a true value
  38. // otherwise returns nil, false
  39. func (e *Entry) Response() (*Response, bool) {
  40. if !e.valid() {
  41. // it has been expired
  42. return nil, false
  43. }
  44. return e.response, true
  45. }
  46. // valid returns true if this entry's response is still valid
  47. // or false if the expiration time passed
  48. func (e *Entry) valid() bool {
  49. return !time.Now().After(e.expiresAt)
  50. }
  51. // LifeChanger is the function which returns
  52. // a duration which will be compared with the current
  53. // entry's (cache life) duration
  54. // and execute the LifeChanger func
  55. // to set the new life time
  56. type LifeChanger func() time.Duration
  57. // ChangeLifetime modifies the life field
  58. // which is the life duration of the cached response
  59. // of this cache entry
  60. //
  61. // useful when we find a max-age header from the handler
  62. func (e *Entry) ChangeLifetime(fdur LifeChanger) {
  63. if e.life < cfg.MinimumCacheDuration {
  64. newLifetime := fdur()
  65. if newLifetime > e.life {
  66. e.life = newLifetime
  67. } else {
  68. // if even the new lifetime is less than MinimumCacheDuration
  69. // then change set it explicitly here
  70. e.life = cfg.MinimumCacheDuration
  71. }
  72. }
  73. }
  74. // CopyHeaders clones headers "src" to "dst" .
  75. func CopyHeaders(dst map[string][]string, src map[string][]string) {
  76. if dst == nil || src == nil {
  77. return
  78. }
  79. for k, vv := range src {
  80. v := make([]string, len(vv))
  81. copy(v, vv)
  82. dst[k] = v
  83. }
  84. }
  85. // Reset called each time the entry is expired
  86. // and the handler calls this after the original handler executed
  87. // to re-set the response with the new handler's content result
  88. func (e *Entry) Reset(statusCode int, headers map[string][]string,
  89. body []byte, lifeChanger LifeChanger) {
  90. if e.response == nil {
  91. e.response = &Response{}
  92. }
  93. if statusCode > 0 {
  94. e.response.statusCode = statusCode
  95. }
  96. if len(headers) > 0 {
  97. newHeaders := make(map[string][]string, len(headers))
  98. CopyHeaders(newHeaders, headers)
  99. e.response.headers = newHeaders
  100. }
  101. e.response.body = body
  102. // check if a given life changer provided
  103. // and if it does then execute the change life time
  104. if lifeChanger != nil {
  105. e.ChangeLifetime(lifeChanger)
  106. }
  107. now := time.Now()
  108. e.expiresAt = now.Add(e.life)
  109. e.LastModified = now
  110. }