forked from trendrr/goshire
/
filters.go
152 lines (127 loc) · 3.79 KB
/
filters.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package cheshire
import (
"log"
"net/http"
)
// Hooks to hook into before and after the controller execution.
type ControllerFilter interface {
//This is called before the Controller is called.
//returning false will stop the execution
Before(*Txn) bool
}
// Additional hooks if you need more granularity into the lifecycle
type FilterAdvanced interface {
ControllerFilter
//Called immediately before the response is written.
BeforeWrite(*Response, *Txn)
//This is called after the controller is called.
//The response has already been sent
AfterWrite(*Response, *Txn)
}
// A generic cache.
type Cache interface {
Set(key string, value []byte, expireSeconds int)
// Sets the value if and only if there is no value associated with this key
SetIfAbsent(key string, value []byte, expireSeconds int) bool
// Deletes the value at the requested key
Delete(key string)
// Gets the value at the requested key
Get(key string) ([]byte, bool)
// Increment the key by val (val is allowed to be negative)
// in most implementation expireSeconds will be from the first increment, but users should not count on that.
// if no value is a present it should be added.
// If a value is present which is not a number an error should be returned.
Inc(key string, val int64, expireSeconds int) (int64, error)
}
type Session struct {
//The cache provider
cache Cache
//Max age for the session
sessionAgeSeconds int
}
func NewSession(cache Cache, sessionMaxSeconds int) *Session {
return &Session{
cache: cache,
sessionAgeSeconds: sessionMaxSeconds,
}
}
//This is called before the Controller is called.
//returning false will stop the execution
func (this *Session) Before(txn *Txn) bool {
if txn.Type() != "html" {
//skip
return true
}
// log.Println("SESSION!")
httpWriter, err := ToHttpWriter(txn)
if err != nil {
log.Printf("ERROR in session.before %s", err)
return true //should we continue with the request?
}
cookie, err := httpWriter.HttpRequest.Cookie("session_id")
if err != nil {
//create new session id
txn.Session.Put("session_id", SessionId())
// log.Println("Created session!")
} else {
//load the session.
sessionId := cookie.Value
// log.Printf("Found session cookie! %s", sessionId)
bytes, ok := this.cache.Get(sessionId)
if !ok {
//create a new session, since the old one is gone
sessionId = SessionId()
// log.Printf("Old session expired, setting new one (%s)", sessionId)
} else {
err = txn.Session.UnmarshalJSON(bytes)
if err != nil {
log.Printf("Error unmarshaling json (%s) -> (%s)", bytes, err)
}
}
txn.Session.Put("session_id", sessionId)
}
return true
}
func (this *Session) BeforeHtmlWrite(txn *Txn, writer http.ResponseWriter) bool {
sessionId, ok := txn.Session.GetString("session_id")
if !ok {
log.Println("Error! No Sessionid in txn. wtf?")
return true
}
if txn.Session.MustBool("delete_session", false) {
log.Println("Deleting session")
cookie := &http.Cookie{
Name: "session_id",
Value: sessionId,
MaxAge: 0,
}
http.SetCookie(writer, cookie)
this.cache.Delete(sessionId)
return true
}
//session will always have session_id param
if len(txn.Session.Map) > 1 {
//We set an internal flag in the session, so
//if keys are removed now we always save the session.
txn.Session.Put("_persisted", true)
//only write the session if there is something in it
cookie := &http.Cookie{
Name: "session_id",
Value: sessionId,
MaxAge: this.sessionAgeSeconds,
}
http.SetCookie(writer, cookie)
bytes, err := txn.Session.MarshalJSON()
if err != nil {
log.Println(err)
}
this.cache.Set(sessionId, bytes, this.sessionAgeSeconds)
}
return true
}
// returns a unique session id
func SessionId() string {
id := RandString(32)
//TODO; this isnt
return id
}