Let's start with WebFinger. First, we need to figure out how to get my WebFinger data from gmail. There's standard place to look for that explanation, given a domain name:
http[s]://{domain-name}/.well-known/host-metaSo for gmail we get the explanation of how to get my WebFinger data like so:$ curl http://gmail.com/.well-known/host-metaOut pops an XRD doc that contains a URI template (in bold, below):
<?xml version='1.0' encoding='UTF-8'?>
<!-- NOTE: this host-meta end-point is a pre-alpha work in progress. Don't rely on it. -->
<!-- Please follow the list at http://groups.google.com/group/webfinger -->
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'
xmlns:hm='http://host-meta.net/xrd/1.0'>
<hm:Host xmlns='http://host-meta.net/xrd/1.0'>gmail.com</hm:Host>
<Link rel='lrdd'
template='http://www.google.com/s2/webfinger/?q={uri}'>
<Title>Resource Descriptor</Title>
</Link>
</XRD>
Substitute my email address for {uri} and curl it:$ curl http://www.google.com/s2/webfinger/?q=banksean@gmail.comThat spits out another XRD that describes some other resources associated with my email address:
<?xml version='1.0'?> <XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'> <Subject>acct:banksean@gmail.com</Subject> <Alias>http://www.google.com/profiles/banksean</Alias> <Link rel='http://portablecontacts.net/spec/1.0' href='http://www-opensocial.googleusercontent.com/api/people/'/> <Link rel='http://webfinger.net/rel/profile-page' href='http://www.google.com/profiles/banksean' type='text/html'/> <Link rel='http://microformats.org/profile/hcard' href='http://www.google.com/profiles/banksean' type='text/html'/> <Link rel='http://gmpg.org/xfn/11' href='http://www.google.com/profiles/banksean' type='text/html'/> <Link rel='http://specs.openid.net/auth/2.0/provider' href='http://www.google.com/profiles/banksean'/> <Link rel='describedby' href='http://www.google.com/profiles/banksean' type='text/html'/> <Link rel='describedby' href='http://s2.googleusercontent.com/webfinger/?q=banksean%40gmail.com&fmt=foaf' type='application/rdf+xml'/> <Link rel='http://schemas.google.com/g/2010#updates-from' href='http://buzz.googleapis.com/feeds/103419049256232792514/public/posted' type='application/atom+xml'/> </XRD>Bolded above is the rel='http://schemas.google.com/g/2010#updates-from' URI for my public status updates. Let's fetch that:
$ curl http://buzz.googleapis.com/feeds/103419049256232792514/public/posted
<?xml version='1.0' encoding='utf-8'?> <feed xmlns='http://www.w3.org/2005/Atom' xmlns:thr='http://purl.org/syndication/thread/1.0' xmlns:media='http://search.yahoo.com/mrss' xmlns:activity='http://activitystrea.ms/spec/1.0/'> <link rel='self' type='application/atom+xml' href='http://buzz.googleapis.com/feeds/103419049256232792514/public/posted'/> <link rel='hub' href='http://pubsubhubbub.appspot.com/'/> <!-- lots more feed data not relevant to this discussion -->It's a standard Atom feed. Amongst a lot of other stuff in the beginning is a rel="hub" link. This is where PubSubHubub comes in. Suppose that I want some other service to be notified whenever I post a status update (for instance, I have an app that reposts it in the sidebar of my blog). I could poll this Atom feed but polling is pretty janky. With PuSH I can register a callback to be notified whenever I post an update. Since this feed has a rel="hub" link set to http://pubsubhubbub.appspot.com/, that's where I go to do register a callback.
If you just navigate to http://pubsubhubbub.appspot.com/ with your browser you get a form you can fill out to create a subscription. One of the fields is for a "Callback" url. I don't run any websites that know how to handle PuSH callbacks (or subscription confirmation, for that matter). Luckily there is a test subscriber on appspot that accepts subscription requests for anything: http://pubsubhubbub-subscriber.appspot.com/. To create your own callback URL for testing, just add /subscriber.{some_unique_identifier} to the end of it.
According to the PuSH spec, I should POST some form fields to the hub URL like so:
$ curl -v http://pubsubhubbub.appspot.com/subscribe \ -d hub.callback=http://pubsubhubbub-subscriber.appspot.com/subscriber.banksean\&\ hub.topic=http://buzz.googleapis.com/feeds/103419049256232792514/public/posted\&\ hub.verify=sync\&hub.mode=subscribe\&hub.verify_token=\&hub.secret=And that creates the subscription. Here's the verbose output:
* About to connect() to pubsubhubbub.appspot.com port 80 (#0) * Trying 74.125.19.141... connected * Connected to pubsubhubbub.appspot.com (74.125.19.141) port 80 (#0) > POST /subscribe HTTP/1.1 > User-Agent: curl/7.16.3 (powerpc-apple-darwin9.0) libcurl/7.16.3 OpenSSL/0.9.7l zlib/1.2.3 > Host: pubsubhubbub.appspot.com > Accept: */* > Content-Length: 219 > Content-Type: application/x-www-form-urlencoded > < HTTP/1.1 204 No Content < Cache-Control: no-cache < Content-Type: text/plain < Expires: Fri, 01 Jan 1990 00:00:00 GMT < Date: Sat, 13 Feb 2010 17:41:29 GMT < Server: Google Frontend < Content-Length: 0 < X-XSS-Protection: 0 < * Connection #0 to host pubsubhubbub.appspot.com left intact * Closing connection #0
The 204 No Content response indicates the subscription was created and is active, according to the spec.
And if you go to http://pubsubhubbub-subscriber.appspot.com/ right now (Saturday morning, October 13th 2009), you'll indeed see a bunch of my posts on it.
Ta Da. No code. Just curl. I love the internet.

This was an extremely helpful post. Thanks!
ReplyDelete