AirProxyのmixiアプリとニコニコ動画対応

今日はデータベースとは関係のないネタです。
AirProxyというソフトウェアをご存知でしょうか。AirProxyはダイヤルアップ接続やAIR-EDGEなどのナローバンド環境において、ブラウズ対象のテキスト・画像を圧縮することでレスポンスを改善することができるHTTPプロキシソフトウェアです。
最近はイー・モバイルUQ WiMAXなどモバイルブロードバンド環境が整備されてきたので、AirProxyを使っている人は減ってきたかもしれませんね。私はAIR-EDGEユーザなのですが、先日発売されたPocket WiFiの評判が良いので買うかどうか悩んでいるところです。
AirProxyはそうしたAIR-EDGEユーザの延命にも一役買っているわけですが、最新バージョンが2007年4月リリースということでかれこれ2年ほど更新されていません。そしてこの2年の間にうまく表示されないサイトが出てきていて、問題になっています。
というわけで、簡単に直してみました。

mixiアプリ対応

AirProxy経由でmixiアプリにアクセスすると、最初の画面がいつまで待っても出ません。これは以下のようなAjaxリクエストに失敗しているためです。

GET /social/data/people/@owner/@self?(略) HTTP/1.1
Keep-Alive: 300
Accept-Encoding: gzip,deflate
Host: (略).app0.mixi-platform.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; ja; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.7
Referer: (略)
X-Mixi-Platform-IO: 1
Content-Type: application/json
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: ja,en-us;q=0.7,en;q=0.3

HTTPリクエストヘッダにContent-Type: application/jsonが指定されているのですが、このHTTPリクエストにはボディが無いようです。ところがAirProxyはクライアントからHTTPリクエストボディが来るのをずっと待ってしまっています。
そのためContent-Typeがapplication/jsonのときは、HTTPリクエストボディを待たないように修正します。

*** org/http/server/HttpInputStream.java	2006-01-30 00:58:08.000000000 +0900
--- src/http/server/HttpInputStream.java	2009-11-29 19:33:04.000000000 +0900
***************
*** 209,214 ****
--- 209,220 ----
  		this.isGzipEncoding = header.isGzipEncoding();
  		this.hasContent = (header.getContentType() != null);
  		this.contentLength = header.getContentLength();
+ 		
+ 		if (contentLength == -1 && header.getContentType() != null
+ 				&& header.getContentType().indexOf("application/json") > -1) {
+ 			this.hasContent = false;
+ 		}
+ 		
  		return header;
  	}

これでAjaxリクエストが通るようになります。ただしこれはあくまで応急処置ですので、他のサイトで不具合が出る可能性がある点に注意してください。きちんと直すにはhttp.server.HttpInputStream#readHeader()を作り直す必要があると思います。

ニコニコ動画対応

AirProxy経由でニコニコ動画にアクセスすると、プレイヤーから「動画情報の読み込みに失敗しました」などのエラーが返されて動画を再生することができません。また、ローカルにキャッシュされているなどの要因により動画を再生できた場合でも、肝心のコメントが表示されません。
これは、動画プレイヤーがgzip圧縮されたコンテンツを読み込めないためです。AirProxyはHTTPレスポンスヘッダのContent-Typeを見て、圧縮可能な形式であれば圧縮を行うことによって通信量を削減するのですが、残念ながら動画プレイヤーはその圧縮されたデータを読み込むことができないようです。ちなみにHTTPリクエストヘッダにはAccept-Encoding: gzip,deflateがついているので、一方的にAirProxyの不具合というわけでもなさそうです。
うまくContent-Typeやその他のヘッダで振り分けることができればよいのですが、決まったパターンは見つかりませんでした。そのため、不本意ながら以下のようなURLフィルタリングで対処しました。

*** org/airproxy/extension/ExtensionManager.java	2006-01-22 15:07:56.000000000 +0900
--- src/airproxy/extension/ExtensionManager.java	2009-11-29 20:07:04.000000000 +0900
***************
*** 47,52 ****
--- 47,57 ----
  			contentType = contentType.toLowerCase();
  		}
  
+ 		if ((url.indexOf("flapi.nicovideo.jp") > -1)
+ 				|| (url.indexOf("msg.nicovideo.jp") > -1)) {
+ 			return null;
+ 		}
+ 
  		if(contentType.startsWith("image/")) {
  			return imageExtensions; // new Extension[] { imageExtension };
  		}

これで動画やコメントが再生できるようになります。ただし、ニコニコ動画がバージョンアップして仕様変更するたびにメンテナンスが必要となります。
動画プレイヤーに返されるデータのContent-Typeは、今のところtext/plain、text/xml、application/xml、application/jsonの4種類となっています。いっそのことこれら4種類のコンテンツは圧縮をあきらめてしまった方がよいかもしれません。その場合、圧縮対象はtext/htmlのみとなります。

感想

週末しばらくAirProxyのソースを眺めていましたが、最近はAjaxなど新しい技術が出てきているので今後もこうした個別対処は避けられない印象です。またWebブラウザやWebサーバに不具合があったとしても、AirProxyを使うことで表示が崩れるのであればAirProxy側で対策を行わなければならないので、なかなか厳しいところです。
本来こうしたソフトウェアが必要なくなるぐらいにインフラが整備されるのが、理想的なのでしょうね。