Skip to content

curl: Add curl_multi_get_handles() #16363

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ PHP NEWS
- COM:
. Fix property access of PHP objects wrapped in variant. (cmb)

- Curl:
. Added curl_multi_get_handles(). (timwolla)

- DOM:
. Added Dom\Element::$outerHTML. (nielsdos)

Expand Down
5 changes: 5 additions & 0 deletions UPGRADING
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ PHP 8.5 UPGRADE NOTES
6. New Functions
========================================

- Curl:
. curl_multi_get_handles() allows retrieving all CurlHandles current
attached to a CurlMultiHandle. This includes both handles added using
curl_multi_add_handle() and handles accepted by CURLMOPT_PUSHFUNCTION.

- PGSQL:
. pg_close_stmt offers an alternative way to close a prepared
statement from the DEALLOCATE sql command in that we can reuse
Expand Down
2 changes: 2 additions & 0 deletions ext/curl/curl.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -3702,6 +3702,8 @@ function curl_upkeep(CurlHandle $handle): bool {}

function curl_multi_add_handle(CurlMultiHandle $multi_handle, CurlHandle $handle): int {}

function curl_multi_get_handles(CurlMultiHandle $multi_handle): array {}

function curl_multi_close(CurlMultiHandle $multi_handle): void {}

function curl_multi_errno(CurlMultiHandle $multi_handle): int {}
Expand Down
8 changes: 7 additions & 1 deletion ext/curl/curl_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 23 additions & 0 deletions ext/curl/multi.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,29 @@ PHP_FUNCTION(curl_multi_remove_handle)
}
/* }}} */

PHP_FUNCTION(curl_multi_get_handles)
{
zval *z_mh;
php_curlm *mh;

ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_OBJECT_OF_CLASS(z_mh, curl_multi_ce)
ZEND_PARSE_PARAMETERS_END();

mh = Z_CURL_MULTI_P(z_mh);

array_init(return_value);
zend_llist_position pos;
zval *pz_ch;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tab character seems unintentional here?

Suggested change
zval *pz_ch;
zval *pz_ch;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've stolen the logic as-is from curl_multi_exec and did not adjust the code style to keep the file internally consistent. This also applies to the other remark.

There would be more to clean up here, for example the removal of the useless (zval *) cast, because a void* casts implicitly to anything.

Perhaps it would even make sense to migrate from zend_llist to HashTable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let's move this to a follow-up PR then.


for (pz_ch = (zval *)zend_llist_get_first_ex(&mh->easyh, &pos); pz_ch;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could merge the declaration within the for loop.

pz_ch = (zval *)zend_llist_get_next_ex(&mh->easyh, &pos)) {

Z_TRY_ADDREF_P(pz_ch);
add_next_index_zval(return_value, pz_ch);
}
}

/* {{{ Get all the sockets associated with the cURL extension, which can then be "selected" */
PHP_FUNCTION(curl_multi_select)
{
Expand Down
71 changes: 71 additions & 0 deletions ext/curl/tests/curl_multi_get_handles.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
--TEST--
array curl_multi_get_handles ( CurlMultiHandle $mh );
--EXTENSIONS--
curl
--FILE--
<?php
$urls = array(
"file://".__DIR__."/curl_testdata1.txt",
"file://".__DIR__."/curl_testdata2.txt",
);

$mh = curl_multi_init();
$map = new WeakMap();

foreach ($urls as $url) {
echo "Initializing {$url}.", PHP_EOL;
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_multi_add_handle($mh, $ch);
printf("%d handles are attached\n", count(curl_multi_get_handles($mh)));
$map[$ch] = $url;
}

do {
$status = curl_multi_exec($mh, $active);
if ($status !== CURLM_OK) {
throw new \Exception(curl_multi_strerror(curl_multi_errno($mh)));
}

if ($active) {
$activity = curl_multi_select($mh);
if ($activity === -1) {
throw new \Exception(curl_multi_strerror(curl_multi_errno($mh)));
}
}

while (($info = curl_multi_info_read($mh)) !== false) {
if ($info['msg'] === CURLMSG_DONE) {
$handle = $info['handle'];
$url = $map[$handle];
echo "Request to {$url} finished.", PHP_EOL;
printf("%d handles are attached\n", count(curl_multi_get_handles($mh)));
curl_multi_remove_handle($mh, $handle);
printf("%d handles are attached\n", count(curl_multi_get_handles($mh)));

if ($info['result'] === CURLE_OK) {
echo "Success.", PHP_EOL;
} else {
echo "Failure.", PHP_EOL;
}
}
}
} while ($active);

printf("%d handles are attached\n", count(curl_multi_get_handles($mh)));

?>
--EXPECTF--
Initializing %scurl_testdata1.txt.
1 handles are attached
Initializing %scurl_testdata2.txt.
2 handles are attached
Request to %scurl_testdata%d.txt finished.
2 handles are attached
1 handles are attached
Success.
Request to %scurl_testdata%d.txt finished.
1 handles are attached
0 handles are attached
Success.
0 handles are attached