Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit f29f02b

Browse filesBrowse files
committed
Do not send deleted session cookie twice in the response
1 parent 91b7bdd commit f29f02b
Copy full SHA for f29f02b

File tree

4 files changed

+78
-0
lines changed
Filter options

4 files changed

+78
-0
lines changed
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
Array
3+
(
4+
[0] => Content-Type: text/plain; charset=utf-8
5+
[1] => Cache-Control: max-age=0, private, must-revalidate
6+
[2] => Cache-Control: max-age=0, must-revalidate, private
7+
[3] => Date: Sat, 12 Nov 1955 20:04:00 GMT
8+
[4] => Expires: %s, %d %s %d %d:%d:%d GMT
9+
[5] => Set-Cookie: PHPSESSID=deleted; expires=%s, %d-%s-%d %d:%d:%d GMT; Max-Age=%d; %s
10+
)
11+
shutdown
+60Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
use Symfony\Component\DependencyInjection\Container;
4+
use Symfony\Component\HttpFoundation\Request;
5+
use Symfony\Component\HttpFoundation\RequestStack;
6+
use Symfony\Component\HttpFoundation\Response;
7+
use Symfony\Component\HttpFoundation\Session\SessionFactory;
8+
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorageFactory;
9+
use Symfony\Component\HttpKernel\Event\RequestEvent;
10+
use Symfony\Component\HttpKernel\Event\ResponseEvent;
11+
use Symfony\Component\HttpKernel\EventListener\SessionListener;
12+
use Symfony\Component\HttpKernel\HttpKernelInterface;
13+
14+
/** @var Response $r */
15+
$r = require __DIR__.'/common.inc';
16+
17+
$sessionId = 'vqd4dpbtst3af0k4sdl18nebkn';
18+
session_id($sessionId);
19+
$sessionName = session_name();
20+
$_COOKIE[$sessionName] = $sessionId;
21+
22+
$request = new Request();
23+
$request->cookies->set($sessionName, $sessionId);
24+
25+
$requestStack = new RequestStack();
26+
$requestStack->push($request);
27+
28+
$sessionFactory = new SessionFactory($requestStack, new NativeSessionStorageFactory());
29+
30+
$container = new Container();
31+
$container->set('request_stack', $requestStack);
32+
$container->set('session_factory', $sessionFactory);
33+
34+
$listener = new SessionListener($container);
35+
36+
$kernel = new class($r) implements HttpKernelInterface {
37+
/**
38+
* @var Response
39+
*/
40+
private $response;
41+
42+
public function __construct(Response $response)
43+
{
44+
$this->response = $response;
45+
}
46+
47+
public function handle(Request $request, int $type = self::MAIN_REQUEST, bool $catch = true): Response
48+
{
49+
return $this->response;
50+
}
51+
};
52+
53+
$listener->onKernelRequest(new RequestEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST));
54+
$session = $request->getSession();
55+
$session->set('foo', 'bar');
56+
$session->invalidate();
57+
58+
$listener->onKernelResponse(new ResponseEvent($kernel, $request, HttpKernelInterface::MAIN_REQUEST, $r));
59+
60+
$r->sendHeaders();

‎src/Symfony/Component/HttpFoundation/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpFoundation/composer.json
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
"require-dev": {
2525
"predis/predis": "~1.0",
2626
"symfony/cache": "^4.4|^5.0|^6.0",
27+
"symfony/dependency-injection": "^5.4|^6.0",
28+
"symfony/http-kernel": "^5.4|^6.0",
2729
"symfony/mime": "^4.4|^5.0|^6.0",
2830
"symfony/expression-language": "^4.4|^5.0|^6.0"
2931
},

‎src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ public function onKernelResponse(ResponseEvent $event)
158158

159159
$isSessionEmpty = $session->isEmpty() && empty($_SESSION); // checking $_SESSION to keep compatibility with native sessions
160160
if ($requestSessionCookieId && $isSessionEmpty) {
161+
// PHP internally sets the session cookie value to "deleted" when setcookie() is called with empty string $value argument
162+
// which happens in \Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler::destroy
163+
// when the session gets invalidated (for example on logout) so we must handle this case here too
164+
// otherwise we would send two Set-Cookie headers back with the response
165+
SessionUtils::popSessionCookie($sessionName, 'deleted');
161166
$response->headers->clearCookie(
162167
$sessionName,
163168
$sessionCookiePath,

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.