context.go

  1// Copyright 2012 The Gorilla Authors. All rights reserved.
  2// Use of this source code is governed by a BSD-style
  3// license that can be found in the LICENSE file.
  4
  5package context
  6
  7import (
  8	"net/http"
  9	"sync"
 10	"time"
 11)
 12
 13var (
 14	mutex sync.RWMutex
 15	data  = make(map[*http.Request]map[interface{}]interface{})
 16	datat = make(map[*http.Request]int64)
 17)
 18
 19// Set stores a value for a given key in a given request.
 20func Set(r *http.Request, key, val interface{}) {
 21	mutex.Lock()
 22	if data[r] == nil {
 23		data[r] = make(map[interface{}]interface{})
 24		datat[r] = time.Now().Unix()
 25	}
 26	data[r][key] = val
 27	mutex.Unlock()
 28}
 29
 30// Get returns a value stored for a given key in a given request.
 31func Get(r *http.Request, key interface{}) interface{} {
 32	mutex.RLock()
 33	if ctx := data[r]; ctx != nil {
 34		value := ctx[key]
 35		mutex.RUnlock()
 36		return value
 37	}
 38	mutex.RUnlock()
 39	return nil
 40}
 41
 42// GetOk returns stored value and presence state like multi-value return of map access.
 43func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
 44	mutex.RLock()
 45	if _, ok := data[r]; ok {
 46		value, ok := data[r][key]
 47		mutex.RUnlock()
 48		return value, ok
 49	}
 50	mutex.RUnlock()
 51	return nil, false
 52}
 53
 54// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
 55func GetAll(r *http.Request) map[interface{}]interface{} {
 56	mutex.RLock()
 57	if context, ok := data[r]; ok {
 58		result := make(map[interface{}]interface{}, len(context))
 59		for k, v := range context {
 60			result[k] = v
 61		}
 62		mutex.RUnlock()
 63		return result
 64	}
 65	mutex.RUnlock()
 66	return nil
 67}
 68
 69// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
 70// the request was registered.
 71func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
 72	mutex.RLock()
 73	context, ok := data[r]
 74	result := make(map[interface{}]interface{}, len(context))
 75	for k, v := range context {
 76		result[k] = v
 77	}
 78	mutex.RUnlock()
 79	return result, ok
 80}
 81
 82// Delete removes a value stored for a given key in a given request.
 83func Delete(r *http.Request, key interface{}) {
 84	mutex.Lock()
 85	if data[r] != nil {
 86		delete(data[r], key)
 87	}
 88	mutex.Unlock()
 89}
 90
 91// Clear removes all values stored for a given request.
 92//
 93// This is usually called by a handler wrapper to clean up request
 94// variables at the end of a request lifetime. See ClearHandler().
 95func Clear(r *http.Request) {
 96	mutex.Lock()
 97	clear(r)
 98	mutex.Unlock()
 99}
100
101// clear is Clear without the lock.
102func clear(r *http.Request) {
103	delete(data, r)
104	delete(datat, r)
105}
106
107// Purge removes request data stored for longer than maxAge, in seconds.
108// It returns the amount of requests removed.
109//
110// If maxAge <= 0, all request data is removed.
111//
112// This is only used for sanity check: in case context cleaning was not
113// properly set some request data can be kept forever, consuming an increasing
114// amount of memory. In case this is detected, Purge() must be called
115// periodically until the problem is fixed.
116func Purge(maxAge int) int {
117	mutex.Lock()
118	count := 0
119	if maxAge <= 0 {
120		count = len(data)
121		data = make(map[*http.Request]map[interface{}]interface{})
122		datat = make(map[*http.Request]int64)
123	} else {
124		min := time.Now().Unix() - int64(maxAge)
125		for r := range data {
126			if datat[r] < min {
127				clear(r)
128				count++
129			}
130		}
131	}
132	mutex.Unlock()
133	return count
134}
135
136// ClearHandler wraps an http.Handler and clears request values at the end
137// of a request lifetime.
138func ClearHandler(h http.Handler) http.Handler {
139	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
140		defer Clear(r)
141		h.ServeHTTP(w, r)
142	})
143}