spring-grasshopper-86

Development journal of Zeke Sikelianos, the eighty-sixth herokai.

Tips for Setting Up CORS on S3

I’ve been working on a project that uses an awesome Javascript library called Color Thief to extract a color palette from an image. Now that S3 has CORS support, it’s easier than ever to do client-side manipulation of user-uploaded images using Canvas. In this post I’ll cover some of the things that tripped me up along the way.

Check out the demo on heroku and the demo source on github.

Testing with curl

Setting up CORS on your S3 bucket can be accomplished pretty easily using the S3 management console web interface. It looks like this:

Once you’ve got your bucket configured, you can use curl to verify that your CORS configuration is working. Simply set an an origin header when making the request:

curl -H "Origin: http://example.com" --verbose \
  http://cors-example.s3.amazonaws.com/rainbow.jpg

You should see the following response headers:

< HTTP/1.1 200 OK
< x-amz-id-2: E1JFVQnxrtk0riqK8q2G6RTlMh4zyxC/OTuV5AEUUDcCa9AXXL/C00iX2i5dmjZW
< x-amz-request-id: AD2BA8F701742FD8
< Date: Tue, 16 Oct 2012 22:30:25 GMT
< Access-Control-Allow-Origin: http://example.com
< Access-Control-Allow-Methods: GET
< Access-Control-Max-Age: 3000
< Access-Control-Allow-Credentials: true

Use the bucket-as-subdomain S3 URL format

S3 URLs come in two flavors: domain-style (bucket.s3.amazonaws.com) and path-style (s3.amazonaws.com/bucket). In order for CORS to work, your must use domain-style URLs.

http://cors-example.s3.amazonaws.com/rainbow.jpg # Good
http://s3.amazonaws.com/cors-example/rainbow.jpg # Bad

Don’t use periods in your bucket names

Using a period in the bucket name name may confuse your browser and/or S3’s interpretation of the subdomain, so it’s probably best to just avoid it.

Run a Development Server

Most browsers won’t let you access files using the file:// protocol. To get around this, use python’s simpleServer to run a local server on port 8000:

python -m SimpleHTTPServer

Some browsers give localhost different privileges than regular domains, so open your server at lvh.me:8000 instead of localhost:8000. lvh.me is a domain that somebody bought and pointed at 127.0.0.1 expressly for this purpose. How nice of them!

Refresh Often

Google Chrome has a tendency to cache images for a bit, regardless of the site from which you’re requesting them. Sometimes you have to force-refresh when you see this error in Chrome’s Javascript console:

Cross-origin image load denied by Cross-Origin Resource Sharing policy.

Don’t Taint the Canvas

When attempting to read data from an image on another domain using a Canvas function like getImageData (which tools like Color Thief rely on), you can’t read the data if the image is already present in the DOM. Instead you must use Javascript to create a new DOM element, then assign its crossOrigin and src attributes, as depicted in this coffeescript snippet:

$ ->
  $('#rainbow').load ->  
    img = new Image
    canvas = document.createElement("canvas")
    ctx = canvas.getContext("2d")
    img.crossOrigin = "Anonymous"
    img.src = this.getAttribute('src')

    img.onload = =>
      canvas.width = img.width
      canvas.height = img.height
      ctx.drawImage(img, 0, 0)
      for rgb in createPalette(img, 5)
        color = "rgb(#{rgb.join(", ")})"
        $("#colors").append("<li style='background-color:#{color}'></li>")      

Further Reading

Here are a handful of links that helped me arrive at this working solution:

A Better MacVim Icon

Today my awesome new teammate @mattonrails helped me trick out my vim setup. I’m excited at the prospect of using MacVim regularly as a replacement to TextMate, but I couldn’t bear the thought of seeing MacVim’s nasty Windows-95-lookin’ icon in my dock every day. Fortunately I’m not the only person who feels this way: The talented Drew Yeaton created a very nice replacement icon which should help make my migration from TextMate more bearable.

To install this icon, download MacVim.icns and replace the one in MacVim.app/Contents/Resources.

I’ve heard it said before that you have to try vim five times before you stick to it – here’s to round two!

Stealthy BASHing

Want to keep sensitive data out of your BASH history? Set this environment variable in .bash_profile or .bashrc, then prepend a space to any sensitive command you type and it will not show up in your history.

export HISTCONTROL=ignoreboth

Alternatively here’s a one-off approach that prompts you for your secret value:

heroku config:add SECRET=`read x; echo $x`

No Stinking Dashes

jQuery (as of 1.7.2) doesn’t allow dashes in HTML data- attribute names, so you’re better off using underscores instead. Check out this jsfiddle for evidence.

Update: The dashes are not the problem: there’s a bug in jQuery 1.7.2 regarding attributes that contain a digit after a dash.

And while we’re on the topic, I discovered today that Haml now supports a :data attribute. Give it a (flat) ruby Hash and each of the key/value pairs will be transformed into a custom HTML5 data attribute. Huzzah!

Break It (Mark)down

Pro Tip: Add two spaces to the end of a line in your markdown file and they’ll be converted to a <br> tag!

Haiku

As a heroku customer, I always wondered what words were used to generate app names like electric-samurai-44 and and morning-waterfall-387. Now that I’m on the inside, I know. The class that generates these names is aptly named “Haiku”.

Adjectives: afternoon, blazing, blooming, cold, deep, electric, empty, evening, falling, fierce, floating, freezing, furious, gentle, glowing, growing, high, hollow, morning, pure, quiet, radiant, severe, sharp, simple, smooth, stark, stormy, strong, vivid, warm, young.

Nouns: autumn, beach, cloud, dawn, day, dusk, earth, fire, flower, fog, frost, galaxy, ice, journey, leaf, light, lightning, meadow, mist, mist, moon, mountain, mountain, night, ocean, planet, rain, river, robot, samurai, sky, snow, spring, stone, stream, summer, sunrise, sunset, sword, warrior, water, waterfall, wind, window, winter.

Bonus: If you happen to create a nameless app on Halloween, these adjectives are thrown into the mix: creepy, eerie, ghostly, ghoulish, grisly, haunted, macabre, scary, spooky.

Double-Slash?

Cruising through some heroku source code today, I came across a stylesheet link tag that looked something like this:

<link href='//nav.heroku.com/header.css' media='all' rel='stylesheet' type='text/css'>

Notice the funky double-slash at the beginning of the URL. Weird, right? I’d never seen it either. It’s a protocol-relative URL. Paul Irish explains:

“If the browser is viewing that current page in through HTTPS, then it’ll request that asset with the HTTPS protocol, otherwise it’ll typically request it with HTTP. This prevents that awful “This Page Contains Both Secure and Non-Secure Items” error message in IE, keeping all your asset requests within the same protocol.”

To Branch or Not to Branch

I recently started a heroku email thread in search of a good git branching strategy. I got some good feedback:

@pvh: “Don’t branch! If you have to branch keep it short (like, a day or two tops). In general, everything you do (everywhere!) should be designed to roll out incrementally in many small steps. […] To be fair, we don’t want ‘branches’, so much as we want transient named pull requests that use branches as a transport mechanism.”

@michaelahale: “I prefer short-lived feature branches. That provides an opportunity for review before committing to master. I’m pretty sure everyone would agree that we do not want [the nvie branching model].”

@pedro: “I think even with incremental roll outs branches are still useful. At the API team we normally use branches for anything that is not trivial or that deserves a review. The changes on the branch most of the time are still designed to be rolled out incrementally, but having a branch and pull request allows us to review those changes before they get to master (and as we move close to automated deploys having master always green/deployable is crucial).”

@glenngillen: “Probably a good summation: scottchacon.com/2011/08/31/github-flow.html

@em_csquared: “I think the real answer is that the ‘heroku style’ would be to do what works best for your team. If other teams are doing something you like you should absolutely steal it. And if they’re doing something you don’t then be an example of a better way. […] I’ve seen us internally use both ‘always commit to master as soon as you can’ and ‘never commit to master’ strategies with success.

The NERD Tree

While looking over Chris Continanza’s shoulder today I couldn’t help but notice the awesome tool he was using to navigate directory trees within vim. It’s called nerdtree. Yep, nerdtree. Being a nerd and an arbophile, I installed it right away and am now climbing trees in vim like a pro. Keyboard-based file navigation in the terminal might just mean one less commercial software dependency in my toolbox: Forklift.

Gmail on the iPhone

ProTip: You might think Gmail would be the option to pick here, but the better choice is actually Exchange. Setting up your Gmail account with Exchange means your calendars and contacts get synced in addition to your mail.