Skip to content

Commit b23f3c5

Browse files
authored
Merge pull request #135 from aszenz/fix-httponly-cookies
Support parsing httponly cookies
2 parents 8cf5352 + 4c6f864 commit b23f3c5

2 files changed

Lines changed: 49 additions & 1 deletion

File tree

lib/Adapter/Artax/NetscapeCookieFileJar.php

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,14 @@ private function parse(string $line): ?ResponseCookie
6969
return null;
7070
}
7171

72-
if ($line[0] === '#') {
72+
// Handle httponly cookies - lines starting with #HttpOnly_ should be parsed
73+
// See: https://curl.se/docs/http-cookies.html
74+
$isHttpOnly = false;
75+
if (str_starts_with($line, '#HttpOnly_')) {
76+
$line = substr($line, 10); // Remove the '#HttpOnly_' prefix
77+
$isHttpOnly = true;
78+
} elseif ($line[0] === '#') {
79+
// Regular comment line, skip it
7380
return null;
7481
}
7582

@@ -104,6 +111,10 @@ private function parse(string $line): ?ResponseCookie
104111
$string .= '; secure';
105112
}
106113

114+
if ($isHttpOnly) {
115+
$string .= '; httponly';
116+
}
117+
107118
return ResponseCookie::fromHeader($string);
108119
}
109120
}

tests/Integration/Adapter/Artax/NetscapeCookieFileJarTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,41 @@ public function testLoadCookies()
7171
(yield $jar->get((new Request('http://127.0.0.1/'))->getUri()))[0]->getValue()
7272
);
7373
}
74+
75+
public function testLoadHttpOnlyCookies()
76+
{
77+
$expire = (new DateTimeImmutable())->modify('+1 day')->format('U');
78+
79+
$cookies = <<<EOT
80+
# Netscape HTTP Cookie File
81+
# This is a comment and should be ignored
82+
83+
#HttpOnly_.example.com TRUE / FALSE $expire session_id abc123
84+
#HttpOnly_example.com FALSE /admin TRUE $expire admin_token xyz789
85+
.example.com TRUE / FALSE $expire regular_cookie normal_value
86+
EOT
87+
;
88+
89+
$this->workspace()->put('httponly_cookies.txt', $cookies);
90+
$path = $this->workspace()->path('httponly_cookies.txt');
91+
92+
$jar = new NetscapeCookieFileJar($path);
93+
94+
$allCookies = $jar->getAll();
95+
96+
// Should have 3 cookies total (2 httponly + 1 regular)
97+
$this->assertCount(3, $allCookies);
98+
99+
// Get cookies for example.com
100+
$exampleCookies = yield $jar->get((new Request('https://example.com/'))->getUri());
101+
102+
// Should include the httponly cookie
103+
$cookieNames = array_map(fn ($cookie) => $cookie->getName(), $exampleCookies);
104+
$this->assertContains('session_id', $cookieNames);
105+
$this->assertContains('regular_cookie', $cookieNames);
106+
107+
// Verify httponly cookie value
108+
$sessionCookie = array_filter($exampleCookies, fn ($cookie) => $cookie->getName() === 'session_id');
109+
$this->assertEquals('abc123', reset($sessionCookie)->getValue());
110+
}
74111
}

0 commit comments

Comments
 (0)