Bug #76675 [NEW]: Segfault with H2 server push
| From: | tobias dot nyholm at gmail dot com | Date: | Sat, 28 Jul 2018 00:12:09 +0000 |
| Subject: | Bug #76675 [NEW]: Segfault with H2 server push | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-216510@lists.php.net to get a copy of this message | ||
From: tobias dot nyholm at gmail dot com
Operating system: OSX
PHP version: 7.2.8
Package: cURL related
Bug Type: Bug
Bug description:Segfault with H2 server push
Description:
------------
When experimenting with HTTP2 server push I found some issues.
1) It does not work when using
CURLOPT_TIMEOUT
2) Segmentation fault when using CURLOPT_WRITEFUNCTION and
CURLOPT_HEADERFUNCTION
3) Segmentation fault when using CURLOPT_WRITEFUNCTION and
CURLOPT_HEADERFUNCTION in CURLMOPT_PUSHFUNCTION.
I started with a working example provided by Davey:
https://github.com/dshafik/php-http2-push-example
Please note my 3 FIXME comments in the test script.
Im on PHP 7.2.8 with cUrl 7.61.0.
Test script:
---------------
<?php
$urls = [];
function parseUrl($headers, $handle)
{
global $urls;
foreach ($headers as $header) {
if (strpos($header, ':path:') === 0) {
$path = substr($header, 6);
$url = curl_getinfo($handle)['url'];
$url = str_replace(
parse_url($url, PHP_URL_PATH),
$path,
$url
);
$urls[$url] = $handle;
}
}
}
function getUrl($handle)
{
$found = false;
global $urls;
foreach ($urls as $url => $h) {
if ($handle == $h) {
$found = $url;
}
}
if (!$found) {
$found = curl_getinfo($handle)['url'];
}
return $found;
}
function get_request($url)
{
$cb = function ($parent, $pushed, $headers) {
curl_setopt($pushed, CURLOPT_RETURNTRANSFER, true);
curl_setopt($pushed, CURLOPT_HEADER, true);
//FIXME These two lines will cause segmentation fault
//curl_setopt($pushed, CURLOPT_HEADERFUNCTION, null);
//curl_setopt($pushed, CURLOPT_WRITEFUNCTION, null);
parseUrl($headers, $pushed);
return CURL_PUSH_OK;
};
$mh = curl_multi_init();
curl_multi_setopt($mh, CURLMOPT_PIPELINING, CURLPIPE_MULTIPLEX);
curl_multi_setopt($mh, CURLMOPT_PUSHFUNCTION, $cb);
$curl = curl_init();
curl_reset($curl);
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2);
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($curl, CURLOPT_MAXREDIRS, 0);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($curl, CURLOPT_HTTPGET, true);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, true);
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP |
CURLPROTO_HTTPS);
curl_setopt($curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTP |
CURLPROTO_HTTPS);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_FAILONERROR, false);
$originalResponseContent = '';
//FIXME Using timeout will weirdly disable pushed responses (content
will be empty)
//curl_setopt($curl, CURLOPT_TIMEOUT, 30);
// -----------
curl_setopt($curl, CURLOPT_RETURNTRANSFER, false);
//FIXME These 2 lines will case segmentation fault
curl_setopt($curl, CURLOPT_HEADERFUNCTION, function ($ch, $data) {
return strlen($data);
});
curl_setopt($curl, CURLOPT_WRITEFUNCTION, function ($ch, $data) use
(&$originalResponseContent) {
$originalResponseContent .= $data;
return strlen($data);
});
curl_multi_add_handle($mh, $curl);
// Start fetching the responses.
$content = null;
$active = null;
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($active && $mrc == CURLM_OK) {
curl_multi_select($mh);
do {
$mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);
while ($info = curl_multi_info_read($mh))
{
if ($info['msg'] == CURLMSG_DONE) {
$handle = $info['handle'];
if ($handle !== null) {
$content = curl_multi_getcontent($handle);
$url = getUrl($handle);
// Debug
echo strlen($content).': '.$url."\n";
curl_multi_remove_handle($mh, $handle);
curl_close($handle);
}
}
}
}
curl_multi_close($mh);
return $originalResponseContent;
}
$url = 'https://http2.golang.org/serverpush';
$response = get_request($url);
echo strlen($response).': '.$url."\n\n";
--
Edit bug report at https://bugs.php.net/bug.php?id=76675&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=76675&r=trysnapshot54
Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=76675&r=trysnapshot55
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=76675&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=76675&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=76675&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=76675&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=76675&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=76675&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=76675&r=support
Expected behavior: https://bugs.php.net/fix.php?id=76675&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=76675&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=76675&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=76675&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=76675&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=76675&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=76675&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=76675&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=76675&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=76675&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=76675&r=mysqlcfg