Skip to content

Commit 447938f

Browse files
authored
Merge branch: Fix merge HTTP headers with cURL options (#63)
HTTP headers were not merged properly, and were also not accounting for possible casing differences. Follow-up of simplepie#912 It was for instance not possible to override the `Accept` header from the cURL options. The existing code could not work properly because we were merging arrays of strings and not arrays of key-values, leading to strange duplicates. Downstream: * FreshRSS/FreshRSS#8246 Upstream: * simplepie#956
1 parent e7b26b4 commit 447938f

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

src/File.php

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -111,15 +111,33 @@ public function __construct(string $url, int $timeout = 10, int $redirects = 5,
111111
if (!$force_fsockopen && function_exists('curl_exec')) {
112112
$this->method = \SimplePie\SimplePie::FILE_SOURCE_REMOTE | \SimplePie\SimplePie::FILE_SOURCE_CURL;
113113
$fp = curl_init();
114-
$headers2 = [];
115-
foreach ($headers as $key => $value) {
116-
$headers2[] = "$key: $value";
117-
}
118-
if (isset($curl_options[CURLOPT_HTTPHEADER])) {
119-
if (is_array($curl_options[CURLOPT_HTTPHEADER])) {
120-
$headers2 = array_merge($headers2, $curl_options[CURLOPT_HTTPHEADER]);
114+
if (is_array($curl_options[CURLOPT_HTTPHEADER] ?? null)) {
115+
// Save the original casing of HTTP headers
116+
$headers_keys = array_combine(array_map('strtolower', array_keys($headers)), array_keys($headers)) ?: [];
117+
// Merge HTTP headers case-insensitively from cURL options with the ones from the dedicated parameter
118+
$headers = array_change_key_case($headers, CASE_LOWER);
119+
foreach ($curl_options[CURLOPT_HTTPHEADER] as $header) {
120+
if (is_string($header)) {
121+
$parts = explode(':', $header, 2);
122+
if (count($parts) >= 2) {
123+
$key = trim($parts[0]);
124+
$headers_keys[strtolower($key)] = $key;
125+
$headers[strtolower($key)] = trim($parts[1]);
126+
}
127+
}
121128
}
122-
unset($curl_options[CURLOPT_HTTPHEADER]);
129+
// Restore original casing of HTTP headers
130+
foreach ($headers_keys as $lower_key => $original_key) {
131+
if ($lower_key !== $original_key && isset($headers[$lower_key])) {
132+
$headers[$original_key] = $headers[$lower_key];
133+
unset($headers[$lower_key]);
134+
}
135+
}
136+
}
137+
unset($curl_options[CURLOPT_HTTPHEADER]);
138+
$headers_inlined = [];
139+
foreach ($headers as $key => $value) {
140+
$headers_inlined[] = "$key: $value";
123141
}
124142
if (version_compare(\SimplePie\Misc::get_curl_version(), '7.10.5', '>=')) {
125143
curl_setopt($fp, CURLOPT_ENCODING, '');
@@ -131,7 +149,7 @@ public function __construct(string $url, int $timeout = 10, int $redirects = 5,
131149
curl_setopt($fp, CURLOPT_CONNECTTIMEOUT, $timeout);
132150
// curl_setopt($fp, CURLOPT_REFERER, \SimplePie\Misc::url_remove_credentials($url)); // FreshRSS removed
133151
curl_setopt($fp, CURLOPT_USERAGENT, $useragent);
134-
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers2);
152+
curl_setopt($fp, CURLOPT_HTTPHEADER, $headers_inlined);
135153
$responseHeaders = '';
136154
curl_setopt($fp, CURLOPT_HEADERFUNCTION, function ($ch, string $header) use (&$responseHeaders) {
137155
$responseHeaders .= $header;

0 commit comments

Comments
 (0)