fix: use cURL cookie engine instead of parse_str for RFC 6265 compliance

parse_str() URL-decodes cookie values, causing the test client to behave
differently from real clients (Dart, Swift) which store values verbatim
per RFC 6265. This masked a production bug where base64 session values
containing %3D%3D would fail to decode on real devices.

Replaces the manual Set-Cookie header parsing with cURL's built-in cookie
engine (CURLOPT_COOKIEFILE='') and reads cookies via CURLINFO_COOKIELIST,
which stores and returns values verbatim without any decoding.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
loks0n
2026-04-08 15:07:46 +01:00
co-authored by Claude Sonnet 4.6
parent 9feb204fd5
commit e2d7dd837d
+7 -22
View File
@@ -219,7 +219,8 @@ class Client
curl_setopt($ch, CURLOPT_HTTPHEADER, $formattedHeaders);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 0);
curl_setopt($ch, CURLOPT_TIMEOUT, 120);
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders, &$cookies) {
curl_setopt($ch, CURLOPT_COOKIEFILE, ''); // enable in-memory RFC 6265 cookie engine
curl_setopt($ch, CURLOPT_HEADERFUNCTION, function ($curl, $header) use (&$responseHeaders) {
$len = strlen($header);
$header = explode(':', $header, 2);
@@ -227,12 +228,6 @@ class Client
return $len;
}
if (strtolower(trim($header[0])) == 'set-cookie') {
$parsed = $this->parseCookie((string)trim($header[1]));
$name = array_key_first($parsed);
$cookies[$name] = $parsed[$name];
}
$responseHeaders[strtolower(trim($header[0]))] = trim($header[1]);
return $len;
@@ -259,6 +254,11 @@ class Client
$responseType = $responseHeaders['content-type'] ?? '';
$responseStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);
foreach (curl_getinfo($ch, CURLINFO_COOKIELIST) as $line) {
$parts = explode("\t", $line);
$cookies[$parts[5]] = $parts[6] ?? '';
}
if ($decode && $method !== self::METHOD_HEAD) {
$strpos = strpos($responseType, ';');
$strpos = \is_bool($strpos) ? \strlen($responseType) : $strpos;
@@ -309,21 +309,6 @@ class Client
];
}
/**
* Parse Cookie String
*
* @param string $cookie
* @return array
*/
public function parseCookie(string $cookie): array
{
$cookies = [];
parse_str(strtr($cookie, ['&' => '%26', '+' => '%2B', ';' => '&']), $cookies);
return $cookies;
}
/**
* Flatten params array to PHP multiple format
*