/
session.py
128 lines (115 loc) · 4.42 KB
/
session.py
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
'''
Created on 2015/11/9
:author: hubo
'''
from vlcp.config import defaultconfig
from vlcp.server.module import Module, api, depend, call_api
from vlcp.event.runnable import RoutineContainer
from vlcp.event import Event, withIndices
from vlcp.service.utils import knowledge
from uuid import uuid4
try:
from Cookie import SimpleCookie, Morsel
except Exception:
from http.cookies import SimpleCookie, Morsel
from vlcp.event.lock import Lock
@depend(knowledge.MemoryStorage)
@defaultconfig
class Session(Module):
'''
HTTP Session with cookies
'''
# Timeout for a session
_default_timeout = 1800
# Cookie name used in session id storage
_default_cookiename = '_session_id'
service = True
class SessionObject(object):
def __init__(self, sessionid):
self.id = sessionid
self.vars = {}
self.lockseq = 0
self.releaseseq = 0
class SessionHandle(object):
def __init__(self, sessionobj, container):
self.sessionobj = sessionobj
self.id = sessionobj.id
self.vars = sessionobj.vars
self._lock = Lock(sessionobj, container.scheduler)
self.container = container
async def lock(self):
"Lock session"
await self._lock.lock(self.container)
def unlock(self):
"Unlock session"
self._lock.unlock()
def __init__(self, server):
'''
Constructor
'''
Module.__init__(self, server)
self.apiroutine = RoutineContainer(self.scheduler)
self.createAPI(api(self.start, self.apiroutine),
api(self.create, self.apiroutine),
api(self.get, self.apiroutine),
api(self.destroy, self.apiroutine))
async def start(self, cookies, cookieopts = None):
"""
Session start operation. First check among the cookies to find existed sessions;
if there is not an existed session, create a new one.
:param cookies: cookie header from the client
:param cookieopts: extra options used when creating a new cookie
:return: ``(session_handle, cookies)`` where session_handle is a SessionHandle object,
and cookies is a list of created Set-Cookie headers (may be empty)
"""
c = SimpleCookie(cookies)
sid = c.get(self.cookiename)
create = True
if sid is not None:
sh = await self.get(sid.value)
if sh is not None:
return (self.SessionHandle(sh, self.apiroutine), [])
if create:
sh = await self.create()
m = Morsel()
m.key = self.cookiename
m.value = sh.id
m.coded_value = sh.id
opts = {'path':'/', 'httponly':True}
if cookieopts:
opts.update(cookieopts)
if not cookieopts['httponly']:
del cookieopts['httponly']
m.update(opts)
return (sh, [m])
async def get(self, sessionid, refresh = True):
"""
Get the seesion object of the session id
:param sessionid: a session ID
:param refresh: if True, refresh the expiration time of this session
:return: Session object or None if not exists
"""
return await call_api(self.apiroutine, 'memorystorage', 'get', {'key': __name__ + '.' + sessionid, 'timeout': self.timeout if refresh else None})
async def create(self):
"""
Create a new session object
:return: Session handle for the created session object.
"""
sid = uuid4().hex
sobj = self.SessionObject(sid)
await call_api(self.apiroutine, 'memorystorage', 'set', {'key': __name__ + '.' + sid, 'value': sobj, 'timeout': self.timeout})
return self.SessionHandle(sobj, self.apiroutine)
async def destroy(self, sessionid):
"""
Destroy a session
:param sessionid: session ID
:return: a list of Set-Cookie headers to be sent to the client
"""
await call_api(self.apiroutine, 'memorystorage', 'delete', {'key': __name__ + '.' + sessionid})
m = Morsel()
m.key = self.cookiename
m.value = 'deleted'
m.coded_value = 'deleted'
opts = {'path':'/', 'httponly':True, 'max-age':0}
m.update(opts)
return [m]