File: curl_setopt_CURLOPT_DEBUGFUNCTION.phpt

package info (click to toggle)
php8.4 8.4.11-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 208,108 kB
  • sloc: ansic: 1,060,628; php: 35,345; sh: 11,866; cpp: 7,201; pascal: 4,913; javascript: 3,091; asm: 2,810; yacc: 2,411; makefile: 689; xml: 446; python: 301; awk: 148
file content (236 lines) | stat: -rw-r--r-- 6,980 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
--TEST--
Curl option CURLOPT_DEBUGFUNCTION
--EXTENSIONS--
curl
--FILE--
<?php
include 'server.inc';

$allowedTypes = [
    CURLINFO_TEXT,
    CURLINFO_HEADER_IN,
    CURLINFO_HEADER_OUT,
    CURLINFO_DATA_IN,
    CURLINFO_DATA_OUT,
    CURLINFO_SSL_DATA_OUT,
    CURLINFO_SSL_DATA_IN,
];

var_dump(CURLOPT_DEBUGFUNCTION);

$host = curl_cli_server_start();

echo "\n===Testing with regular CURLOPT_VERBOSE with verbose=false===\n";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$host}/get.inc?test=file");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, function() {
    echo 'This should not be called';
}));
curl_exec($ch);
curl_setopt($ch, CURLOPT_VERBOSE, 1);

echo "\n===Testing with regular CURLOPT_VERBOSE on stderr===\n";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "{$host}/get.inc?test=file");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
$stderr = fopen('php://temp', 'wb+');
curl_setopt($ch, CURLOPT_STDERR, $stderr);
$curlVerboseOutput = curl_exec($ch);
rewind($stderr);
$receivedOutput = stream_get_contents($stderr);
fclose($stderr);
var_dump(str_contains($receivedOutput, 'Host'));

echo "\n===Testing with CURLOPT_DEBUGFUNCTION happy path===\n";
$stderr = fopen('php://temp', 'wb+');
curl_setopt($ch, CURLOPT_STDERR, $stderr);

$debugOutput = [];
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, function(CurlHandle $curlHandle, int $type, string $data) use ($allowedTypes, &$debugOutput) {
    if (!in_array($type, $allowedTypes)) {
        throw new Exception('Unexpected type value: '. $type);
    }
    $debugOutput[$type][] = $data;
}));

$result = curl_exec($ch);
rewind($stderr);
$receivedOutputWithDebugFunction = stream_get_contents($stderr);
fclose($stderr);
echo "Received stderr empty:\n";
var_dump($result);
var_dump($receivedOutputWithDebugFunction);

// Header-out should be an exact match
var_dump(str_contains($receivedOutput, $debugOutput[CURLINFO_HEADER_OUT][0]));

// Header-in fields should match, except for the "Date" header that is dynamic.
foreach ($debugOutput[CURLINFO_HEADER_IN] as $headerReceived) {
    if (str_starts_with($headerReceived, 'Date')) {
        continue;
    }
    if (!str_contains($receivedOutput, $headerReceived)) {
        throw new \Exception('DEBUGFUNCTION header field does not match the previous verbose debug message');
    }
}

echo "\n===Test attempting to set CURLINFO_HEADER_OUT while CURLOPT_DEBUGFUNCTION in effect throws===\n";
$ch = curl_init();
var_dump(curl_setopt($ch, CURLINFO_HEADER_OUT, true));
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, null));
var_dump(curl_setopt($ch, CURLINFO_HEADER_OUT, true));
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, 'strlen'));
try {
    var_dump(curl_setopt($ch, CURLINFO_HEADER_OUT, true));
}
catch (\ValueError $e) {
    var_dump($e->getMessage());
}
$chCopy = curl_copy_handle($ch);
try {
    var_dump(curl_setopt($chCopy, CURLINFO_HEADER_OUT, true));
}
catch (\ValueError $e) {
    var_dump($e->getMessage());
}
var_dump(curl_setopt($chCopy, CURLOPT_DEBUGFUNCTION, null));
var_dump(curl_setopt($chCopy, CURLINFO_HEADER_OUT, true));

echo "\n===Test attempting to set CURLOPT_DEBUGFUNCTION while CURLINFO_HEADER_OUT does not throw===\n";
$ch = curl_init();
var_dump(curl_setopt($ch, CURLINFO_HEADER_OUT, true));
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, null));
var_dump(curl_setopt($ch, CURLINFO_HEADER_OUT, true));
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, 'strlen'));
$chCopy = curl_copy_handle($ch);
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, 'strlen'));
var_dump(curl_setopt($chCopy, CURLOPT_DEBUGFUNCTION, null));
var_dump(curl_setopt($chCopy, CURLINFO_HEADER_OUT, 1));

echo "\n===Test CURLOPT_DEBUGFUNCTION=null works===\n";
$ch = curl_init("{$host}/get.inc?test=file");
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, null));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
var_dump(curl_exec($ch));

echo "\n===Test CURLINFO_HEADER_OUT works while CURLOPT_DEBUGFUNCTION in effect===\n";
$ch = curl_init("{$host}/get.inc?test=file");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
var_dump(curl_getinfo($ch, CURLINFO_HEADER_OUT));
var_dump(curl_setopt($ch, CURLINFO_HEADER_OUT, true));
var_dump(curl_getinfo($ch, CURLINFO_HEADER_OUT));
var_dump(curl_setopt($ch, CURLOPT_DEBUGFUNCTION, static function() {}));
var_dump(curl_getinfo($ch, CURLINFO_HEADER_OUT));
var_dump($result = curl_exec($ch));
var_dump(curl_getinfo($ch, CURLINFO_HEADER_OUT));

echo "\n===Test CURLOPT_DEBUGFUNCTION can throw within callback===\n";
$ch = curl_init("{$host}/get.inc?test=file");
curl_setopt($ch, CURLOPT_DEBUGFUNCTION, static function() {
    throw new \RuntimeException('This should get caught after verbose=true');
});
var_dump(curl_exec($ch));
curl_setopt($ch, CURLOPT_VERBOSE, true);
try {
    var_dump($result = curl_exec($ch));
}
catch (\RuntimeException $e) {
    var_dump($e->getMessage());
}
var_dump(curl_getinfo($ch, CURLINFO_HEADER_OUT));

echo "\n===Test CURLOPT_DEBUGFUNCTION on shared handles work===\n";
$ch = curl_init("{$host}/get.inc?test=file");
$called = false;
curl_setopt_array($ch, [
    CURLOPT_VERBOSE => true,
    CURLOPT_DEBUGFUNCTION => static function() use (&$called) {
        $called = true;
    },
]);
var_dump($called);
curl_exec($ch);
var_dump($called);
$called = false;
$ch2 = curl_copy_handle($ch);
curl_exec($ch2);
var_dump($called);
var_dump(curl_getinfo($ch2, CURLINFO_HEADER_OUT));

echo "\nDone";
?>
--EXPECTF--
int(20094)

===Testing with regular CURLOPT_VERBOSE with verbose=false===
bool(true)

===Testing with regular CURLOPT_VERBOSE on stderr===
bool(true)

===Testing with CURLOPT_DEBUGFUNCTION happy path===
bool(true)
Received stderr empty:
string(0) ""
string(0) ""
bool(true)

===Test attempting to set CURLINFO_HEADER_OUT while CURLOPT_DEBUGFUNCTION in effect throws===
bool(true)
bool(true)
bool(true)
bool(true)
string(87) "CURLINFO_HEADER_OUT option must not be set when the CURLOPT_DEBUGFUNCTION option is set"
string(87) "CURLINFO_HEADER_OUT option must not be set when the CURLOPT_DEBUGFUNCTION option is set"
bool(true)
bool(true)

===Test attempting to set CURLOPT_DEBUGFUNCTION while CURLINFO_HEADER_OUT does not throw===
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)

===Test CURLOPT_DEBUGFUNCTION=null works===
bool(true)
string(0) ""

===Test CURLINFO_HEADER_OUT works while CURLOPT_DEBUGFUNCTION in effect===
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
string(0) ""
string(%d) "GET /get.inc?test=file HTTP/%s
Host: %s:%d
Accept: */*

"

===Test CURLOPT_DEBUGFUNCTION can throw within callback===
bool(true)
string(41) "This should get caught after verbose=true"
string(%d) "GET /get.inc?test=file HTTP/%s
Host: %s:%d
Accept: */*

"

===Test CURLOPT_DEBUGFUNCTION on shared handles work===
bool(false)
bool(true)
bool(true)
string(71) "GET /get.inc?test=file HTTP/%s
Host: %s:%d
Accept: */*

"

Done