Download (direct link):
To understand how to solve the multiple-submit problem, we must first understand how servlets work with respect to sessions. As everyone knows, HTTP is inherently a stateless protocol. To handle state, we need some way for the browser to communicate to the back end that the current request is part of a larger block of requests. Additionally, the server needs a way to manage the data for a given set of requests. The servlet session provides us a solution to this problem. The HttpServlet methods doGet() and doPost() are provided with two specific parameters: HttpServletRequest and HttpServletResponse. The servlet request parameter allows us to access what is commonly referred to as the servlet session. Servlet sessions have mechanisms for accessing and storing state information. But what exactly is a servlet session?
A servlet session is a number of things. It is:
¦¦ A set of states managed by the Web server and represented by a specific identifier
¦¦ Shared by all requests for a given client
¦¦ A place to store state data
¦¦ Defined, at least for HttpServlets, via the HttpSession interface
Before we look at how we can solve our problem with multiple submits with a server-side solution, we need to understand the servlet session lifecycle. As with EJBs and other server-side entities, servlet sessions go through a defined set of states during their lifetime. Figure 36.3 shows pictorially the lifecycle of a servlet session.
Too Many Submits 317
Figure 36.3 Servlet session lifecyle.
Examining how a session moves through its various states during its lifecycle will help us understand how we can solve the multiple-submit problem with a session. Servlets move through three distinct states: does not exist, new, and not new or in-use.
1. Initially, a servlet session does not exist. A session starts here or returns to this state for a number of reasons. The most likely are that the user has never accessed the state before or the session was invalidated because the user left the site (timed out) or explicitly left (logged out).
2. Sessions move from does not exist to new when the session is first created. The distinction between new and not new is important because the HTTP is stateless. Sessions cannot move to not new from being a prospective session to an actual session according to the servlet specification, until the client returns the session back to the server. Thus, sessions are new because the client does not yet know about the session or the client decides not to join the session.
3. When the session is returned back to the server from the client via a cookie or URL rewriting (more on URL rewriting in a moment), then the session becomes in-use or not new.
4. Continued use of the session, via its various get and set methods, results in the session remaining in use.
5. Transitions 5 and 6 happen when a session times out because inactivity of a session causes it to be explicated invalidated. Application servers handle timeouts in a variety of ways. BEA WebLogic Server handles timeouts by allowing the application deployer the ability to set the session timeout via a special deployment descriptor (weblogic.xml) packaged with the Web application.
318 Item 36
Now that we understand the lifecycle of a session, how do we go about obtaining a session and using it to our advantage?
The HttpServletRequest interface offers two methods for obtaining a session:
¦¦ public HttpSession getSession(). Always returns either a new session or an existing session.
¦¦ getSession() returns an existing session if a valid session ID was provided via a cookie or in some other fashion.
¦¦ getSession() returns a new session if it is the client's first session (no ID), the supplied session has timed out, the client provided an invalid session, or the provided session has been explicitly invalidated.
¦¦ public HttpSession getSession(boolean). May return a new session or an existing session or null depending on how the Boolean is set.
¦¦ getSession(true) returns an existing session if possible; otherwise, it creates a new session
¦¦ getSession(false) returns an existing session if possible; otherwise, it returns null.
At first glance, it appears that we should always use getSession(true). However, you should be careful in that an out-of-memory style of attack can be performed on your site by always creating new sessions on demand. An unscrupulous hacker could discover your site was creating sessions and keep pumping requests, each of which would result in a new session. By using getSession(false) and then redirecting to a login page when a session is not detected, you can protect against such attacks.
There are a number of interesting methods on HttpSession objects such as isNew(), getAttribute(), setAttribute(), and so on. For an exhaustive review, see the Servlet specification or any of the excellent John Wiley & Sons publications.
Getting back to our problem at hand, we have still only solved half of our problem. We'd like to be able to use our sessions to somehow skip over the session new state and move to the session in-use stage automatically. We can achieve this final step by redirecting the browser back to the handling servlet automatically. Listing 36.3 combines servlet session logic with the ability to redirect, with a valid session, the client back to the handling servlet.