-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathSimpleSessions.dyalog
147 lines (133 loc) · 5.05 KB
/
SimpleSessions.dyalog
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
:Class SimpleSessions
⍝ Default Session Handler, used by the WebServer sample
⍝ Manages HTTP sessions using cookies
⍝ When a HTTP request arrives, checks to see if the session cookie is included and the session
⍝ is in the list of valid sessions. If it is, assign the Session property of the request.
⍝ If it isn't, create a new session and set the cookie
:Field Public Sessions ⍝ Should be private, really
:Field Public Server
:Class Page
:Field Public URL←''
:Field Public State←⎕NS ''
:EndClass
:Class Session
:Field Public ID←0
:Field Public User←''
:Field Public LastActive←0
:Field Public Cookie←''
:Field Public AuthCookieName←''
:Field Public Timeout←0
:Field Public State
:Field Public New←1
:Field Public Pages←0⍴⎕NEW Page
:Field Public Server←⍬
:EndClass
∇ Start server;tn;root
:Access Public
:Implements Constructor
⍝ Initialize Session handler
Server←server
Sessions←(Server.Framework≡'HRServer')⍴⎕NEW Session
root←Server.Config.AppRoot
Timeout←Server.Config.SessionTimeout
timeout←Timeout÷24×60 ⍝ Convert minutes to fractions of a day
:If Server.Framework≡'MiServer'
:Trap 22
tn←(root,'sessions.dcf')⎕FCREATE 0
(0 ¯1 0)⎕FSTAC tn
0 ⎕FAPPEND tn ⍝ Session Number
⎕FUNTIE tn
:EndTrap
tn←(root,'sessions.dcf')⎕FSTIE 0
NextSession←⎕FREAD tn,1
⎕FUNTIE tn
:EndIf
∇
∇ GetSession req;c;tn;now;session;ns;new;t_out;i;r
:Access Public
⍝ Return session. Right argument is a HttpRequest.
:If 'HRServer'≡Server.Framework
req.Session←⊃Sessions
:Else
:Hold 'Sessions'
session←req.GetCookie'Session'
now←#.Dates.DateToIDN ⎕TS
:If new←(1⊃⍴Sessions)<i←Sessions.Cookie⍳⊂session ⍝ Cookie is not in the table
c←SessionCookie NextSession
Sessions←Sessions,r←⎕NEW Session
r.(ID User LastActive Cookie State Server)←NextSession''now c(⎕NS'')Server
NextSession←(2*30)|NextSession+1
tn←(req.Server.Config.AppRoot,'sessions.dcf')⎕FSTIE 0
NextSession ⎕FREPLACE tn,1
⎕FUNTIE tn
req.SetCookie'Session'c'/' 30 'HttpOnly'
req.Session←r
req.Server.onSessionStart req
:Else ⍝ Old session
(r←i⊃Sessions).LastActive←now ⍝ Just register activity
r.New←0
req.Session←r
:EndIf
:EndHold
:EndIf
∇
∇ KillSessions ids;mask;i
:Access Public
:Hold 'Sessions'
:If ∨/mask←Sessions.ID∊ids
:For i :In mask/⍳⍴mask
Server.onSessionEnd i⊃Sessions
:EndFor
Sessions/⍨←~mask
:EndIf
:EndHold
∇
∇ Logout req;session;i;z
:Access Public Instance
⍝ End session due to user request
:If Server.Framework≡'MiServer'
session←req.GetCookie'Session'
:If (1⊃⍴Sessions)≥i←Sessions.Cookie⍳⊂session ⍝ Cookie is in the table
req.Server.onSessionEnd(i⊃Sessions)
req.DelCookie'Session'
:If 0≠⍴z←req.Session.AuthCookieName ⋄ req.DelCookie z ⋄ :EndIf
req.Return'Logged out ...'
:Else
req.Return'No session established ...'
:EndIf
:EndIf
∇
∇ r←SessionCookie n;⎕RL;z;seed;p
⍝ Create Cookie from session ID or vice versa
:If (10|⎕DR n)∊0 2 ⍝ Session ID from Cookie
z←⎕UCS #.Base64.Decode n
⎕RL←256⊥2↑z ⋄ p←30?30
r←30⍴0 ⋄ r[p]←2↓z
r←256⊥4↑r
:Else ⍝ Session ID to Cookie
⎕RL←10000000|3⊃⎕AI
⎕RL←seed←?¯1+256*2 ⋄ p←30?30
r←#.Base64.Encode #.Base64.Char(256 256⊤seed),((256 256 256 256⊤n),¯1+?26⍴256)[p]
:EndIf
∇
∇ HouseKeeping Server;now;m;i;p
⍝ Check to see if any sessions have expired due to inactivity
⍝ Call any page application callbacks (_Close) if necessary
:Access Public
:If Server.Framework≡'MiServer'
now←#.Dates.DateToIDN ⎕TS
:If ∨/m←Sessions.LastActive<now-timeout
:Hold 'Sessions'
:For i :In m/⍳⍴m
Server.onSessionEnd i⊃Sessions
:If 0≠⍴p←(i⊃Sessions).Pages
:AndIf 0≠⊃p.⎕NC⊂'_Close'
p._Close i⊃Sessions
:EndIf
:EndFor
Sessions←(~m)/Sessions
:EndHold
:EndIf
:EndIf
∇
:EndClass