Clientside Session Timeout’s

There comes a time in web application development that you need to ‘timeout’ idle users. This comes in a variety of ways, here’s a few common reasons that you may desire this activity.

  • Security – you don’t want to leave sensitive data on a users screen when they’ve gone to lunch or left for the day.
  • Server Resources – persisting/keeping an active ‘session’ available on the server takes resources (the exact type varies, but this is usually database, memory or file resources)
  • Server ‘enforced’ session timeout’s and the potential errors and lost data experienced by the users in that circumstance.

My personal approach to this has evolved over time, here’s a brief synopsis:

  1. Use standard server-side session timeout, often leading to a bad user experience when they loose data on a form submit.
  2. Use META REFRESH…where timeout is in seconds, in this example it’s 60 seconds (1 minute).
    <meta http-equiv="refresh" content="60;url=http://www.giantgeek.com/" />
  3. Use javascript 'timeout' (problem is that this is not 'measureable')
    
    <script type="text/javascript">
    setTimeout("javascript:myTimeout();",minutes*60000); // code minutes
    </script>
  4. Use javascript countdown timer and custom code event.

<html>
<head>
<title>Timeout example</title>
<script type=”text/javascript”>
var build=’testing’;
var timerID = 0;
var loadTime = null;
var stopTime = null;
function xload(){
loadTime=grvMillis();
grvWindowStatus(build);
grvSetTimeout();
}
function xclose(){
grvWindowStatus(”);
}
function grvMillis(){
return new Date().getTime();
}
// Start timer
function grvTimerUpdate(){
timerID = grvTimerClear(timerID);
if(loadTime == null){
loadTime=grvMillis();// Start Time
}
// Calculate Current Time in seconds
var timeNow = grvMillis();

var think = calcMinSec( calcTimeDiff(timeNow,loadTime) );
var remain = calcMinSec( calcTimeDiff(stopTime,timeNow) );
grvWindowStatus(build + ” ” + think + ” ” + remain );
timerID = setTimeout(“grvTimerUpdate()”,1000);
}
function calcMinSec(diff){
var mm = removeDecimal(diff/60);
var ss = zeroPad(removeDecimal(diff-(mm*60)),2);
return (mm + “:” + ss);
}
function calcTimeDiff(tmpStart,tmpStop){
var diff = (tmpStart – tmpStop)/1000;
return diff;
}
function removeDecimal(val){
var rc=””;
val = val + “”;
if(val!=””){
var pos = val.indexOf(“.”);
if(pos > -1){
rc=val.substr(0,val.indexOf(“.”));
} else {
rc=val;
}
}
return rc;
}
function zeroPad(x,sz){
x = x + “”;
while(x.length < sz){
x = “0” + x;
}
return x;
}
function grvTimerClear(x){ // this clears a timer from the queue
if(x){
clearTimeout(x);
x = 0;
}
return x;
}
function grvSetTimeout(){
var min=45; xID=grvTimeout(“javascript:grvTimeoutUSER()”,min); // EXAMPLE: this could be conditional!
stopTime = grvCalculateTimeout(min);
grvTimerUpdate();
}
function grvCalculateTimeout(mins){
var timeNow = grvMillis();
var exp = timeNow + (mins*60*1000);
var timeExp = new Date(exp).getTime();
return timeExp;
}
function grvTimeout(x,minutes){ // this sets a timer(request) in a queue
return setTimeout(x,minutes*60000);
}
function grvTimeoutUSER(){
alert(‘Session Inactivity Timeout [USER]’);
// DO WHAT YOU NEED TO HERE!}
function grvWindowStatus(txt){
window.defaultStatus=txt;
}
</script>
</head>
<body onunload=”xclose();” onload=”xload();”>
</body>
</html>

Another benefit of this last solution is that you also have access to the user “Think Time” and can therefore measure how long the user spends on a given page.

Cheers!

Adding Support for ‘disabled’ OPTION tags in MSIE

This is a very annoying bug/oversight in MSIE (including the recently released MSIE7!).

For some reason, Microsoft didn’t implement the ‘disabled’ attribute on <option> tags.
All other modern (even the old Netscape 4.x) browsers support this, why would they not do the same.
This is probably for the same reason that all versions of MSIE (prior to MSIE7) left the rendering of the SELECT tag to the operating system itself, above the browser HTML.
Thankfully, you can still access the attribute on the DOM element with javascript!

My solution has evolved over time, here’s the current release code.

To emulate this behavior in MSIE, you’ve got several different challenges to overcome.

  1. You must ‘persist’ the current value of the SELECT so that you can ‘restore’ it when the user chooses a disabled field, I do this during the onload event.
  2. When the ‘onchange’ event for the SELECT tag is invoked, the currently selected OPTION’s attributes must be read and checked.
  3. If the selected OPTION is ‘disabled’, then the previous value must be restored.
  • As this solution only stores one value per SELECT, the ‘multiple’ SELECT is not currently supported.
  • In the future I’ll probably do some ‘event injection’ so that the HTML itself is cleaner. Problem is that in more complex solutions like ‘dependent dropdowns’ this becomes tricky.
  • The [if IE] ‘comment’ is critical as it is conditional logic supported only in MSIE and simplifies what was previously done via various ‘browser-sniffing’ tricks.
  • The example code in this example excludes the CDATA escapes and several tags required for valid XHTML for brevity.
  • FYI, the example also contains the MSIE background-image cache fix discussed in a previous post.

<!DOCTYPE >
<html>
<head>
<script type=”text/javascript”>
var isMSIE=false;
<!–[if IE]>
<script type=”text/javascript”>
isMSIE=true;
</script>
<script src=”/js/grv-msie-hacks.js” type=”text/javascript”></script>
<![endif]–>

<script type=”text/javascript”>
function xload(){
if(isMSIE){
grvMsieInitHacks();
}
}
function xchange(obj){
// note: javascript emulation of <option disabled…> (for MSIE)
if(isMSIE){
grvMsieSelectFix_restore(obj);
}
}
</script>
</head>

<body onload=”xload();”>

<form action=”#” method=”GET”>
<select name=”s” id=”s” size=”1″ onchange=”xchange(this);”>
<option value=”n1″>Normal1</option>
<option value=”di” disabled=”disabled”>Dis</option>
<option value=”n1″>Normal2</option>
</select>
</form>
</body>
</html>

JavaScript file (grv-msie-hacks.js):

/*
* Code library to add several ‘broken’ features in MSIE 6 and 7
* @version $Id: $
*/
function grvMsieInitHacks(){
grvMsieCacheFix();
grvMsieSelectFix_init()
}
function grvMsieCacheFix(){
try{
document.execCommand(“BackgroundImageCache”,false,true);
}catch(e)
{}
}
/* Added new functions to support <option disabled…> emulation
*
* First part, necessary for <body onLoad…>
* builds array of all initial selections for <select>s on page (for LT or EQ MSIE7)
* WAS: disabledOptionEmulation();
*/
function grvMsieSelectFix_init() {
if (document.getElementsByTagName) {
var allSelects = document.getElementsByTagName(“select”); // build array of all <select> tags
if (allSelects.length > 0) { // if array has values…
window.allSelectsCurrentIndex = new Array(); // new array to hold initial selections
for (var i=0, individualSelect; individualSelect = allSelects[i]; i++) { // crawl through all <select> tags
individualSelect.onfocus = function(){ window.allSelectsCurrentIndex[this.id] = this.selectedIndex; } // fill array with selectedIndex values
}
}
}
}

/* companion code for grvMsieSelectFix_init()
* resets <option> selection if disabled to last good selection (for LT or EQ MSIE7)
* WAS: restoreSelection(inOptionChoice)
*/
function grvMsieSelectFix_restore(inOptionChoice) {
if (inOptionChoice.options[inOptionChoice.selectedIndex].disabled){
// if new choice is disabled…
inOptionChoice.selectedIndex = window.allSelectsCurrentIndex[inOptionChoice.id]; // deny selection, revert back to last ‘known good’ choice (typically, the initial selection at page load)
} else { // if new choice isn’t disabled…
window.allSelectsCurrentIndex[inOptionChoice.id] = inOptionChoice.selectedIndex; // update array so last ‘known good’ choice is now the latest user selection
}
}

Hopefully, Microsoft will get around to fixing this correctly some day… maybe for MSIE8!

MSIE Conditional code

This is not so much as a MSIE bug, but rather a non-standard “feature” (added in MSIE 5.5) that is often helpful when constructing websites that you try to build with valid XHTML and CSS. As all non-Microsoft browsers will see these as simple
HTML markup comments, it gives you the flexibility to deal with the inconsistencies and quicks in the various versions of MSIE. This is particularly important for the numerous changes introduced with MSIE7.

I’ve tested this with <style />, <script /> and <meta /> tags, but wouldn’t doubt that it works anywhere (but don’t see any typical situations for that!)

Some simple instructions:

  1. Start with an HTML comment
  2. Add the opening brackets, so it resembles <!–[if …]>
  3. Add the closing brackets too… <![endif]–> (don’t forget that extra less than and bang/exclamation point!)
  4. Add the versioning info, this should be pretty obvious, but i’ll list the most common ones.
    IE 7 = MSIE7
    IE 6 = MSIE6
    IE 5.5000 = MSIE 5.5
  5. Some modifiers, (should you want a range of versions):
    lt = Less Than
    gt = Greater Than
  6. Make sure that the body content of the tag (which now resembles an HTML comment) is coded.
  7. That’s it, now be sure to test for expected behaviors!

Some Examples:

<!–[if IE 6]>
<style type=”text/css”>
/* <![CDATA[ */
html {
overflow-y: scroll;
}
/* ]]> */
</style>
<![endif]–><!–[if lt IE 5.5000]><style type=”text/css”>@import “/css/IE50Fixes.css”;</style><![endif]–>
<!–[if IE 5.5000]><style type=”text/css”>@import “/css/IE55Fixes.css”;</style><![endif]–>
<!–[if IE 6]><style type=”text/css”>@import “/css/IE60Fixes.css”;</style><![endif]–>
<!–[if IE 7]><style type=”text/css”>@import “/css/IE70Fixes.css”;</style><![endif]–>
<!–[if lt IE 7]><script type=”text/javascript” src=”/js/IEFixes.js”></script>
<meta http-equiv=”imagetoolbar” content=”no” /><![endif]–>

Cheers!

Microsoft Virtual PC

I happened to spend most of this week in an IBM class using VMWare for the training environment (Windows XP Pro hosted on a Windows 2000 machine). This got me wondering about the free systems offered by many providers.

Here’s a few quick thoughts on Microsoft‘s offering, which admittedly seems pretty good.

Their product overview shows that you can run most (all?) previous Microsoft Operating System’s (MS-DOS, Windows 95/98/Me/2000/XP/Vista… etc. ), even IBM’s OS/2 all on a single host machine with enough resources. Minimum usage per VM appears to be about 64MB RAM and 500MB disk space for the older OS’s, newer versions obviously requiring significantly more resources.

Since I’ve got most of these old OS installation disks in storage, I’ll give this a try and see how well it works. This may make for some interesting testing lab scenarios.

References:

WOT – Website reputation

Previously I discussed the McAfee SiteAdvisor plugin. Another similar project is WOT.

The differences with it are as follows:

  1. Instead of a centralized service, WOT is democratic. As such, the result is based on the feedback of any user that takes the time to rate a given website.
  2. WOT is available for Firefox and MSIE.

Since this coexists well within the browser, there’s no reason you can’t use both!

References:

Happy surfing!

McAfee SiteAdvisor

This is a great free plugin for Firefox and MSIE. After installation of the plugin, web links particularly in search engines like Google will contain an image/icon displaying a level of trust as well as some basic information about the website.

As a website owner, it is recommended that you add your site. To do so, you must first prove that you can publish content on the website. This is accomplished by submitting a form, after which you are given a filename (typically the domain with a ‘randomized’ hashcode) to create on your website.

NOTE: when doing this you must also insure that your website generates proper “404 Not Found” HTTP errors for non-existent files, as the verification process also tests that scenario.

Once listed, McAfee will scan your website for vulnerable downloads, reviews, related (linked) websites, as well as track outbound email (possible SPAM) generating from your domain.

References:

Here’s to a safer online experience.

TEXTAREA maxlength – or lack of!

I’m not sure why this was previously overlooked in HTML4/XHTML1, but it’s been a real pain for developers for years. The ‘rows’ and ‘cols’ attributes are useless (like ‘size’ is in the INPUT tag) as they are based on display size of fixed-width fonts like Courier and not the actual input limitations. INPUT has always supported a ‘maxlength’ attribute for this purpose.

Good news, this is part of WebForms2 and HTML5 (proposal) plans to add it!

A decent fix that I currently use… optimally you would use a common ‘maxsize’ function.

[textarea name=”junit” id=”junit” onkeyup=”maxsize(this,100);”][/textarea]
[script type=”text/javascript”]
function maxsize(obj,mx){
if(obj.value.length>mx)
{
obj.value=obj.value.substring(0,mx); }
}
[/script]

WARNING:

You should ALWAYS perform server-side validation of the length too, otherwise you leave the door open for someone to hack your form and submit longer data.

References:

Cheers!

MSIE6 javascript memory leaks

Argh…. yet again, this crappy product has another bug that developers must work around!

It seems that Microsoft doesn’t release memory to javascript objects from memory when created on a page… even when the page is unloaded.

Let’s think about this one for a second, why would you want to keep a javascript variable or DOM reference in memory after the user has navigated away from that page? This violates the stateless paradigm that web applications generally work with, besides… how would a developer be able to get that information (memory) back on the next page anyways? Perhaps, it was some genious that tried to keep state in javascript when the ‘BACK’ button was pressed… we’ll probably never know.

There’s a great quote I found while researching this…

“IE has an issue where it leaks memory when a circular reference is created between a COM object and a javascript object. In IE, the DOM is implemented via COM ….. This memory is not reclaimed until the browser closes. The simplest solution is to pretend there is no garbage collector for objects and make sure you always clean-up after yourself.”

References:

Microsoft ‘chimes in’:

Tools to help:

Cheers!

Installing Perl CGI on Apache (for Windows)

Installing Perl on a Win32 installation of Apache is trivial. Just a few short years ago (roughly the year 2000) most commercial website still ran large amounts of Perl code. Several open-source projects like BugZilla still rely on this powerful scripting language.

Here’s a few simple steps and advice to consider when the need comes to add this feature to your installation.

  1. Download Perl for Win32 – ActiveState Perl is the standard distribution to use, and installation is a snap.URL = http://www.activestate.com/Products/ActivePerl/a) Get the MSI file version as it’s executable (the AS version is a ZIP file for manual installs)

    b) The default path it chooses is “C:\Perl”, I advise that you use “c:\usr” instead as it makes it easier to port programs to and from UNIX/LINUX.

    c) The MSI installer takes care of the PATH file settings, so you should have no other work for installation.

  2. Modify the Apache httpd.conf file to enable (uncomment or add the following lines).

    AddHandler cgi-script .cgi
    AddHandler cgi-script .pl

  3. Restart Windows to ensure that the new configuration is available to the operating system.
  4. Test your install…a) Create a new file on the server named /cgi-bin/hello.pl with the following content:

    #!/usr/bin/perl
    print “Content-type:text/html\n\n”;
    print “hello world”;

    b) Start (or restart) the Apache service.

    c) Access the file in the browser, example:

    URL = http://localhost/cgi-bin/hello.pl

    d) If everything works, you should see the words “hello world”, otherwise, if you see the source code or ‘500 Server Error’ then the config has a problem.

Happy Scripting.

Custom JavaScript error notification

Debugging JavaScript errors is a time-consuming effort requiring keen eyes and a sharp mind.

MSIE typically only gives a cryptic ‘Object Expected’ error message and little more (even with the Microsoft Script Debugger installed!).

Some tools like FireBug and the Venkman debugger (both for Mozilla/Firefox) help in this matter, but often it helps to have an alert when an issue occurs.

Here’s a simple implementation that I’ve found useful…

[script type=”text/javascript”]
window.onerror=myErrorHandler;

function myErrorHandler(msg,url,l){
var txt=”There was an error on this page.\n”;
txt+=”Error: ” + msg + “\n”;
txt+=”URL: ” + url + “\n”;
txt+=”Line: ” + l + “\n\n”;
txt+=”Click OK to continue.\n\n”;
alert(txt); return true; }
[/script]

REFERENCES:

That’s it….