View Javadoc

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