| @ -0,0 +1,27 @@ | |||
| Copyright (c) 2012 Rodrigo Moraes. All rights reserved. | |||
| Redistribution and use in source and binary forms, with or without | |||
| modification, are permitted provided that the following conditions are | |||
| met: | |||
| * Redistributions of source code must retain the above copyright | |||
| notice, this list of conditions and the following disclaimer. | |||
| * Redistributions in binary form must reproduce the above | |||
| copyright notice, this list of conditions and the following disclaimer | |||
| in the documentation and/or other materials provided with the | |||
| distribution. | |||
| * Neither the name of Google Inc. nor the names of its | |||
| contributors may be used to endorse or promote products derived from | |||
| this software without specific prior written permission. | |||
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |||
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |||
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |||
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |||
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |||
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |||
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |||
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |||
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |||
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |||
| @ -0,0 +1,101 @@ | |||
| // 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.Mutex | |||
| 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() | |||
| defer mutex.Unlock() | |||
| if data[r] == nil { | |||
| data[r] = make(map[interface{}]interface{}) | |||
| datat[r] = time.Now().Unix() | |||
| } | |||
| data[r][key] = val | |||
| } | |||
| // Get returns a value stored for a given key in a given request. | |||
| func Get(r *http.Request, key interface{}) interface{} { | |||
| mutex.Lock() | |||
| defer mutex.Unlock() | |||
| if data[r] != nil { | |||
| return data[r][key] | |||
| } | |||
| return nil | |||
| } | |||
| // Delete removes a value stored for a given key in a given request. | |||
| func Delete(r *http.Request, key interface{}) { | |||
| mutex.Lock() | |||
| defer mutex.Unlock() | |||
| if data[r] != nil { | |||
| delete(data[r], key) | |||
| } | |||
| } | |||
| // 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() | |||
| defer mutex.Unlock() | |||
| clear(r) | |||
| } | |||
| // 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() | |||
| defer mutex.Unlock() | |||
| 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++ | |||
| } | |||
| } | |||
| } | |||
| 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) | |||
| }) | |||
| } | |||
| @ -0,0 +1,52 @@ | |||
| // 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" | |||
| "testing" | |||
| ) | |||
| type keyType int | |||
| const ( | |||
| key1 keyType = iota | |||
| key2 | |||
| ) | |||
| func TestContext(t *testing.T) { | |||
| assertEqual := func(val interface{}, exp interface{}) { | |||
| if val != exp { | |||
| t.Errorf("Expected %v, got %v.", exp, val) | |||
| } | |||
| } | |||
| r, _ := http.NewRequest("GET", "http://localhost:8080/", nil) | |||
| // Get() | |||
| assertEqual(Get(r, key1), nil) | |||
| // Set() | |||
| Set(r, key1, "1") | |||
| assertEqual(Get(r, key1), "1") | |||
| assertEqual(len(data[r]), 1) | |||
| Set(r, key2, "2") | |||
| assertEqual(Get(r, key2), "2") | |||
| assertEqual(len(data[r]), 2) | |||
| // Delete() | |||
| Delete(r, key1) | |||
| assertEqual(Get(r, key1), nil) | |||
| assertEqual(len(data[r]), 1) | |||
| Delete(r, key2) | |||
| assertEqual(Get(r, key2), nil) | |||
| assertEqual(len(data[r]), 0) | |||
| // Clear() | |||
| Clear(r) | |||
| assertEqual(len(data), 0) | |||
| } | |||
| @ -0,0 +1,80 @@ | |||
| // 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 gorilla/context stores values shared during a request lifetime. | |||
| For example, a router can set variables extracted from the URL and later | |||
| application handlers can access those values, or it can be used to store | |||
| sessions values to be saved at the end of a request. There are several | |||
| others common uses. | |||
| The idea was posted by Brad Fitzpatrick to the go-nuts mailing list: | |||
| http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53 | |||
| Here's the basic usage: first define the keys that you will need. The key | |||
| type is interface{} so a key can be of any type that supports equality. | |||
| Here we define a key using a custom int type to avoid name collisions: | |||
| package foo | |||
| import ( | |||
| "github.com/gorilla/context" | |||
| ) | |||
| type key int | |||
| const MyKey key = 0 | |||
| Then set a variable. Variables are bound to an http.Request object, so you | |||
| need a request instance to set a value: | |||
| context.Set(r, MyKey, "bar") | |||
| The application can later access the variable using the same key you provided: | |||
| func MyHandler(w http.ResponseWriter, r *http.Request) { | |||
| // val is "bar". | |||
| val = context.Get(r, foo.MyKey) | |||
| // ... | |||
| } | |||
| And that's all about the basic usage. We discuss some other ideas below. | |||
| Any type can be stored in the context. To enforce a given type, make the key | |||
| private and wrap Get() and Set() to accept and return values of a specific | |||
| type: | |||
| type key int | |||
| const mykey key = 0 | |||
| // GetMyKey returns a value for this package from the request values. | |||
| func GetMyKey(r *http.Request) SomeType { | |||
| if rv := context.Get(r, mykey); rv != nil { | |||
| return rv.(SomeType) | |||
| } | |||
| return nil | |||
| } | |||
| // SetMyKey sets a value for this package in the request values. | |||
| func SetMyKey(r *http.Request, val SomeType) { | |||
| context.Set(r, mykey, val) | |||
| } | |||
| Variables must be cleared at the end of a request, to remove all values | |||
| that were stored. This can be done in an http.Handler, after a request was | |||
| served. Just call Clear() passing the request: | |||
| context.Clear(r) | |||
| ...or use ClearHandler(), which conveniently wraps an http.Handler to clear | |||
| variables at the end of a request lifetime. | |||
| The Router from the package gorilla/mux calls Clear(), so if you are using it | |||
| you don't need to clear the context manually. | |||
| */ | |||
| package context | |||