In this issue of 15 Seconds we will show you how to share the same cookie across multiple sub-domains and multiple domains. We will also discuss sharing state information across web farms using SQL Server. The examples in this issue highlight the power of redirection within Active Server page and enforce the concepts that are related to cookie manipulation.
Sharing Cookies Between Sub Domains
A sub-domain is a subset of the main domain that has a separate IP. For example, if you purchase the domain
myserver.com from the INTERNIC you can break it down into sub domains like the following:
You can issue a cookie on the www.myserver.com sub-domain like this:
<% Response.Cookies("UID")=1 %>
This cookie will only last for the length of the user session, defined by the amount of time that browser stays open. The cookie’s scope is just the
www.myserver.com domain. If you request this cookie on other sub domains within the same domain you will not be able to get the value associated to
You can solve this problem by substituting the code in Example 2 for the code in Example 1.
<% Response.Cookies("UID")=1 Response.Cookies("UID").Domain = ".myserver.com" %>
By setting the
Domain property of the cookie to the domain of the sub domain you instruct the browser to send the cookie to all sub domains. Notice the period before the domain name, this is very important. RFC 2109 specifies that the Domain setting on cookies must have two periods.
Sharing Cookies Between Domains
Sharing cookies between domains is trickier then sharing cookies between sub-domains of a single domain. An example of this working is the three domains owned by Microsoft, msnbc.com, msn.com, and microsoft.com, these three domains share the same cookie for each user. To share a cookie between domains, you will need two domains, for example
slave.com. One of the domains will issue the cookies and the other domain will ask the first domain what cookie should be issued to the client. In this case
myserver.com will issue the cookie and
slave.com will use the cookie issued by
myserver.com. Here is the
Example 3 : cookie.inc
<% UID=Request.Cookies("UID") If ((IsNull(UID)) OR (Len(UID)=0)) Then Set UIDGen=Server.CreateObject("SMUM.Example.1") 'Here is the method call to assign the cookie UID = UIDGen.GetCookie() Response.Cookies("UID")= UID Response.Cookies("UID").Domain=".myserver.com" Response.Cookies("UID").Expires = "December 31, 1999" End If %>
The object created in this example was demonstrated in the Apr 22, 1997 issue of 15 Seconds entitled: “Active Server Components with VB 5.0.” You can download just the object from this issue and use it in the code above. When the GetCookie method is called, a random 128-bit number is produced that is guaranteed to be unique to the user. UID stands for Unqiue IDentifer.
Notice that this code is contained in a cookie.inc file that can be included at the top of all Active Server pages within the
Requesting Cookie from Another Domain.
Now the interesting part, how does
slave.com get the same cookie from
domain.com. This technique is implemented through a set of redirects. Let’s take a look at the code that is implemented on
Example 4 : getcookie.inc
<% UID=Request.Cookies("UID") If ((IsNull(UID)) OR (Len(UID)=0)) Then strURL=Request.ServerVariables("URL")) strQueryString=Request.ServerVariables("QUERY_STRING")) If (Len(strQueryString)>0) Then strReturn= Server.URLEncode(strURL & "?" & strQueryString) Else strReturn= Server.URLEncode(strURL) End If Respone.Redirect("http://myserver.com/slave.asp?Return=" & strReturn) End If %>
Notice that we do not actually assign the cookie in this page. Instead, if there is no cookie available we redirect to a special page on
myserver.com. We also bundle up the address of the page we are on for future use. Let’s take a look at
Example 5 : slave.asp
<!--#include virtual="/cookie.inc"--> <% strReturn=Server.URLEncode(Request("Return")) Response.Redirect("http://slave.com/return.asp?Return=" & strReturn & "&UID=" & UID) %>
Notice that we included
cookie.inc from Example 3. Since
slave.asp resides on
myserver.com the cookie that is issued in
cookie.inc has a scope of just
myserver.com. If the user didn’t have a cookie on
myserver.com they are given one, because of the code in
cookie.inc. This way if they are visiting
slave.com first and then visit
myserver.com they will have the same cookie. If the user already has a cookie from
myserver.com and they visit
slave.com for the first time they will be redirected to
myserver.com where that cookie will be retrieved. Because the cookie only has the scope of the domain that it is issued on we have to redirect to the master domain to get the cookie and then redirect back to the slave domain. Here is the code for
return.asp which resides on
Example 6 : return.asp
<% UID = Request ("UID") strReturn=Request("Return") Response.Cookies("UID")= UID Response.Cookies("UID").Domain=".slave.com" Response.Cookies("UID").Expires = "December 31, 1999" Response.Redirect(strReturn) %>
return.asp sets the UID cookie to the UID that is passed from
myserver.com passes the same UID as it uses for a cookie, both servers end up with the same cookie for the same user. In other words the user ends up with two cookies on their machine, one from
myserver.com and one from
slave.com, and they equal the same UID. Also note that the final redirect is back to the page the user requested on
slave.com, the redirect uses the return information that the
getcookie.inc bundled up.
Return.asp should always be called from
slave.asp and for no other reason.
In summary, every active server page should include
getcookie.inc at the top of the page and if a cookie needs to be set
getcookie.inc will handle the problem.
Because we wanted to make the examples easy to understand, we didn’t add any error handle. However, if the client browser did not accept cookies, then the code demonstrated above would cause an endless loop of redirection. For this reason we need to change Example 6 to read:
Example 7 : return.asp
<% UID = Request ("UID") strReturn=Server.URLEncode(Request("Return")) Response.Cookies("UID")= UID Response.Cookies("UID").Domain=".slave.com" Response.Cookies("UID").Expires = "December 31, 1999" Response.Redirect("http://slave.com/test.asp?Return=" & strReturn) %>
Now we can add
test.asp which tests to make sure that the cookie took. Here is what the code looks like:
Example 8 : return.asp
<% UID = Request.Cookies("UID") If Not ((IsNull(UID)) OR (Len(UID)=0)) Then strReturn=Request("Return") Response.Redirect(strReturn) End If %> <HTML> <BODY> <H1>You must a browser that accept cookies on http://slave.com</H1> </BODY> </HTML>
If the user doesn’t have a cookie from
myserver.com and he requests a page that has
cookie.inc included, they will be issued a cookie. This scenario is the best case scenario. If the user doesn’t have a cookie from
slave.com and he requests a page that has
getcookie.inc included and they haven’t visited
myserver.com then they will have to undergo four redirects and be issued two cookies. This is the worst case scenario. Fortunately, the worst case scenario only happens once. All requests after that do not have to undergo any redirects. In the worst case scenario, it is best to use a technique that produces a random number quickly, because the user will be confused if they see to many redirections on their first page request. The technique of using a COM object to issue a random UID is much quicker then getting a IDENTITY value from SQL Server.
Sharing More Then One Cookie
The more cookies you try to share with this technique, the harder the problem becomes. It is recommend that you use a different approach to storing state and user information besides cookies. Once you have the UID of the user, you can use the UID to get other information about that user from SQL Server. Using the UID as a primary key to the database enables you to use only one cookie in your web application. This makes the technique mentioned above usable.
Web farms are more then one Web server serving the same information with the same domain name. Each machine has a separate IP, but the domain name server uses a technique called round-robin to give clients a different IP with every request. Because the clients receive a different IP for every request they are directed to a different server for each page. Web farms distribute the requested load across multiple machines making the site appear faster.
Because, session variables are stored in the RAM on each machine, session variables that are set on one machine are not the same on another machine in a web farm. For this reason you can not use session variables in a web farm. However, instead of session variables you can use a cookie which is a primary key to a SQL Server database that stores the state information for the user. As long as all the machines in the web farm are writing to the same SQL Server you can share state information between all the machines in a web farm. And because each machine has the same domain name, the client returns the same cookie to each machine making the distribution of the primary keys a trivial matter.
You can download the files in this example at: