blob: 81cb128b19cad7e0a9ee89d7626746d1cf859564 [file] [log] [blame]
David K. Bainbridge215e0242017-09-05 23:18:24 -07001// 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}