Blog

Help! Chrome's ignoring my Cache-Control headers!

You're a web developer and you've discovered your web app's sending a lot of static assets over the wire with every page load. These are static assets, so there's no need – they don't ever change. If you configure your web server with the right headers, you can tell browsers to cache them forever. Pages will load faster, and your server will be under less load. So you create a .htaccess file with something like this in it:

<ifModule mod_headers.c>
Header set Cache-Control "max-age=604800, public"
</ifModule>

You load your website and watch the network inspector in Chrome. You hit refresh, but you still see loads of requests for your static files. You hit refresh again. Maybe it cached this time, or maybe not. But refresh again, and everything gets retransferred! You start looking at individual requests. The headers are being set properly. You read the spec, and everything looks fine. Other browsers are respecting the headers and doing the right thing. What the hell's going on?

You're not going mad, and you probably haven't messed up. Chrome's trying to be helpful: it can't tell you're a web developer, and it doesn't know you're tapping that refresh button to test the server. Chrome's detecting the multiple refreshes, presuming you're doing it because the page is broken, and reloading everything from the server. I haven't figured out the exact behaviour it uses to do this, but it seems it involves whether you click through to other pages or not. As a result, you'll get more reliable testing if you navigate around your app a bit rather than clicking refresh.

Trick or Treat?

I've lived in London for 6 years now, but tonight was the first time I was visited by trick-or-treaters. Every year prior I indulged the Guardianista fantasy of making friends with the local youth – and the Daily Mail fantasy that I must bribe my way to safety via sweeties – by buying a giant bag of fun-size chocolate bars. And every year prior nobody came. I was left with broken dreams and a lot of chocolate.

But tonight was different. I arrived home late, and had just collapsed on the sofa when there was a sudden knock on the door. Standing up, I gazed down the half-lit hallway to see the silhouette of a teenager in a bad costume. "I'll pretend I'm not in," I thought. Then a couple of braincells kicked in and I realised the lights were on. I had to answer it.

I rushed to the kitchen and looked in the cupboard. Nothing. No sweets, no pastries, no chocolate. But there was one thing. One vague possibility. I grabbed it and headed to the door.

When I opened it the two teens had cut their losses and were halfway across the road, but they turned around when they heard the door open. "Err, trick or treat?" one asked, hopefully, not moving closer. And that's when I found myself possessed by a spirit infinitely older than my own, speaking words I'd promised myself I would never utter.

"I'm really sorry, I've just got home from a long day at work and I haven't got any sweets in the house," I said. "But I can give you this pomegranate if you wanted."

At some point – some point in the past year – I have changed from the person who buys sweets for Halloween to the person who offers trick-or-treaters fruit. Children tell playground horror stories about people like me. I can make excuses and plead special circumstances, but let's face facts: they asked for sweets. They got fruit.

The ghouls shrugged non-committally and walked off, and I thank them for that. No egging of the house, no shouted abuse. Perhaps they understood that the crashing realisation of what I have become is the greatest trick of all. But they probably just thought they'd try next door.

My biggest co-incidence

It's 2005. I'm in Australia, technically. I'm on a boat sailing round the Whitsunday islands with 30 other people. We put to sea for 3 days. 3 days of beautiful scenery, deserted beaches, and giant card games below decks. 3 days of diving, sunbathing, and talking. 3 days of whales. 3 days of no shaving, no warm running water, and no phone signal.

Sunrise over the Whitsunday islands.

I got talking to one of the English women in our group. We soon discovered we'd gone to the same university. But not only that: at the same time. But not only that: we had some friends in common. But not only that: I had been to her house. One of our friends in common was her old housemate, and we'd met there for pre-club drinks. And here we were, in the middle of nowhere, on the opposite side of the planet.

My laser-cut iPad stand

I sometimes use my iPad as a second screen – an auxiliary display for alerts (if you're a masochist) or side-channel apps (to do lists, calendars, Pomodoro timers, etc). If you've got a smart cover you can use it as a stand, but otherwise you have two choices: buy one, or make one. I made one – or actually two. One for home, one for work.

I started with a design on Thingiverse and made some minor changes: I altered the slot size to work with 5mm Perspex and extended the rear feet because I was worried about the stand's stability. After a few rounds of trial and error on the laser cutter, I got a snug fit and a working stand. I used some scrap Perspex for mine, so there are some small cut-outs on the bottom edge.

If I were doing this again I'd either make the rear leg rounded so the notch wasn't supported with such a thin bit of Perspex (Perspex shatters easily) or make this out of something like MDF or ABS. I've used this stand for over a year on a daily basis and it's not failed in use, but I did drop one and the foot broke at the narrowest part. I'd also consider raising the iPad a little further off the desk, so you could charge it in a portrait orientation.

My main use case for this these days is to display Concentrate! while working, though I've also used it to keep an eye on the news at times of civil unrest and media inquisitions.

Download the DXF file to make your own, or check it out on Thingiverse.

Workarounds for a couple of unetbootin bugs

Bug number one: a corrupted Ubuntu installer

The symptom
the Ubuntu 12.04 alternate installer fails when installing the base system, telling you that the disk is corrupt. You'll get an error message along the lines of "problem reading data from the CDROM".
The problem
Unetbootin/7zip have known bugs with long file names/file paths. These have been open for a couple of years, so don't expect them to be fixed soon.
The solution
Use Ubuntu's startup disk creator instead. You can either run it from the launcher or as usb-creator-gtk from a console.

Bug number two: your DBAN USB key won't boot.

The symptom
When you try to boot from your DBAN USB key you get the boot menu, but attempting to boot any of the entries fails with the message "Could not find ramdisk image:/ubninit".
The problem
Unetbootin doesn't configure syslinux.cfg properly.
The solution
Edit syslinux.cfg, replacing all occurrences of "ubninit" with "ISOLINUX.BIN" and the one occurrence of "ubnkern" with "DBAN.BZI". It's case sensitive, so make sure it's all uppercase.

Bonus DBAN/Unetbootin tip

Unetbootin creates a default boot option for DBAN that includes the --autonuke flag. This means your DBAN key is especially dangerous – if you boot off the key, either by accident or design, it'll wipe all disks without any human intervention. Avoid this by removing the --autonuke option from the section marked label unetbootindefault while you've got syslinux.cfg open.

Everything I know about selling on eBay

I've been selling a lot of stuff on eBay as part of an ongoing decluttering/minimalism drive lately. I've given a few people this braindump in person, but it's probably more useful as a written list. All of these tips apply to eBay auctions – I've got little experience with "Buy it Now" items.

Make sure it's worth it.

By the time you've photographed, uploaded, form-filled, written about your item, packed it, addressed it, and taken it to the post office you will have spent at least an hour per item. This isn't a good use of your time if it sells for 99p. (I sometimes list stuff that I know isn't going to perform well if it's not suitable for charity shops and/or I'll feel guilty about throwing it away.)

What does and doesn't sell?

Things that sell well:

  • Photographic equipment
  • Computer equipment
  • Anything that would make you go "Oooooh" at a jumble sale.

Things that sell OK:

  • CDs
  • DVD boxed sets
  • Actually collectible collectibles
  • obsolete computer hardware
  • small organisational things (wallets, purses, folders, cases). I don't understand why, but they seem to.

Things that don't sell:

  • Books
  • DVDs
  • Chargers and cables
  • Small furniture.

Don't get your hopes up.

Searching eBay for completed listings similar to your item will give you an idea about what it's really worth. You may think it's worth £100 but if everyone else's sold for £40, yours will sell for £40. A good listing and a bit of luck might help you do a bit better, but it might also do a bit worse.

Buy a scale, and use eBay's postage calculator.

I bought a small hanging scale for £5 and weigh everything I'm selling. If you weigh the item with a jiffy bag you'll get an exact cost for postage. I recycle envelopes and boxes from other purchases, but you can also buy packaging from pound shops and on eBay itself. Don't buy from the post office – it's really expensive.

List items for free.

If you your listing starts at 99p and only has one photo then you don't pay anything. You can use custom HTML in the description and include extra photos that way, presuming you have somewhere to host them. Beware! Flickr explicitly blocks image links from eBay referers.

Place 10 day listings and start them on Thursday evening.

It's worth spending 6p per item to schedule all your listings to start on Thursday evening. They'll finish on Sunday evening – a time when people are at home and likely to be looking at the computer. It also gets two weekends to attract bidders and watchers. Theoretically you only have to go to the post office once, on Monday, but there's always one arsehole who won't pay you until Tuesday evening.

Buy it Now probably isn't worth it.

The Buy it Now option disappears as soon as you get your first bidder. People will make a 99p bid in to stop other people buying it outright.

Good pictures help, lots of pictures help.

If it's just a book or a DVD this isn't important, but if you want to sell something that's worth more than £50 then photograph it from every angle and write a lot about it. You'll get more watchers and bidders that way. If you can include photos of your item working, then do so.

Cross-link if you like, but it doesn't work.

If I'm selling a bunch of similar items then I add links to the others in each listing. Other books by the same author, a laptop case for a laptop, or a keyboard that matches a mouse; that kind of thing. I've also got a standard boilerplate that links through to my other items for sale. Despite this, it's very rare to sell more than one thing to anyone. It's probably not worth the hassle.

Most bids happen in the last few minutes.

It's not unusual for bids to trickle in for the first 9 days and only pick up in the last few minutes/seconds. If you've got a lot of watchers – say, more than 15 – then this becomes more likely. Don't panic if you've not hit your expected price before the last day.

Fill out the proof of postage certificate at home.

You can save yourself some time at the Post Office by filling out the certificate at home. Sometimes the counter staff will give you a pad for free, but you can also order over the phone or online. I've also managed to order via email but I've seen suggestions that this only works for business addresses. So far I've never had to use the proof of postage, but it's reassuring and definitely worth doing for larger trades. PayPal and eBay are biased towards the buyer, so if there is a dispute all documentation helps you.

Take a book to the post office.

There will be queues. You will be bored. Take a book.

How to run a script when a filesystem gets mounted on Linux

I wanted to run a script when a filesystem gets mounted on my Ubuntu server. I thought this would be a common task but it took me a while to find the answer. Some people suggested using udev, but udev responds to device changes. If you're trying to trigger something like a backup when you plug in a USB drive, udev is the way to go. But it's no use if your device is always connected but not always mounted.

When my server starts, /home isn't mounted automatically. /home's on an encrypted filesystem, and the system runs without a keyboard and monitor, so I want it to boot up normally without /home and I'll mount it the next time I login. When /home becomes available, it should start a media server and NFS sharing.

It's not well documented, but it's easy under Ubuntu. You need to use upstart and create an init script. These live in /etc/init/ and can have any name ending in .conf. You can either write your script directly in the init script, or call another script elsewhere. As I only had a couple of tasks to perform the behaviour's more obvious if it's in the init script. Here's what mine looks like:

# mounted-home - Trigger actions when home becomes available. 

description "Trigger actions when /home becomes available." 

start on mounted MOUNTPOINT=/home 

task 

script
    /etc/init.d/forked-daapd restart
    service nfs-kernel-server restart   
end script

You could also write a complementary script that stops these things when the home directory is unmounted, but I don't normally unmount my home dir and there's no harm in running this script repeatedly – the restart command will start it if it's stopped, or bounce it if it's already running.

A brief review of Catball Eats it All

Let me state my biases upfront. I love quirky, ridiculous games. I love great game music. And I love cats. Catball Eats It All ticks all of these boxes. Later I discovered it started as a Kickstarter project - icing on the indie cake.

Catball Eats It All is a pinball-platformer game for iOS. You are the Catball, and must roll & float through the level eating all the little bits of food before the timer runs out. Once you've got all the food, you eat the level itself. It's a simple concept, and the delight is in the execution: great artwork (from Nosego), great music (from Ben Thornewill/Jukebox the Ghost), and great sound effects. There's also a refreshing absence of freemium piffle. Overall, it's a charmer.

There are some flaws, however: the controls can be irritating and hard to master. In many ways, the controls are the game. It's sometimes fairly hard but that tends to flow from the controls rather than the game itself. It also made a poor first impression, downloading its level data when you run it for the first time (instead of when you install it), so you're out of luck if you try it out somewhere without internet. Fortunately, this was fixed in a recent update.

It's a bit of a slow burner, and I found myself playing it more for the music than the gameplay. But it's a lovely little game for 69p, and definitely worth your time - especially if you like Kometun, pinball, or cats.

Overall: 7/10. Recommended; Available from the iTunes store.

Lessons from my recent iPad debacle.

A series of unfortunate events left my iPad reset to its factory defaults and unable to restore from backup. All my data: gone. This was a horrid reminder of things that I knew but hadn't fully internalised. Please learn from my mistakes and absorb the following:

Don't forget your iTunes backup password. There's no going back if you tick the "encrypt my backups" option. You can't trash the old backups and make a new one with a known password. You can't recover the old password (unless it's really weak and you'll pay £80). Your iPad will still back up – but you can't restore without the password. If you forget your password and want a usable backup, you must blank your iPad and start from scratch.

iPad encryption is strong. Really strong. I think of the iPad as a consumer device and expected security to match – allowing new backups, and/or weak encryption. Nope: it uses AES256 for encryption, SHA-1 hashes for filenames¹, and random keys as part of each backup². All the encryption's handled on the iPad and no data leaves the iPad unencrypted³. Each file in the backup gets a different encryption key¹. You need the passcode to unlock the device, and checking this is done on the iPad itself.

Ubiquitous capture for passwords is vital. Use a password safe – a program that stores your passwords, so you can memorise 1 really strong password & use randomised passwords for everything – and make sure everything goes in there. No paper scraps. No "Oh, I'll remember this one." EVERYTHING. If you find a password you've written down, put it in the password safe as "unknown" before destroying it.

Password reuse can be a good thing. Why the fuck didn't I use my Apple ID password? Or the unlock code for the iPad? Or my encrypted HD password? Or my encrypted PC backup password? Because I'm a fucking idiot, that's why.

If you don't have more than one copy of your data, you don't have it. My password safe was on my iPad. I would have been stuck even if I'd stored it in there. You need multiple copies of your data, in multiple locations, and not tied to any one device.

¹ iPhone Data Protection in-depth, slide 48.
² iPhone Data Protection in-depth, slide 52.
³ Data Decryption & Password Recovery, slide 25.
Evolution of iOS Protection and iPhone Forensics: from iPhone OS to iOS 5, slides 29-30.