diff options
author | Pierrick Charron <pierrick@php.net> | 2012-12-22 19:04:45 -0500 |
---|---|---|
committer | Pierrick Charron <pierrick@php.net> | 2012-12-22 19:04:45 -0500 |
commit | b10a3b9466b77bccf7e9a6e6207df2de1a997855 (patch) | |
tree | b75aab62a9ba4aa153ca985e5b9a2134add6781f /ext/curl | |
parent | 5499c7d201ad22f551dfc370ae09132acf4f75ec (diff) | |
parent | a2b6d9c1047a4e5f3419ebc3489a66d62aa12d07 (diff) | |
download | php-git-b10a3b9466b77bccf7e9a6e6207df2de1a997855.tar.gz |
Merge branch 'PHP-5.3' into PHP-5.4
* PHP-5.3:
Fixed segfault due to libcurl connection caching
Diffstat (limited to 'ext/curl')
-rw-r--r-- | ext/curl/interface.c | 24 | ||||
-rw-r--r-- | ext/curl/tests/curl_multi_segfault.phpt | 56 |
2 files changed, 80 insertions, 0 deletions
diff --git a/ext/curl/interface.c b/ext/curl/interface.c index 110603725f..a23f859946 100644 --- a/ext/curl/interface.c +++ b/ext/curl/interface.c @@ -977,6 +977,15 @@ PHP_MSHUTDOWN_FUNCTION(curl) } /* }}} */ +/* {{{ curl_write_nothing + * Used as a work around. See _php_curl_close_ex + */ +static size_t curl_write_nothing(char *data, size_t size, size_t nmemb, void *ctx) +{ + return size * nmemb; +} +/* }}} */ + /* {{{ curl_write */ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx) @@ -2648,6 +2657,21 @@ static void _php_curl_close_ex(php_curl *ch TSRMLS_DC) #endif _php_curl_verify_handlers(ch, 0 TSRMLS_CC); + + /* + * Libcurl is doing connection caching. When easy handle is cleaned up, + * if the handle was previously used by the curl_multi_api, the connection + * remains open un the curl multi handle is cleaned up. Some protocols are + * sending content like the FTP one, and libcurl try to use the + * WRITEFUNCTION or the HEADERFUNCTION. Since structures used in those + * callback are freed, we need to use an other callback to which avoid + * segfaults. + * + * Libcurl commit d021f2e8a00 fix this issue and should be part of 7.28.2 + */ + curl_easy_setopt(ch->cp, CURLOPT_HEADERFUNCTION, curl_write_nothing); + curl_easy_setopt(ch->cp, CURLOPT_WRITEFUNCTION, curl_write_nothing); + curl_easy_cleanup(ch->cp); /* cURL destructors should be invoked only by last curl handle */ diff --git a/ext/curl/tests/curl_multi_segfault.phpt b/ext/curl/tests/curl_multi_segfault.phpt new file mode 100644 index 0000000000..dde8189411 --- /dev/null +++ b/ext/curl/tests/curl_multi_segfault.phpt @@ -0,0 +1,56 @@ +--TEST-- +Segfault due to libcurl connection caching +--CREDITS-- +--SKIPIF-- +<?php +if (!extension_loaded("curl")) exit("skip curl extension not loaded"); +if (false === getenv('PHP_CURL_FTP_REMOTE_SERVER')) exit("skip PHP_CURL_FTP_REMOTE_SERVER env variable is not defined"); +if (false === getenv('PHP_CURL_FTP_REMOTE_USER')) exit("skip PHP_CURL_FTP_REMOTE_USER env variable is not defined"); +if (false === getenv('PHP_CURL_FTP_REMOTE_PASSWD')) exit("skip PHP_CURL_FTP_REMOTE_PASSWD env variable is not defined"); +?> +--FILE-- +<?php + $host = getenv('PHP_CURL_FTP_REMOTE_SERVER'); + $username = getenv('PHP_CURL_FTP_REMOTE_USER'); + $password = getenv('PHP_CURL_FTP_REMOTE_PASSWD'); + + // FTP this script to a server + $fp = fopen ( __FILE__ , "r" ); + $url = "ftp://$username:$password@$host/" ; + + $ch = curl_init (); + + curl_setopt ( $ch , CURLOPT_URL, $url ); + curl_setopt ( $ch , CURLOPT_RETURNTRANSFER, 1 ); + + //force passive connection + curl_setopt ( $ch , CURLOPT_FTP_USE_EPSV, 0 ); + curl_setopt ( $ch , CURLOPT_FTP_SKIP_PASV_IP, 1 ); + + $cmh = curl_multi_init(); + curl_multi_add_handle($cmh, $ch); + + $active = null; + + do { + $mrc = curl_multi_exec($cmh, $active); + } while ($mrc == CURLM_CALL_MULTI_PERFORM); + + + while ($active && $mrc == CURLM_OK) { + if (curl_multi_select($cmh) != -1) { + do { + $mrc = curl_multi_exec($cmh, $active); + } while ($mrc == CURLM_CALL_MULTI_PERFORM); + } + } + + var_dump(is_string(curl_multi_getcontent($ch))); + curl_multi_remove_handle($cmh, $ch); + curl_close($ch); + curl_multi_close($cmh); +?> +===DONE=== +--EXPECTF-- +bool(true) +===DONE=== |