Firefox:リンク別、またはとげのあるフォークによるファイルサイズ

リンクプロパティと拡張機能のスクリーンショット

Link Properties Plus拡張機能の外観の短い履歴と、その主要部分がどのように機能するかの説明が注目されます。

この拡張機能を使用すると、ファイル全体をダウンロードせずに、参照(すべてのリダイレクト後の直接リンクを含む)により、ファイルのサイズ、最終変更日、およびその他のプロパティを参照できます。 もちろん、これらすべてがサーバーによって報告されない限り。





どうでしたか

むかしむかし、 Extended Link Properties拡張があり、機能していました。

その後、すでに閉じられたforum.addonsmirror.netweb.archive.orgにコピー )に更新されたバージョンがありました。



1.3.x

しかし、 2009年6月に、私は何か奇妙なものが欲しかった。 良い(結果の観点から)か悪い(十分な睡眠があれば良い)かどうか、そして時々奇妙な何かが欲しいのです。

その結果、拡張機能はファイルアクション選択ウィンドウで動作することを学びました。 さて、ボーナスとしてマイナーな改善。

残念ながら、組み込みのファイルローダーがファイルのダウンロードを開始し、ユーザーがこのファイルをどうするかを選択するのを待たずに、いくつかの困難がありました。 もちろん、これは別の「問題」です(残念ながら、過剰なトラフィックはもはやそれほど重大ではありません)が、はるかに深刻になりました。ファイルのダウンロード中、同じリンクを使用してリクエストを行うことはできませんでした。が送信されましたが、ダウンロード後に答えが返されます。 もちろん、リクエストがなければ、あなたは何も知りません。リモートサーバーのみがどのファイルを持っているかを知っています。

だから、アイデアはリンクに追加するようになりました "? ランダムな数字 。」 はい、サーバーが変更されたリクエストに他の情報を返す可能性がありますが、これは何もしないよりもはるかに優れています。

ちなみに、新しいバージョンではハックは不要になりましたが、添付ファイルからPDFファイルを開こうとすると1人のユーザーがクラッシュしたり、Thunderbirdがクラッシュしたりしました。

しかし、 AMOでそれを広めることはなんとなく怠け者でした-そして、ダウンロードウィンドウのハックは同じであり、改善を続けることがより面白かったです。 さらに拡張機能の識別子を変更し、元の識別子で既にバージョンをインストールしたユーザーに何らかの方法で通知する必要がありました。

その後、Firefox 3.7a1preでは、コンテキストメニューから[プロパティ]項目が削除され、元の拡張機能が永久に機能しなくなりました。 代替拡張機能であるElement Propertiesのサポートを追加する必要がありました。



1.4.x

そうかもしれないが、 2010年5月に新しいバージョンが登場したが、まだテスト版である。 すでに独自のウィンドウがあり、リモートプロパティダイアログからは独立しています。 まあ、様々な便利な化粧品のささいさなしではできませんでした。

同時に、誤解が発見されました: Extended Link Properties + 、そのコードは私のバージョン1.3.5に完全に対応していました-変更はありましたが、ローカライズにのみ影響しました。

もちろん、私は気分を害しました-彼らは私に尋ねませんでした(そしてAMOにそれを置くように私を説得しようとしませんでした)が、私は時間と神経を無駄にしたくありませんでした。 :)テストされていない変更がたくさんある未完成の新しいバージョンがありました-それを行うのははるかに面白かったです(そしてもっと便利です-はい、これは一種のエゴイズムです)。 そのため、分解の代わりに、FTPリンクのサポートが登場しました。

それまでの間、 バグ455913を修正しました。nsIHelperAppLauncherはコンテンツの長さに関する情報を提供する必要があるため 、ダウンロードダイアログですぐにサイズを確認できるようになりました。



1.5.x

数か月間、ゆっくりと断続的に行われました。2011年4月に1.4.1pre1、リリース-ほぼ2年後、2013年1月にリリースされました。

しかし、新しい識別子で完全なフォークが作成され、デフォルトの非表示メニューの代わりに赤いボタンを備えた新しいバージョンのFirefoxのサポートが追加され、プロパティウィンドウから直接任意のHTTPリファラーを開いて保存する機能が追加されました。 また、Thunderbirdのサポート、ほぼすべてのプロトコルの処理、ファイルへの直接リンクの表示もサポートしています。 そして、かつて長らく約束されていたウィンドウの自動クローズも。



それは、いわば、歴史的な基準でした。

次に、参照によってファイルプロパティを取得する最も単純な実装を作成します。

ゆっくりと最後に、結果のコードへのリンクが提供されます。



今のように、実装

手始めに、コードをテストする最も簡単な方法。

about:configおよびrunでdevtools.chrome.enabled = trueを有効にする必要があります

Web開発-シンプルなJavaScriptエディター、別名Scratchpad(Shift + F4)

次に選択

環境-ブラウザ

それだけです。拡張機能などの権限で実行されるコードをテストできます(したがって、恐ろしいものは実行しないでください)。



リンクプロパティを取得するための最小オプション

任意のリクエストを送信するにはnsIChannelがあり、 nsIIOService.newChannel()またはnsIIOService.newChannelFromURI()のいずれかが必要であることを読むこともできます。

テキストリンクがあります。 つまり、newChannel()を使用することは論理的ですが、実践だけがURIが必要であることを示しています-何も返さないカスタムプロトコル( Custom Buttons )に出くわすか、約:: nsIAboutModule-一般に、エンターテインメント、しかしあなたはそのようなリンクについて何かを見つけることができます。

したがって、詳細はまだ明確ではありませんが、nsIChannelのインスタンスを作成し、そのインスタンスでasyncOpen()を呼び出す必要があることは明らかです。 そして、このasyncOpen()はnsIStreamListenerの実装を最初の引数として受け取り 、送信されたリクエストの結果を知らせます。

おそらく例を示しましょう。

//     : var uriString = "https://addons.mozilla.org/firefox/downloads/latest/413716/addon-413716-latest.xpi"; var referer = "https://addons.mozilla.org/"; var ios = Components.classes["@mozilla.org/network/io-service;1"] .getService(Components.interfaces.nsIIOService); var uri = ios.newURI(uriString, null, null); var scheme = uri.scheme && uri.scheme.toLowerCase(); var channel = scheme == "about" && "nsIAboutModule" in Components.interfaces //    about:  ? Components.classes["@mozilla.org/network/protocol/about;1?what=" + uri.path.replace(/[?&#].*$/, "")] .getService(Components.interfaces.nsIAboutModule) .newChannel(uri) : ios.newChannelFromURI(uri);
      
      





これでnsIChannelのインスタンスができたので、何かする必要があります。 :)

まず、nsIStreamListenerを実装する必要があります。 次に、 nsIHttpChannel.visitRequestHeaders() / nsIHttpChannel.visitResponseHeaders()が便利です(結果のnsIChannelもnsI Http Channelである場合 )。 nsI FTP ChannelにはlastModifiedTimeプロパティがあります。

したがって、次の続きを取得します。

 var observer = { ... }; //     nsIStreamListener  nsIHttpHeaderVisitor var data = []; //         var headers = []; //   ,   if(channel instanceof Components.interfaces.nsIHttpChannel) { //   instanceof   // channel.QueryInterface(Components.interfaces.nsIHttpChannel), //           channel.requestMethod = "HEAD"; // HEAD- channel.setRequestHeader("Referer", referer, false); channel.visitRequestHeaders(observer); headers.push(""); //       } //    ,  nsIFTPChannel    channel instanceof Components.interfaces.nsIFTPChannel; channel.asyncOpen(observer, null);
      
      





もちろん、一般に、必要なくグローバル変数を伝播することは良くありませんが、より視覚的です。 また、サンプルをモジュールやその他のカプセル化に分割するのに問題がある場合は、悪い知らせがあります。 :)



ここで、必要なインターフェイスを実装するオブザーバーオブジェクトを作成してみましょう。

 var observer = { // nsIRequestObserver (nsIStreamListener   ) onStartRequest: function(aRequest, aContext) { if(aRequest instanceof Components.interfaces.nsIHttpChannel) aRequest.visitResponseHeaders(this); else { if("contentType" in channel) data.push(" : " + channel.contentType); if("contentLength" in channel) data.push(" : " + channel.contentLength); if("responseStatus" in channel && "responseStatusText" in channel) data.push(": " + channel.responseStatus + " " + channel.responseStatusText); if("lastModifiedTime" in aRequest && aRequest.lastModifiedTime) { // Firefox 4 var t = aRequest.lastModifiedTime; data.push(" : " + new Date(t > 1e14 ? t/1000 : t).toLocaleString()); } } }, onStopRequest: function(aRequest, aContext, aStatusCode) { if(aRequest instanceof Components.interfaces.nsIChannel && aRequest.URI) data.push(" : " + aRequest.URI.spec); this.done(); }, // nsIStreamListener onDataAvailable: function(aRequest, aContext, aInputStream, aOffset, aCount) { // , -   ,     ,  aRequest.cancel(Components.results.NS_BINDING_ABORTED); }, // nsIHttpHeaderVisitor visitHeader: function(aHeader, aValue) { headers.push(aHeader + ": " + aValue); switch(aHeader) { //   -    case "Content-Length": data.push(" : " + aValue); break; case "Content-Type": data.push(" : " + aValue); break; case "Last-Modified": data.push(" : " + new Date(aValue).toLocaleString()); } }, done: function() { alert( data.join("\n") + "\n\n:\n" + headers.join("\n") ); } };
      
      







その結果、次のメッセージが表示されます。

  : application/x-xpinstall  : 26  2013 . 0:46:30  : 46897  : https://addons.cdn.mozilla.net/storage/public-staging/413716/link_properties_plus-1.5.1-fx+sm+tb.xpi : Host: addons.mozilla.org User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:20.0) Gecko/20100101 Firefox/20.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: ru-ru,ru;q=0.8,en-us;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Referer: https://addons.mozilla.org/ Server: nginx X-Backend-Server: web13.addons.phx1.mozilla.com Content-Type: application/x-xpinstall Accept-Ranges: bytes Last-Modified: Tue, 26 Feb 2013 00:46:30 GMT X-Cache-Info: caching Content-Length: 46897 Cache-Control: max-age=79492 Expires: Sun, 07 Apr 2013 17:32:01 GMT Date: Sat, 06 Apr 2013 19:27:09 GMT
      
      







リダイレクト追跡

リダイレクトの追跡には、 nsIChannel.notificationCallbacksがあります 。 つまり、追加する必要があります

 channel.notificationCallbacks = observer;
      
      





チャンネルとオブザーバーオブジェクトを作成した後、オブザーバーオブジェクト自体にnsIInterfaceRequestor実装を追加します。 同時に、 nsIInterfaceRequestor.getInterface()nsIChannelEventSinkの実装を返してリダイレクトを処理できる必要があります。

そこで、2つの既存の情報の隣にリダイレクト情報の「受信者」を追加します。

 var redirects = []; //     
      
      





そして、出力関数を更新します

  done: function() { alert( data.join("\n") + "\n\n:\n" + redirects.join("\n") + "\n\n:\n" + headers.join("\n") ); }
      
      





そして、私たちのオブザーバーに追加する必要があります

 var observer = { ... // nsIInterfaceRequestor getInterface: function(iid) { if(iid.equals(Components.interfaces.nsIChannelEventSink)) return this; throw Components.results.NS_ERROR_NO_INTERFACE; }, // nsIChannelEventSink onChannelRedirect: function(oldChannel, newChannel, flags) { // Gecko < 2 this.onRedirect.apply(this, arguments); }, asyncOnChannelRedirect: function(oldChannel, newChannel, flags, callback) { //    ,    ! callback.onRedirectVerifyCallback(Components.results.NS_OK); this.onRedirect.apply(this, arguments); }, onRedirect: function(oldChannel, newChannel, flags) { if(!redirects.length) //     redirects.push(oldChannel.URI.spec); // https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIChannelEventSink#Constants var ces = Components.interfaces.nsIChannelEventSink; var types = []; if(flags & ces.REDIRECT_TEMPORARY) types.push(""); if(flags & ces.REDIRECT_PERMANENT) types.push(""); if(flags & ces.REDIRECT_INTERNAL) types.push(""); redirects.push("=> (" + types.join(", ") + ") " + newChannel.URI.spec); }, ...
      
      







その結果、結論が追加されます

 : https://addons.mozilla.org/firefox/downloads/latest/413716/addon-413716-latest.xpi => () https://addons.mozilla.org/firefox/downloads/latest/link-properties-plus/addon-link-properties-plus-latest.xpi => () https://addons.mozilla.org/firefox/downloads/file/185918/link_properties_plus-1.5.1-fx+sm+tb.xpi => () https://addons.cdn.mozilla.net/storage/public-staging/413716/link_properties_plus-1.5.1-fx+sm+tb.xpi
      
      







プライベートモード

プライベートモードのサポートを追加できるようになりました。 記事「 ウィンドウごとのプライベートブラウジングのサポート」には、適切な例があります。

 var channel = Services.io.newChannel("http://example.org", null, null); channel.QueryInterface(Components.interfaces.nsIPrivateBrowsingChannel); channel.setPrivate(true); // force the channel to be loaded in private mode
      
      





そして、プライベートモードが既にサポートされていることを確認できます。

 if( private // - && "nsIPrivateBrowsingChannel" in Components.interfaces && channel instanceof Components.interfaces.nsIPrivateBrowsingChannel && "setPrivate" in channel ) channel.setPrivate(true);
      
      





もちろん、実際のコードでは、リンクソースのプライバシーを判断する必要があります。 しかし、これについてはすでに書きました。 リソースの助けを借りて、 //gre/modules/PrivateBrowsingUtils.jsmを使用すると、任意のウィンドウオブジェクトのプライバシーを確​​認できます。



合計

結果は単一のファイルです:

https://gist.github.com/Infocatcher/5327631

リビジョンでは、機能のビルドアップを追跡できます。リダイレクト処理の追加とプライベートモードのサポートです。



以上です。 残っているのは、エラー処理を追加し、ユーザーフレンドリなビューに変換し、alert()をより便利なものに置き換え、関数呼び出しを添付して、インターフェイスにリンクプロパティを取得することです。



PSリダイレクトトラッキングとプライベートモードのサポートを備え拡張機能の新しいバージョンは、まだ検証待ちです。



All Articles