-
Notifications
You must be signed in to change notification settings - Fork 26
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
Fix for RedisSession.created #37
Fix for RedisSession.created #37
Conversation
Change RedisSession.created to represent the time the session was first created, rather than the time this particular session *instance* was initialised.
Please hold on the merge for now (though feel free to take a look at it and see if you like the changes) -- I got to spend a bit more time with the code mmerickel showed me yesterday, and there are a couple of issues re: backward compatibility and exception handling that we would need to discuss. I'll link to his gist in the invalidate issue thread and explain more there in a bit. Thanks! |
Update some docstrings that should have been updated following the change from persisting only the session dict to persisting a tuple.
…uple. Move timeout out of managed_dict, as it is metadata that is not part of the session. Previously any timeout set via .adjust_timeout_for_session() would be lost after .clear(), for example. Serialise session dict, created time, and timeout for storage in Redis as a dict instead of a tuple, as a dict is more extensible, more readable and less bug-prone.
This fix adds support for the use of a new session within the same request after an .invalidate() call. invalidate() now deletes the session_id key from Redis, and RedisSession now knows to start a new session with a new session_id when it is needed. (Previously invalidate() only cleared the session dict and set a header to delete the cookie, and did not take into account the use of the session after invalidate().) It also fixes the cookie setting after invalidate(). Previously invalidate() just added another Set-Cookie header to the response to delete the cookie, meaning there could be more than one Set-Cookie headers for the same cookie name, which should not happen according to RFC 6265. This has been fixed to set one and only one Set-Cookie header (if any is needed) in the response callback, and to handle the various combinations of whether the request started with a new session or existing session, whether a new session was used after invalidate(), more than one invalidate()s in the same request, and the cookie_on_exception setting.
The signed secret being bad is just one of the possible reasons why the value cannot be deserialized.
More commits, and finally, the invalidate fix (#33)! With many thanks to mmerickel for the SessionState idea. Some notes and questions: If request.session starts with an existing session, we invalidate(), then On the whole cookie_on_exception's purpose still seems really unclear to me. I Right now the cookie callback makes its decision based on the The implementation of the _cookie_callback may not be very easy to understand Is RedisSession.default_timeout intended to be part of the API? I don't think In test_session.py, I split makeOne() into set_up_session_in_redis() and I hope the rest makes sense, and please let me know if there's anything you'd |
Just a quick update: I started reviewing this and so far so good. Need to wrap up some coursework tonight but will address your questions by tomorrow night at the latest. Thanks! |
Appreciate it! (And don't worry about taking a bit longer if you're busy, I already really appreciate how responsive you've been :) ) |
Answers --
Anyway, looks great! I'm going to take a couple days to review in more detail and test, but I don't foresee any major changes to what's there. |
Thanks for reviewing! As you don't mind, I think we can remove the timeout parameter and the default_timeout attribute from RedisSession -- if we need the default value we can get it from request.registry.settings. I'll have the changes for you either tomorrow or Friday. |
They are no longer needed now that the timeout is inserted into Redis by the factory at the beginning of a new session.
Added commit to remove RedisSession's timeout parameter and default_timeout attribute, and update tests. DummySession still has a timeout parameter, but that's okay, right? |
Spent some time reviewing the changes today and the interactive tests seem fine (me poking at it in a sample pyramid app), but the tests are failing for me with pyramid==1.4.1 and WebOb==1.2.3, on both python 2.7 and python 3.3. Here's a gist with the output: https://gist.github.com/ericrasmussen/481f036738c4b5f6c305 The issue seems to be pyramid.session.signed_serialize producing session IDs that end with something like 'VxAS4=' and webob adding a header with that same key as 'VxAS4\075'. '=' is 075 in octal so I'm guessing something in the test case isn't handling a conversion that seems to work fine in an actual pyramid app. Have you seen this error? If not, can you let me know what versions of pyramid and webob you're testing on? Thanks! |
The tests fail for me too on WebOb==1.2.3, but they pass fine on WebOb>=1.3. This looks to be the issue: https://github.com/Pylons/webob/blob/master/docs/news.txt#L63
With WebOb==1.2.3, the tests fail because we are comparing the cookie values with '=' quoted by I'm thinking about whether it's worth involving |
I'm actually starting to think we should just require WebOb >= 1.3 in Can you think of anything I'm missing? If not, let's just add that to On Sun, May 18, 2014 at 2:09 AM, Ira [email protected] wrote:
|
Update: Found two bugs after we talked yesterday:
Will fix those too. In light of these bugs I think we really ought to add tests to check that those As for the assert problem, neither of the negative assertion options we looked at yesterday inspire confidence. So here's the best approach available to us that I can see: make another If you're okay with those changes, let me know and I'll go ahead with them. May not have time tomorrow, but can have them for you by Friday (barring more issues coming up...) |
``cookie_httponly``'s default is True, but docstring had it as False.
It was already accessible as an import.
To assert that a header is one that sets a cookie as opposed to one that deletes a cookie, we no longer assert the serialized session_id. This means the tests would not break if `response.set_cookie()` makes any changes to the serialized session_id before inserting it into the cookie, as WebOb<=1.3 did by quoting certain characters. The alternative approach chosen is to assert that 'Max-Age=0' is not in the header string. A Set-Cookie header is either one to set cookie (in which case 'Max-Age=0' would not be in the string), or one to delete cookie (in which case 'Max-Age=0' would be in the string.) It is a negative assertion, but all the alternatives would make the tests too complicated and/or difficult to make sense of. This is the least bad approach I can see for now.
Rearrange the ordering to be consistent with the factory's own parameters and docstring, so that any missing parameters would be easier to spot.
`cookie_path` parameter had no effect because it was not used by the factory at all. We now set and delete cookie with its value as intended.
The factory was not making use of the `cookie_domain` value when setting a header to delete cookie, meaning any cookie with a domain different from the default would not have been deleted (as a cookie only gets deleted if the path and domain match the ones used when the cookie was set).
Turned out even the approach of making a new With that first commit where I fixed the default value of |
Just wanted to clarify, with the typo, I just wasn't sure if I could change it myself now that I've pushed, whether it would mess up this pull request. Can I do it myself? (rebase -i and push -f?) |
I think you can still rebase. Whatever's on your fork and branch is what will be in the pull request. But the typo doesn't seem like an issue to me. The test looks like it should be good too. Will try to wrap up a couple things this week so I can merge and then add to the docs and change log. Thanks! |
If you don't mind the typo, I'll let it go. It's not a big deal, not worth the risk (it's probably fine to rebase as you said, but I'll test that another time!) I can write up a list of the changes I've made, if that would help? |
I updated the changelog as we talked about and tried to follow the existing format, but please feel free to edit/reword/reformat to your liking! You may want to take a look at this other issue (#38) before release -- as mmerickel mentioned that would be another change that would break all existing sessions, so you may want to do both in the same release. Thanks! |
Also, is the changelog looking as wrong for you as it does for me on GitHub? Is that GitHub, or something in the markup that we can fix? |
GitHub's rst renderer is a little weird so it's more or less expected. You can try building the change log with sphinx to double check but it's not a priority to spend time on that, as long as it's fairly easy to read. The updates look good. I'm going to merge now and then work on the other release bits this week. Thanks so much for all the great work! |
Fix for RedisSession.created
FYI -- all of your fixes and updates (plus a couple tiny misc things) are On Sun, Jun 15, 2014 at 3:21 PM, Ira [email protected] wrote:
|
Thanks very much for the release! (Hope that means you and your toddler have been getting better sleep! :) ) You may remember I mentioned back in #33 (comment) that we can replace the use of pipeline with the new parameters for .set(), introduced in Redis 2.6.12 and redis-py 2.7.4 (you just changed the required version of redis-py from >= 2.4.11 to <=2.9.1 -- I guess the lower bound is far enough back that we don't have to worry about it any more?) I think it would be a really worthwhile change, and should be fairly straightforward -- I can maybe work on a PR for you some time next week and you can merge as and when you're ready to drop support for Redis < 2.6.12 and redis-py < 2.7.4? Also, while I was working on the previous PR, I noticed that in test_util.py, And reading over some of my own code comments and docstrings now, I may also submit a PR for minor rewordings, just to make the comments clearer in a couple places, if that's okay. Sorry about that -- probably over-worrying on my part, but I think they could be clearer, and I feel responsible :) |
PRs for everything you mentioned are welcome! About the version pinning, being more specific is probably better. I'm not I'm not sure what the best solution is there. They're going to issue On Sat, Jul 5, 2014 at 3:52 PM, Ira [email protected] wrote:
|
I saw the submitted issue and PR over here, so I understood why you pinned to <= 2.9.1 -- was just wondering whether you meant to drop the >=2.4.11 part? I hadn't seen the response you got over on the redis-py side though. So if I understand everything correctly: the breaking changes are here to stay. And from what I can see, pyramid_redis_sessions is just passing those values on. It seems to me that it's not pyramid_redis_sessions' responsibility at all, and if anything we could just not and maybe should not specify Once redis-py 2.10.2 comes out, we can stop pinning to <= 2.9.1 and users using (The other PRs should be coming later in the week! :) ) |
Dropping >= 2.4.11 is just an oversight. If you can add that back in with If I understand the kwargs solution you're proposing, it would work, and I see two other solutions:
The second option isn't that fun from a code or maintenance standpoint, but I don't think I'll be able to get to any of it this weekend, but let me On Tue, Jul 8, 2014 at 5:22 PM, Ira [email protected] wrote:
|
Yeah, the kwargs solution gives up the control, and I understand your reservations about that. Of course if you don't mind supporting both versions of the settings and having to watch redis-py closely for changes (for example, if redis-py changes the default value for a parameter, you'd have to notice and change yours too), then that would be best for your users :) Option 1 on the other hand seems like it would mean people wouldn't be able to upgrade if they're stuck on anything but the most recent versions of redis-py, so that doesn't seem a great option. If you don't have time to do option 2 yet, the kwargs option would as far as I can see be good enough as a stopgap to get everything working for everyone until you do. I submitted the other changes as separate PRs, as last time the PR really got quite huge and unwieldy. Hope that's okay! |
Thanks! Started merging them but will probably take me a few days to get On Sun, Jul 13, 2014 at 11:50 AM, Ira [email protected] wrote:
|
The three commits:
Change
RedisSession.created
to represent the time the session was first created, rather than the time this particular session instance was initialised.The tuple approach follows the one in Pyramid (https://github.com/Pylons/pyramid/blob/master/pyramid/session.py#L368), and keeps the value out of the session dict. If you think that's okay, I think it would also make sense to follow the same approach with the timeout value?
Re-arrange imports as we discussed.
PEP 8 mostly, and in test-related code place less dependable imports in test methods wherever possible.
Remove support for Python 2.6 from setup.py as we discussed.
Do you also want to add support for Python 3.4? I think there's a bug with Nose that breaks something with Python 3.4 at the moment, but the tests pass with
python -m unittest
.Please let me know if there's anything you need me to change. Thanks!