1 module hunt.http.routing.impl.HttpSessionHandlerImpl;
2 
3 import hunt.http.routing.AbstractHttpSessionHandler;
4 import hunt.http.routing.RoutingContext;
5 import hunt.http.server.HttpSession;
6 
7 import hunt.http.Cookie;
8 import hunt.http.Exceptions;
9 
10 import hunt.logging;
11 
12 import std.algorithm;
13 import std.string;
14 import std.range;
15 import std.uuid;
16 import std.variant;
17 
18 /** 
19  * 
20  */
21 class HttpSessionHandlerImpl : AbstractHttpSessionHandler {
22 
23     private SessionStore sessionStore;
24     private string contextSessionKey = "_contextSessionKey";
25 
26     this(RoutingContext routingContext, SessionStore sessionStore,
27             string sessionIdParameterName, int defaultMaxInactiveInterval) {
28         super(routingContext, sessionIdParameterName, defaultMaxInactiveInterval);
29         this.sessionStore = sessionStore;
30     }
31 
32     string getContextSessionKey() {
33         return contextSessionKey;
34     }
35 
36     void setContextSessionKey(string contextSessionKey) {
37         this.contextSessionKey = contextSessionKey;
38     }
39 
40     // override
41     HttpSession getSessionById(string id) {
42         return sessionStore.get(id);
43     }
44 
45     // override
46     HttpSession getSession() {
47         return getSession(true);
48     }
49 
50     // override
51     HttpSession getSession(bool create) {
52         return _getSession(create, -1);
53     }
54 
55     // override
56     HttpSession getAndCreateSession(int maxAge) {
57         return _getSession(true, maxAge);
58     }
59 
60     private HttpSession _getSession(bool create, int maxAge) {
61         Variant attr = routingContext.getAttribute(contextSessionKey);
62         HttpSession currentSession;
63         if (attr.type == typeid(HttpSession)) {
64             currentSession = attr.get!(HttpSession);
65             if(currentSession !is null)
66                 return currentSession;
67         }
68         
69         try {
70             string sid = getSessionId(create);
71             version(HUNT_HTTP_DEBUG) infof("SessionId: %s, size: %d", sid, sessionStore.size());
72             if(sessionStore.contains(sid)) {
73                 currentSession = sessionStore.get(sid);
74                 routingContext.setAttribute(contextSessionKey, currentSession);
75             } else {
76                 currentSession = createSession(maxAge);
77             }
78         } catch(Exception ex) {
79             version(HUNT_DEBUG) warning(ex.msg);
80             if(create) {
81                 SessionInvalidException cause1 = cast(SessionInvalidException)ex;
82                 SessionNotFoundException cause2 = cast(SessionNotFoundException)ex;
83                 if(cause1 !is null || cause2 !is null) {
84                     currentSession = createSession(maxAge);
85                 } else {
86                     version(HUNT_HTTP_DEBUG) warning(ex);
87                 }
88             } else {
89                 SessionInvalidException cause = cast(SessionInvalidException)ex;
90                 if(cause !is null) {
91                     removeCookie();
92                 } else {
93                     version(HUNT_HTTP_DEBUG) warning(ex);
94                 }
95             }
96         }
97 
98         return currentSession;
99     }
100 
101     private void removeCookie() {
102         Cookie cookie = new Cookie(sessionIdParameterName, requestedSessionId);
103         cookie.setMaxAge(0);
104         routingContext.addCookie(cookie);
105     }
106 
107 
108     // override
109     int getSessionSize() {
110         return sessionStore.size();
111     }
112 
113     // override
114     bool removeSession() {
115         try {
116         sessionStore.remove(requestedSessionId);
117         removeCookie();
118         routingContext.getAttributes().remove(contextSessionKey);
119         } catch(Exception ex) {
120             version(HUNT_DEBUG) warning(ex.msg);
121             version(HUNT_HTTP_DEBUG) warning(ex);
122             return false;
123         }
124         return true;
125     }
126 
127     // override
128     bool removeSessionById(string id) {
129         return sessionStore.remove(id);
130     }
131 
132     // override
133     bool updateSession(HttpSession httpSession) {
134         routingContext.setAttribute(contextSessionKey, httpSession);
135         return sessionStore.put(requestedSessionId, httpSession);
136     }
137 
138     protected string getSessionId(bool create) {
139         if (create && requestedSessionId.empty()) {
140             requestedSessionId = randomUUID().toString().replace("-", "");
141         }
142         version(HUNT_HTTP_DEBUG_MORE) tracef("create: %s, requestedSessionId: %s", create, requestedSessionId);
143         return requestedSessionId;
144     }
145 
146     protected HttpSession createSession(int maxAge) {
147         version(HUNT_HTTP_DEBUG) info("creating new session: ", requestedSessionId);
148         HttpSession newSession = HttpSession.create(requestedSessionId, defaultMaxInactiveInterval);
149         sessionStore.put(newSession.getId(), newSession);
150         createCookie(maxAge);
151         routingContext.setAttribute(contextSessionKey, newSession);
152         return newSession;
153     }
154 
155     private void createCookie(int maxAge) {
156         Cookie cookie = new Cookie(sessionIdParameterName, requestedSessionId);
157         if (maxAge > 0) {
158             cookie.setMaxAge(maxAge);
159         }
160         routingContext.addCookie(cookie);
161     }
162 }