WinHTTPにHTTP/2の対応が入ったようです。そこで、簡単にですが確かめてみました。
WinHTTPは、Windowsの汎用的なHTTPとWebSocketのAPIです。そんなわけで、自身でときどき使ったり、使っているアプリをたまに見かけたりします。
フラグをMSDNライブラリで見つけた
この前、WinHttpSetOption関数で指定するOption Flagsを見ていたところ、WINHTTP_PROTOCOL_FLAG_HTTP2というものが増えていることに気付きました。
WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL Sets a DWORD bitmask of acceptable advanced HTTP versions. Supported on Windows 10, version 1607 and newer. Possible values are:
- WINHTTP_PROTOCOL_FLAG_HTTP2 (0x1). Supported on Windows 10, version 1607 and newer
Legacy versions of HTTP (1.1 and prior) cannot be disabled using this option. The default is 0x0.
WINHTTP_PROTOCOL_FLAG_HTTP2の意味が書かれていませんが、どう考えてもHTTP/2を使うというフラグに違いありません。
使ってみる
というわけでさっそくコードを書いてみます。
#include
#include
#include
#include
#include
#include
struct winhttp_deleter
{
using pointer = HINTERNET;
void operator()(_In_ HINTERNET h) const noexcept
{
WinHttpCloseHandle(h);
}
};
using unique_hinternet = std::unique_ptr;
int main()
{
unique_hinternet session(WinHttpOpen(
nullptr,
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
nullptr,
nullptr,
0));
if (session == nullptr)
{
std::quick_exit(1);
}
// ~~ ここから ~~
DWORD protocolOption = WINHTTP_PROTOCOL_FLAG_HTTP2;
if (!WinHttpSetOption(
session.get(),
WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL,
&protocolOption,
sizeof protocolOption))
{
std::wclog << "HTTP/2 is not supported." << std::endl;
}
// ~~ ここまで ~~
unique_hinternet connect(WinHttpConnect(
session.get(),
L"www.yahoo.co.jp",
INTERNET_DEFAULT_PORT,
0));
if (connect == nullptr)
{
std::quick_exit(1);
}
unique_hinternet request(WinHttpOpenRequest(
connect.get(),
L"HEAD",
L"/",
nullptr,
WINHTTP_NO_REFERER,
WINHTTP_DEFAULT_ACCEPT_TYPES,
WINHTTP_FLAG_SECURE));
if (connect == nullptr)
{
std::quick_exit(1);
}
if (!WinHttpSendRequest(
request.get(),
WINHTTP_NO_ADDITIONAL_HEADERS,
0,
WINHTTP_NO_REQUEST_DATA,
0,
0,
0))
{
std::quick_exit(1);
}
if (!WinHttpReceiveResponse(request.get(), nullptr))
{
std::quick_exit(1);
}
WCHAR buffer[256];
DWORD size = sizeof buffer;
if (WinHttpQueryHeaders(
request.get(),
WINHTTP_QUERY_VERSION,
WINHTTP_HEADER_NAME_BY_INDEX,
buffer,
&size,
WINHTTP_NO_HEADER_INDEX))
{
std::wcout << buffer << std::endl;
}
std::quick_exit(0);
}
HTTP/2になっていることを確かめる(その1)
さて、どうやってHTTP/2であることを確認しよう?と少し悩みました。ウェブサイトでHTTP/2を使うとなれば、TLS (HTTPS)併用が事実上必須です。TLSで暗号化されていては、内容の確認は難しいです。
考えた結果「WiresharkでTLSの様子を見て、ALPNでh2が入っていたら良し」ということにしました。これがその結果です。
良さそうですね。h2になっているので、HTTP/2でしょう。
HTTP/2になっていることを確かめる(その2)
よくよく考えたら私はwww.activebasic.comのアクセスを見られます。というわけで、www.activebasic.comにアクセスさせて、アクセスログでHTTP/2であることを確認できることに気付きました。
分かりやすいように、User Agentを指定します。
--- a/http.cpp
+++ b/http.cpp
@@ -21,3 +21,3 @@
unique_hinternet session(WinHttpOpen(
- nullptr,
+ L"WinHTTP-Test-App/0.0",
WINHTTP_ACCESS_TYPE_AUTOMATIC_PROXY,
@@ -43,3 +43,3 @@
session.get(),
- L"www.yahoo.co.jp",
+ L"www.activebasic.com",
INTERNET_DEFAULT_PORT,
実際のアクセスログの該当行はこんなです。LTSVです。protocol:HTTP/2.0かつagent:WinHTTP-Test-App/0.0となっています。
domain:www.activebasic.com host:153.203.0.68 server:160.16.87.113 user:- time:30/Apr/2017:01:09:27 +0900 method:HEAD path:/index.html protocol:HTTP/2.0 status:200 size:7312 referer:- agent:WinHTTP-Test-App/0.0 response_time:1207 cookie:- set_cookie:-
WinHTTPが報告するバージョンは1.1
上記プログラムではWINHTTP_QUERY_VERSIONを使って、通信に使ったHTTPのバージョンを取得し、それをwcoutに出力するようにしています。その出力は、上記2つの確認時、いずれも以下のようになりました。
HTTP/1.1
びっくりです。実際には、HTTP/2で通信しているにもかかわらず、WINHTTP_QUERY_VERSIONでは、HTTP/1.1という文字列を返してきました。なお、WINHTTP_QUERY_RAW_HEADERS_CRLFでも同様にHTTP/1.1となっていました。
以上、Windows 10 1607で、WinHTTPにHTTP/2への対応が入っていることを見つけた話でした。
なお、ずっと前から関数WinHttpSetOption用の定数WINHTTP_OPTION_HTTP_VERSIONと構造体HTTP_VERSION_INFOがあるのに、新たな定数WINHTTP_OPTION_ENABLE_HTTP_PROTOCOLを追加してくるあたり、苦労が窺えます。
WinHTTPがHTTP/2に対応した (Windows 10 1607) is a post from: イグトランスの頭の中