Wednesday, January 21, 2015

The Origin of Toads.co

Today's comic got a little complicated. So some sinister-looking toad has started a new company to compete with Amphibian.com and has hired away all the worker frogs. Since everybody's over at the other company today, the comic is actually at the toad's company website - toads.co.

I thought it would be simple to point toads.co to the same server as amphibian.com and have the application just use a different stylesheet when the toads URL is detected. As it turns out, it wasn't really that simple.

One of the things I forgot about was how picky browsers can be about cross-domain loading. While there's no issue with sourcing images or JavaScript from other domains, I ran into a minor issue with Font Awesome loading font files cross-domain.

If you haven't heard of Font Awesome, you should check it out. By creating a custom font of pictures (remember Wingdings? It's like that, but useful) it essentially gives you a library of scalable vector icons that can be customized with CSS.

Due to the way Cross-Origin Resource Sharing is designed, a server is expect to specify in a response header if the requesting domain is allowed to use a web font. The header is called Access-Control-Allow-Origin. If amphibian.com is hosting the font, by default only pages at amphibian.com can use it. But if I add the special header to the response when I serve the font, I can specify other domains that are allowed to access it.

My goal, therefore, was to set the "Access-Control-Allow-Origin" header to "http://toads.co" so my social media icons wouldn't be missing when viewed from toads.co. Initially I wasn't sure how to do that, since all static content is served automatically by Express's static middleware. This is the only middleware that is still "built-in" to Express, but it is really just a wrapper for the serve-static module.

To add a certain response header to only some files, I had to supply a setHeaders function when I set up the middleware.

app.use(express.static("public", {
    "setHeaders": function(res, path, stat) {
        if (path.match(/\.(ttf|ttc|otf|eot|woff|font.css|css)$/)) {
            res.setHeader("Access-Control-Allow-Origin", "http://toads.co");
        }
    }
}));

Personally, I think the name of the function is a little misleading. While the intention is certainly to give you a place to set headers, you can pretty much do whatever you want inside. You get access to the response object, the path of the request, and the file stat for the file at that path. There's a small caveat - because the function doesn't return anything, you can't really make any asynchronous calls that defer any processing. You have to do whatever you need to do synchronously. Set the headers you need to set and move on.

My method simply checks to see if the requested file ends with one of the font extensions, and if it does the special header gets set.

I set out to do something that I thought would be simple, and ended up learning something new. Not a bad deal. I hope those frogs got as good of a deal at their new jobs...

Amphibian.com comic for 21 January 2015