-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[HttpFoundation][Sessions] Losing session in case of many concurrent requests. #4668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Do you have a failing TC with concurrent access ? As PHP is supposed to take care of serializing the requests (ie you can't have 2 concurrent requests for the same session) the issue might be related to PHP. |
I suspected this would be the case, that's why the native |
@Drak what exactly did you suspect ? If there could be concurrent requests for the same session then all non-native handler are flawed - but this this not be the case (as it is handled by PHP). |
@vicb - Just that the locking is handled in the files handler see source but only for windows. I would also like to see a test case though to know if this is just theoretical or not. |
Problem with session appear after last update (about 5 days ago). Earlier when Symfony used native PHP session handler everything was OK. I cant give you a concrete test case because this problem occurs randomly. Some time I can work on dev environment for 30 minutes and problem does not exist, but some time every refresh is crashed. Important thing is that the problem alway appear when browser load asset file (js, css, templates), never when load page (html). I use to load JavaScript and templates file a requirejs witch generate so many request. I work all day on my patch and the problem did not appear. My dev PC work on linux Kubuntu 12.04. I dont test patch on Windows. |
@yanoosh thanks for the update. I should have some time to investigate beginning of next week. What are the symptoms when it crashes ? |
$success = (bool)fwrite($handle, $data); | ||
flock($handle, LOCK_UN); | ||
fclose($handle); | ||
return $success; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing extra line before return
flock($handle, LOCK_UN); | ||
fclose($handle); | ||
} else { | ||
$data = ''; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would put this $data = '';
before the if (is_readable(...)) {
in case the inner if returns false.
I created a repository which allows you to test my patch. https://github.com/yanoosh/symfony-session-test |
@yanoosh I used to test concurrency some weeks ago with this code - the handler comes for php.net. I did not notice any problem: If you execute two concurrent requests, the second one will block until the first one is done (i.e. the session data have been written). Doing the test again this morning with 3 concurrent requests: Once the first request is over, the 2 other (blocked) ones start at the same time. This is then where you might see an issue. |
It seems that all storage handlers are affected by this issue. The symptoms would not exactly be the same but let's say you have 2 concurrent requests. If they start at the same time they will both get the same copy of session data (as reading the session data would occur at about the same time). Now let's say that one of the request results in updating / adding some values into the session and is the first to terminate, the updated / added value would be written into the session storage. Then the second request terminates. The copy of the session it has has not been updated (it is the same at what the first request got while reading the initial data) but would overwrite the data updated / added by the other session. Scenario:
All of the storage handlers are concerned by this issue. Native handlers are not concerned:
@Drak what do you think ? |
if (is_readable($path)) { | ||
$handle = fopen($path, 'r'); | ||
flock($handle, LOCK_SH); | ||
if (0 < $size = filesize($path)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why do we need filesize()
here ? isn't the return value from fread()
good enough - also filesize
caches the file size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If second argument in fread will be not greater than zero then PHP throw error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea would be to issue a fread($handle, 50000)
and loop if not at eof - you should really be careful with the filesize cache, got trapped a few times !
@vicb post realized me that my PR does not resolved problem with session handling. To get rid of all problem associated with sessions we have to decide:
For me best solution will be 2 - in C code is condition for systems PHP_WIN32 https://github.com/php/php-src/blob/master/ext/session/mod_files.c#L172. |
@yanoosh regarding your last message: 1- we must add locks to all session handlers, |
Implemented changes which are discussed. Waiting for your opinions. |
return !(false === fwrite($this->handle, $data)); | ||
} | ||
|
||
protected function initSessionFile($id){ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The brace should be on a new line.
… replaced file_put/get_contents functions by fopen/fclose.
…nd removed else statement.
…ock in read and unlock in close method.
…nvoke method save and close to finish session.
… storage handler which is subject of test. In case when any of unrelated method will be damaged result of test case will be invalid.
Overall I think this PR is wrong to persist the session ID in the object instance - that's not how save handlers are supposed to operate - they don't track the session, they simply a CRUD driver - they should not be concerned with anything beyond doing that. Before these recent changes, the PR was OK. |
@Drak you have right that CRUD class should not track session, but how we prevent from overwrite session by other requests. Lock session must exist to properly handling a requests. We can move lock session somewhere else, but where ? |
Commits ------- a351362 [HttpFoundation] Add NativeSessionHandler tests 653821a [HttpFoundation] Remove FileSessionHandler 3456787 Partially revert "[HttpFoundation][Sessions] Refactored tests" 39813a0 Revert "[FrameworkBundle] Refactor session file handler service name and update changelogs" fbee4cf Restore NativeFileSessionHandler Discussion ---------- [Session] Restore NativeFileSessionStorage Bug fix: no Feature addition: yes Backwards compatibility break: no Symfony2 tests pass: yes Fixes the following tickets: #4668 Todo: - License of the code: MIT This reverts the removal of the native file handler.
Bug fix: yes
Feature addition: no
Backwards compatibility break: no
Symfony2 tests pass: yes
License of the code: MIT
When symfony handling many request of one session many instances try read and write session file. The first phase of writing the file is empty and then write session data. If script load an empty file then session will be incorrect. Easiest way to prevent this behaviour is use flock function which allows to control file usage.