Home > Latest topics

Latest topics > nsIContentPolicyによる内部でのリダイレクト

宣伝1。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

宣伝2。Firefox Hacks Rebooted発売中。本書の1/3を使って、再起動不要なアドオンの作り方のテクニックや非同期処理の効率のいい書き方などを解説しています。既刊のFirefox 3 Hacks拡張機能開発チュートリアルと併せてどうぞ。

Firefox Hacks Rebooted ―Mozillaテクノロジ徹底活用テクニック
浅井 智也 池田 譲治 小山田 昌史 五味渕 大賀 下田 洋志 寺田 真 松澤 太郎
オライリージャパン

nsIContentPolicyによる内部でのリダイレクト - Mar 27, 2007

URNサポートをさらに更新して、今度こそあらゆる場面でちゃんとURNをURLにリダイレクトできるようにした。

何かヒントはないかと思ってbbs2chreaderのb2rThreadRedirector.jsを見たら、nsIContentPolicyの実装?を使って内部的にリダイレクトを行えるようだということが分かった。リダイレクト処理をプロトコルハンドラから分離して同様の実装に移してみたところ、うまくいった。URN用のプロトコルハンドラは現在では、単にurn:というスキーマのURIへのアクセスを受け付けるための役割しか果たしていない。

というわけで、以下、Firefox内部でリダイレクトを行う方法をメモしておこう。

FirefoxにはnsICategoryManagerという機能があって、nsIContentPolicyの型のオブジェクトを登録しておくことで、URIの読み込み処理において一種のフィルタリングを行えるようになっている。

nsIContentPolicyのオブジェクトはshouldLoadというメソッドを持つのだけれども、このメソッドの返り値がComponents.interfaces.nsIContentPolicy.ACCEPTであればFirefoxはそのままURIの読み込みを継続する。Components.interfaces.nsIContentPolicy.REJECT_REQUESTであれば、FirefoxはそのURIの読み込みを中断する、という動作になる。メソッドの引数には読み込もうとしているURI、Content-Type、読み込み元のページの情報などが渡されるので、「こういうURIが特定のページから読み込まれそうになったらブロックする」みたいな判別を行うことができる。

というわけで手順。

まずJavaScriptでのXPCOMコンポーネントの作り方に従って、nsIContentPolicyのインターフェースを持ったコンポーネントを作成する。今回は新しいインターフェースを定義するわけではないので、IDL定義を書く必要はない。コンポーネントの内容を定義するJavaScriptのファイルを用意するだけでよい。

このコンポーネント定義においては、nsIContentPolicyのインターフェースが要求しているプロパティとメソッドを一通り用意しておく必要がある。以下の例のTYPE_OTHERからshouldProcessまでがそれ。


const nsIContentPolicy = Components.interfaces.nsIContentPolicy;

function MyContentPolicy() {
}

MyContentPolicy.prototype = {
  contractID       : '@piro.sakura.ne.jp/mycontentpolicy;1',
  classDescription : 'My Content Policy',
  classID          : Components.ID('{********-****-****-****-************}'),

  QueryInterface : function(aIID)
  {
    if (!aIID.equals(Components.interfaces.nsIContentPolicy) &&
      !aIID.equals(Components.interfaces.nsISupportsWeakReference) &&
      !aIID.equals(Components.interfaces.nsISupports))
      throw Components.results.NS_ERROR_NO_INTERFACE;
    return this;
  },

  TYPE_OTHER       : nsIContentPolicy.TYPE_OTHER,
  TYPE_SCRIPT      : nsIContentPolicy.TYPE_SCRIPT,
  TYPE_IMAGE       : nsIContentPolicy.TYPE_IMAGE,
  TYPE_STYLESHEET  : nsIContentPolicy.TYPE_STYLESHEET,
  TYPE_OBJECT      : nsIContentPolicy.TYPE_OBJECT,
  TYPE_DOCUMENT    : nsIContentPolicy.TYPE_DOCUMENT,
  TYPE_SUBDOCUMENT : nsIContentPolicy.TYPE_SUBDOCUMENT,
  TYPE_REFRESH     : nsIContentPolicy.TYPE_REFRESH,
  ACCEPT           : nsIContentPolicy.ACCEPT,
  REJECT_REQUEST   : nsIContentPolicy.REJECT_REQUEST,
  REJECT_TYPE      : nsIContentPolicy.REJECT_TYPE,
  REJECT_SERVER    : nsIContentPolicy.REJECT_SERVER,
  REJECT_OTHER     : nsIContentPolicy.REJECT_OTHER,

  shouldLoad : function(aContentType, aContentLocation,
                        aRequestOrigin, aContext, aMimeTypeGuess, aExtra) {
  },
  shouldProcess : function(aContentType, aContentLocation,
                           aRequestOrigin, aContext, aMimeTypeGuess, aExtra) {
  }
};

リダイレクトを行う場合は、shouldProcessは常にACCEPTを返すようにしておいて、shouldLoadの方でリダイレクト処理を行う。URNサポートの場合なら「読み込もうとしているURIのスキーマがurn:の時、対応するURLにリダイレクトする」という事なので、こんな感じになる。


shouldLoad : function(aContentType, aContentLocation,
                      aRequestOrigin, aContext, aMimeTypeGuess, aExtra) {
  if (aContentLocation.scheme == 'urn') {
    // URNの時はリダイレクトする(ここに処理を書く)
  }
  else {
    return this.ACCEPT; // URN以外は素通し
  }
},
shouldProcess : function(aContentType, aContentLocation,
                         aRequestOrigin, aContext, aMimeTypeGuess, aExtra) {
    return this.ACCEPT;
}

実際のリダイレクト処理というのは、現在のコンテキストに対して別のURIを読み込むように指示して、代わりに現在読み込もうとしているURIの読み込み処理を中断するということになる。これは以下のように書く。


aContext.loadURI('http://www.example.jp/', null, null);
return this.REJECT_REQUEST;

で、これだけだと単にそういうコンポーネントが定義されているというだけで、何の処理も行ってくれない。これをnsICategoryManagerのフィルタとして使うには、nsICategoryManagerにこのコンポーネントを登録してやらないといけない。そのために、モジュール定義のregisterSelfに以下の強調部分を書き加える。

registerSelf : function (aComponentManager, aFileSpec, aLocation, aType)
{
  if (this._firstTime) {
    this._firstTime = false;
    throw Components.results.NS_ERROR_FACTORY_REGISTER_AGAIN;
  }
  aComponentManager = aComponentManager
                       .QueryInterface(Components.interfaces.nsIComponentRegistrar);

  const categoryManager = Components.classes['@mozilla.org/categorymanager;1']
                          .getService(Components.interfaces.nsICategoryManager);
  for (var key in this._objects) {
    var obj = this._objects[key];
    aComponentManager.registerFactoryLocation(obj.CID, obj.className, obj.contractID, aFileSpec, aLocation, aType);

    categoryManager.addCategoryEntry('content-policy', obj.contractID,
                                     obj.contractID, true, true);
  }
},

これで、このファイルで定義されたコンポーネントがnsICategoryManagerに登録されて、フィルタとして機能するようになる。

分類:Mozilla > XUL, , , , , , , 時刻:13:54 | Comments/Trackbacks (0) | Edit

Comments/Trackbacks

TrackBack ping me at


の末尾に2014年1月19日時点の日本の首相のファミリーネーム(ローマ字で回答)を繋げて下さい。例えば「noda」なら、「2007-03-27_redirect.trackbacknoda」です。これは機械的なトラックバックスパムを防止するための措置です。

Post a comment

writeback message: Ready to post a comment.

2014年1月19日時点の日本の首相のファミリーネーム(ひらがなで回答)

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のつぶやき

オススメ

Mozilla Firefox ブラウザ無料ダウンロード