]>
Commit | Line | Data |
---|---|---|
9b12e4fe JC |
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 | ||
5 | package context | |
6 | ||
7 | import ( | |
8 | "net/http" | |
9 | "sync" | |
10 | "time" | |
11 | ) | |
12 | ||
13 | var ( | |
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. | |
20 | func 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. | |
31 | func 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. | |
43 | func 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. | |
55 | func 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. | |
71 | func 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. | |
83 | func 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(). | |
95 | func Clear(r *http.Request) { | |
96 | mutex.Lock() | |
97 | clear(r) | |
98 | mutex.Unlock() | |
99 | } | |
100 | ||
101 | // clear is Clear without the lock. | |
102 | func 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. | |
116 | func 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. | |
138 | func 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 | } |