Home > Latest topics

Latest topics 近況報告

たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。

萌えるふぉくす子さんだば子本制作プロジェクトの動向はもえじら組ブログで。

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

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

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

Page 2/239: 1 2 3 4 5 6 7 8 9 »

ローカルプロキシっぽいことをローカルプロキシを立てずにやろうとして挫折したことのまとめ - May 28, 2009

FireMobileSimulatorでのローカルプロキシ実装の試みを見て、UxUデバッグ用ローカルプロキシみたいな事をできるようにしてみたい、と思った。

ただ、HTTPのことはこれっぽっちも分からない。ソケット通信も、一応独自プロトコルっぽいものを使って別プロファイルで動作中のFirefoxからテスト結果を受け取るということはできるようになったけど、それ以上の事は分かってないまま。なので、まじめにローカルプロキシを立てる以外の方法で、「特定のURIにアクセスしようとした時だけ、あらかじめ定義しておいたルールに従って別のリソースを返す」ということをできるようにしてみようと考えた。

僕が現在把握している方法としては、以下の物がある。

  1. ローカルプロキシを実装して、その中でリダイレクトするやり方。
  2. http-on-modify-requestイベントのタイミングでリダイレクトするやり方。
  3. nsIContentPoilcyのshouldLoad()の中でリダイレクトするやり方。

1はthorikawaさんが頑張っておいでなので、それに期待している(ソースがGPL互換ならUxUにそのまま入れられるので)。他人のフンドシ。他力本願。ここでは後の2つについての挫折の経緯だけ書き留めておく。

結論を先に言っておくと、2も3も実装上の制限により全滅っぽい。やはり、ローカルプロキシをちゃんと実装するしか完全な解決策はないようだ。thorikawaさん期待age。

http-on-modify-requestイベントを使うやり方

これは、現在FireMobileSimulator等ですでに使われている。nsHttpChannelはリクエストを送信する前にnsIObserverServiceを通じてhttp-on-modify-requestイベントを、レスポンスが返ってきた後にhttp-on-examine-responseとかhttp-on-examine-merged-responseとかhttp-on-examine-cached-responseとかのイベントを通知する(SubjectはnsHttpChannel自身)ので、このタイミングでリダイレクトをしようという話。

リクエストし直す場合

FireMobileSimulatorの場合、nsHttpChannelの現在の通信をキャンセルした上で、nsHttpChannelからnsIWebNavigationを引っ張ってきてloadURI()で新しく通信を始めてる。

var redirected = 'http://www.example.com/';
var observer = {
  observe : function(aSubject, aTopic, aData) {
    if (aTopic == 'http-on-modify-request') {
    var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel)
                              .QueryInterface(Ci.nsIRequest);
    // ここでキャンセル
    httpChannel.cancel(Components.results.NS_ERROR_FAILURE);
    // リクエストし直し
    httpChannel.notificationCallbacks
      .getInterface(Ci.nsIWebNavigation)
      .loadURI(redirected, Ci.nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
  }
};
Cc['@mozilla.org/observer-service;1']
  .getService(Ci.nsIObserverService)
  .addObserver(observer, 'http-on-modify-request', false);

通常のbrowserやiframeの場合はこれでいいんだけど、img要素やXMLHttpRequestからの通信では失敗する。具体的にはhttpChannel.notificationCallbacks.getInterface(Ci.nsIWebNavigation)の時点でエラーになる。例えばXMLHttpRequestによる通信なら、httpChannel.notificationCallbacks.getInterface(Ci.nsIXMLHttpRequest)とすれば元のリクエストを取得できるので、こんな感じで場合に応じて再リクエストの方法を振り分けてやる必要がある。(XMLHttpRequestの場合については、どうやれば再リクエストできるのかまではたどり着けてない。もしかしたら無理なのかも。)

nsIURIのspecを書き換える場合

nsIChannelのURIプロパティはnsIURIインターフェースの読み取り専用プロパティなので、通信先のURIを書き換えることはできない……ように見える。でも実はnsIURIのspecプロパティの方は書き換え可能なので、ここに新しいURIを代入することででもリダイレクトできてしまう。

observe : function(aSubject, aTopic, aData) {
  if (aTopic == 'http-on-modify-request') {
  var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
  httpChannel.URI.spec = redirected;
}

とはいえこの方法は全くお勧めできない。動く場合もあるけど、動かない場合もある、という感じで実に不安定だ。nsHttpChannelの実装を見れば分かるけど、http-on-modify-requestが通知された段階ですでにその時のリクエスト先URIに基づいた初期化処理がいくつか終わってしまっているので、それと矛盾するURIを設定する(例えば、HTTPのリクエストだった物をFile URLにリダイレクトするとか)と、この後の内部処理でエラーが起こるっぽい。

レスポンスヘッダを書き換える

http-on-examine-responseの方ではnsIHttpChannelのsetResponseHeader()を利用できるので、LocationヘッダにURIを設定してみたんだけど、ダメだった。残念ながらヘッダを解釈してくれなかった。

nsHttpChannelの実装を見たら、HTTPのステータスコードが301とか302とかの時だけLocationヘッダを見るようになってた。ステータスコードを保持しているプロパティは読み取り専用なので、強制的にLocationヘッダを読ませるということはできそうにない。

nsIContentPoilcyのshouldLoad()を使うやり方

これはURNサポートなどで実際に使っている。詳しい方法は2007年当時のエントリに書いてあるけど、要約するとこういうことだ。

  1. nsIContentPolicyインターフェースを備えたXPCOMコンポーネントを作成して、
  2. カテゴリマネージャに登録しておき、
  3. 処理したいURIが渡ってきたら、元の通信の読み込みを中止させて、代わりに別のURIで通信を始める。

やってみると、一見上手く動いてくれてるように見えるんだけど、XPConnect特権がある実行コンテキストで作成したImageやnsIXMLHttpRequestのインスタンスからの通信が捕捉されなくて、UxUの用途では使えない感じだった。まあ仮に捕捉できたところで、元の通信を止めて別のURIで通信するようにさせる方法は分かってない(もしかしたら無いかもしれない)んだけど。

あと、shouldLoad()の第2引数はnsIURIインターフェースなのでこれのspecプロパティを書き換えたらどうだろう?と思ってやってみたけど、これもうまくいかなかった。browser要素等での読み込みの場合だと、nsDocShellのInternalLoad()でエラーが発生する。実装を見た感じでは、nsIContentPolicyに処理が渡ってくるより前に元のURIに基づいてセキュリティ関係の機能が初期化されてるので、その後でURIを書き換えたのがいけなかったんじゃないかと思う。

まとめ

とにかく、nsHttpChannelのインスタンスが作成された後からどうこうしようと思うのがそもそも手遅れくさい。それより前のステップでアクセス先のURIを書き換えようと思ったら、ローカルプロキシを立てる以外に手は無いようだ。

いいかげん諦めてMozilla Partyの発表資料作ることにします……

XPCOMのRubyバインディング - Mar 15, 2009

僕をRubyの人にさせるんだったらRXPCOMでも作ってくんないと無理ですよ!(←Ruby覚えてもアドオン開発以外やる気なしなのか!) とかなんとかこないだ会社で言ってたけど、調べてみたらもうありました、rbXPCOM

Thunderbirdでメールの本文を文字列として取得する - Feb 06, 2008

nsIMsgDBHdrとnsIMsgFolderからメールの本文を文字列として取得する方法をあれこれ試してみてこんな感じのところに辿り着きましたとさ。

続きを表示する ...

Chromeウィンドウを最前面にする・最背面にする - Sep 26, 2007

Chromeウィンドウでは、window.open()window.openDialog()の第3引数でalwaysRaisedフラグを指定することで、「常に最前面に表示」状態のウィンドウを開くことができる(通常のスクリプトではこのフラグを使うには特権が必要)。じゃあ、すでに開かれているウィンドウを最前面にすることはできないのか? というのが今日のお題。

フォクすけクロックを使ってみて、Firefoxのウィンドウの下に時計が隠れてしまうのは不便きわまりないと思ったので、これをどうにかしたかった。最初は、前述のalwaysRaisedを使った方法でいけるかなと思ったんだけど、Firefoxのアドオンとして動作する時はこれでいいけどXULRunnerアプリとして動作する時には「開く元の親ウィンドウ」が無いからこれじゃダメだ、と気がついた。

んでちょっと調べてみた所によると、どうもnsIXULWindowインターフェースのzLevelというプロパティをいじることで、ウィンドウの重ね合わせの優先順位を動的に変更できるようだということが分かってきた。

以下のようにいくつかのインターフェースを経由することで、Chromeウィンドウ(nsIDOMWindow)からnsIXULWindowのインターフェースに辿り着くことができる。

var Ci = Components.interfaces;
var XULWindow = window
    .QueryInterface(Ci.nsIInterfaceRequestor)
    .getInterface(Ci.nsIWebNavigation)
    .QueryInterface(Ci.nsIDocShellTreeItem)
    .treeOwner
    .QueryInterface(Ci.nsIInterfaceRequestor)
    .getInterface(Ci.nsIXULWindow);

XULWindow.zLevel = Ci.nsIXULWindow.raisedZ;

zLevelに指定可能な値はnsIXULWindowインターフェースにおいて定数プロパティとして定義されていて、以下の種類がある。

プロパティ実際の値意味
Ci.nsIXULWindow.lowestZ 0 すべてのウィンドウの最背面
Ci.nsIXULWindow.loweredZ 4 すべてのChromeウィンドウの最背面
Ci.nsIXULWindow.normalZ 5 通常
Ci.nsIXULWindow.raisedZ 6 すべてのChromeウィンドウの最前面
Ci.nsIXULWindow.highestZ 9 すべてのウィンドウの最前面

lowestZloweredZの違いは、前者がエクスプローラその他Windowsネイティブのアプリケーションのウィンドウも含めてすべての最背面になるのに対して、後者はあくまでFirefoxのウィンドウの中での最背面になるだけであるということ。loweredZを指定したChromeウィンドウが他のネイティブアプリのウィンドウの下にある時、そのChromeウィンドウをクリックすると、そのChromeウィンドウがネイティブアプリのウィンドウの上に表示されるようになると同時に、それに「押し上げられる」形で、FirefoxのウィンドウすべてがそのChromeウィンドウより前面に表示される。

highestZraisedZもそれと同様に、後者を指定したウィンドウは上にネイティブアプリのウィンドウが重なりうるけど、前者にはいかなるウィンドウも上には重ならない……のかと思いきや、こちらはどっちを指定してみてもraisedZで期待される通りの挙動にしかならなかった(Firefoxのウィンドウの中での最前面になるだけで、他のネイティブアプリのウィンドウが前面にくると、その下に隠れてしまう)。これってバグ?

ちなみに、数値で1~3を指定した場合はloweredZ(4)を指定したのと同じ挙動になるようだ。多分7~8はraisedZ(6)と同じで、それ以上はすべてhighestZ(9)と同じになるんだろうと思うけど……前述の通りhighestZraisedZは実際の挙動に違いが全然無いので、それを確認することはできなかった。

あと、ずっと前にEz Sidebarでこの問題にぶち当たってから気になってるもののずっと直ってないみたいなんだけど、raisedZ以上が指定されたウィンドウがあると、通常のウィンドウで開いたモーダルダイアログが親ウィンドウの下に潜ってしまうという問題が起こる。パスワードの入力を求めるダイアログ等がFirefoxのウィンドウの下に潜ってしまって使い物にならないので、これはマジで困る。どうにかならんものだろうか。

――ということで対策を考えてみた。

var XULWindow = window
     .QueryInterface(Ci.nsIInterfaceRequestor)
     .getInterface(Ci.nsIWebNavigation)
     .QueryInterface(Ci.nsIDocShellTreeItem)
     .treeOwner
     .QueryInterface(Ci.nsIInterfaceRequestor)
     .getInterface(Ci.nsIXULWindow);
var observer = {
  observe : function(aSubect, aTopic, aData)
  {
    if (aTopic == "xul-window-registered") {
      XULWindow.zLevel = Ci.nsIXULWindow.normalZ;
      window.setTimeout(function() {
        XULWindow.zLevel = Ci.nsIXULWindow.highestZ;
      }, 250);
    }
  }
};

var ObserverService = Cc["@mozilla.org/observer-service;1"]
      .getService(Ci.nsIObserverService);
ObserverService.addObserver(MakeOnTopObserver,
                            "xul-window-registered", false);

新しいウィンドウが開かれる直前にウィンドウのzLevelを元に戻して、ウィンドウが開かれた後にまた最前面に戻す。こうすれば最後の問題は回避できる。

XUL/Migemo 0.7.0 - Jun 28, 2007

XUL/Migemo 0.7.0公開した。このバージョンから「Forked Edition」を外して、おこがましくも本家XUL/Migemoの後継とさせていただくことにした。

前のバージョンからの最大の変更点は、ローマ字と平仮名の相互変換処理部分にRuby/Romkanを移植して採用したこと。これはMigemoの大本であるRuby/Migemoが使用しているライブラリでもある。今までは元の処理に増築に増築を重ねたみたいなややこしい物になってたけど、これで、平仮名からローマ字への逆変換も含めて大部分のコードを共通化できて見通しが良くなった、と思う。ただ、速度面で若干遅くなってないかどうか心配ではある。体感できる程の差は無いと思うんだけど。

Ruby/Romkanのコードって無駄がない感じですごいなーと思った。Ruby自体、エレガントにそういう物を作れる言語なんだな、とも。Rubyでたった7KBちょいの物がJavaScriptへの移植で30KB近くにまで膨れ上がってしまうとは……いや、これは単に僕の技術力がヘボいだけか。

あと、Ruby/Romkan自体はRubyのライセンスに準拠していて、RubyはGPL2ということで、XUL/Migemo全体もこの際だからGPL2にしてみた。

XUL/Migemo [Forked Edition] 0.6.xでAPIまわりがゴタゴタしてる件 - Jun 21, 2007

うあああやっちまった。既にAPI使ってくれてる人がいたにもかかわらずAPIを予告なしに変更するというを…… 一応、本家XUL/Migemoと互換のAPI(xulMigemoCoreオブジェクト)も備えていて、そちらは動作を変えないようにしているので、XPCOMを叩かずにそっちを使ってもらっていれば今回の変更の影響は受けなかったと思うんだけど、そんなことを言っても後の祭りというやつで。

なぜこうもグダグダになってしまっているかというと、どうすれば国際化を楽にできるか、サービス同士の絡みを最小限に抑えられるか、という点で自分の中で考えが固まっていなかったからだ。

続きを表示する ...

XUL/Migemo勝手改造版の国際化(?) - Jun 19, 2007

XUL/Migemo勝手改造版のXPCOMコンポーネントの機能のうち、日本語の検索に特化した部分とそれ以外とを分割して、国際化というか多言語対応できるようにしてみた。……まぁ、一番メンドクサイ所(入力から正規表現を作る部分)は実質的に日本語専用なので、あんまり意味が無いと言われればその通りなんだけど。

それだけじゃ何なので、おまけとしてやっつけ仕事で英語用のエンジンを作ってみた。「fx a-o」で「Firefox Add-ons」にヒットするようになったりしてちょっと面白いけど、あんまり役に立たないね……

独自エンジンの作り方も書いたので、暇な人が中国語(ピーイン)入力用エンジンとか作ってみてくれることに期待しておきます。

※21日追記。他人(Mozilla)のことには文句言うくせに性凝りもなくAPIをかなり大幅に変更した。誰もまだ手を付けてないことを祈ろう。

※21日追記(2)。APIの使い方とかエンジンの開発の仕方を英訳した

フォルダの指定で相対パスと絶対パスの両方の指定に対応する - Jun 05, 2007

掲示板で、XUL/Migemo勝手改造版の辞書フォルダの置き場所について相対パスでの指定もできるようにならないか、という要望が出てたのでがんばってみたよ。

以下、解説。

続きを表示する ...

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

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

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

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

続きを表示する ...

Firefoxで独自プロトコルを定義する方法 - Mar 26, 2007

独自のプロトコルというか独自のスキーマを使えるようにしたくてやり方を調べてみたら、あちこちでAdding a New Protocol to Mozillaという文書が紹介されてたんだけど、日本語訳が無かったのでとりあえず気合いと勘で訳してみた。誤訳があったらゴメンナサイ。

続きを表示する ...

Page 2/239: 1 2 3 4 5 6 7 8 9 »

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のつぶやき

オススメ

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