Firefox拡張入門第7回(独自プロトコルの定義 - ttp)

2ちゃんねるなどでリンク避けとして"ttp://..."を使うことがあります。
今回の拡張では、ttpプロトコルを定義して、"http://..."と同様に扱えるようにしましょう。

  1. ttpプロトコルを扱うXPCOMコンポーネントのクラスを登録します。
  2. そのクラスのnewURI関数で、URIの部品を受け取って、nsIURIのインスタンスを返します。(注)
  3. そのクラスのnewChannel関数で、↑で作ったnsIURIのインスタンスを受け取って、ttpプロトコルのためのnsIChannelのインスタンスを返します。ここではhttpプロトコルのnewChannel関数に処理を丸投げするので簡単です。

(注)"ここではhttpプロトコルのnewURI関数に処理を丸投げするので簡単です"・・・だと芸がないですもんね。

拡張のcomponentsディレクトリ以下に、jsファイルを置けば自動で認識してくれます。

//XPCOMコンポーネントを作るための便利ライブラリを使います。
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");

//プロトコルを扱うクラス
function TTProtocol() {}

TTProtocol.prototype = {
  //クラスの説明
  classDescription: "TTP Protocol",
  //XPCOMコンポーネントのID。 末尾の"...=ttp"に注目。
  contractID      : "@mozilla.org/network/protocol;1?name=ttp",
  //XPCOMコンポーネントのUUID。UUIDは各自で生成します。
  classID         : Components.ID("0bc360c0-a913-11de-8a39-0800200c9a66"),
  QueryInterface  : XPCOMUtils.generateQI([Components.interfaces.nsIProtocolHandler]),
  //プロコトルのスキーム。
  scheme: "ttp",
  //ポート番号は任意。HTTPと同様。
  defaultPort: -1,
  //プロトコルの設定。HTTPと同様。
  protocolFlags: Components.interfaces.nsIProtocolHandler.URI_STD |
                 Components.interfaces.nsIProtocolHandler.URI_LOADABLE_BY_ANYONE,
  //ポート番号は任意。
  allowPort: function TTProtocolAllowPort(aPort, aScheme) {
    return false;
  },
  //URIを処理する関数。
  //部品を受け取ってnsIURIのインスタンスを返します。
  newURI: function TTProtocolNewURI(aSpec, aCharset, aBaseURI) {
    var uri = Components.classes["@mozilla.org/network/standard-url;1"]
                .createInstance(Components.interfaces.nsIStandardURL);
    uri.init(Components.interfaces.nsIStandardURL.URLTYPE_STANDARD, -1,
             aSpec, aCharset, aBaseURI);
    uri.QueryInterface(Components.interfaces.nsIURI);
    return uri;
  },
  //通信チャンネルを作る関数。
  //↑で作ったnsIURIのインスタンスを受け取ってnsIChannelのインスタンスを返します。
  newChannel: function TTProtocolNewChannel(aURI) {
    var IOService = Components.classes["@mozilla.org/network/io-service;1"].
                      getService(Components.interfaces.nsIIOService);
    return IOService.newChannel("h" + aURI.spec, null, null);
  }
};

//コンポーネントの生成。
function NSGetModule(compMgr, fileSpec){
	return XPCOMUtils.generateModule([TTProtocol]);
}


特にclassIDには、各コンポーネント固有のUUIDが必要なのでUUID (GUID) Generator on the WEBで生成してください。

newURI関数

この関数は、絶対アドレスと相対アドレスの両方を扱う役目があります。
絶対アドレスのときは、aSpecに文字列"http://.../main.html"、aBaseURIにnullが入っています。
相対アドレスのときは、aSpecに文字列"../images/01.jpg", aBaseURIにnsIURIのインスタンスで、specが"http://.../main.html"なものが入っています。
newURI関数は、これらの部品をもとに、nsIURIのインスタンスを作って返します。

newURI関数のnsIStandardURL

この部品をイチから料理するのは面倒です。
特に"http://..."の処理は複雑で、":80"があったり、"user@domain"があったり・・・。
似たり寄ったりの処理を"ftp://..."や"file://..."でも使うので、このnsIStandardURLがあります。
今回の"ttp://..."はhttpと同じなので、コイツに任せればおしまいです。
さらに柔軟にURIを作りたいときは、nsISimpleURIを使うこともあるようです。

独自プロトコルの使いどころ

ブラウザの窓の中に、"CSSJavascriptを駆使したブラウザ的なページ"を作りはじめたら、
このテクニックが必要なサインです。ブラウザの中にブラウザを作っていませんか?
例えばGMailの画面は、gmailto:があるとスッキリする気がします。
Webブラウザの未来Web-based protocol handlersに期待しましょう。