Programming Tutorials Browser Tutorials Articles Struts Tutorials Hibernate Tutorials

  Tutorial: Take control of the servlet environment, Part 3 - JavaWorld January 2001

Take control of the servlet environment, Part 3 - JavaWorld January 2001

Tutorial Details:

Take control of the servlet environment, Part 3
Take control of the servlet environment, Part 3
By: By Thomas E. Davis and Craig Walker
Beware of the cookie monster
n Part 1 of "Take control of the servlet environment," we introduced the Rudimental Servlet Extension Framework (RSEF) and explained how it works. In Part 2 , we implemented a concrete example that allowed you to take control of your sessions (away from the servlet engine) and store them into a database. In our concluding article, we'll discuss a nasty little cookie pitfall, how it can bite you, and how you can use RSEF to avoid it. Then, once we have better control over our cookies, we'll use them to implement a new twist on our session solution from last month.
Take control of the servlet environment: Read the whole series!
Part 1: Invisibly extend the functionality of the servlet API
Part 2: Alternatives to servlet session management
Part 3: Beware of the cookie monster
The trouble with cookies
Magical little pieces of data, cookies help a Web server identify and remember a particular Web browser. The first time a browser connects to the server, the server says, "Hi there! Here's a cookie for you, but don't eat it! Show me this cookie each time you come back to visit." Then, during all subsequent browser-to-server requests, the server can identify the visitor.
Behind the scenes, cookies are mapped to domains. Domains are, for the purposes of this discussion, Website addresses. For example, the domain for http://www.yahoo.com/ is www.yahoo.com. Actually, yahoo.com is the domain, and www is a subdomain; herein lies the problem. Cookies are actually mapped to the full path -- domain and subdomain -- and subdomains can go deeper than one layer, for example http://us.f36.mail.yahoo.com/ or http://lw3fd.law3.hotmail.msn.com/.
But why does this present a problem? Suppose you have a visitor surfing your Website at http://www.rudiment.net/. Any cookies that you send to the browser will map to www.rudiment.net. For the purposes of organization, you have segregated a portion of your site at the address http://members.rudiment.net/. As a visitor bounces back and forth between the two addresses, the server cannot share the cookie values. This behavior resembles scope or namespaces in programming. A cookie named "session" might exist in both the www cookie and the members cookie under the rudiment.net domain, with each instance being unique.
But wait, it gets worse. Suppose the user types http://www.members.rudiment.net/ into his or her browser. Assuming that you have this subdomain mapped to http://members.rudiment.net (or your DNS is configured for wildcards) and your Webpages use relative links (both topics beyond the scope of this article), the cookies are now written to the www.members version of the rudiment.net domain instead of the normal www, as the figure below illustrates.
Cookies map to domain and subdomain
Two major problems result:
First, you cannot access any data that you write to the browser at the www.members subdomain if the visitor returns later to the members address. When the browser passes a cookie back to the server, it passes only the values stored in the lowest-level subdomain of the request.
Second, if the user enters the www.members version after having previously visited the members version, and any cookies are still active, your servlet will see two versions of the cookie and will not distinguish between the two. Here's how the "COOKIE" header looks when passed from the browser:
"session=1324;session=1234"
When your servlet looks for the session cookie, it will discover two of them. And if you add or update the session cookie, there's no guarantee that you'll recover the correct value. Why? Because the updated cookie will be written to the www.members version, but when the servlet requests it during the next execution, you might receive the members version first. This is catastrophic! The header value might now look like this:
"session=1324;session=5678"
The Cookie class does contain a getDomain() method, but it doesn't do what you would think. Look at the header, "session=1324;session=5678" , above. The browser does not pass in the domain information, so there's no way for the servlet engine to know which subdomain each cookie came from.
RSEF to the rescue
So how do you avoid such a debacle? It's actually quite simple. Behind the scenes, hidden from the servlet, you prepend the cookie names with the current server address before passing them up to the servlet engine. Then, when the servlet requests the cookies, you look them up based on the prepended names. For example, our enigmatic and seemingly redundant session cookies would now be named members.rudiment.net/session and www.members.rudiment.net/session as far as the browser and the server are concerned. But when the servlet asks for the session cookie, it will receive the correct version.
In order to achieve this functionality unobtrusively, you need to implement two more concrete wrappers. You need a ResponseWrapper that will prepend the cookie names, and a RequestWrapper that knows how to retrieve cookies based on the prepended names.
The server address possesses the crucial point of the cookie identification. This address originates from an HTTP header value labeled HOST. The header value is extracted from the request object. However, the ResponseWrapper needs access to the value in order to perform the name-prepending. This is another reason for the complex web of relationships between the wrapper classes (see Part 1 ).
In order to reduce code duplication, you centralize the functionality for prepending the cookie names in a utility class. The class has one method, getPrefix() , which extracts the HOST value from a request object. It then appends a slash (our arbitrary delimiter) to the address. This ensures that in the case of a null or empty string, you at least have a lone slash to work with:
public class Util
{
private Util(){}
private static final String delim = "/";
protected static String getPrefix( HttpServletRequest request )
{
if( null != request )
{
String tmp = request.getHeader( "HOST" );
if( null != tmp )
{
return( tmp + delim );
}
}
return( "null" + delim );
}
}
The next logical piece is the ResponseWrapper . It overrides the addCookie() method to perform the name-prepending before propagating the cookie to the engine:
public void addCookie( Cookie cookie )
{
if( null != _request ) // debugging
{
if( null != cookie ) // naughty servlet
{
Cookie warped =
new Cookie(
Util.getPrefix( _request ) + cookie.getName(),
cookie.getValue() );
warped.setMaxAge( cookie.getMaxAge() );
super.addCookie( warped );
}
}
}
The RequestWrapper strips off the domains at the servlet's request. It also discards any cookies that lack the expected prefix; now, the servlet will not receive two cookies with the same name.
Our version of the RequestWrapper overrides the getCookies() method to iterate through the superclass's set of cookies, stripping off the prefixes and discarding unexpected cookies; it then returns the clean versions:
public Cookie[] getCookies()
{
Vector list = new Vector();
Cookie[] cookies = super.getCookies();
if( null != cookies )
{
String prefix = Util.getPrefix( super );
for( int x = 0; x < cookies.length; x++ )
{
if( ( null != cookies[x] )
&& ( cookies[x].getName().startsWith( prefix ) ) )
{
String name = cookies[x].getName();
String value = cookies[x].getValue();
Cookie warped =
new Cookie(
name.substring( prefix.length(),
name.length() ),
value );
warped.setMaxAge( cookies[x].getMaxAge() );
list.addElement( warped );
}
else
{
// skip it (sub- or super- domain cookie bug)
}
}
}
Cookie[] gold = new Cookie[ list.size() ];
list.copyInto( gold );
return( gold );
}
That sums up the power and versatility of RSEF. The icing on the cake is that you can seamlessly combine this cookie fix with the database storage solution discussed in Part 2 , taking advantage of both. The bootstrap servlet discussed in Part 1 helps you achieve this combination of features.
Back in session
Now that you have a firm grasp on cookies, let's use them to improve the session wrapper discussed in Part 2 . If, for some reason, you do not have access to a centralized database for storing your session data, you can store it in the client's cookies. This approach features some advantages; for example, no server-side storage (i.e., database) or server-side garbage collection (expired sessions) are required. However, the session data must transfer from the browser to the server each time a request is issued, and back again when the page is served.
One cookie at a time
The simplest and easiest way to implement the session-stored-in-cookies solution is to use a separate cookie for each name-value pair of session data. In the downloadable source code, available in Resources below, you'll find the class net.rudiment.servlet.session.cookie.SessionWrapper that performs such logic.
In order to differentiate the session-related cookies from other cookies, you will prefix the cookie names with some arbitrary value. The wrapper class contains a simple utility method for this:
private static final String prefix = "session/";
private String mangle( String name )
{
return( prefix + name );
}
When placing a piece of data into the session, the wrapper mangles the name and writes it to a cookie:
public void putValue( String name, Object value )
{
String ser = Serialize.objectToString( value );
Cookie cookie = new Cookie( mangle( name ), ser );
cookie.setMaxAge( -1 );
_response.addCookie( cookie );
// cache it in case it is referenced again
// during this servlet execution
super.putValue( name, value );
}
( Note: The Serialize tool referenced above, and later on, stretches outside the scope of this article. The tool utilizes object I/O streams in conjunction with byte array I/O streams to convert a


 

Read Tutorial at: Click here to view the tutorial

Rate Tutorial:
Take control of the servlet environment, Part 3 - JavaWorld January 2001

View Tutorial:
Take control of the servlet environment, Part 3 - JavaWorld January 2001

Related Tutorials:

Java security evolution and concepts, Part 5
Java security evolution and concepts, Part 5
 
Boost Struts with
Boost Struts with XSLT and XML
 
Jtrix: Web services beyond SOAP
Jtrix: Web services beyond SOAP
 
Create your own type 3 JDBC driver, Part 2
Create your own type 3 JDBC driver, Part 2
 
Rumble in the jungle: J2EE versus .Net, Part 1
Rumble in the jungle: J2EE versus .Net, Part 1
 
J2SE 1.4 breathes new life into the CORBA community, Part 1
J2SE 1.4 breathes new life into the CORBA community, Part 1
 
Business process automation made easy with Java, Part 1
Business process automation made easy with Java, Part 1
 
Servlet 2.4: What's in store
Servlet 2.4: What's in store
 
Introducing the Portlet Specification, Part 2
Introducing the Portlet Specification, Part 2
 
Once again, only introduction
Once again, only introduction
 
good design pattern
good design pattern
 
Impressive !
Impressive !
 
Java and GIS, Part 2: Mobile LBS
Java and GIS, Mobile LBS Using LBS First, let\'s make sure that we understand what an LBS application is. Typically, an LBS application is trying to answer the question \"Where am I?\" and then do something with that information. There are a number
 
Clustering and Load Balancing in Tomcat 5, Part 1
The latest version of the Tomcat servlet container provides clustering and load balancing capabilities that are essential for deploying scalable and robust web applications.
 
Comparing The Performance of J2EE Servers
Performance ReportThe standardization of the application server, thanks to Sun\'s J2EE specifications, has spawned a wealth of implementations. There are offerings from big players such as Sun, IBM, BEA and Oracle as well as numerous offerings from low-co
 
Taming Tiger, Part 3
J2SE 5—code named "Tiger"—is the most significant revision to the Java language since its original inception. Tarak Modi's primary goal with his three-part series on Tiger is to familiarize readers with J2SE 5's most important additions and show how t
 
Unclog the server bottleneck with active containers.
In server-side control architectures such as Java ServerFaces (JSF) or Struts, a majority of the control events must be handled on the server side to update the state of the control. For every user event, the entire page data is sent back to the server...
 
Definition of Bioinformatics
Definition of Bioinformatics Definition of Bioinformatics About Bioinformatics In February 2001, the human genome was finally deciphered! In other words, scientists have succeeded in reading the chain of more than 3 billion base pairs that
 
Open Source Web Frameworks in Java
Open Source Web Frameworks in Java Open Source Web Frameworks in Java Struts Struts Frame work is the implementation of Model-View-Controller (MVC) design pattern for the JSP. Struts is maintained as a part of Apache Jakarta project and is open
 
Understanding Struts Controller
Understanding Struts Controller Understanding Struts Controller In this section I will describe you the Controller part of the Struts Framework. I will show you how to configure the struts-config.xml file to map the request to some destination
 
Site navigation
 

 

Send your comments, Suggestions or Queries regarding this site at roseindia_net@yahoo.com.

Copyright © 2006. All rights reserved.