Wednesday, September 24, 2008

My understanding of sessions in web application.

Most often in web applications we might need to manage information over a series of requests or over a user session. Lets take the classic example of adding 2 numbers. In an ordinary scenarios we will use a form to get the 2 numbers ,send it to the server which adds the no and sends it back to the user as response. The above mentioned computation consists of only one request and response. Now we want the interactions in different way. Instead of sending the first number and second number in a single page we want the first page sending the first number and second page sending the second number and a third page showing the results. These series of request can be called as user session. Now the issue with this design is that the computation spans over 3 request-response round trip. As HTTP is a stateless protocol, second request does not have any relation to the first request for the server. So now the question is how do we build this relation or how do we make the server aware that a series of request comes under one user session.

There are many ways through which the state information over a series of requests can be stored. It can be done by storing the information in the client side(cookies),in the server side(sessions,continuations) carry it with the request and response headers(hidden form fields).

Session management in servlet container

The container maintains memory space for each session which is identified by an id. All the information we need to keep over a session are maintained in this memory space and are maintained as java objects. The unique id known as session id is used to identify which session a particular request belongs to. So obviously session id has to be carried along with the request. The container allots the session object according to session id of the request.

Now its time to get our hands wet...We shall create 3 JSP pages

firstpage.jsp

<.html>
<.head>
<.title> The first page< /title >
< /head >
<.body>
< .form action="secondpage.jsp" method="get">
First no :
<.input type="text" name="firstno" value="0"> <>
<.input type="submit" value="Next">
< /form >
< /body >
< /html >


This page serves as interface to get the 1st no from the user. The page gets the no and puts it in the request object.

secondpage.jsp

<.html>
<.head>
<.title> The Second page< /title >
< /head >
<.body>
< % String a = request.getParameter("firstno"); session.setAttribute("firstno",a); % >
<.form action="resultpage.jsp" method="get">
Second no :
<.input type="text" name="secondno" value="0"> <>
<.input type="submit" value="Next">
< /form >
< /body >
< /html >

Similar to the first page this page receives the 2nd no puts it in the request object. In addition, it also adds the value of the 1st no to the session object so that it can be retrieved later.

resultpage.jsp

<.html>
<.head>
<.title> Result Page< /title >
< /head >
<.body>
< % int b=Integer.parseInt(request.getParameter("secondno")); int a=Integer.parseInt(session.getAttribute("firstno").toString()); out.println(a+b); % >
< /body >
< /html >

This page processes the input values and gives the result. It retrieves the second number from the previous request object and the first number from the session object.

The above web application should run without any problem in a simple jsp/Tomcat setup. OK if you were success full in running the above web application we can continue with the
discussion. Now we have used session object to store our values in it.

One question which used to bother me when I did session programming is how does the request carry the session id. HTTP spec does not contain any information on session, so HTTP has no clue what a session is. So the container have to implement some way to pass the session id from one page to the next. This is what Apache Tomcat a jsp/servlet container
does. It checks a parameter with key JSESSIONID in cookie values as well as request URL ,if it finds one it picks up the session object corresbonding to that particular session-id.

My professor use to teach me web technology by doing postmortem on HTTP request/response packets. I have found itthe best way to learn web technology of any level.So lets see the HTTP request headers of our small web application.

HTTP request headers of the first page

Host localhost:8080
User-Agent Mozilla/5.0 Gecko/2008070208 Firefox/3.0.1
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
Connection keep-alive
Cookie JSESSIONID=DF88F04F5D2574711121214DD4AC9FA7

Nothing intresting in HTTP response. But if you see the HTTP request you can see teh cookie parameters send to the server with t he first request

Cookie JSESSIONID=DF88F04F5D2574711121214DD4AC9FA7

This is how the session managment is done is using cookies. But we are not using sessions in our first page then why do it pass the session id. Its because JSP by default checks weather there is a session existing for that request if it does not exit it creates a session and sets its id in the cookie parameter. That's why we see session id from the first page request. Now lets scan the second pages request and response headers.

HTTP request headers of the second page

Host localhost:8080
User-Agent Mozilla/5.0 Gecko/2008070208 Firefox/3.0.1
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
Connection keep-alive
Referer http://localhost:8080/httpsession/firstpage.jsp
Cookie JSESSIONID=DF88F04F5D2574711121214DD4AC9FA7

If you look at the JSESSIONID value in the cookie header of the request you will find the the same session id value. So the container keeps the session id in the cookie till the session gets destroyed. Now the third request header will also have a similar cookie header parameter. This is how sessions are implemented over cookies. Now try to disable cookies in
your browser, you will find that your web application does not work. So how do we do session management when cookies are disabled we can see in the later discussion.

Ohhh...Cookies are disabled..! URL rewritting for yor rescue :)

So what you do when cookies are disabled.You have to find some other way of transferring the session id. I have mentioned in the earlier discussion that Tomcat looks in the cookie as well as request parameters for JSESSIONID parameter. So we have to embed session id in the request URL. Lets try it out.

There won't be any change to the first and the result page they will the same. Remember we do not have problem in adding and removing values to and from the session object but our
problem is how do we pass on the session id between two requests. That's why there is no change in the result page.

<.head>
<.html>
<.title> The Second page< /title >
< /head >
<.body>
< % String a = request.getParameter("firstno"); session.setAttribute("firstno",a); String url =response.encodeURL("resultpage.jsp"); % >
<.form action="<"> method="get" >
Second no : < type="text" name="secondno" vlaue="0"> <>
<.form type="submit" value="Next">
< /form >
< /body >
< /html >

Here we generate the form action URL from the through encodeURL method. encodeURL first checks whether it could add the session-id in the cookies ,if it cannot add it to the
cookies it rewrites the URL adding the session id to the request URL. So if the cookies are disabled in the browser the URL string which is replaced at the form. Lets us examine
the request headers of resultpage.

Host localhost:8080
User-Agent Mozilla/5.0 Gecko/2008091620 Firefox/3.0.2
Accept text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language en-us,en;q=0.5
Accept-Encoding gzip,deflate
Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive 300
Connection keep-alive
Referer http://localhost:8080/httpsession/secondpage.jsp?firstno=34

You can notice that there is no cookie header in this particular request.So it is obvious that session id is not passed through cookies. Now if we see the URL at the address bar of the page it would be something like this.


http://localhost:8080/httpsession/resultpage.jsp;jsessionid=B5EB1435EDF939B65A20148187884DE8?secondno=45

You can do the same thing by using this code instead of using encodeURL

String url="resultpage.jsp;jsessionid="+request.getSession().getId();

But it won't check whether cookies are enabled or not.

So encodeURL rewrites the URL to embed the session-id parameter to it. The container identifies which session a particular request belongs to by looking at the jsessionid value in the request URL. You might have noticed that unlike the request parameter the jsessionid is embedded in to the URL using a ; delimiter. So jsessionid is not a request parameter in the request.

0 comments:

Post a Comment