Webfinger Process on YQL

■ Webfingerって?

以下のドキュメントをチェックしてください。

emailからメタデータを取得する方法の定義ですね。
例えばそのメタデータOpenIDのエンドポイントが載っていると、脇脱毛おすすめ脱毛エステサロン【大阪】とか呼ばれてたものに近いですね。
詳細な仕様は別途まとめようかと思っています。今回は動作確認から。

■ 動作確認

例として私のYahoo!Incのメアドを使って(晒して)Webfingerの処理をしてみます。

$ curl -I "http://yahoo.com/.well-known/host-meta"
HTTP/1.1 301 Moved Permanently
...
Location: http://www.yahoo.com/.well-known/host-meta
...
$ curl -I "http://www.yahoo.com/.well-known/host-meta"
HTTP/1.1 200 OK
$ curl "http://www.yahoo.com/.well-known/host-meta"
<?xml version='1.0' encoding='UTF-8'?>
<XRD xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0'>
  <Host xmlns='http://host-meta.net/xrd/1.0'>yahoo.com</Host>
  <Link>
    <Title>WebFinger</Title>
    <Rel>http://webfinger.info/rel/service</Rel>
    <Rel>describedby</Rel>
    <URITemplate>http://webfinger.yahooapis.com/?id={%id}</URITemplate>
  </Link>
</XRD>
$ curl -I "http://webfinger.yahooapis.com/?id=ritou_06yjp@yahoo.com"
HTTP/1.1 200 OK
...
$ curl "http://webfinger.yahooapis.com/?id=ritou_06yjp@yahoo.com"
<?xml version="1.0" encoding="UTF-8"?>
<XRD xmlns="http://docs.oasis-open.org/ns/xri/xrd-1.0">
<Subject>acct:ritou06_yjp@yahoo.com</Subject>
<Alias>http://profiles.yahoo.com/ritou06_yjp</Alias>
</XRD>

YQLの動作確認

Google グループにあるとおり、現在YQL上でWebfingerの動作を確認できます。
YQLコンソール(Y!Incのログインが必要)

ここで、好きなメアドを指定するとWebfingerの動作結果が出てきます。
いきなり結果出してもしょうがないので、YQLの処理の流れ?を追ってみます。

$ curl -I "http://datatables.org/alltables.env"
HTTP/1.1 301 Moved Permanently
...
Location: http://www.datatables.org/alltables.env
...
$ curl -I "http://www.datatables.org/alltables.env"
HTTP/1.1 200 OK
...
$ curl "http://www.datatables.org/alltables.env"
...
use 'http://www.datatables.org/data/webfinger.xml' as webfinger;
...

YQLのつくりについては今まで少しも知らなかったのですが、どうやらSQLっぽい文のTableに当たる部分と処理はここで定義されているようです。
webfingerの場合は以下のように"/data/webfinger.xml"ファイルを見るっぽいです。

$ curl -I "http://www.datatables.org/data/webfinger.xml"
HTTP/1.1 200 OK
...
$ curl "http://www.datatables.org/data/webfinger.xml"
<?xml version="1.0" encoding="UTF-8"?>
<table xmlns="http://query.yahooapis.com/v1/schema/table.xsd">
  <meta>
    <sampleQuery>select * from {table} where account='sam@sampullara.com'</sampleQuery>
  </meta>
  <bindings>
    <select itemPath="" produces="XML">
      <urls>
        <url>http://webfinger/</url>
      </urls>
      <inputs>
        <key id='account' type='xs:string' paramType='variable' required='true'/>
      </inputs>
      <execute><![CDATA[
// Remove the acct: if present
account = account.replace(/^acct:/, "");
// Get the domain, later we can support more types
var split = account.split("@");
if (split.length != 2) {
  response.object = <error>must provide a valid account address</error>;
  y.exit();
}
var id = split[0];
var domain = split[1];
// Check for the host-meta
var hostmeta = y.rest("http://" + domain + "/.well-known/host-meta").contentType("application/xml").get();
if (hostmeta.status != 200) {
  response.object = <error>status: {hostmeta.status}</error>;
  y.exit();
}
hostmeta = hostmeta.response;
if (!(hostmeta.respo instanceof XML)) {
  hostmeta = hostmeta.substring(hostmeta.indexOf("?>") + 2).replace("{", "<![CDATA[{]" + "]>");
  hostmeta = eval("var a__ = " + hostmeta + ";a__;");
}
default xml namespace = 'http://host-meta.net/xrd/1.0';
var host = hostmeta..Host;
if (!host) {
  response.object = <error><message>Host not found</message><hostmeta>{hostmeta.response}</hostmeta></error>;
  y.exit();
}
if (host != domain) {
  response.object = <error><message>Domain mismatch</message><hostmeta>{hostmeta.response}</hostmeta></error>;
  y.exit();
}
default xml namespace = 'http://docs.oasis-open.org/ns/xri/xrd-1.0';
var links = hostmeta.Link;
for (var i in links) {
  var link = links[i];
  var rels = link.Rel;
  for (var j in rels) {
    var rel = rels[j];
    if (rel.toLowerCase() == "http://webfinger.info/rel/service" || rel.toLowerCase() == "describedby") {
      var url = link.URITemplate.toString().replace("{%id}", encodeURI(account));
      url = url.replace("{%uri}", encodeURI("acct:" + account));
      url = url.replace("{id}", account);
      url = url.replace("{uri}", "acct:" + account);
      url = url.replace("{userInfo}", id);
      url = url.replace("{%userInfo}", encodeURI(id));
      url = url.replace("{host}", domain);
      url = url.replace("{%host}", encodeURI(domain));
      response.object = y.rest(url).get().response;
      y.exit();
    }
  }
}
      ]]></execute>
    </select>
  </bindings>
</table>

ここで、Webfingerの仕様で定義されている内容によって結果を探す方法がわかります。
YQLはこのxmlファイルを見てそのあとの処理を決めているということなのでしょう。
なので、最終的に"動作確認"のような結果が取得されます。

このような処理の流れ、なかなか興味深いですね。
OpenSocialのContainerとGadgetの関係に似てるのかなって思ったり。

Gmailの場合

$ curl -I "http://gmail.com/.well-known/host-meta"
HTTP/1.1 200 OK
...
$ curl "http://gmail.com/.well-known/host-meta"
<?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'>
  <Host xmlns='http://host-meta.net/xrd/1.0'>gmail.com</Host>

  <Link>
    <Rel>http://webfinger.info/rel/service</Rel>
    <Rel>describedby</Rel>
    <URITemplate>http://www.google.com/s2/webfinger/?q={%id}</URITemplate>
  </Link>
</XRD>

"this host-meta end-point is a pre-alpha work in progress. Don't rely on it."

■ 他にやってる人

YQLの他に、http://webfingerclient-dclinton.appspot.com/でも動作確認できますね。
現在の仕様ぐらいだったら難しくないので、PHPで簡単なWebfinger Clientを作ってみたいと思います。