Pages

Saturday, February 13, 2010

Curl-ing up with WebFinger and PubSubHubub

This morning I've been playing around with WebFinger and PubSubHubub. One of the great things about open web APIs is that you can tinker around with them without even writing an application. Just use curl!

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-meta
So for gmail we get the explanation of how to get my WebFinger data like so:
$ curl http://gmail.com/.well-known/host-meta
Out 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.com
That 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&amp;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.

1 comment: