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