Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

New protocol support in NSURLSession

こんにちは、間藤です。
今回はWWDC15の以下のセッションに関する話題を取り上げます。

Networking with NSURLSession - WWDC 2015 - Videos - Apple Developer

この中の「New protocol support in NSURLSession」にフォーカスしてみようと思います。つまり、HTTP/2サポートに関する話です。

You Only Need an HTTP/2 Server

NSURLSessionを使って通信処理を実装していれば、アプリの実装上HTTP/2対応を意識する必要はないということですね。サーバがHTTP/2に対応すればよいと。
これで話を終えるわけにもいかないので、本当にそうなのか確認してみようと思います。

その通信はHTTP/2なのか?

NSURLSessionで通信するサンプル実装を書くのは難しくありません。問題は、その通信のプロトコルがHTTP/2なのかをどう確認するかです。残念なことにNSURLSession(あるいはNSHTTPURLResponse)から確認することは出来ないようです。

How to check in IOS 9 if HTTP/2 is used? | Apple Developer Forums

自前でHTTP/2に対応したサーバをたてて確認することも可能ですが、もっと手軽に確認する方法はないのか確認したところ、以下の情報を見つけました。

www.floriangoessler.de

「How to test whether we are communicating via HTTP/2?」のところを読むと、おおよそ以下のようなことが書いてあります。

  • 残念ながらNSURLSessionは利用するプロトコルに関する情報を我々に与えてくれない
  • CharlesはHTTP/2(とSPDYも)未対応
  • WiresharkはEl Capitanで動かすにはいくつか問題があって使えない
  • Akamaiが提供するテストページを利用しよう!

なお、パケットキャプチャ(CharlesやWireshark)の話は、後ほど取り上げようと思います。

AkamaiのテストページにHTTP/2対応のブラウザでアクセスすると、

f:id:IntelligentTechnology:20151007155149j:plain

と表示されます。
非対応ブラウザでアクセスすると、

f:id:IntelligentTechnology:20151007155331j:plain

となります。
親切なことに検証アプリもGitHubに公開されています。

FGoessler/iOS-HTTP2-Test · GitHub

このサンプルでは、Akamaiテストページに接続し、レスポンスに"You are using HTTP/2 right now!"という文字列が含まれているかをチェックすることで、プロトコルを確認するようになっています。

NSURLConnectionはDeprecated

iOS9でNSURLConnectionはDeprecatedになりました。そして、NSURLConnectionを利用すると、サーバがHTTP/2対応していても、プロトコルはHTTP/2にはなりません。(詳細は後述します)
上に紹介した検証アプリでは、NSURLSessionとNSURLConnectionでそれぞれ通信し、そのことを確認しています。さらに、検証アプリは、両者のパフォーマンスも比較するようになっています。

Encrypted connection only

WWDCのセッションで言われているように、暗号化された通信のみがHTTP/2になります。

UIWebViewは?

上の検証アプリでは、UIWebViewについては確認されていなかったので、別途確認をしてみました。単にUIWebViewでAkamaiテストページをロードするサンプルで動作確認しました。利用端末はiPad Air(iOS9.0)です。
結果は以下の通りです。

f:id:IntelligentTechnology:20151007163952j:plain

UIWebViewはSPDY対応どまりということでしょうか?

パケットキャプチャの話

私は、iOS端末(Android端末もですが)の通信内容を確認する際、Charlesを利用しています。非常によくできたツールなので、大変助かっています。ただ、残念なことにHTTP/2にまだ対応していません。

Web Performance: Useful tools for HTTP/2 debugging | Akamai

将来的には対応してくれるものと期待しています。
一方、定番ツールであるWiresharkは対応していますので、その必要が生じた場合は当面これを使っていくことになるのかなと思います。Charlesが便利過ぎることもあって、私はあまりWiresharkには慣れていないのですが、あれこれと今回の確認に利用してみました。使ってみて思いましたが、Wiresharkのほうが生のパケットを確認できるので、こちらを使っていたほうが勉強にはなるなぁと。
利用したバージョンは、Development Release (1.99.9) です。OS XユーザはDevelopment Releaseを利用するように推奨されていましたので、これに素直に従いました。なお、上に紹介したページでは、El CapitanだとWiresharkがうまく動作しないといったことが書かれていましたが、私はまだアップグレードしていないこともあり、そういった問題には遭遇していません。

iOS9のUIWebView(再掲)

前述の通り、UIWebView上でAkamaiテストページにアクセスすると、SPDYで通信されているいう結果になりました。そのことをWiresharkで確認してみます。
TLSハンドシェイクのClientHelloで以下のようなパケットを送っていることが確認できました。※ALPN(Application Layer Protocol Negotiation)でネゴシエーションしているようです。

f:id:IntelligentTechnology:20151008170648j:plain

応答であるServerHelloも念のために確認すると、

f:id:IntelligentTechnology:20151008170907j:plain

確かにSPDYを利用しているようです。
一方、NSURLSessionでの通信を確認すると、ClientHelloは、

f:id:IntelligentTechnology:20151008171250j:plain

そして、ServerHelloは、

f:id:IntelligentTechnology:20151008171337j:plain

でした。
Akamaiテストページが示した通りであることが確認できました。ちなみに、NSURLConnectionもUIWebViewと同様の結果でした。

本来やりたいことは

ここまで利用されているプロトコルを確認することにフォーカスしてきましたが、そもそもツールでやりたいことは何かと言えば、クライアント/サーバ間の通信内容を確認することです。例えば、テストしていてアプリが想定外の挙動をした場合、原因を探るために通信内容を確認するだとか。ですから、「利用されているプロトコルがなんであるか」を確認したい場面はそれほどないのかなと思います。
そして、それをWiresharkでやろうとした場合、なかなか難しい問題があります。
通信内容をちゃんと確認するには、暗号化された通信データの復号が必要です。Charlesの場合は、プロキシとして介在することで、そのあたりを解決してくれます。Wiresharkに関しては、以下の記事が参考になります。

d.hatena.ne.jp

ただ、ここに書かれているように、サーバの秘密鍵をWiresharkに登録する方法では、forward secrecyな暗号スイートには対応できません。クライアントがChromeかFirefoxであれば以下の方法で復号可能になります。

Wireshark で HTTP/2 over TLS の通信をダンプする方法 · GitHub

確かにこれなら通信内容をばっちり確認できます。(実際できました)
ですが、これをiOS端末に対してやろうとすると・・・適用できません。(良い方法を思いつきません)

Charlesが使えないわけではありません

HTTP/2対応しているクライアント/サーバ間の通信をCharles経由で確認した場合、その通信プロトコルはHTTP/1.1になります。間に介在するCharlesがHTTP/2に対応してないので、当然の結果です。確認したいことがHTTPのヘッダフィールドに関するものであれば、Charlesを使うのは適切でないと言えるでしょう。ですが、例えばPOSTパラメータの内容を確認したいといった使い道であれば、Charlesは活用できると思います。