| // Copyright 2012 The Gorilla Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package context |
| |
| import ( |
| "net/http" |
| "sync" |
| "time" |
| ) |
| |
| var ( |
| mutex sync.RWMutex |
| data = make(map[*http.Request]map[interface{}]interface{}) |
| datat = make(map[*http.Request]int64) |
| ) |
| |
| // Set stores a value for a given key in a given request. |
| func Set(r *http.Request, key, val interface{}) { |
| mutex.Lock() |
| if data[r] == nil { |
| data[r] = make(map[interface{}]interface{}) |
| datat[r] = time.Now().Unix() |
| } |
| data[r][key] = val |
| mutex.Unlock() |
| } |
| |
| // Get returns a value stored for a given key in a given request. |
| func Get(r *http.Request, key interface{}) interface{} { |
| mutex.RLock() |
| if ctx := data[r]; ctx != nil { |
| value := ctx[key] |
| mutex.RUnlock() |
| return value |
| } |
| mutex.RUnlock() |
| return nil |
| } |
| |
| // GetOk returns stored value and presence state like multi-value return of map access. |
| func GetOk(r *http.Request, key interface{}) (interface{}, bool) { |
| mutex.RLock() |
| if _, ok := data[r]; ok { |
| value, ok := data[r][key] |
| mutex.RUnlock() |
| return value, ok |
| } |
| mutex.RUnlock() |
| return nil, false |
| } |
| |
| // GetAll returns all stored values for the request as a map. Nil is returned for invalid requests. |
| func GetAll(r *http.Request) map[interface{}]interface{} { |
| mutex.RLock() |
| if context, ok := data[r]; ok { |
| result := make(map[interface{}]interface{}, len(context)) |
| for k, v := range context { |
| result[k] = v |
| } |
| mutex.RUnlock() |
| return result |
| } |
| mutex.RUnlock() |
| return nil |
| } |
| |
| // GetAllOk returns all stored values for the request as a map and a boolean value that indicates if |
| // the request was registered. |
| func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) { |
| mutex.RLock() |
| context, ok := data[r] |
| result := make(map[interface{}]interface{}, len(context)) |
| for k, v := range context { |
| result[k] = v |
| } |
| mutex.RUnlock() |
| return result, ok |
| } |
| |
| // Delete removes a value stored for a given key in a given request. |
| func Delete(r *http.Request, key interface{}) { |
| mutex.Lock() |
| if data[r] != nil { |
| delete(data[r], key) |
| } |
| mutex.Unlock() |
| } |
| |
| // Clear removes all values stored for a given request. |
| // |
| // This is usually called by a handler wrapper to clean up request |
| // variables at the end of a request lifetime. See ClearHandler(). |
| func Clear(r *http.Request) { |
| mutex.Lock() |
| clear(r) |
| mutex.Unlock() |
| } |
| |
| // clear is Clear without the lock. |
| func clear(r *http.Request) { |
| delete(data, r) |
| delete(datat, r) |
| } |
| |
| // Purge removes request data stored for longer than maxAge, in seconds. |
| // It returns the amount of requests removed. |
| // |
| // If maxAge <= 0, all request data is removed. |
| // |
| // This is only used for sanity check: in case context cleaning was not |
| // properly set some request data can be kept forever, consuming an increasing |
| // amount of memory. In case this is detected, Purge() must be called |
| // periodically until the problem is fixed. |
| func Purge(maxAge int) int { |
| mutex.Lock() |
| count := 0 |
| if maxAge <= 0 { |
| count = len(data) |
| data = make(map[*http.Request]map[interface{}]interface{}) |
| datat = make(map[*http.Request]int64) |
| } else { |
| min := time.Now().Unix() - int64(maxAge) |
| for r := range data { |
| if datat[r] < min { |
| clear(r) |
| count++ |
| } |
| } |
| } |
| mutex.Unlock() |
| return count |
| } |
| |
| // ClearHandler wraps an http.Handler and clears request values at the end |
| // of a request lifetime. |
| func ClearHandler(h http.Handler) http.Handler { |
| return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| defer Clear(r) |
| h.ServeHTTP(w, r) |
| }) |
| } |