プロキシサーバを作りたい
Web 開発を行っていて、僕の環境だけ LiveReload が期待通りに機能せず、500 エラーが頻発するという現象に見舞われた。
原因は LiveReload で、HTML から LiveReload 関連の script タグをいくつか取り除くだけでエラーが出なくなるので、ソースツリーには手を加えずに script タグを取り除く、ということをしたい。
試したのは Chrome Extension で取り除く方法。
これは:
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) { if (tab.url.startsWith("http://ubuntu:8080/")) { chrome.tabs.sendMessage(tab.id, { command: "remove_livereload" }, function(msg) { if (msg !== undefined) { alert(msg); } }); } });
のような感じでコールバックを仕込んで:
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) { if (msg.command === "remove_livereload") { $("script").each(function(index, element) { if ($(element).attr("type") === "text/javascript") { if ($(element).text().indexOf('WEB_SOCKET_SWF_LOCATION = "/__rack/WebSocketMain.swf";') !== -1 || $(element).attr("src") === "/__rack/swfobject.js" || $(element).attr("src") === "/__rack/web_socket.js" || $(element).text().indexOf("RACK_LIVERELOAD_PORT = 35729;") !== -1 || $(element).attr("src") === "/__rack/livereload.js?host=0.0.0.0&port=35729") { $(element).remove(); } } }); } });
のような感じで DOM 操作することで、目的の script タグを除去することができる。
ただし、chrome.tabs.onUpdated.addListener というコールバック名からも分かる通り、HTML をパースして DOM ツリーが完成した後で呼び出されるので、このタイミングだと JavaScript は動いてしまっている。
Chrome API リファレンスをくまなく見てみたところ、以下のイベントコールバックを見つけた。
chrome.webNavigation.onDOMContentLoaded.addListener
これは DOM をパースし終えて、まだ JS の処理を行う前に呼び出されるコールバックなんだけど、このコールバックで通知されるのは、JS がアクセスしようとしている URL だったりして、またちょっと目的を果たせない。
このコールバックでちょっと遊んでみたんだけど、世の中は広告だらけだなぁ、と改めて実感した。Chrome で新規タブを開くだけで、Chrome が Google の広告サーバにアクセスしてるのがわかった。
さて、Chrome Extension の仕様として、コールバック内で DOM 操作などは行えず、サンプルのように sendMessage でメッセージを送り、onMessage コールバック内で行う必要がある。つまり非同期なので、いくら最適なタイミングでコールバックが呼び出されたとしても、実際の処理を行うタイミングで処理が進んでしまっているので、JS が行う通信を完全に防ぐことは Chrome Extension ではできない。
もしかしたら Firefox なら出来るのかもしれないけど、ブラウザ拡張でどうにかするのは諦めて、プロキシサーバを立てて見ようと思う。Nginx が簡単そうだけど、Haskell で汎用的に作りたいような気分。