.

Coffee Powered

code and content

Making HAML faster

Haml’s among my favorite of the Rails technology stack. Clean, self-correcting templates that mean less typing and more doing for me. I love it.

Unfortunately, there have been a number of performance regressions introduced into Haml recently, and that sucks, because Rails spends a lot of time building views, and I’d really like those numbers to be smaller.

Over the past couple of weeks, I’ve been on-and-off profiling Haml and working on various performance patches. I mentioned one of them in my previous post – avoiding exceptions as flow control. There are a couple more we need to watch out for, though.
Read More »

JRuby Performance: Exceptions are not flow control

I started playing with JRuby tonight, and got my application up and running on it in under 10 minutes (kudos to the JRuby team!), but when I started measuring its performance, I was seriously unimpressed. This didn’t quite line up with what I’ve read of JRuby, so I decided to do a little digging.
Read More »

Mongrations reloaded

Users of MongoMapper may be familiar with mongrations, a Rails plugin to provide you with ActiveRecord-style migration tools for MongoDB. You don’t need them for schema changes, obviously, since MongoDB is schemaless, and you can define any changes you need to in your model. However, there are times that deploying a changeset will require some data change, or some maintenance stuff to be run. For that, mongrations is super helpful. Or was.

It’s been broken for some time now, and not really in much of a state to be used by anyone, but I needed it, so I fixed it up. You can get my source on github, but I’ve done one easier and made it a gem. Major changes are:

  • Bad assumptions fixed. Actually works now.
  • Reorganized the whole thing and repackaged it as a gem. Doesn’t work as a Rails plugin anymore, but that’s okay. Just add it to to your environment or Gemfile and you’re good to go.
  • Added tests!
  • Fixed documentation, and normalized rake tasks names.

To get it, you can just gem install mongrations and you’re off to the races.

This is primarily going to be useful for MongoMapper people, who are likely still on Rails 2.3.x. If you’re using mongoid, check out mongoid_rails_migrations instead.

Rails, Varnish, Cookie Sessions, and CSRF tokens

Cookies! Delicious and performance-shattering.I’ve recently been trying to figure out how to get Rails to place nicely with Varnish. It doesn’t do that very well. In a nutshell:

  • Varnish is easy to use, if your app isn’t setting session cookies until you actually need them. The presence of a session cookie usually means that content shouldn’t be cacheable.
  • Hitting any page with a form results in Rails generating a CSRF token and sticking it in the session, generating a session cookie and effectively locking the rest of the session out of being cacheable (even if it should be).
  • Just *breathing* the method session in your app initializes your session.
  • The Rails cookie session middleware assumes you always want to write a session cookie.

Fortunately, since so much of this is in Rack middleware, we can fix its mistakes with a middleware of our own. In a nutshell, I’m going to:

  • Avoid writing CSRF tokens until we actually need them
  • Check and see if we have an “empty” session (ie, no interesting data, just the session ID)
  • Prevent session cookies from being sent to the browser unless there’s actually useful data in them.

Read More »

Mobile and secure – setting up OpenVPN with DD-WRT and Android

So, with all the hubbub about Firesheep lately, and the fact that I’m becoming more mobile in my computing, I figured that it was time for me to get a VPN set up. I didn’t want to pay for one, and hey, it turns out that I have all the tools I need to manage my own.

Like any good geek, I’m running a WRT54G with the aftermarket DD-WRT firmware. This is handy, since DD-WRT supports OpenVPN right out of the box, so to speak.

I have two targets I’d like to secure: My laptop (running Windows 7) and my Nexus One (running Cyanogen Mod 6.1).

Setting up OpenVPN on the router

This is straightforward and easily culled from online resources. Assuming you’re running DD-WRTv24, it’s dead simple to get up and running. I’ll be using a Fedora 11 box for certificate and key generation.

Install OpenVPN

yum install openvpn

Set up the key generation environment and generate a Certificate Authority cert

cd /usr/share/openvpn/easy-rsa/2.0
source ./vars
./clean-all
./build-dh
./build-ca

Provide whatever information you’d like for the cert, but set the Common Name to something usable, like “OpenVPN CA”.

Generate a certificate and key for your OpenVPN server (DD-WRT, in this case)

./build-key-server server

Provide whatever information you’d like for the cert, but set the Common Name to something usable, like “OpenVPN Server”.

Install the certificates and keys to the OpenVPN server

  1. In your DD-WRT install, go to Services -> VPN
  2. Set OpenVPN Daemon -> Start OpenVPN to “enable”
  3. Set Start Type to “WAN Up”
  4. Copy the contents of your ca.crt into “Public Server Cert”
  5. Copy the key bits of your server.crt into Public Client Cert. It looks something like this:
    -----BEGIN CERTIFICATE-----
    MIIDnjCCAwegAwIBAgIBATANBgkqhkiG9w0BAQUFADB0MQswCQYDVQQGEwJVUzEL
    MAkGA1UECBMCQVoxEDAOBgNVBAcTB1Bob2VuaXgxEDAOBgNVBAoTB09wZW5WUE4x
    ...
    i1fFhoNuFxC2z3D+Otg1SuBvA6v/zENRMTPduAr163G105brjN2BiAyEcTjxsqfl
    c6H57iwLaoyxxiJZVYx2WBYX0+13qf/jPoCd/IkCDnOv64R+8z4stgQlAUmNlNLU
    J/8BjCn+3FmA7uosamYi3bsW
    -----END CERTIFICATE-----

    Be sure to include the BEGIN and END lines.

  6. Copy the contents of server.key into “Private Client Key”
  7. Copy the contents of dh1024.pem into “DH PEM”
  8. Copy something like the following into “OpenVPN config”:
    
    push "route 192.168.1.0 255.255.255.0"
    server 192.168.66.0 255.255.255.0
    
    dev tun0
    proto udp
    keepalive 10 120
    dh /tmp/openvpn/dh.pem
    ca /tmp/openvpn/ca.crt
    cert /tmp/openvpn/cert.pem
    key /tmp/openvpn/key.pem
    management localhost 5001
    

    The “push” line should be the subnet of your local network (“192.168.1.0 255.255.255.0″ means “all addresses between 192.168.1.1 and 192.168.1.255), and the “server” line should be the subnet of your new virtual network. In most cases, these defaults should work just fine.

  9. Click “Save”
  10. Go to Administration -> Commands
  11. Enter the following:
    
    iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT
    iptables -I FORWARD 1 --source 192.168.66.0/24 -j ACCEPT
    
    iptables -I FORWARD -i br0 -o tun0 -j ACCEPT
    iptables -I FORWARD -i tun0 -o br0 -j ACCEPT
    
  12. Click Save Firewall
  13. Go to Administration -> Management, then click Reboot Router

Now, it’s time to configure our clients.

Generate certificates for the laptop and phone


./build-key laptop
./build-key phone

Package relevant certificates into a .p12 file for the phone

Android can import .p12 files, which consist of a root certificate, client certificate, and client key. We already have those three, so we just need to package them up.


cd /usr/share/openvpn/easy-rsa/2.0/keys
openssl pkcs12 -export -in phone.crt -inkey phone.key -certfile ca.crt -name "Phone VPN" -out phone.p12

Once that’s done, copy the .p12 file to the root of your phone’s SD card. To install it, you’re going to go to Settings -> Location and Security -> Install from SD Card. Just follow the steps – the import should find your .p12 file and import your certificates. You’ll be asked to create a certificate storage password if you haven’t imported any certificates before. Do so.

Configure the phone VPN

  1. Go to Settings -> Wireless & Networks -> VPN Settings
  2. Click Add VPN
  3. Select Add OpenVPN VPN
  4. Set a name for your network (I chose “home”)
  5. Under Set VPN Server you need to set your router’s WAN address. The easiest way to do this is to use something like DynDNS to get a host name to map to your IP address, but this is a topic for another post.
  6. Set the CA and user certificates to the certificates you just imported
  7. Hit the back button and connect! Your phone should now be using your VPN, and you can connect to public wifi with it with impunity.

Configuring the Windows VPN

  1. Grab the client download from openvpn.net and install it.
  2. Once installed, open a text editor. We have to create our VPN config file manually, but it’s not much of an issue to do so.
  3. Create a file in C:\Program Files (X86)\OpenVPN\config (or equivalent) called home.ovpn. In it, paste the following:
    
    remote xxx.homedns.org 1194
    client
    remote-cert-tls server
    dev tun0
    proto udp
    resolv-retry infinite
    nobind
    persist-key
    persist-tun
    float
    route-delay 30
    ca ca.crt
    cert laptop.crt
    key laptop.key
    

    Save it. Be sure to replace the hostname in the first line with your home hostname or IP.

  4. You probably noticed the certificate key references in the config file. Copy the laptop.crt, laptop.key, and ca.crt files you generated earlier into the same directory as the home.ovpn file
  5. Start the OpenVPN GUI. I had to run it as an administrator to get it to work properly.
  6. Double-click the tray icon and hit Connect. After a few seconds, your machine should be connected to your VPN, and the systray will notify you of your new virtual IP.

Congrats, that’s all there is to it! You can now route all your mobile traffic securely through your home connection, and rest assured that it’s safe from prying eyes. In my case, I get some extra benefits like being able to access my development servers and Samba shares without any extra hassle – definitely a nice perk!

Enjoy, and be secure!

Hack night at Gangplank

So, I finally made it down to Gankplank. I’ve been meaning to get down here for a while, but I’ve just not made it happen. I took the weekend to get my development environment up to snuff on my laptop (so I can actually work anywhere now!) and decided to give it a shot.

This place is cool. Very cool. The atmosphere is invigorating – it’s exactly the sort of place I’d love to really put in some serious time at. Smart people, lots of technology, and a laid-back, fun, productive atmosphere. Awesome.

It also highlights fairly starkly the fact that I don’t have much in the way of “hack” projects to work on. Most all my stuff these days is Real Work(TM), which, good as it is, isn’t the sort of thing that you can really unwind with. I need a project that I can work on and let it fail – something I can sink some serious creative juices into. I want to break out of what I’ve been working on for 90 hours per week for the last couple of years, and sink my teeth into something truly creative.

I’ve got a lot of directions I could go – I have a few webapps in mind, some node.js ideas, a few experiments with MongoDB. I want to do more Android development and get better with Java; I want to learn Clojure and maybe even poke at Haskell. I want to find an excuse to use Amazon’s compute clusters to solve some ridiculously huge-scale problem. More than that, I want to find out what I don’t know about yet, and put some effort towards learning it.

I don’t have a good answer for what I want to do tonight, but it’s a good starting point. I’m excited at the opportunity and sheer energy this place provides – a place to work, to be creative, to talk and play and laugh and hack and enjoy. I’ll find something interesting to do yet.

Solving error n8156-6003 when trying to play Netflix Watch Instantly content.

This is mostly search engine bait, because I couldn’t find a solution on my own when searching, but managed to stumble across it anyhow.

I recently did a Windows 7 x64 reinstall, and after doing so, Netflix wouldn’t play in any of my clients – Windows Media Center, Chrome, IE, you name it. After various solutions (DRM reset, security component upgrade, Silverlight uninstall and reinstall), it turns out the solution is stupidly easy:

Run your browser as an Administrator. Open Netflix, start watching a movie. Once it successfully starts playing, you can close your browser and then resume watching whatever you’d like to watch.

I can only guess that some initial setup doesn’t get done properly, and it fails if you’re trying to do the initial license acquisition in a non-elevated program. Hopefully this saves someone else a headache!

Write-once read-only fixtures for Rails tests

In the project I’m currently working on, I’m heavily using factory_girl to generate test data, rather than using the old Rails fixtures standby. However, I still have a set of read-only fixtures (which are used for testing read-only models against a legacy database). I’m using these in my tests, but since they are read only (like, seriously – the models are marked as by using after_find to call readonly!, ensuring that records will not be accidentally written), there’s no need to wipe and re-insert them per-test.

It’s not too hard to set up fixtures to be inserted once per test suite run –

In your test_helper.rb, above the class ActiveSupport::TestCase definition, add the following:

Fixtures.reset_cache
fixtures_folder = File.join(RAILS_ROOT, 'test', 'fixtures')
fixtures = Dir[File.join(fixtures_folder, '*.yml')].map {|f| File.basename(f, '.yml') }
Fixtures.create_fixtures(fixtures_folder, fixtures)
Fixtures.reset_cache

Next, turn off transactional fixtures and comment out the fixtures macro:

self.use_transactional_fixtures = false
# fixtures :all

That’s all there is to it. Your fixtures will be inserted into your test database once when test_helper is included for the first time, and then not again for the rest of the test suite run. This should speed your tests up substantially.

Pain-free CSS3 with Sass and CSSPie

So, you have a great design for a site. Lots of rounded corners, soft shadows, and beautiful gradients. “This’ll be fun!”, you think.

Enter IE.

“Oh, crap”, you think.

Modern web design in IE is a pain in the rear. Fortunately, we have modern tools that make it a not-pain.

  • SASS (Syntactically Awesome Stylesheets) is a macro language for CSS. It lets you express CSS as nested rules, and gives you mix-ins, functionality extensions, variables, partials, and a whole lot more.
  • CSSPie is a set of behaviors for Internet Explorer that gives you CSS3 visual styles without really slow Javascript hacks like CurvyCorners.

When combined, the two are a shot of liquid awesome injected directly into your brain.

I’ve settled on a fairly standard setup for my projects. I have:

  • My application.sass file.
  • My _mixins.sass partial.
  • My PIE.htc behavior file.

Macros is very straightforward:

@mixin pie
  behavior: url(/behaviors/PIE.htc)
.pie
  +pie

@mixin shadows($color: #aaa, $x: 1px, $y: 2px, $spread: 2px)
  @extend .pie
  -moz-box-shadow: $color $x $y $spread
  -webkit-box-shadow: $color $x $y $spread
  box-shadow: $color $x $y $spread

@mixin inset-shadows($color: #aaa, $x: 1px, $y: 1px, $spread: 1px)
  @extend .pie
  -moz-box-shadow: inset $x $y $spread $color
  -webkit-box-shadow: inset $x $y $spread $color
  box-shadow: inset $x $y $spread $color

@mixin corners($tl: 5px, $tr: nil, $br: nil, $bl: nil)
  @extend .pie
  @if $tr == nil
    $tr: $tl
  @if $br == nil
    $br: $tl
  @if $bl == nil
    $bl: $tl
  -moz-border-radius: $tl $tr $br $bl
  -webkit-border-top-left-radius: $tl
  -webkit-border-bottom-left-radius: $bl
  -webkit-border-top-right-radius: $tr
  -webkit-border-bottom-right-radius: $br
  border-radius: $tl $tr $br $bl

@mixin vertical-gradient($start: #000, $end: #ccc)
  @extend .pie
  background: $end
  background: -webkit-gradient( linear, left top, left bottom, color-stop(0, $start), color-stop(1, $end) )
  background: -moz-linear-gradient(center top, $start 0%, $end 100%)
  -pie-background: linear-gradient(90deg, $start, $end)

What’s going on here? We’re defining several mix-ins for Sass:

+shadows([color, [x, [y, [spread]]]])

+inset-shadows([color, [x, [y, [spread]]]])

+corners(size)

+corners(topleft, topright, bottomright, bottomleft)

+vertical-gradient(start, end)

Now, in your CSS, you can just do the following:

body
  font:
    family: Arial
    size: 10pt

.box
  +corners
  +shadows(#ccc)
  +vertical-gradient(#eee, #fff)

  h3
    color: #444

.dark-box
  +corners(20px)
  +shadows(#888, 4px, 4px, 4px)
  +vertical-gradient(#444, #000)
  color: #fff
  h3
    color: #fff

.box, .dark-box
  padding: 1em
  margin-bottom: 1em

This expands to:

.pie, .box, .dark-box {
  behavior: url(/projects/PIE.htc);
}

body {
  font-family: Arial;
  font-size: 10pt;
}

.box {
  -moz-border-radius: 5px 5px 5px 5px;
  -webkit-border-top-left-radius: 5px;
  -webkit-border-bottom-left-radius: 5px;
  -webkit-border-top-right-radius: 5px;
  -webkit-border-bottom-right-radius: 5px;
  border-radius: 5px 5px 5px 5px;
  -moz-box-shadow: #cccccc 1px 2px 2px;
  -webkit-box-shadow: #cccccc 1px 2px 2px;
  box-shadow: #cccccc 1px 2px 2px;
  background: white;
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #eeeeee), color-stop(1, white));
  background: -moz-linear-gradient(center top, #eeeeee 0%, white 100%);
  -pie-background: linear-gradient(270deg, #eeeeee, white);
}
.box h3 {
  color: #444444;
}

.dark-box {
  -moz-border-radius: 20px 20px 20px 20px;
  -webkit-border-top-left-radius: 20px;
  -webkit-border-bottom-left-radius: 20px;
  -webkit-border-top-right-radius: 20px;
  -webkit-border-bottom-right-radius: 20px;
  border-radius: 20px 20px 20px 20px;
  -moz-box-shadow: #888888 4px 4px 4px;
  -webkit-box-shadow: #888888 4px 4px 4px;
  box-shadow: #888888 4px 4px 4px;
  background: black;
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #444444), color-stop(1, black));
  background: -moz-linear-gradient(center top, #444444 0%, black 100%);
  -pie-background: linear-gradient(270deg, #444444, black);
  color: white;
}
.dark-box h3 {
  color: white;
}

.box, .dark-box {
  padding: 1em;
  margin-bottom: 1em;
}

Check out the live demo.

Here are screenshots of the demo in Chrome 6, Firefox 4.0b3, Internet Explorer 8. Can you tell which browser is which?

Debugging memory leaks in Ruby with GDB, round 2.

In part 1, I described how I located leaky Sets in MongoMapper by diffing the Ruby ObjectSpace with GDB. Today, I’m going to show you how to solve the problems that those sorts of diffs can reveal. In today’s example, we’re tracking leaky sets. In particular, a set is holding onto class references. We are going to:

  1. Set up object creation tracking on the Set class
  2. Find the leaky instance of our set using GDB
  3. Locate what code created that Set instance

Read More »