1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.eclipse.jetty.server.session;
21
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Enumeration;
25 import java.util.Iterator;
26 import java.util.Set;
27 import java.util.concurrent.TimeUnit;
28 import java.util.concurrent.TimeoutException;
29
30 import javax.servlet.ServletContext;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpSessionActivationListener;
33 import javax.servlet.http.HttpSessionBindingEvent;
34 import javax.servlet.http.HttpSessionBindingListener;
35 import javax.servlet.http.HttpSessionContext;
36 import javax.servlet.http.HttpSessionEvent;
37
38 import org.eclipse.jetty.io.IdleTimeout;
39 import org.eclipse.jetty.util.log.Log;
40 import org.eclipse.jetty.util.log.Logger;
41 import org.eclipse.jetty.util.thread.Locker;
42 import org.eclipse.jetty.util.thread.Locker.Lock;
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63 public class Session implements SessionHandler.SessionIf
64 {
65 private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
66
67
68
69
70
71 public final static String SESSION_CREATED_SECURE="org.eclipse.jetty.security.sessionCreatedSecure";
72
73
74
75
76
77
78
79 public enum State {VALID, INVALID, INVALIDATING};
80
81
82
83
84
85 protected SessionData _sessionData;
86 protected SessionHandler _handler;
87 protected String _extendedId;
88 protected long _requests;
89 protected boolean _idChanged;
90 protected boolean _newSession;
91 protected State _state = State.VALID;
92 protected Locker _lock = new Locker();
93 protected boolean _resident = false;
94 protected SessionInactivityTimeout _sessionInactivityTimer = null;
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 public class SessionInactivityTimeout extends IdleTimeout
110 {
111
112
113
114 public SessionInactivityTimeout()
115 {
116 super(getSessionHandler().getScheduler());
117 }
118
119
120
121
122 @Override
123 protected void onIdleExpired(TimeoutException timeout)
124 {
125
126 if (LOG.isDebugEnabled()) LOG.debug("Timer expired for session {}", getId());
127 getSessionHandler().sessionInactivityTimerExpired(Session.this);
128 }
129
130
131
132
133 @Override
134 public boolean isOpen()
135 {
136
137
138
139
140 try (Lock lock = _lock.lockIfNotHeld())
141 {
142 return isValid() && isResident();
143 }
144 }
145
146
147
148
149 @Override
150 public void setIdleTimeout(long idleTimeout)
151 {
152 if (LOG.isDebugEnabled()) LOG.debug("setIdleTimeout called: "+idleTimeout);
153 super.setIdleTimeout(idleTimeout);
154 }
155
156 }
157
158
159
160
161
162
163
164
165
166
167 public Session (SessionHandler handler, HttpServletRequest request, SessionData data)
168 {
169 _handler = handler;
170 _sessionData = data;
171 _newSession = true;
172 _sessionData.setDirty(true);
173 _requests = 1;
174 }
175
176
177
178
179
180
181
182
183
184
185 public Session (SessionHandler handler, SessionData data)
186 {
187 _handler = handler;
188 _sessionData = data;
189 }
190
191
192
193
194
195
196
197
198
199 public long getRequests()
200 {
201 try (Lock lock = _lock.lockIfNotHeld())
202 {
203 return _requests;
204 }
205 }
206
207
208
209
210
211
212 public void setExtendedId (String extendedId)
213 {
214 _extendedId = extendedId;
215 }
216
217
218 protected void cookieSet()
219 {
220 try (Lock lock = _lock.lockIfNotHeld())
221 {
222 _sessionData.setCookieSet(_sessionData.getAccessed());
223 }
224 }
225
226 protected boolean access(long time)
227 {
228 try (Lock lock = _lock.lockIfNotHeld())
229 {
230 if (!isValid())
231 return false;
232 _newSession=false;
233 long lastAccessed = _sessionData.getAccessed();
234 _sessionData.setAccessed(time);
235 _sessionData.setLastAccessed(lastAccessed);
236 _sessionData.calcAndSetExpiry(time);
237 if (isExpiredAt(time))
238 {
239 invalidate();
240 return false;
241 }
242 _requests++;
243 return true;
244 }
245 }
246
247
248 protected void complete()
249 {
250 try (Lock lock = _lock.lockIfNotHeld())
251 {
252 _requests--;
253 }
254 }
255
256
257
258
259
260
261
262
263
264 protected boolean isExpiredAt(long time)
265 {
266 try (Lock lock = _lock.lockIfNotHeld())
267 {
268 return _sessionData.isExpiredAt(time);
269 }
270 }
271
272
273
274
275
276
277
278
279 protected boolean isIdleLongerThan (int sec)
280 {
281 long now = System.currentTimeMillis();
282 try (Lock lock = _lock.lockIfNotHeld())
283 {
284 return ((_sessionData.getAccessed() + (sec*1000)) <= now);
285 }
286 }
287
288
289
290
291
292
293
294
295
296
297
298
299 protected void callSessionAttributeListeners (String name, Object newValue, Object oldValue)
300 {
301 if (newValue==null || !newValue.equals(oldValue))
302 {
303 if (oldValue!=null)
304 unbindValue(name,oldValue);
305 if (newValue!=null)
306 bindValue(name,newValue);
307
308 if (_handler == null)
309 throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
310 _handler.doSessionAttributeListeners(this,name,oldValue,newValue);
311 }
312 }
313
314
315
316
317
318
319
320
321
322 public void unbindValue(java.lang.String name, Object value)
323 {
324 if (value!=null&&value instanceof HttpSessionBindingListener)
325 ((HttpSessionBindingListener)value).valueUnbound(new HttpSessionBindingEvent(this,name));
326 }
327
328
329
330
331
332
333
334
335 public void bindValue(java.lang.String name, Object value)
336 {
337 if (value!=null&&value instanceof HttpSessionBindingListener)
338 ((HttpSessionBindingListener)value).valueBound(new HttpSessionBindingEvent(this,name));
339 }
340
341
342
343
344
345
346
347 public void didActivate()
348 {
349 HttpSessionEvent event = new HttpSessionEvent(this);
350 for (Iterator<String> iter = _sessionData.getKeys().iterator(); iter.hasNext();)
351 {
352 Object value = _sessionData.getAttribute(iter.next());
353 if (value instanceof HttpSessionActivationListener)
354 {
355 HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
356 listener.sessionDidActivate(event);
357 }
358 }
359 }
360
361
362
363
364
365
366
367 public void willPassivate()
368 {
369 HttpSessionEvent event = new HttpSessionEvent(this);
370 for (Iterator<String> iter = _sessionData.getKeys().iterator(); iter.hasNext();)
371 {
372 Object value = _sessionData.getAttribute(iter.next());
373 if (value instanceof HttpSessionActivationListener)
374 {
375 HttpSessionActivationListener listener = (HttpSessionActivationListener) value;
376 listener.sessionWillPassivate(event);
377 }
378 }
379 }
380
381
382 public boolean isValid()
383 {
384 try (Lock lock = _lock.lockIfNotHeld())
385 {
386 return _state==State.VALID;
387 }
388 }
389
390
391
392 public long getCookieSetTime()
393 {
394 try (Lock lock = _lock.lockIfNotHeld())
395 {
396 return _sessionData.getCookieSet();
397 }
398 }
399
400
401
402 @Override
403 public long getCreationTime() throws IllegalStateException
404 {
405 try (Lock lock = _lock.lockIfNotHeld())
406 {
407 checkValidForRead();
408 return _sessionData.getCreated();
409 }
410 }
411
412
413
414
415
416
417 @Override
418 public String getId()
419 {
420 try (Lock lock = _lock.lockIfNotHeld())
421 {
422 return _sessionData.getId();
423 }
424 }
425
426
427 public String getExtendedId()
428 {
429 return _extendedId;
430 }
431
432 public String getContextPath()
433 {
434 return _sessionData.getContextPath();
435 }
436
437
438 public String getVHost ()
439 {
440 return _sessionData.getVhost();
441 }
442
443
444
445
446
447 @Override
448 public long getLastAccessedTime()
449 {
450 try (Lock lock = _lock.lockIfNotHeld())
451 {
452 return _sessionData.getLastAccessed();
453 }
454 }
455
456
457
458
459 @Override
460 public ServletContext getServletContext()
461 {
462 if (_handler == null)
463 throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
464 return _handler._context;
465 }
466
467
468
469
470 @Override
471 public void setMaxInactiveInterval(int secs)
472 {
473 try (Lock lock = _lock.lockIfNotHeld())
474 {
475 _sessionData.setMaxInactiveMs((long)secs*1000L);
476 _sessionData.calcAndSetExpiry();
477 _sessionData.setDirty(true);
478 updateInactivityTimer();
479 if (LOG.isDebugEnabled())
480 {
481 if (secs <= 0)
482 LOG.debug("Session {} is now immortal (maxInactiveInterval={})", _sessionData.getId(), secs);
483 else
484 LOG.debug("Session {} maxInactiveInterval={}", _sessionData.getId(), secs);
485 }
486 }
487 }
488
489
490
491
492
493
494 public void updateInactivityTimer ()
495 {
496 try (Lock lock = _lock.lockIfNotHeld())
497 {
498 if (LOG.isDebugEnabled())LOG.debug("updateInactivityTimer");
499
500 long maxInactive = _sessionData.getMaxInactiveMs();
501 int evictionPolicy = getSessionHandler().getSessionCache().getEvictionPolicy();
502
503 if (maxInactive <= 0)
504 {
505
506 if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY)
507 {
508
509 setInactivityTimer(-1L);
510 if (LOG.isDebugEnabled()) LOG.debug("Session is immortal && no inactivity eviction: timer cancelled");
511 }
512 else
513 {
514
515 setInactivityTimer(TimeUnit.SECONDS.toMillis(evictionPolicy));
516 if (LOG.isDebugEnabled()) LOG.debug("Session is immortal; evict after {} sec inactivity", evictionPolicy);
517 }
518 }
519 else
520 {
521
522 if (evictionPolicy < SessionCache.EVICT_ON_INACTIVITY)
523 {
524
525 setInactivityTimer(_sessionData.getMaxInactiveMs());
526 if (LOG.isDebugEnabled()) LOG.debug("No inactive session eviction");
527 }
528 else
529 {
530
531 setInactivityTimer(Math.min(maxInactive, TimeUnit.SECONDS.toMillis(evictionPolicy)));
532 if (LOG.isDebugEnabled()) LOG.debug("Inactivity timer set to lesser of maxInactive={} and inactivityEvict={}", maxInactive, evictionPolicy);
533 }
534 }
535 }
536 }
537
538
539
540
541
542
543 private void setInactivityTimer (long ms)
544 {
545 if (_sessionInactivityTimer == null)
546 _sessionInactivityTimer = new SessionInactivityTimeout();
547 _sessionInactivityTimer.setIdleTimeout(ms);
548 }
549
550
551
552
553
554 public void stopInactivityTimer ()
555 {
556 try (Lock lock = _lock.lockIfNotHeld())
557 {
558 if (_sessionInactivityTimer != null)
559 {
560 _sessionInactivityTimer.setIdleTimeout(-1);
561 _sessionInactivityTimer = null;
562 if (LOG.isDebugEnabled()) LOG.debug("Session timer stopped");
563 }
564 }
565 }
566
567
568
569
570 @Override
571 public int getMaxInactiveInterval()
572 {
573 try (Lock lock = _lock.lockIfNotHeld())
574 {
575 return (int)(_sessionData.getMaxInactiveMs()/1000);
576 }
577 }
578
579
580
581
582 @Override
583 @Deprecated
584 public HttpSessionContext getSessionContext()
585 {
586 checkValidForRead();
587 return SessionHandler.__nullSessionContext;
588 }
589
590
591 public SessionHandler getSessionHandler()
592 {
593 return _handler;
594 }
595
596
597
598
599
600
601
602
603 protected void checkValidForWrite() throws IllegalStateException
604 {
605 checkLocked();
606
607 if (_state != State.VALID)
608 throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
609
610 if (!isResident())
611 throw new IllegalStateException("Not valid for write: id="+_sessionData.getId()+" not resident");
612 }
613
614
615
616
617
618
619
620
621 protected void checkValidForRead () throws IllegalStateException
622 {
623 checkLocked();
624
625 if (_state == State.INVALID)
626 throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" created="+_sessionData.getCreated()+" accessed="+_sessionData.getAccessed()+" lastaccessed="+_sessionData.getLastAccessed()+" maxInactiveMs="+_sessionData.getMaxInactiveMs()+" expiry="+_sessionData.getExpiry());
627
628 if (!isResident())
629 throw new IllegalStateException("Invalid for read: id="+_sessionData.getId()+" not resident");
630 }
631
632
633
634 protected void checkLocked ()
635 throws IllegalStateException
636 {
637 if (!_lock.isLocked())
638 throw new IllegalStateException("Session not locked");
639 }
640
641
642
643
644 @Override
645 public Object getAttribute(String name)
646 {
647 try (Lock lock = _lock.lockIfNotHeld())
648 {
649 checkValidForRead();
650 return _sessionData.getAttribute(name);
651 }
652 }
653
654
655
656
657 @Override
658 @Deprecated
659 public Object getValue(String name)
660 {
661 try (Lock lock = _lock.lockIfNotHeld())
662 {
663 return _sessionData.getAttribute(name);
664 }
665 }
666
667
668
669
670 @Override
671 public Enumeration<String> getAttributeNames()
672 {
673 try (Lock lock = _lock.lockIfNotHeld())
674 {
675 checkValidForRead();
676 final Iterator<String> itor = _sessionData.getKeys().iterator();
677 return new Enumeration<String> ()
678 {
679
680 @Override
681 public boolean hasMoreElements()
682 {
683 return itor.hasNext();
684 }
685
686 @Override
687 public String nextElement()
688 {
689 return itor.next();
690 }
691
692 };
693 }
694 }
695
696
697
698
699
700 public int getAttributes()
701 {
702 return _sessionData.getKeys().size();
703 }
704
705
706
707
708
709 public Set<String> getNames()
710 {
711 return Collections.unmodifiableSet(_sessionData.getKeys());
712 }
713
714
715
716
717
718
719
720 @Deprecated
721 @Override
722 public String[] getValueNames() throws IllegalStateException
723 {
724 try (Lock lock = _lock.lockIfNotHeld())
725 {
726 checkValidForRead();
727 Iterator<String> itor = _sessionData.getKeys().iterator();
728 if (!itor.hasNext())
729 return new String[0];
730 ArrayList<String> names = new ArrayList<String>();
731 while (itor.hasNext())
732 names.add(itor.next());
733 return names.toArray(new String[names.size()]);
734 }
735 }
736
737
738
739
740
741 @Override
742 public void setAttribute(String name, Object value)
743 {
744 Object old=null;
745 try (Lock lock = _lock.lockIfNotHeld())
746 {
747
748 checkValidForWrite();
749 old=_sessionData.setAttribute(name,value);
750 }
751 if (value == null && old == null)
752 return;
753 callSessionAttributeListeners(name, value, old);
754 }
755
756
757
758
759
760
761
762 @Override
763 @Deprecated
764 public void putValue(String name, Object value)
765 {
766 setAttribute(name,value);
767 }
768
769
770
771
772
773
774
775 @Override
776 public void removeAttribute(String name)
777 {
778 setAttribute(name, null);
779 }
780
781
782
783
784
785
786
787 @Override
788 @Deprecated
789 public void removeValue(String name)
790 {
791 setAttribute(name, null);
792 }
793
794
795
796
797
798
799 public void renewId(HttpServletRequest request)
800 {
801 if (_handler == null)
802 throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
803
804 String id = null;
805 String extendedId = null;
806 try (Lock lock = _lock.lockIfNotHeld())
807 {
808 checkValidForWrite();
809 id = _sessionData.getId();
810 extendedId = getExtendedId();
811 }
812
813 _handler._sessionIdManager.renewSessionId(id, extendedId, request);
814 setIdChanged(true);
815 }
816
817
818
819
820
821
822
823
824
825
826 @Override
827 public void invalidate()
828 {
829 if (_handler == null)
830 throw new IllegalStateException ("No session manager for session "+ _sessionData.getId());
831
832 boolean result = false;
833
834 try (Lock lock = _lock.lockIfNotHeld())
835 {
836 switch (_state)
837 {
838 case INVALID:
839 {
840 throw new IllegalStateException();
841 }
842 case VALID:
843 {
844
845 result = true;
846 _state = State.INVALIDATING;
847 break;
848 }
849 default:
850 {
851 LOG.info("Session {} already being invalidated", _sessionData.getId());
852 }
853 }
854 }
855
856 try
857 {
858
859 if (result)
860 {
861
862 _handler.getSessionIdManager().invalidateAll(_sessionData.getId());
863 }
864 }
865 catch (Exception e)
866 {
867 LOG.warn(e);
868 }
869 }
870
871
872
873
874
875 public Lock lock ()
876 {
877 return _lock.lock();
878 }
879
880
881
882
883
884
885
886 protected void doInvalidate() throws IllegalStateException
887 {
888 try (Lock lock = _lock.lockIfNotHeld())
889 {
890 try
891 {
892 if (LOG.isDebugEnabled())
893 LOG.debug("invalidate {}",_sessionData.getId());
894 if (isValid())
895 {
896 Set<String> keys = null;
897
898 do
899 {
900 keys = _sessionData.getKeys();
901 for (String key:keys)
902 {
903 Object old=_sessionData.setAttribute(key,null);
904 if (old == null)
905 return;
906 callSessionAttributeListeners(key, null, old);
907 }
908
909 }
910 while (!keys.isEmpty());
911 }
912 }
913 finally
914 {
915
916 _state = State.INVALID;
917 }
918 }
919 }
920
921
922 @Override
923 public boolean isNew() throws IllegalStateException
924 {
925 try (Lock lock = _lock.lockIfNotHeld())
926 {
927 checkValidForRead();
928 return _newSession;
929 }
930 }
931
932
933
934
935 public void setIdChanged(boolean changed)
936 {
937 try (Lock lock = _lock.lockIfNotHeld())
938 {
939 _idChanged=changed;
940 }
941 }
942
943
944
945 public boolean isIdChanged ()
946 {
947 try (Lock lock = _lock.lockIfNotHeld())
948 {
949 return _idChanged;
950 }
951 }
952
953
954
955 @Override
956 public Session getSession()
957 {
958
959 return this;
960 }
961
962
963 protected SessionData getSessionData()
964 {
965 return _sessionData;
966 }
967
968
969 public void setResident (boolean resident)
970 {
971 _resident = resident;
972 }
973
974
975 public boolean isResident ()
976 {
977 return _resident;
978 }
979
980 }