-
Notifications
You must be signed in to change notification settings - Fork 0
/
session_caching.go
81 lines (69 loc) · 2.57 KB
/
session_caching.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
package chained
import (
"bytes"
"sync"
"time"
tls "github.com/refraction-networking/utls"
)
// expiringSessionCache is a tls.ClientSessionCache that expires tickets older than the
// configured TTL. Because we use one of these per proxy server, it does not need to care about
// session key names nor LRU logic.
type expiringSessionCache struct {
sync.RWMutex
server string
ttl time.Duration
defaultState *tls.ClientSessionState
currentState *tls.ClientSessionState
lastUpdated time.Time
allowTLS13 bool
}
// newExpiringSessionCache returns an expiringSessionCache. It initializes the current state from whatever is stored on disk
// for the given server. For this to work, PersistSessionStates has to be called prior to creating this cache.
func newExpiringSessionCache(server string, ttl time.Duration, defaultState *tls.ClientSessionState) *expiringSessionCache {
currentState, lastUpdated := persistedSessionStateFor(server)
if currentState != nil {
log.Debugf("Found persisted session state for %v with timestamp %v", server, lastUpdated)
}
return &expiringSessionCache{
server: server,
ttl: ttl,
defaultState: defaultState,
currentState: currentState,
lastUpdated: lastUpdated,
}
}
// Put adds the provided cs to the cache. It does nothing if cs is nil in
// thinking that the handshake failure when resuming session may be temporary.
// sessionKey is required by the ClientSessionCache interface but ignored here.
func (c *expiringSessionCache) Put(sessionKey string, cs *tls.ClientSessionState) {
if cs == nil {
return
}
c.Lock()
defer c.Unlock()
// don't save v1.3 session states because we can't actually resume them when using parrots
// https://github.com/getlantern/lantern-internal/issues/4170
// https://github.com/getlantern/lantern-internal/issues/3850
if cs.Vers() == tls.VersionTLS13 && !c.allowTLS13 {
return
}
if c.currentState != nil && bytes.Equal(c.currentState.SessionTicket(), cs.SessionTicket()) {
// same as the old ticket, don't bother updating and leave timestamp alone
return
}
c.currentState = cs
c.lastUpdated = time.Now()
saveSessionState(c.server, c.currentState, c.lastUpdated)
}
// Get returns the cached ClientSessionState if it's not expired, or
// defaultState. sessionKey is required by the ClientSessionCache interface but
// ignored here.
func (c *expiringSessionCache) Get(sessionKey string) (*tls.ClientSessionState, bool) {
c.RLock()
defer c.RUnlock()
state := c.currentState
if state == nil || time.Since(c.lastUpdated) > c.ttl {
state = c.defaultState
}
return state, state != nil
}