HTTP リクエストへの介入

HTTP リクエストへ介入するには webRequest API を用います。 この API を利用すると、HTTP リクエストの生成段階における様々なタイミングにリスナー関数を追加できます。 追加したリスナーの中では、以下の処理を行うことができます。

  • リクエストヘッダーや本体とレスポンスヘッダーにアクセス
  • リクエストのキャンセルやリダイレクト
  • リクエスト・レスポンスヘッダーの改変

この記事では、以下の 3 つの目的それぞれについて、webRequest モジュールの使い方を説明します。

  • リクエストの生成時にリクエスト URL を記録する
  • リクエストをリダイレクトする
  • リクエストヘッダーを改変する

リクエスト URL の記録

まず "requests" というディレクトリーを新しく作成しましょう。 このディレクトリー内に "manifest.json" というファイルを作成し、以下を追加してください。

json
{
  "description": "Demonstrating webRequests",
  "manifest_version": 2,
  "name": "webRequest-demo",
  "version": "1.0",

  "permissions": ["webRequest", "<all_urls>"],

  "background": {
    "scripts": ["background.js"]
  }
}

続いて "background.js" というファイルを作成し、以下のスクリプトを書き込んでください。

js
function logURL(requestDetails) {
  console.log(`Loading: ${requestDetails.url}`);
}

browser.webRequest.onBeforeRequest.addListener(logURL, {
  urls: ["<all_urls>"],
});

ここでは、リクエストを作成する直前にonBeforeRequest (en-US) を利用して、 logURL() 関数を呼んでいます。 logURL() 関数では、イベントオブジェクトからリクエスト URL を取得し、ブラウザーのコンソールに出力しています。 {urls: ["<all_urls>"]} パターン は、すべての URL に対する HTTP リクエストに介入することを表しています。

試してみるには次のようにします。

ブラウザーコンソールには、ブラウザーがリクエストされたすべてのリソースの URL が表示されるはずです。 例えば、このスクリーンショットは、 Wikipedia のページを読み込んだときの URL を示しています。

ブラウザーコンソールのメニュー : 拡張機能から URL を表示

リクエストのリダイレクト

さて、 webRequest を使って HTTP リクエストをリダイレクトさせてみましょう。まず最初に manifest.json を以下の内容へ変更します。

json
{
  "description": "Demonstrating webRequests",
  "manifest_version": 2,
  "name": "webRequest-demo",
  "version": "1.0",

  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "https://developer.mozilla.org/"
  ],

  "background": {
    "scripts": ["background.js"]
  }
}

変更点は次の通りです。

  • webRequestBlockingpermission に追加しました。 この特別な権限は、拡張機能がリクエストを変更したいときにリクエストされます。
  • <all_urls> 権限を個々のホスト権限に置き換えてください。これはリクエストされた権限数を最小限にするための良い習慣です。

続いて "background.js" を以下のように書き換えます。

js
let pattern = "https://developer.mozilla.org/*";
const targetUrl =
  "https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_second_WebExtension/frog.jpg";

function redirect(requestDetails) {
  console.log(`Redirecting: ${requestDetails.url}`);
  if (requestDetails.url === targetUrl) {
    return;
  }
  return {
    redirectUrl: targetUrl,
  };
}

browser.webRequest.onBeforeRequest.addListener(
  redirect,
  { urls: [pattern], types: ["image"] },
  ["blocking"],
);

ここでも onBeforeRequest (en-US) イベントリスナーを使用し、それぞれのリクエストが行われる直前に関数を実行します。 この関数は redirectUrl を関数内で指定された対象の URL に置き換えます。この場合、 2 つめの拡張機能 にあるカエルの画像を指定します。

今回はすべてのリクエストに介入しないこととします。{urls:[pattern], types:["image"]} というオプションにより、(1) "https://developer.mozilla.org/" 配下の URL であり、かつ (2) 画像リソースなリクエストのみに介入します。 詳細は webRequest.RequestFilter (en-US) を参照してください。

また、"blocking" というオプションも渡していることに注意してください。 このオプションは、リクエストを改変する際に必ず必要となります。これによってネットワークリクエストがリスナー関数にブロックされるため、リスナー関数から処理が戻るまでブラウザーは待機します。 "blocking" に関する詳細は webRequest.onBeforeRequest (en-US) のドキュメントを参照してください。

それでは実際に動かしてみましょう。画像が多く載っている MDN のページ(the page listing extension user interface components など)を開き、拡張機能をリロード します。終わったら MDN のページをリロードしてみましょう。

ページ内の画像をカエルの画像に置き換えた場合

リクエストヘッダーの改変

最後の例として、webRequest を使ってリクエストヘッダーを改変してみましょう。ここでは、ブラウザーが Opera 12.16 と認識されるように "User-Agent" ヘッダーを改変してみます。ただし、"http://useragentstring.com/" の配下へアクセスした際にのみ改変することとします。

"manifest.json" を更新して、以下のように http://useragentstring.com/ を記載します。

json
{
  "description": "Demonstrating webRequests",
  "manifest_version": 2,
  "name": "webRequest-demo",
  "version": "1.0",

  "permissions": [
    "webRequest",
    "webRequestBlocking",
    "http://useragentstring.com/"
  ],

  "background": {
    "scripts": ["background.js"]
  }
}

"background.js" を以下のように書き換えます。

js
let targetPage = "http://useragentstring.com/*";

let ua =
  "Opera/9.80 (X11; Linux i686; Ubuntu/14.10) Presto/2.12.388 Version/12.16";

function rewriteUserAgentHeader(e) {
  e.requestHeaders.forEach((header) => {
    if (header.name.toLowerCase() === "user-agent") {
      header.value = ua;
    }
  });
  return { requestHeaders: e.requestHeaders };
}

browser.webRequest.onBeforeSendHeaders.addListener(
  rewriteUserAgentHeader,
  { urls: [targetPage] },
  ["blocking", "requestHeaders"],
);

ここでは、リクエストヘッダーが送信される直前に関数を実行するため onBeforeSendHeaders (en-US) イベントリスナーを利用しています。

このリスナー関数は、 URL が targetPageパターンに一致したリクエストに対してのみ呼び出されます。 ここでも再び、"blocking" がオプションとして与えられていることに注意してください。また、"requestHeaders" もオプションで渡すことにより、送信予定のリクエストヘッダーを含んだ配列がリスナー関数に渡されます。 これらのオプションに関しては webRequest.onBeforeSendHeaders (en-US) で詳細を確認してください。

リスナー関数では、リクエストヘッダーの配列から "User-Agent" ヘッダーを探し、ヘッダーの値を変数 ua の値で置き換え、改変された配列を最後に返しています。この改変された配列は、やがてサーバーへ送信されることとなります。

それでは実際に動かしてみましょう。 useragentstring.com へアクセスし、自分のブラウザーが Firefox と判定されることを確認します。ここで拡張機能を再読み込みし、 useragentstring.com のページを再読み込みします。すると、先程 Firefox と判定されたのは Opera になっているはずです。

useragentstring.com が変更されたユーザーエージェント文字列の詳細を示している様子

詳細情報

webRequest API でできることを詳しく知りたい場合は、リファレンスドキュメントを参照してください。