Skip to content

Commit ef38d22

Browse files
committed
Abort curl transfer if callback throws exception
Solves bug #16513 Also includes #16790
1 parent e2ea940 commit ef38d22

7 files changed

Lines changed: 229 additions & 8 deletions

ext/curl/interface.c

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,8 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
557557
_php_curl_verify_handlers(ch, /* reporterror */ true);
558558
/* TODO Check callback returns an int or something castable to int */
559559
length = php_curl_get_long(&retval);
560+
} else if (EG(exception)) {
561+
length = -1;
560562
}
561563

562564
zval_ptr_dtor(&argv[0]);
@@ -606,7 +608,7 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
606608
static int curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
607609
{
608610
php_curl *ch = (php_curl *)clientp;
609-
int rval = 0;
611+
int rval = 1;
610612

611613
#if PHP_CURL_DEBUG
612614
fprintf(stderr, "curl_progress() called\n");
@@ -633,8 +635,8 @@ static int curl_progress(void *clientp, double dltotal, double dlnow, double ult
633635
if (!Z_ISUNDEF(retval)) {
634636
_php_curl_verify_handlers(ch, /* reporterror */ true);
635637
/* TODO Check callback returns an int or something castable to int */
636-
if (0 != php_curl_get_long(&retval)) {
637-
rval = 1;
638+
if (0 == php_curl_get_long(&retval)) {
639+
rval = 0;
638640
}
639641
}
640642

@@ -647,7 +649,7 @@ static int curl_progress(void *clientp, double dltotal, double dlnow, double ult
647649
static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
648650
{
649651
php_curl *ch = (php_curl *)clientp;
650-
int rval = 0;
652+
int rval = 1;
651653

652654
#if PHP_CURL_DEBUG
653655
fprintf(stderr, "curl_xferinfo() called\n");
@@ -674,8 +676,8 @@ static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, cu
674676
if (!Z_ISUNDEF(retval)) {
675677
_php_curl_verify_handlers(ch, /* reporterror */ true);
676678
/* TODO Check callback returns an int or something castable to int */
677-
if (0 != php_curl_get_long(&retval)) {
678-
rval = 1;
679+
if (0 == php_curl_get_long(&retval)) {
680+
rval = 0;
679681
}
680682
}
681683

@@ -688,13 +690,13 @@ static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, cu
688690
static int curl_prereqfunction(void *clientp, char *conn_primary_ip, char *conn_local_ip, int conn_primary_port, int conn_local_port)
689691
{
690692
php_curl *ch = (php_curl *)clientp;
691-
int rval = CURL_PREREQFUNC_OK;
693+
int rval = CURL_PREREQFUNC_ABORT;
692694

693695
// when CURLOPT_PREREQFUNCTION is set to null, curl_prereqfunction still
694696
// gets called. Return CURL_PREREQFUNC_OK immediately in this case to avoid
695697
// zend_call_known_fcc() with an uninitialized FCC.
696698
if (!ZEND_FCC_INITIALIZED(ch->handlers.prereq)) {
697-
return rval;
699+
return CURL_PREREQFUNC_OK;
698700
}
699701

700702
#if PHP_CURL_DEBUG
@@ -823,6 +825,8 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
823825
}
824826
// TODO Do type error if invalid type?
825827
zval_ptr_dtor(&retval);
828+
} else if (EG(exception)) {
829+
length = CURL_READFUNC_ABORT;
826830
}
827831

828832
zval_ptr_dtor(&argv[0]);
@@ -915,6 +919,8 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
915919
// TODO: Check for valid int type for return value
916920
_php_curl_verify_handlers(ch, /* reporterror */ true);
917921
length = php_curl_get_long(&retval);
922+
} else if (EG(exception)) {
923+
length = -1;
918924
}
919925
zval_ptr_dtor(&argv[0]);
920926
zval_ptr_dtor(&argv[1]);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
CURLOPT_HEADERFUNCTION aborts transfer when callback throws
3+
--EXTENSIONS--
4+
curl
5+
--SKIPIF--
6+
<?php
7+
if (!defined('CURLOPT_HEADERFUNCTION')) {
8+
die('skip CURLOPT_HEADERFUNCTION not available');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
include 'server.inc';
15+
$host = curl_cli_server_start();
16+
$ch = curl_init("{$host}/get.inc");
17+
18+
curl_setopt($ch, CURLOPT_HEADERFUNCTION,
19+
function (): int {
20+
throw new Exception('header exception');
21+
}
22+
);
23+
24+
try {
25+
curl_exec($ch);
26+
} catch (Exception $e) {
27+
echo $e->getMessage(), "\n";
28+
}
29+
30+
var_dump(curl_errno($ch) === CURLE_WRITE_ERROR);
31+
32+
?>
33+
--EXPECTF--
34+
header exception
35+
bool(true)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
CURLOPT_PREREQFUNCTION aborts transfer when callback throws
3+
--EXTENSIONS--
4+
curl
5+
--SKIPIF--
6+
<?php
7+
if (!defined('CURLOPT_PREREQFUNCTION')) {
8+
die('skip CURLOPT_PREREQFUNCTION not available');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
include 'server.inc';
15+
$host = curl_cli_server_start();
16+
$ch = curl_init("{$host}/get.inc");
17+
18+
curl_setopt($ch, CURLOPT_PREREQFUNCTION,
19+
function (): int {
20+
throw new Exception('prereq exception');
21+
}
22+
);
23+
24+
try {
25+
curl_exec($ch);
26+
} catch (Exception $e) {
27+
echo $e->getMessage(), "\n";
28+
}
29+
30+
var_dump(curl_errno($ch) === CURLE_ABORTED_BY_CALLBACK);
31+
32+
?>
33+
--EXPECTF--
34+
prereq exception
35+
bool(true)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
CURLOPT_PROGRESSFUNCTION aborts transfer when callback throws
3+
--EXTENSIONS--
4+
curl
5+
--SKIPIF--
6+
<?php
7+
if (!defined('CURLOPT_PROGRESSFUNCTION')) {
8+
die('skip CURLOPT_PROGRESSFUNCTION not available');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
include 'server.inc';
15+
$host = curl_cli_server_start();
16+
$ch = curl_init("{$host}/get.inc");
17+
18+
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
19+
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION,
20+
function (): int {
21+
throw new Exception('info exception');
22+
}
23+
);
24+
25+
try {
26+
curl_exec($ch);
27+
} catch (Exception $e) {
28+
echo $e->getMessage(), "\n";
29+
}
30+
31+
var_dump(curl_errno($ch) === CURLE_ABORTED_BY_CALLBACK);
32+
33+
?>
34+
--EXPECTF--
35+
info exception
36+
bool(true)
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
CURLOPT_READFUNCTION aborts transfer when callback throws
3+
--EXTENSIONS--
4+
curl
5+
--SKIPIF--
6+
<?php
7+
if (!defined('CURLOPT_READFUNCTION')) {
8+
die('skip CURLOPT_READFUNCTION not available');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
include 'server.inc';
15+
$host = curl_cli_server_start();
16+
$ch = curl_init("{$host}/get.inc");
17+
18+
$file = new CURLFile(__DIR__ . '/curl_testdata1.txt');
19+
curl_setopt($ch, CURLOPT_POST, ['file' => $file]);
20+
21+
curl_setopt($ch, CURLOPT_READFUNCTION,
22+
function (): int {
23+
throw new Exception('read exception');
24+
}
25+
);
26+
27+
try {
28+
curl_exec($ch);
29+
} catch (Exception $e) {
30+
echo $e->getMessage(), "\n";
31+
}
32+
33+
var_dump(curl_errno($ch) === CURLE_ABORTED_BY_CALLBACK);
34+
35+
?>
36+
--EXPECTF--
37+
read exception
38+
bool(true)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
CURLOPT_WRITEFUNCTION aborts transfer when callback throws
3+
--EXTENSIONS--
4+
curl
5+
--SKIPIF--
6+
<?php
7+
if (!defined('CURLOPT_WRITEFUNCTION')) {
8+
die('skip CURLOPT_WRITEFUNCTION not available');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
include 'server.inc';
15+
$host = curl_cli_server_start();
16+
$ch = curl_init("{$host}/get.inc");
17+
18+
curl_setopt($ch, CURLOPT_WRITEFUNCTION,
19+
function (): int {
20+
throw new Exception('write exception');
21+
}
22+
);
23+
24+
try {
25+
curl_exec($ch);
26+
} catch (Exception $e) {
27+
echo $e->getMessage(), "\n";
28+
}
29+
30+
var_dump(curl_errno($ch) === CURLE_WRITE_ERROR);
31+
32+
?>
33+
--EXPECTF--
34+
write exception
35+
bool(true)
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
CURLOPT_XFERINFOFUNCTION aborts transfer when callback throws
3+
--EXTENSIONS--
4+
curl
5+
--SKIPIF--
6+
<?php
7+
if (!defined('CURLOPT_XFERINFOFUNCTION')) {
8+
die('skip CURLOPT_XFERINFOFUNCTION not available');
9+
}
10+
?>
11+
--FILE--
12+
<?php
13+
14+
include 'server.inc';
15+
$host = curl_cli_server_start();
16+
$ch = curl_init("{$host}/get.inc");
17+
18+
curl_setopt($ch, CURLOPT_NOPROGRESS, 0);
19+
curl_setopt($ch, CURLOPT_XFERINFOFUNCTION,
20+
function (): int {
21+
throw new Exception('info exception');
22+
}
23+
);
24+
25+
try {
26+
curl_exec($ch);
27+
} catch (Exception $e) {
28+
echo $e->getMessage(), "\n";
29+
}
30+
31+
var_dump(curl_errno($ch) === CURLE_ABORTED_BY_CALLBACK);
32+
33+
?>
34+
--EXPECTF--
35+
info exception
36+
bool(true)

0 commit comments

Comments
 (0)