Skip to content

Commit 5ff006e

Browse files
ext/curl: fix CURLOPT_SEEKFUNCTION GC, reset and test issues
Register the seek callback with the cycle collector in curl_get_gc() so a seek closure that captures its own handle can be collected, and free it in _php_curl_reset_handlers() so curl_reset() clears it, matching the other callbacks. Drop the deprecated curl_close() call from curl_seekfunction.phpt, which emitted an unexpected deprecation notice and failed the strict EXPECT, and add a curl_copy_handle() test exercising the seek callback on a copied handle.
1 parent 6b1cff4 commit 5ff006e

3 files changed

Lines changed: 52 additions & 1 deletion

File tree

ext/curl/interface.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,10 @@ static HashTable *curl_get_gc(zend_object *object, zval **table, int *n)
456456
zend_get_gc_buffer_add_zval(gc_buffer, &curl->handlers.write_header->stream);
457457
}
458458

459+
if (ZEND_FCC_INITIALIZED(curl->handlers.seek)) {
460+
zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.seek);
461+
}
462+
459463
if (ZEND_FCC_INITIALIZED(curl->handlers.progress)) {
460464
zend_get_gc_buffer_add_fcc(gc_buffer, &curl->handlers.progress);
461465
}
@@ -2920,6 +2924,10 @@ static void _php_curl_reset_handlers(php_curl *ch)
29202924
ZVAL_UNDEF(&ch->handlers.std_err);
29212925
}
29222926

2927+
if (ZEND_FCC_INITIALIZED(ch->handlers.seek)) {
2928+
zend_fcc_dtor(&ch->handlers.seek);
2929+
}
2930+
29232931
if (ZEND_FCC_INITIALIZED(ch->handlers.progress)) {
29242932
zend_fcc_dtor(&ch->handlers.progress);
29252933
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
Test curl_copy_handle() preserves CURLOPT_SEEKFUNCTION
3+
--EXTENSIONS--
4+
curl
5+
--FILE--
6+
<?php
7+
include 'server.inc';
8+
$host = curl_cli_server_start();
9+
10+
$body = 'Hello cURL seek!';
11+
$offset = 0;
12+
$seekCalls = 0;
13+
14+
$ch = curl_init("{$host}/get.inc?test=redirect");
15+
curl_setopt($ch, CURLOPT_UPLOAD, true);
16+
curl_setopt($ch, CURLOPT_INFILESIZE, strlen($body));
17+
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
18+
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
19+
curl_setopt($ch, CURLOPT_READFUNCTION, function ($ch, $fd, int $length) use ($body, &$offset) {
20+
$chunk = substr($body, $offset, $length);
21+
$offset += strlen($chunk);
22+
return $chunk;
23+
});
24+
curl_setopt($ch, CURLOPT_SEEKFUNCTION, function ($ch, int $offset_, int $origin) use (&$offset, &$seekCalls) {
25+
if ($origin !== SEEK_SET) {
26+
return CURL_SEEKFUNC_CANTSEEK;
27+
}
28+
$seekCalls++;
29+
$offset = $offset_;
30+
return CURL_SEEKFUNC_OK;
31+
});
32+
33+
// The copied handle must inherit the seek callback; exercise it on the copy
34+
// after freeing the original.
35+
$ch2 = curl_copy_handle($ch);
36+
unset($ch);
37+
38+
$response = curl_exec($ch2);
39+
var_dump($seekCalls > 0);
40+
var_dump(str_contains($response, $body));
41+
?>
42+
--EXPECT--
43+
bool(true)
44+
bool(true)

ext/curl/tests/curl_seekfunction.phpt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ $response = curl_exec($ch);
3535
// and the resent body must have reached the redirect target intact.
3636
var_dump($seekCalls > 0);
3737
var_dump(str_contains($response, $body));
38-
curl_close($ch);
3938
?>
4039
--EXPECT--
4140
bool(true)

0 commit comments

Comments
 (0)