curl のビルドオプション
システムにインストールされている curl のバージョンが 7.3.3 とそれ以降であり、0.6.0 とそれ以降の nghttp2 がシステムにインストールされている状態でビルドオプションに --with-nghttp2=PATH
が指定されていれば、PHP の curl エクステンションで HTTP/2 が利用できます。
./configure --prefix=`pwd`/local --with-nghttp2
curl version: 7.42.0-DEV
Host setup: x86_64-apple-darwin14.1.0
Install prefix: /Users/masakielastic/test/curl/local
Compiler: gcc
SSL support: enabled (OpenSSL)
SSH support: no (--with-libssh2)
zlib support: enabled
GSS-API support: no (--with-gssapi)
TLS-SRP support: no (--enable-tls-srp)
resolver: default (--enable-ares / --enable-threaded-resolver)
IPv6 support: enabled
Unix sockets support: enabled
IDN support: enabled
Build libcurl: Shared=yes, Static=yes
Built-in manual: enabled
--libcurl option: enabled (--disable-libcurl-option)
Verbose errors: enabled (--disable-verbose)
SSPI support: no (--enable-sspi)
ca cert bundle: no
ca cert path: no
LDAP support: enabled (OpenLDAP)
LDAPS support: enabled
RTSP support: enabled
RTMP support: no (--with-librtmp)
metalink support: no (--with-libmetalink)
HTTP2 support: enabled (nghttp2)
Protocols: DICT FILE FTP FTPS GOPHER HTTP HTTPS IMAP IMAPS LDAP LDAPS POP3 POP3S RTSP SMB SMBS SMTP SMTPS TELNET TFTP
curl -V
を実行すれば、nghttp2 のビルドオプションが有効であるかを調べることができます。
curl 7.41.0 (x86_64-apple-darwin14.1.0) libcurl/7.41.0 OpenSSL/1.0.2a zlib/1.2.5 nghttp2/0.7.7
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets
curl コマンドによるリクエスト
次のコマンドを実行してレスポンスを目で確認してみましょう。
curl --http2 -v https://http2bin.org/get
ヘッダーだけ出力することもできます。
curl -I --http2 https://http2bin.org/get
結果は次のとおりです。「HTTP/2.0 200」が含まれていることを確認します。
* Trying 104.131.161.90...
* Connected to http2bin.org (104.131.161.90) port 443 (#0)
* ALPN, offering h2-14, http/1.1
* successfully set certificate verify locations:
* CAfile: /usr/local/etc/openssl/cert.pem
CApath: none
* NPN, negotiated HTTP2 (h2-14)
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: OU=Domain Control Validated; OU=EssentialSSL; CN=www.http2bin.org
* start date: 2015-02-21 00:00:00 GMT
* expire date: 2016-02-21 23:59:59 GMT
* issuer: C=GB; ST=Greater Manchester; L=Salford; O=COMODO CA Limited; CN=COMODO RSA Domain Validation Secure Server CA
* SSL certificate verify ok.
* Using HTTP2
* http2_send len=54
* before_frame_send() was called
* on_frame_send() was called
* before_frame_send() was called
* on_frame_send() was called
> GET /get HTTP/1.1
Host: http2bin.org
Accept: */*
* http2_recv: 16384 bytes buffer
* nread=27
* on_frame_recv() was called with header 4
* nghttp2_session_mem_recv() returns 27
* before_frame_send() was called
* on_frame_send() was called
* http2_recv: 16384 bytes buffer
* nread=9
* on_frame_recv() was called with header 4
* nghttp2_session_mem_recv() returns 9
* http2_recv: 16384 bytes buffer
* nread=345
* on_begin_headers() was called
* got http2 header: server: h2o/1.1.1
* got http2 header: date: Mon, 16 Mar 2015 21:47:58 GMT
* got http2 header: content-type: application/json
* got http2 header: access-control-allow-origin: *
* got http2 header: access-control-allow-credentials: true
* got http2 header: x-clacks-overhead: GNU Terry Pratchett
* on_frame_recv() was called with header 1
* on_data_chunk_recv() len = 218, stream = 1
* 218 data written
* on_frame_recv() was called with header 0
* on_stream_close() was called, error_code = 0
* nghttp2_session_mem_recv() returns 345
< HTTP/2.0 200
< server:h2o/1.1.1
< date:Mon, 16 Mar 2015 21:47:58 GMT
< content-type:application/json
< access-control-allow-origin:*
< access-control-allow-credentials:true
< x-clacks-overhead:GNU Terry Pratchett
<
{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "keep-alive",
"Host": "http2bin.org",
"Via": "2 http2bin.org"
},
"origin": "106.184.75.63",
"url": "https://http2bin.org/get"
}
* Connection #0 to host http2bin.org left intact
インストール
homebrew
あらかじめ最新の OpenSSL が使えるようにしておきます。brew link コマンドを実行しておかないと、Mac OS X にインストールされてあるデフォルトの OpenSSL が使われます。
brew update
brew install openssl
brew link openssl --force
openssl version
curl をインストールする際のビルドオプションに --with-nghttp2
を指定します。
brew install curl --with-nghttp2 --with-openssl
brew link curl --force
以前の公式 fomula ではビルドオプションが利用できなかったのと最新バージョンを試したかったので、自分の formula を用意していました。次のコマンドでインストールできます。
brew update
brew install masakielastic/http2/curl --with-openssl
brew link curl --force
linuxbrew
主要な Linux ディストリビューションで個人のディレクトリの領域に curl をインストールして試すのであれば、パッケージ管理ツールの linuxbrew が便利です。linuxbrew は Mac OSX の homebrew の Linux 対応バージョンです。Ubunutu に導入した際に次のパッケージを追加で導入する必要がありました。
sudo apt-get install pkg-conf python-setuptools
次のコマンドで curl がインストールされます。
brew install curl --with-nghttp2
Ubuntu 16.04 LTS
再コンパイルすることで HTTP/2 を利用できるようになります。launchpad に 手順 が記されています。
最初に nghttp2 とビルドに必要なツールをインストールします。
sudo apt install libnghttp2-dev
sudo apt build-dep curl
次にソースコードをダウンロードします。
apt source curl
cd curl-7.47.0
debian/control を編集して Build-Depends の項目で libnghttp2-dev を追加します。
Build-Depends: debhelper (>= 9),
autoconf,
automake,
ca-certificates,
groff-base,
libgnutls-dev,
libidn11-dev,
libkrb5-dev,
libldap2-dev,
libnss3-dev,
librtmp-dev (>= 2.4+20131018.git79459a2-3~),
libssl-dev,
libnghttp2-dev,
...
ビルドしてインストールします。テストに5分から10分ほどかかります。
sudo debian/rules binary
sudo dpkg -i ../*deb
CURL_HTTP_VERSION_2_0 の定義
HTTP/2 リクエストを送信するために必要なことは CURLOPT_HTTP_VERSION
に対応する値として CURL_HTTP_VERSION_2_0
を指定することだけです。PHP 5.6.8、5.5.24 系から使えるようになります。それ以前のバージョンでは CURL_HTTP_VERSION_2_0
を自分で定義する必要があります。
if (!defined('CURL_HTTP_VERSION_2_0')) {
define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}
なお、curl/curl.h
では CURL_HTTP_VERSION_2_0
は次のように enum で定義されています。
enum {
CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
like the library to choose the best possible
for us! */
CURL_HTTP_VERSION_1_0, /* please use HTTP 1.0 in the request */
CURL_HTTP_VERSION_1_1, /* please use HTTP 1.1 in the request */
CURL_HTTP_VERSION_2_0, /* please use HTTP 2.0 in the request */
CURL_HTTP_VERSION_LAST /* *ILLEGAL* http version */
};
curl エクステンション
if (!defined('CURL_HTTP_VERSION_2_0')) {
define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}
$url = 'https://http2bin.org/get';
$opts = [
CURLOPT_VERBOSE => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_SSL_VERIFYPEER => false
];
$ch = curl_init($url);
curl_setopt_array($ch, $opts);
curl_exec($ch);
curl_close($ch);
Guzzle
バージョン 5 を対象とします。
use GuzzleHttp\Client;
if (!defined('CURL_HTTP_VERSION_2_0')) {
define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}
$client = new Client();
$client
->get(
'https://http2bin.org/get', [
'future' => true,
'config' => [
'curl' => [
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0
]
],
'debug' => true
]
)
->then(function($response) {
var_dump(
$response->getStatusCode(),
$response->getHeader('Content-Type'),
(string) $response->getBody()
);
});
RingPHP
use GuzzleHttp\Ring\Client\CurlHandler;
if (!defined('CURL_HTTP_VERSION_2_0')) {
define('CURL_HTTP_VERSION_2_0', CURL_HTTP_VERSION_1_1 + 1);
}
$handler = new CurlHandler();
$response = $handler([
'http_method' => 'GET',
'scheme' => 'https',
'uri' => '/get',
'headers' => [
'host' => ['http2bin.org']
],
'client' => [
'curl' => [
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0
],
'debug' => true
]
]);
$response->then(function (array $response) {
var_dump($response);
});
HTTP/2 が利用できるかの判定方法
HTTP/2 が利用できるかどうかで curl のオプションの構成を変えたい場合、curl_version
を使います。
if (!defined('CURL_VERSION_HTTP2')) {
define('CURL_VERSION_HTTP2', 1<<16);
}
if (curl_version()['features'] & CURL_VERSION_HTTP2) {
echo "HTTP/2 は利用できます。\n";
} else {
echo "HTTP/2 は利用できません。\n";
}
CURL_VERSION_HTTP2
は curl/curl.h で定義されています。
#define CURL_VERSION_HTTP2 (1<<16) /* HTTP2 support built-in */
#define CURL_VERSION_GSSAPI (1<<17) /* Built against a GSS-API library */
#define CURL_VERSION_KERBEROS5 (1<<18) /* Kerberos V5 auth is supported */
#define CURL_VERSION_UNIX_SOCKETS (1<<19) /* Unix domain sockets support */
HTTP/2 対応のサーバーを利用する
h2o
h2o バージョン 1.3 から php-fpm に対応しています。Mac OS X であれば、homebrew を使ってインストールおよび起動できます。設定ファイルのパスは /usr/local/etc/h2o/h2o.conf
で、ポート番号は 8080
です。
brew install h2o
ln -sfv /usr/local/opt/h2o/*.plist ~/Library/LaunchAgents
launchctl load ~/Library/LaunchAgents/homebrew.mxcl.h2o.plist
file.custom-handler:
extension: .php
fastcgi.connect:
host: 127.0.0.1
port: 9000
type: tcp
listen:
port: 8080
ssl:
certificate-file: /path/to/server.crt
key-file: /path/to/server.key
hosts:
"127.0.0.1.xip.io:8080":
paths:
/:
file.dir: /usr/local/var/h2o/
Ubuntu の php-fpm を利用する場合、Unix ソケット形式で書く必要がありました。
file.custom-handler:
extension: .php
fastcgi.connect:
port: /var/run/php5-fpm.sock
type: unix
PHP の開発バージョンを試すためにシステムにあらかじめ導入されている php-fpm 以外の Fast CGI のプロセスが必要であれば、h2o に生成と管理を任せることができます。次の設定は Ubuntu で確認しました。
file.custom-handler:
extension: .php
fastcgi.spawn:
command: "PHP_FCGI_CHILDREN=10 exec /usr/bin/php-cgi"
user: nobody
nginx
nginx 1.9.5 から利用できるようになりました。ソースコードからビルドする場合、--with-http_v2_module
オプションを指定します。Debian/Ubuntu の場合、nginx.org のリポジトリを利用することができます。/etc/apt/sources.list
に次のようなコードを追加します。
deb http://nginx.org/packages/ubuntu/ trusty nginx
deb-src http://nginx.org/packages/ubuntu/ trusty nginx
listen ディレクティブに指定します。
server {
listen 443 ssl http2 default_server;
ssl_certificate server.crt;
ssl_certificate_key server.key;
#...
}
Apache
Apache 2.4.17 で mod_http2 モジュールが利用できるようになりました。ビルドオプションに --enable-http2
を指定します。Ubuntu の場合、PPA が利用できます。
sudo add-apt-repository -y ppa:ondrej/apache2
設定ファイルに Protocols ディレクティブを追加します。
# /etc/apache2/sites-available/000-default.conf
Protocols h2c http/1.1
# /etc/apache2/sites-available/default-ssl.conf
Protocols h2 http/1.1
リバースプロキシーによる HTTP/2 対応
ポート番号 80 で HTTP1 のサーバーが起動しており、ポート番号 8080 から HTTP2 クライアントでアクセスできるようにしてみましょう。
nghttpx
nghttpx
であれば、次のコマンドを実行します。SSL/TLS の証明書はあらかじめ用意してあることが前提です。
nghttpx -f0.0.0.0,8080 -b127.0.0.1,80 server.key server.crt
h2o
h2o の場合、次のような設定ファイルを用意します。
listen:
port: 8080
ssl:
certificate-file: examples/h2o/server.crt
key-file: examples/h2o/server.key
hosts:
default:
paths:
/:
proxy.reverse.url: http://127.0.0.1:80/
access-log: /dev/stdout
h2o
を起動させてみましょう。
h2o -c proxy.conf
CDN サービス
CloudFlare は HTTP/2 に対応しており、独自の SSL/TLS を設定できない共有ホスティングサービスで利用できます。私はウェブクロウの無料プランで HTTP/2 通信を確認しました (参考記事)。
2016年4月にサーバープッシュに対応されました。PHP のサンプルコードをブログの記事で紹介されています。
共有ホスティングサービス
2016年5月の時点で日本国内の業者は対応していません。ロリポップが今後の対応を宣言しています。海外では A2 Hosting や SiteGroundが対応しています。