1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.server.session;
15
16 import static java.lang.Math.round;
17
18 import java.util.Arrays;
19 import java.util.Collections;
20 import java.util.Enumeration;
21 import java.util.EventListener;
22 import java.util.HashSet;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.Set;
26 import java.util.concurrent.CopyOnWriteArrayList;
27
28 import javax.servlet.ServletRequest;
29 import javax.servlet.SessionCookieConfig;
30 import javax.servlet.SessionTrackingMode;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpSession;
33 import javax.servlet.http.HttpSessionAttributeListener;
34 import javax.servlet.http.HttpSessionBindingEvent;
35 import javax.servlet.http.HttpSessionContext;
36 import javax.servlet.http.HttpSessionEvent;
37 import javax.servlet.http.HttpSessionListener;
38
39 import org.eclipse.jetty.http.HttpCookie;
40 import org.eclipse.jetty.server.AbstractConnector;
41 import org.eclipse.jetty.server.Request;
42 import org.eclipse.jetty.server.Server;
43 import org.eclipse.jetty.server.SessionIdManager;
44 import org.eclipse.jetty.server.SessionManager;
45 import org.eclipse.jetty.server.handler.ContextHandler;
46 import org.eclipse.jetty.util.component.AbstractLifeCycle;
47 import org.eclipse.jetty.util.log.Logger;
48 import org.eclipse.jetty.util.statistic.CounterStatistic;
49 import org.eclipse.jetty.util.statistic.SampleStatistic;
50
51
52
53
54
55
56
57
58
59
60
61 @SuppressWarnings("deprecation")
62 public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager
63 {
64 final static Logger __log = SessionHandler.LOG;
65
66 public Set<SessionTrackingMode> __defaultSessionTrackingModes =
67 Collections.unmodifiableSet(
68 new HashSet<SessionTrackingMode>(
69 Arrays.asList(new SessionTrackingMode[]{SessionTrackingMode.COOKIE,SessionTrackingMode.URL})));
70
71
72 public final static int __distantFuture=60*60*24*7*52*20;
73
74 static final HttpSessionContext __nullSessionContext=new HttpSessionContext()
75 {
76 public HttpSession getSession(String sessionId)
77 {
78 return null;
79 }
80
81 @SuppressWarnings({ "rawtypes", "unchecked" })
82 public Enumeration getIds()
83 {
84 return Collections.enumeration(Collections.EMPTY_LIST);
85 }
86 };
87
88 private boolean _usingCookies=true;
89
90
91
92
93 protected int _dftMaxIdleSecs=-1;
94 protected SessionHandler _sessionHandler;
95 protected boolean _httpOnly=false;
96 protected SessionIdManager _sessionIdManager;
97 protected boolean _secureCookies=false;
98 protected final List<HttpSessionAttributeListener> _sessionAttributeListeners = new CopyOnWriteArrayList<HttpSessionAttributeListener>();
99 protected final List<HttpSessionListener> _sessionListeners= new CopyOnWriteArrayList<HttpSessionListener>();
100
101 protected ClassLoader _loader;
102 protected ContextHandler.Context _context;
103 protected String _sessionCookie=__DefaultSessionCookie;
104 protected String _sessionIdPathParameterName = __DefaultSessionIdPathParameterName;
105 protected String _sessionIdPathParameterNamePrefix =";"+ _sessionIdPathParameterName +"=";
106 protected String _sessionDomain;
107 protected String _sessionPath;
108 protected int _maxCookieAge=-1;
109 protected int _refreshCookieAge;
110 protected boolean _nodeIdInSessionId;
111 protected boolean _checkingRemoteSessionIdEncoding;
112 protected String _sessionComment;
113
114 public Set<SessionTrackingMode> _sessionTrackingModes;
115
116 private boolean _usingURLs;
117
118 protected final CounterStatistic _sessionsStats = new CounterStatistic();
119 protected final SampleStatistic _sessionTimeStats = new SampleStatistic();
120
121
122 public AbstractSessionManager()
123 {
124 setSessionTrackingModes(__defaultSessionTrackingModes);
125 }
126
127
128 public ContextHandler.Context getContext()
129 {
130 return _context;
131 }
132
133
134 public ContextHandler getContextHandler()
135 {
136 return _context.getContextHandler();
137 }
138
139
140 public HttpCookie access(HttpSession session,boolean secure)
141 {
142 long now=System.currentTimeMillis();
143
144 AbstractSession s = ((SessionIf)session).getSession();
145
146 if (s.access(now))
147 {
148
149 if (isUsingCookies() &&
150 (s.isIdChanged() ||
151 (getSessionCookieConfig().getMaxAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge()))
152 )
153 )
154 {
155 HttpCookie cookie=getSessionCookie(session,_context==null?"/":(_context.getContextPath()),secure);
156 s.cookieSet();
157 s.setIdChanged(false);
158 return cookie;
159 }
160 }
161 return null;
162 }
163
164
165 public void addEventListener(EventListener listener)
166 {
167 if (listener instanceof HttpSessionAttributeListener)
168 _sessionAttributeListeners.add((HttpSessionAttributeListener)listener);
169 if (listener instanceof HttpSessionListener)
170 _sessionListeners.add((HttpSessionListener)listener);
171 }
172
173
174 public void clearEventListeners()
175 {
176 _sessionAttributeListeners.clear();
177 _sessionListeners.clear();
178 }
179
180
181 public void complete(HttpSession session)
182 {
183 AbstractSession s = ((SessionIf)session).getSession();
184 s.complete();
185 }
186
187
188 @Override
189 public void doStart() throws Exception
190 {
191 _context=ContextHandler.getCurrentContext();
192 _loader=Thread.currentThread().getContextClassLoader();
193
194 if (_sessionIdManager==null)
195 {
196 final Server server=getSessionHandler().getServer();
197 synchronized (server)
198 {
199 _sessionIdManager=server.getSessionIdManager();
200 if (_sessionIdManager==null)
201 {
202 _sessionIdManager=new HashSessionIdManager();
203 server.setSessionIdManager(_sessionIdManager);
204 }
205 }
206 }
207 if (!_sessionIdManager.isStarted())
208 _sessionIdManager.start();
209
210
211 if (_context!=null)
212 {
213 String tmp=_context.getInitParameter(SessionManager.__SessionCookieProperty);
214 if (tmp!=null)
215 _sessionCookie=tmp;
216
217 tmp=_context.getInitParameter(SessionManager.__SessionIdPathParameterNameProperty);
218 if (tmp!=null)
219 setSessionIdPathParameterName(tmp);
220
221
222 if (_maxCookieAge==-1)
223 {
224 tmp=_context.getInitParameter(SessionManager.__MaxAgeProperty);
225 if (tmp!=null)
226 _maxCookieAge=Integer.parseInt(tmp.trim());
227 }
228
229
230 if (_sessionDomain==null)
231 _sessionDomain=_context.getInitParameter(SessionManager.__SessionDomainProperty);
232
233
234 if (_sessionPath==null)
235 _sessionPath=_context.getInitParameter(SessionManager.__SessionPathProperty);
236
237 tmp=_context.getInitParameter(SessionManager.__CheckRemoteSessionEncoding);
238 if (tmp!=null)
239 _checkingRemoteSessionIdEncoding=Boolean.parseBoolean(tmp);
240 }
241
242 super.doStart();
243 }
244
245
246 @Override
247 public void doStop() throws Exception
248 {
249 super.doStop();
250
251 invalidateSessions();
252
253 _loader=null;
254 }
255
256
257
258
259
260 public boolean getHttpOnly()
261 {
262 return _httpOnly;
263 }
264
265
266 public HttpSession getHttpSession(String nodeId)
267 {
268 String cluster_id = getSessionIdManager().getClusterId(nodeId);
269
270 AbstractSession session = getSession(cluster_id);
271 if (session!=null && !session.getNodeId().equals(nodeId))
272 session.setIdChanged(true);
273 return session;
274 }
275
276
277
278
279
280
281 public SessionIdManager getIdManager()
282 {
283 return getSessionIdManager();
284 }
285
286
287
288
289
290 public SessionIdManager getSessionIdManager()
291 {
292 return _sessionIdManager;
293 }
294
295
296
297
298
299
300 @Override
301 public int getMaxInactiveInterval()
302 {
303 return _dftMaxIdleSecs;
304 }
305
306
307
308
309
310 @Deprecated
311 public int getMaxSessions()
312 {
313 return getSessionsMax();
314 }
315
316
317
318
319
320 public int getSessionsMax()
321 {
322 return (int)_sessionsStats.getMax();
323 }
324
325
326
327
328
329 public int getSessionsTotal()
330 {
331 return (int)_sessionsStats.getTotal();
332 }
333
334
335
336
337
338 @Deprecated
339 public SessionIdManager getMetaManager()
340 {
341 return getSessionIdManager();
342 }
343
344
345
346
347
348 @Deprecated
349 public int getMinSessions()
350 {
351 return 0;
352 }
353
354
355 public int getRefreshCookieAge()
356 {
357 return _refreshCookieAge;
358 }
359
360
361
362
363
364
365 public boolean getSecureCookies()
366 {
367 return _secureCookies;
368 }
369
370
371 public String getSessionCookie()
372 {
373 return _sessionCookie;
374 }
375
376
377 public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure)
378 {
379 if (isUsingCookies())
380 {
381 String sessionPath = (_sessionPath==null) ? contextPath : _sessionPath;
382 sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath;
383 String id = getNodeId(session);
384 HttpCookie cookie = null;
385 if (_sessionComment == null)
386 {
387 cookie = new HttpCookie(
388 _sessionCookie,
389 id,
390 _sessionDomain,
391 sessionPath,
392 _cookieConfig.getMaxAge(),
393 _cookieConfig.isHttpOnly(),
394 requestIsSecure&&_cookieConfig.isSecure());
395 }
396 else
397 {
398 cookie = new HttpCookie(
399 _sessionCookie,
400 id,
401 _sessionDomain,
402 sessionPath,
403 _cookieConfig.getMaxAge(),
404 _cookieConfig.isHttpOnly(),
405 requestIsSecure&&_cookieConfig.isSecure(),
406 _sessionComment,
407 1);
408 }
409
410 return cookie;
411 }
412 return null;
413 }
414
415 public String getSessionDomain()
416 {
417 return _sessionDomain;
418 }
419
420
421
422
423
424 public SessionHandler getSessionHandler()
425 {
426 return _sessionHandler;
427 }
428
429
430
431
432
433 @SuppressWarnings("rawtypes")
434 public Map getSessionMap()
435 {
436 throw new UnsupportedOperationException();
437 }
438
439
440
441
442 public int getSessions()
443 {
444 return (int)_sessionsStats.getCurrent();
445 }
446
447
448 public String getSessionIdPathParameterName()
449 {
450 return _sessionIdPathParameterName;
451 }
452
453
454 public String getSessionIdPathParameterNamePrefix()
455 {
456 return _sessionIdPathParameterNamePrefix;
457 }
458
459
460
461
462
463 public boolean isUsingCookies()
464 {
465 return _usingCookies;
466 }
467
468
469 public boolean isValid(HttpSession session)
470 {
471 AbstractSession s = ((SessionIf)session).getSession();
472 return s.isValid();
473 }
474
475
476 public String getClusterId(HttpSession session)
477 {
478 AbstractSession s = ((SessionIf)session).getSession();
479 return s.getClusterId();
480 }
481
482
483 public String getNodeId(HttpSession session)
484 {
485 AbstractSession s = ((SessionIf)session).getSession();
486 return s.getNodeId();
487 }
488
489
490
491
492
493 public HttpSession newHttpSession(HttpServletRequest request)
494 {
495 AbstractSession session=newSession(request);
496 session.setMaxInactiveInterval(_dftMaxIdleSecs);
497 addSession(session,true);
498 return session;
499 }
500
501
502 public void removeEventListener(EventListener listener)
503 {
504 if (listener instanceof HttpSessionAttributeListener)
505 _sessionAttributeListeners.remove(listener);
506 if (listener instanceof HttpSessionListener)
507 _sessionListeners.remove(listener);
508 }
509
510
511
512
513
514 @Deprecated
515 public void resetStats()
516 {
517 statsReset();
518 }
519
520
521
522
523
524 public void statsReset()
525 {
526 _sessionsStats.reset(getSessions());
527 _sessionTimeStats.reset();
528 }
529
530
531
532
533
534
535 public void setHttpOnly(boolean httpOnly)
536 {
537 _httpOnly=httpOnly;
538 }
539
540
541
542
543
544
545 public void setIdManager(SessionIdManager metaManager)
546 {
547 setSessionIdManager(metaManager);
548 }
549
550
551
552
553
554 public void setSessionIdManager(SessionIdManager metaManager)
555 {
556 _sessionIdManager=metaManager;
557 }
558
559
560
561
562
563
564
565 public void setMaxInactiveInterval(int seconds)
566 {
567 _dftMaxIdleSecs=seconds;
568 }
569
570
571
572 public void setRefreshCookieAge(int ageInSeconds)
573 {
574 _refreshCookieAge=ageInSeconds;
575 }
576
577
578
579 public void setSessionCookie(String cookieName)
580 {
581 _sessionCookie=cookieName;
582 }
583
584
585
586
587
588
589
590
591 public void setSessionHandler(SessionHandler sessionHandler)
592 {
593 _sessionHandler=sessionHandler;
594 }
595
596
597
598 public void setSessionIdPathParameterName(String param)
599 {
600 _sessionIdPathParameterName =(param==null||"none".equals(param))?null:param;
601 _sessionIdPathParameterNamePrefix =(param==null||"none".equals(param))?null:(";"+ _sessionIdPathParameterName +"=");
602 }
603
604
605
606
607
608 public void setUsingCookies(boolean usingCookies)
609 {
610 _usingCookies=usingCookies;
611 }
612
613
614 protected abstract void addSession(AbstractSession session);
615
616
617
618
619
620
621 protected void addSession(AbstractSession session, boolean created)
622 {
623 synchronized (_sessionIdManager)
624 {
625 _sessionIdManager.addSession(session);
626 addSession(session);
627 }
628
629 if (created)
630 {
631 _sessionsStats.increment();
632 if (_sessionListeners!=null)
633 {
634 HttpSessionEvent event=new HttpSessionEvent(session);
635 for (HttpSessionListener listener : _sessionListeners)
636 listener.sessionCreated(event);
637 }
638 }
639 }
640
641
642
643
644
645
646
647 public abstract AbstractSession getSession(String idInCluster);
648
649 protected abstract void invalidateSessions() throws Exception;
650
651
652
653
654
655
656
657
658 protected abstract AbstractSession newSession(HttpServletRequest request);
659
660
661
662
663
664
665 public boolean isNodeIdInSessionId()
666 {
667 return _nodeIdInSessionId;
668 }
669
670
671
672
673
674 public void setNodeIdInSessionId(boolean nodeIdInSessionId)
675 {
676 _nodeIdInSessionId=nodeIdInSessionId;
677 }
678
679
680
681
682
683
684
685 public void removeSession(HttpSession session, boolean invalidate)
686 {
687 AbstractSession s = ((SessionIf)session).getSession();
688 removeSession(s,invalidate);
689 }
690
691
692
693
694
695
696
697 public void removeSession(AbstractSession session, boolean invalidate)
698 {
699
700 boolean removed = removeSession(session.getClusterId());
701
702 if (removed)
703 {
704 _sessionsStats.decrement();
705 _sessionTimeStats.set(round((System.currentTimeMillis() - session.getCreationTime())/1000.0));
706
707
708 _sessionIdManager.removeSession(session);
709 if (invalidate)
710 _sessionIdManager.invalidateAll(session.getClusterId());
711
712 if (invalidate && _sessionListeners!=null)
713 {
714 HttpSessionEvent event=new HttpSessionEvent(session);
715 for (HttpSessionListener listener : _sessionListeners)
716 listener.sessionDestroyed(event);
717 }
718 }
719 }
720
721
722 protected abstract boolean removeSession(String idInCluster);
723
724
725
726
727
728 public long getSessionTimeMax()
729 {
730 return _sessionTimeStats.getMax();
731 }
732
733
734 public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
735 {
736 return __defaultSessionTrackingModes;
737 }
738
739
740 public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
741 {
742 return Collections.unmodifiableSet(_sessionTrackingModes);
743 }
744
745
746 @Override
747 public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
748 {
749 _sessionTrackingModes=new HashSet<SessionTrackingMode>(sessionTrackingModes);
750 _usingCookies=_sessionTrackingModes.contains(SessionTrackingMode.COOKIE);
751 _usingURLs=_sessionTrackingModes.contains(SessionTrackingMode.URL);
752 }
753
754
755 @Override
756 public boolean isUsingURLs()
757 {
758 return _usingURLs;
759 }
760
761
762
763 public SessionCookieConfig getSessionCookieConfig()
764 {
765 return _cookieConfig;
766 }
767
768
769 private SessionCookieConfig _cookieConfig =
770 new SessionCookieConfig()
771 {
772 @Override
773 public String getComment()
774 {
775 return _sessionComment;
776 }
777
778 @Override
779 public String getDomain()
780 {
781 return _sessionDomain;
782 }
783
784 @Override
785 public int getMaxAge()
786 {
787 return _maxCookieAge;
788 }
789
790 @Override
791 public String getName()
792 {
793 return _sessionCookie;
794 }
795
796 @Override
797 public String getPath()
798 {
799 return _sessionPath;
800 }
801
802 @Override
803 public boolean isHttpOnly()
804 {
805 return _httpOnly;
806 }
807
808 @Override
809 public boolean isSecure()
810 {
811 return _secureCookies;
812 }
813
814 @Override
815 public void setComment(String comment)
816 {
817 _sessionComment = comment;
818 }
819
820 @Override
821 public void setDomain(String domain)
822 {
823 _sessionDomain=domain;
824 }
825
826 @Override
827 public void setHttpOnly(boolean httpOnly)
828 {
829 _httpOnly=httpOnly;
830 }
831
832 @Override
833 public void setMaxAge(int maxAge)
834 {
835 _maxCookieAge=maxAge;
836 }
837
838 @Override
839 public void setName(String name)
840 {
841 _sessionCookie=name;
842 }
843
844 @Override
845 public void setPath(String path)
846 {
847 _sessionPath=path;
848 }
849
850 @Override
851 public void setSecure(boolean secure)
852 {
853 _secureCookies=secure;
854 }
855
856 };
857
858
859
860
861
862
863 public long getSessionTimeTotal()
864 {
865 return _sessionTimeStats.getTotal();
866 }
867
868
869
870
871
872 public double getSessionTimeMean()
873 {
874 return _sessionTimeStats.getMean();
875 }
876
877
878
879
880
881 public double getSessionTimeStdDev()
882 {
883 return _sessionTimeStats.getStdDev();
884 }
885
886
887
888
889
890 public boolean isCheckingRemoteSessionIdEncoding()
891 {
892 return _checkingRemoteSessionIdEncoding;
893 }
894
895
896
897
898
899 public void setCheckingRemoteSessionIdEncoding(boolean remote)
900 {
901 _checkingRemoteSessionIdEncoding=remote;
902 }
903
904
905
906
907
908
909
910
911
912 public interface SessionIf extends HttpSession
913 {
914 public AbstractSession getSession();
915 }
916
917 public void doSessionAttributeListeners(AbstractSession session, String name, Object old, Object value)
918 {
919 if (!_sessionAttributeListeners.isEmpty())
920 {
921 HttpSessionBindingEvent event=new HttpSessionBindingEvent(session,name,old==null?value:old);
922
923 for (HttpSessionAttributeListener l : _sessionAttributeListeners)
924 {
925 if (old==null)
926 l.attributeAdded(event);
927 else if (value==null)
928 l.attributeRemoved(event);
929 else
930 l.attributeReplaced(event);
931 }
932 }
933 }
934 }