Skip to content

Commit b0c9beb

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

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
@@ -554,6 +554,8 @@ static size_t curl_write(char *data, size_t size, size_t nmemb, void *ctx)
554554
_php_curl_verify_handlers(ch, /* reporterror */ true);
555555
/* TODO Check callback returns an int or something castable to int */
556556
length = php_curl_get_long(&retval);
557+
} else if (EG(exception)) {
558+
length = -1;
557559
}
558560

559561
zval_ptr_dtor(&argv[0]);
@@ -603,7 +605,7 @@ static int curl_fnmatch(void *ctx, const char *pattern, const char *string)
603605
static int curl_progress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
604606
{
605607
php_curl *ch = (php_curl *)clientp;
606-
int rval = 0;
608+
int rval = 1;
607609

608610
#if PHP_CURL_DEBUG
609611
fprintf(stderr, "curl_progress() called\n");
@@ -630,8 +632,8 @@ static int curl_progress(void *clientp, double dltotal, double dlnow, double ult
630632
if (!Z_ISUNDEF(retval)) {
631633
_php_curl_verify_handlers(ch, /* reporterror */ true);
632634
/* TODO Check callback returns an int or something castable to int */
633-
if (0 != php_curl_get_long(&retval)) {
634-
rval = 1;
635+
if (0 == php_curl_get_long(&retval)) {
636+
rval = 0;
635637
}
636638
}
637639

@@ -644,7 +646,7 @@ static int curl_progress(void *clientp, double dltotal, double dlnow, double ult
644646
static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
645647
{
646648
php_curl *ch = (php_curl *)clientp;
647-
int rval = 0;
649+
int rval = 1;
648650

649651
#if PHP_CURL_DEBUG
650652
fprintf(stderr, "curl_xferinfo() called\n");
@@ -671,8 +673,8 @@ static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, cu
671673
if (!Z_ISUNDEF(retval)) {
672674
_php_curl_verify_handlers(ch, /* reporterror */ true);
673675
/* TODO Check callback returns an int or something castable to int */
674-
if (0 != php_curl_get_long(&retval)) {
675-
rval = 1;
676+
if (0 == php_curl_get_long(&retval)) {
677+
rval = 0;
676678
}
677679
}
678680

@@ -685,13 +687,13 @@ static int curl_xferinfo(void *clientp, curl_off_t dltotal, curl_off_t dlnow, cu
685687
static int curl_prereqfunction(void *clientp, char *conn_primary_ip, char *conn_local_ip, int conn_primary_port, int conn_local_port)
686688
{
687689
php_curl *ch = (php_curl *)clientp;
688-
int rval = CURL_PREREQFUNC_OK;
690+
int rval = CURL_PREREQFUNC_ABORT;
689691

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

697699
#if PHP_CURL_DEBUG
@@ -822,6 +824,8 @@ static size_t curl_read(char *data, size_t size, size_t nmemb, void *ctx)
822824
}
823825
// TODO Do type error if invalid type?
824826
zval_ptr_dtor(&retval);
827+
} else if (EG(exception)) {
828+
length = CURL_READFUNC_ABORT;
825829
}
826830

827831
zval_ptr_dtor(&argv[0]);
@@ -916,6 +920,8 @@ static size_t curl_write_header(char *data, size_t size, size_t nmemb, void *ctx
916920
// TODO: Check for valid int type for return value
917921
_php_curl_verify_handlers(ch, /* reporterror */ true);
918922
length = php_curl_get_long(&retval);
923+
} else if (EG(exception)) {
924+
length = -1;
919925
}
920926
zval_ptr_dtor(&argv[0]);
921927
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)