Search code examples
curllibcurlcentos7php-opensslphp-7.1

PHP 7.1: no cURL with HTTP/2


My question is not about finding out if a server supports HTTP/2 (they both do) but how to make sure PHP is utilizing HTTP/2 with the correct cURL settings for the most current PHP version in CentOS (built from Remi's repository). My own answer addresses some oddities concerning this.

I've setup my CentOS 7 server to support HTTP/2 with the help of this fine guide: Setting up HTTP/2 on your web server

So I've got the latest releases, compiled and installed them and all is working fine. Pages are served with HTTP/2 headers, exactly as they should.

Now I'd like to utilize HTTP/2 functionality in my PHP scripts. Mainly by doing cURL calls in HTTP/2 fashion. I found out I needed to upgrade libcurl and build and compile it with specific HTTP/2 support. With some setbacks, I got it to work.

So curl -V tells me:

curl 7.55.0-DEV (x86_64-unknown-linux-gnu) libcurl/7.55.0-DEV OpenSSL/1.1.0f zlib/1.2.7 nghttp2/1.23.1
Release-Date: [unreleased]
Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: IPv6 Largefile NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy 

Great!

And phpinfo() gives me the same version (7.55.0-DEV) in conjunction with the newly installed OpenSSL, which is:

OpenSSL 1.1.0f 25 May 2017

And Apache, BTW:

Server version: Apache/2.4.26 (Unix)
Server built:   Jul  7 2017 09:47:22

However, when I write a simple PHP script with a cURL call and the CURLOPT_HTTP_VERSION option set to CURL_HTTP_VERSION_2_0, as outlined in this example: https://stackoverflow.com/a/37146586/1005334, it tells me the server does not have HTTP/2 support...

How can this be?

One thing I noticed, is the bit about the OpenSSL module in phpinfo() still mentions my old OpenSSL version (OpenSSL 1.0.1e-fips), although the OpenSSL-version mentioned with the cURL module states OpenSSL 1.1.0f.

I've installed PHP 7.1 (it currently stands at version 7.1.7) from Remi's repository, could it be it is built against an older OpenSSL version so it will not work with my newer one? I also read support in PHP 7 for HTTP/2 is not quite apparent, but I imagine it shouldn't be a problem, right?

Or is OpenSSL not the problem and should I look elsewhere, perhaps compiling PHP from source with some intended flags?


Solution

  • After some fiddling, it seems I can get a HTTP/2 response through a PHP cURL call with Remi's PHP packages and a freshly built cURL/OpenSSL.

    I was using this piece of code to test (taken from here):

    if (curl_version()["features"] & CURL_VERSION_HTTP2 !== 0) {
        $url = "https://www.google.com/";
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL            =>$url,
            CURLOPT_HEADER         =>true,
            CURLOPT_NOBODY         =>true,
            CURLOPT_RETURNTRANSFER =>true,
            CURLOPT_HTTP_VERSION   =>CURL_HTTP_VERSION_2_0,
        ]);
        $response = curl_exec($ch);
        if ($response !== false && strpos($response, "HTTP/2.0") === 0) {
            echo "HTTP/2 support!";
        } elseif ($response !== false) {
            echo "No HTTP/2 support on server.";
        } else {
            echo curl_error($ch);
        }
        curl_close($ch);
    } else {
        echo "No HTTP/2 support on client.";
    }
    

    The tweaks required, were:

    CURLOPT_HTTP_VERSION => 3
    

    ...and:

    if ($response !== false && strpos($response, "HTTP/2") === 0)
    

    So instead of CURL_HTTP_VERSION_2_0 as HTTP version in the cURL options, I used 3, which should mean the same, but apparently PHP does not pick up the correct value when using CURL_HTTP_VERSION_2_0.

    Looking at the raw response this gave, I noticed Google was sending back HTTP/2 instead of HTTP/2.0.

    I hope this can help someone!