scotfl.ca

March, 2006

Server-side Sessions Are A Hack

There is no reason for the server to manage sessions. CGI languages used to be so removed from the real web that basic HTTP operations were a mystery to them. Thus, there was no CGI-based HTTP Authorization. This lead to the proliferation of login-by-form and server-side session management by your CGI language. And thousands of innocent URIs being sullied by ugly “PHPSESSIONKEY” variables.

Web browsers are really good at maintaining sessions. So good, in fact, that CGI languages tend use a small part of the browser’s system to manage their system. PHP, for example, takes the PHPSESSIONKEY out of the URL and hides it in a cookie. This cleans up the URIs, but it still leaves all the heavy lifting happening on the server.

Servers are busy. Web browsers have lots of free cycles available to them. Why not just use the browser’s sessions then?

Well, we tend to keep a fair chuck of data in the session variables. It’s very convenient to do so. And sending all of that data is expensive in both time and bandwidth. Not to mention the fact that there more often we put the data on the wire, the better the chance someone is going to do something nasty with it. So we can’t just stuff out session variables into a cookie. But if we look at the data in those session variables, we see that 99% of it is just two things: authentication and preferences. If we use HTTP authentication, we don’t have to hold on to that part of the session variable any more. So all we’re left with is the user’s preferences. And this is just a caching mechanism. We pulled the preferences out of the data store when they logged in and stuffed them into the session variable to avoid having to re-fetch them. Is this ‘optimization’ worth the cost? Is avoiding one SELECT statement worth giving up a stateless server? I’d suggest it isn’t. If you are servicing enough requests per second that the database can’t transparently cache the SELECT for you, you are probably going to be better served by moving the more common preferences into the URL. Because GET parameters are even faster to access that a session variable…

Form authorization + JavaScript allows us to use things like CRAM-SHA1 as authentication mechanisms. CRAM-SHA1 is awesome and secure and wonderful. Yet nobody does it, most sites just fire off a POST with the username and password in plain text. (And, for the record, if you MD5 the password in the browser it counts as plaintext because I don’t need the password, the digest hash of a constant string is a constant.) This is a bad situation. Luckily, HTTP 1.1 offers digest authorization and every remotely modern browser supports it out of the box. Heck, even browsers that don’t have JS have Digest. Digest authentication encrypts the password, prevents replay attacks, and even automatically expires sessions if you want it to.

Still, forms are prettier than the browser’s login/password dialog. Luckily, we can keep them.

The assumption: client and server are separate systems. Server is HTTP-server based, client is housed in a browser (located on the same webserver as the server app) and connects to server via XMLHTTPRequest. (Non-browser clients will be able to connect via normal HTTP libraries.)

Step one: the login form. The onsubmit function of the form takes the username and password and fires off an XMLHttpRequest with those credentials to some arbitrary part of the server that requires authorization (and prefereably incurs little to no processing on the server), let’s say ‘GET / HTTP/1.1′. If the request comes back unauthorized, we just add a ‘login failed’ message to the form and let the user try again. If the request succeeds, we’re in. We can then take the credentials, base64 encode them (not to encrypt them, just to make sure they’re in a clean set of characters) and jam them into a cookie in the browser. JavaScript can read and write cookies, you see.

Now, we set document.location to the welcome page or whatever is suitable. From the user’s perspective there’s no difference between this and the page refresh, server-side session management way of doing things. But on the server life is completely stateless and free. From now on, when the user clicks something that requires a call to the server, you get the cookie from the browser and pass the credentials to XMLHttpRequest. When the user clicks logout, jsut delete the cookie and set document.location to the login page.

The really nifty part is that if you’re careful, you can have your cake and eat it too. JavaScript-enabled browsers get to talk directly to the server and format the data locally. Non-JavaScript-enabled browsers won’t see the onsubmit handler. So we can make the target of the form the authentication part of an old-style server-side session application if we need to support browsers without JavaScript.

The one thing we lose by making the server completely stateless is the ability to track logins and logouts. Every other activity is still log-able in a stateless system. If we need to track sign-in/sign-out, there’s noting stopping us from having a resource on the server that when accessed records a login or logout. For instance, instead of requesting / to test the credentials, POST to /user/login. If the request is authorized, the server can get the user’s information from the login/password tuple and record the login. When the user clicks logout, POST to /user/logout and do the same thing. The server is still stateless and we get a complete activity log.

Because the cookie our javascript is using never actually leaves the user’s computer, we can happily eat up as much of the 4KB size limit as we want without worrying about transmission time. So if there’s any small pices of data we’d like to cache, we’ve got a quick and easy place to do it.

My main motivation for this is that stateless servers are far, far easier to write and the client-side code is going to have to know the state anyway. So why not push the state all the way out to the client. Or, as we used to say: push the processing to the edge of the network. But I’m sure that sort of phrase is ‘Web 2.0′-ish enough…

Technorati Tags

Posted on 29 March 2006 in Uncategorized

Comments Off

Client-Side Testing of Servers… in JavaScript

I have a very simple desire. I want to do black box testing of my server-side code. Which means I need to fire a bunch of HTTP requests at the server and pay attention to both the data sent back and the HTTP response codes because I’m aiming for a RESTful API. Since JavaScript is rapidly becoming my favourite language, I’d prefer to do it in JavaScript. And, I’d prefer to use XMLHTTPRequests because they are comfortably familiar. Oh, and I want to run the tests from the command line (and scripts and such) rather than in a browser.

First contender: SpiderMonkey, the grand-daddy of all JavaScript engines. SpiderMonkey is the JavaScript engine in Mozilla and its descendants (and is itself the latest generation of the original Netscape JavaScript engine). The command line version is small, fast, builds on Mac OS X out of the box, and doesn’t have any of the browser-related classes. I could write a libcurl-based XMLHTTPRequest implementation and get SpiderMonkey to export my C extension into the JavaScript environment. But I want to write tests, not extensions. SpiderMonkey is awesome as an interactive JavaScript environment, though, because it’s faster and far smaller than Rhino.

Speaking of Rhino, it’s the second contender. Rhino is a Java-based JavaScript interpreter. It was created at Netscape when they tried building the entire browser in Java. They scrapped the product, but Rhino survived. It’s the Interpreter of choice for server-side JavaScript engines. But it doesn’t have the browser classes either. Again, I could write my own XMLHTTPResource, but I don’t want to. As an interactive environment Rhino is a bit slower than SpiderMonkey and a fair bit larger (especially when you factor Java in). Still, in interactive mode you’d be hard-pressed to tell the difference.

There is one last option from the Mozilla folks. And that option is Mozilla, or, more precisely, a part of the browser: xpcshell. The big Mozilla browser (and it’s rechristened existence as SeaMonkey) has a whole lot of components. One of those components is a command line JavaScript interpreter, xpcshell. Basically, it’s SpiderMonkey with a huge web browser grafted onto it. And that’s the key, the huge web browser brings with it all the web browser infrastructure, including XMLHTTPRequest.

So, I have found my tool hidden deep within the bowels of SeaMonkey. SeaMonkey.app/Contents/MacOS/xpcshell to be exact. (Windows and Linux users can rest assured that XPCShell is bundled with SeaMonkey, but you’ll have to go on your own personal safari to find it.)

And now, the thorn in the rose. XPCShell does indeed give you access to XMLHTTPRequest, but not as the friendly global object we all know and love. You have to bring it into the JavaScript environment yourself via the XPCom bindings. Luckily, that turns out to be really simple. All we have to do is define our own XMLHTTPRequest constructor that returns an XMLHTTPRequest generated via the XPCOM interface. (Which sounds way more complicated than it is.)

if (XMLHTTPRequest === undefined) {
    var XMLHTTPRequest = function () {
        var class = "@mozilla.org/xmlextras/xmlhttprequest;1";
        var service = Components.interfaces.nsIXMLHttpRequest;
        return Components.classes[class].getService(service);
    }
}

I added the class and service variables to keep the line length down since long lines of code tend to look like crap in my blog layout. So feel free to optimize them out.

And that’s it, I have a command line JavaScript interpreter that gives me XMLHTTRequest. If you’ll excuse me, I have some tests to write.

Technorati Tags , , , , ,

Posted on 10 March 2006 in Uncategorized

Comments Off

Tech Writers

Amy Hoy, over at (24)slash7, has been blogging about Ruby on Rails for about as long as I’ve known the framework existed.† She has an introductory article on the MVC pattern that you should go read right now if you haven’t already. Even if you know MVC inside and out, you’ll probably find that Amy presents the material much better than you can. At least, that was my reaction. That link is my gift to anyone who’s ever been asked “What is MVC?” and responded “It’s pretty simple, actually. MVC is … uh, well, um…”

In her latest post, Amy is talking about whether women make better tech writers than men. She says no, sex and gender don’t come into it, and she backs that up with some good arguments. I agree with her, but that’s not what inspired me to write this entry. This was:

And after yet some more time I realized I didn’t have to settle for being David Pogue with boobs, I could be even better.

Well, that line and the fact that I heartily endorse pretty much every tech writer she mentions in that entry. I can honestly say that I can’t think of a single living person who’s name I’d rather see in the by-line of an article I am about to read than Andy Ihnatko’s. [Do me a favour and imagine that sentence was less tortured and more complimentary.]

I do take issue with one thing she said, though. Cryptonomicon wasn’t a very good novel. The characters felt like two-dimensional caricatures who were there simply to push the plot along and allow Stephenson to digress into the topics he actually wanted to write about. In the realm of tech-heavy novels I much prefer, say, Tom Clancy’s The Hunt For Red October where out main characters all have history and back story and motivation. (Ramius feels the Soviet Union was ultimately responsible for the death of his wife and that détente requires that nether side get ahead of the other in an arms race. Jack Ryan was basically an academic who found himself dropped into the middle of a very dangerous, very tense situation and told to prevent a war — all he really wanted to do was get home to his wife and daughter and get back to writing. It wasn’t until the later books that Ryan became a super hero and Harrison Ford had to take over the role.) However, that’s just the way I remember the books. Before I’d trust myself to write more than one paragraph on the topic I would have to read them again.

But, I digress. Go, read Amy’s articles and take a look at her cheat sheets: they’re very handy. If you can get there, she’s speaking in my home town of Vancouver next month at the Canada on Rails YVR06 conference. I, sadly, will be in Saskatchewan at that time. (Don’t worry, everyone else had to look up where it is, too.)


† Saying things like that makes me feel old, which is weird because the span of time is fourteen months at most. On the other hand, Amy talks about reading MacAddict when she was twelve and that does make me feel old. After all, I was sixteen when they started publishing…

, ,

Posted on 4 March 2006 in Uncategorized

Comments Off

FireBug

I use Safari as my day-today browser. It’s fast, clean, and has gorgeous text rendering. But it doesn’t run on Windows. Most of the people who use the applications I build do use Windows. Luckily, for a lot of those applications, I can specify Firefox as the browser of choice, side-stepping the entire IE morass.

My applications are developed using Camino. It’s fast, clean, and has very nice text rendering. For the most part, everything works quite nicely. It when things stop working that everything falls apart. Camino doesn’t have a JavaScript Console. So when my JavaScript fails, it does so with nary a bang nor a whimper.

Enter Firefox. Firefox is fast, clunky, and has okay text rendering. Actually, Firefox has perfectly fine text rendering, but its buttons and menus and general interface are so completely out of place on the Mac that they drag everything else down with them. (Firefox on Windows uses native buttons and menus, Firefox for Mac is uglier than Firefox for Windows.) Which is why I use Camino. The fact that Camino has actual Mac buttons instead of Windows 95-ish things offsets its lack of a JavaScript Console. Still, when things go bad, I brave the ugly and rejoice in the JavaScript Console and Web Developer extension.

And then I get frustrated because I’m bouncing between three browsers with four windows between them. And Firefox always seems to have the exact wrong window forward every time I switch to it. Yes, I have a small screen at the moment, but this will still be just as frustrating once I’ve upgraded to a 20″ iMac with a second display.

Or, to be correct, I should say that all of that was a problem. I’m still bouncing between three browsers, but they each have precisely one window and that window always shows me exactly what I want to see. (Excluding the times I hit ⌘-tab too many times and end up in Mail or something…)

The reason for this wonderous change is FireBug (http://www.joehewitt.com/software/firebug/), a plucky little Firefox plug-in that everyone should have. Simply put, FireBug takes over a small part of the bottom of your browser window to show JavaScript Console messages, DOM Element details, XMLHTTPRequests, and pretty much everything you’d want to be able to see in a little frame at the bottom of your window.

Yes, I did in fact say XMLHTTPRequests. With the checking of a single box, every AJAX request the page sends out is logged and the XHR object, parameters and response are all laid out for your inspection.

The sheer utility of FireBug is equalled only by my joy in using it. I am tempted to go write some buggy JavaScript just so that I can enjoy debugging it with my new tool. It’s that much of an improvement.

Loading a page and watching the AJAX requests roll by, with their little JSON bundles of data is currently a joyous experience. I’m sure the shine will wear off eventually and FireBug will become just another tool. But the fact that I’ll never again have to open a second window to discover that I forgot to qualify the completion handler with the object’s variable name will stick with me for a long time to come.

FireBug integrates the DOM Inspector and JavaScript Console into the Window (filtering out JavaScript messages from other windows and tabs), and then goes even further opening up whole new vistas of debugging possibilities. Plus, it’s the prettiest part of the Firefox window.

Highly Recommended.

, , , , ,

Posted on 3 March 2006 in Uncategorized

3 Comments »

The *Most* Important VLC Preference

VideoLAN Client is a wonderful piece of software. It does many, many wonderful things. The one I’m concerned with at the moment is playing videos stored on a web server. You just give VLC the address of the file and it downloads it, playing as it goes. This is incredibly useful if you have a bunch of videos stored on one machine on your LAN (which has a web server running on it) and you want to play them on another machine.

There is a downside: when you pause a playing video for too long, VLC will lose its connection to the server. This means that when you unpause the video the buffer plays out (about one to three seconds) and the playback stops. Then you have to restart it and jump around in the video until you find where you were. By which point, VLC will have messed up its video and audio sync and you have to stop and restart the video again, jumping straight back to the point in the video you located the first time you restarted it. In short: a major pain in the ass.

The preference I’m writing this entry in honour of fixes that. In Preferences > Input/Codecs > Access modules > HTTP/HTTPS. At this point, the preference in question is not there, click Advanced to make it visible. Now check Auto-reconnect and Continuous stream.

Now when you pause the playback, VLC will pick up where it left off no matter how long you paused it. Just like it should be.

Posted on 2 March 2006 in Uncategorized

Comments Off