View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.server.session;
20  
21  import static org.junit.Assert.assertEquals;
22  import static org.junit.Assert.assertTrue;
23  
24  import java.io.IOException;
25  import java.util.ArrayList;
26  import java.util.List;
27  
28  import javax.servlet.ServletException;
29  import javax.servlet.http.HttpServlet;
30  import javax.servlet.http.HttpServletRequest;
31  import javax.servlet.http.HttpServletResponse;
32  import javax.servlet.http.HttpSession;
33  import javax.servlet.http.HttpSessionBindingEvent;
34  import javax.servlet.http.HttpSessionBindingListener;
35  import javax.servlet.http.HttpSessionEvent;
36  import javax.servlet.http.HttpSessionListener;
37  
38  import org.eclipse.jetty.client.HttpClient;
39  import org.eclipse.jetty.client.api.ContentResponse;
40  import org.eclipse.jetty.client.api.Request;
41  import org.eclipse.jetty.servlet.ServletContextHandler;
42  import org.eclipse.jetty.servlet.ServletHolder;
43  import org.junit.Test;
44  
45  /**
46   * AbstractSessionInvalidateAndCreateTest
47   *
48   * This test verifies that invalidating an existing session and creating
49   * a new session within the scope of a single request will expire the
50   * newly created session correctly (removed from the server and session listeners called).
51   * See https://bugs.eclipse.org/bugs/show_bug.cgi?id=377610
52   */
53  public abstract class AbstractSessionInvalidateAndCreateTest
54  {
55      public class MySessionListener implements HttpSessionListener
56      {
57          List<String> destroys;
58  
59          public void sessionCreated(HttpSessionEvent e)
60          {
61  
62          }
63  
64          public void sessionDestroyed(HttpSessionEvent e)
65          {
66              if (destroys == null)
67                  destroys = new ArrayList<>();
68  
69              destroys.add((String)e.getSession().getAttribute("identity"));
70          }
71      }
72  
73      public abstract AbstractTestServer createServer(int port, int max, int scavenge);
74  
75  
76  
77      public void pause(int scavengePeriod)
78      {
79          try
80          {
81              Thread.sleep(scavengePeriod * 2500L);
82          }
83          catch (InterruptedException e)
84          {
85              e.printStackTrace();
86          }
87      }
88  
89      @Test
90      public void testSessionScavenge() throws Exception
91      {
92          String contextPath = "";
93          String servletMapping = "/server";
94          int inactivePeriod = 1;
95          int scavengePeriod = 2;
96          AbstractTestServer server = createServer(0, inactivePeriod, scavengePeriod);
97          ServletContextHandler context = server.addContext(contextPath);
98          TestServlet servlet = new TestServlet();
99          ServletHolder holder = new ServletHolder(servlet);
100         context.addServlet(holder, servletMapping);
101         MySessionListener listener = new MySessionListener();
102         context.getSessionHandler().addEventListener(listener);
103     
104         try
105         {
106             server.start();
107             int port1 = server.getPort();
108             
109             HttpClient client = new HttpClient();
110             client.start();
111             try
112             {
113                 String url = "http://localhost:" + port1 + contextPath + servletMapping;
114 
115 
116                 // Create the session
117                 ContentResponse response1 = client.GET(url + "?action=init");
118                 assertEquals(HttpServletResponse.SC_OK,response1.getStatus());
119                 String sessionCookie = response1.getHeaders().getStringField("Set-Cookie");
120                 assertTrue(sessionCookie != null);
121                 // Mangle the cookie, replacing Path with $Path, etc.
122                 sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
123 
124 
125                 // Make a request which will invalidate the existing session and create a new one
126                 Request request2 = client.newRequest(url + "?action=test");
127                 request2.header("Cookie", sessionCookie);
128                 ContentResponse response2 = request2.send();
129                 assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
130 
131                 // Wait for the scavenger to run, waiting 2.5 times the scavenger period
132                 pause(scavengePeriod);
133 
134                 //test that the session created in the last test is scavenged:
135                 //the HttpSessionListener should have been called when session1 was invalidated and session2 was scavenged
136                 assertTrue(listener.destroys.contains("session1"));
137                 assertTrue(listener.destroys.contains("session2"));
138                 //session2's HttpSessionBindingListener should have been called when it was scavenged
139                 assertTrue(servlet.unbound);
140             }
141             finally
142             {
143                 client.stop();
144             }
145         }
146         finally
147         {
148             server.stop();
149         }
150     }
151 
152     public static class TestServlet extends HttpServlet
153     {
154         private boolean unbound = false;
155 
156         @Override
157         protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
158         {
159             String action = request.getParameter("action");
160             if ("init".equals(action))
161             {
162                 HttpSession session = request.getSession(true);
163                 session.setAttribute("identity", "session1");
164             }
165             else if ("test".equals(action))
166             {
167                 HttpSession session = request.getSession(false);
168                 if (session != null)
169                 {
170                     session.invalidate();
171 
172                     //now make a new session
173                     session = request.getSession(true);
174                     session.setAttribute("identity", "session2");
175                     session.setAttribute("listener", new HttpSessionBindingListener()
176                     {
177 
178                         public void valueUnbound(HttpSessionBindingEvent event)
179                         {
180                             unbound = true;
181                         }
182 
183                         public void valueBound(HttpSessionBindingEvent event)
184                         {
185 
186                         }
187                     });
188                 }
189             }
190         }
191     }
192 }