Home > Latest topics

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

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

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


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

Post a comment

writeback message: Ready to post a comment.

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

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のコメント

最近のつぶやき