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