My Rails session is getting reset when I have concurrent requests - ruby-on-rails

I think I might be misunderstanding something about Rails sessions, so please bear with me, I might not be phrasing my question the best way.
I'm working on an iPhone app with a Ruby on Rails backend. I have a web view which by default goes to the index action of one controller (and uses sessions), and in the background a bunch of API calls going to a different controller (and which don't need to use sessions).
The problem is, the sessions set by my web view seem to be overwitten by the API calls. My staging server is pretty slow, so there's lots of time for the requests to overlap each other - what I see in the logs is basically this:
Request A (first controller) starts. Session is empty.
Request B (second controller) starts. Session is empty.
Request A finishes. Request A has done authentication, and stored the user ID in the session. Session contains user ID.
Request B finishes. Session is empty.
Request C starts. Session is empty - not what I want.
Now, the strange thing is that request B should NOT be writing anything to the session.
I do have before and after filters which READ from the session - things like:
user = User.find_by_id(session[:id])
or
logger.debug session.inspect
and if I remove all of those, then everything works as expected - session contents get set by request A, and they're still there when request C starts.
So. I think I'm missing something about how sessions work. Why would reading from the session overwrite it? Should I be accessing it some other way? Am I completely on the wrong track and the problem is elsewhere?
Thank you for any insights!

This is the result of a race condition caused by how rails handles session. See http://www.paulbutcher.com/2007/05/race-conditions-in-rails-sessions-and-how-to-fix-them/
It seems like you can't have concurrent requests modifying session reliable. The solution is to use a different method of storing session (e.g. active_record or redis) or you could eliminate the concurrent requests.

Your sessions are maybe cookie based. If that's the case then each of request is starting with the same cookie(session). The cookie holds the session content. Try switching the storage to be on the server. But I in your case with the authentication I think it would be much better to not do this async.
Request A (first controller) starts. Session is empty.
Request B (second controller) starts. Session is empty.
Request A finishes. Request A has done authentication, and stored the user ID in the session. Session contains user ID
.....AND returning the session content in a cookie.
Request B finishes. Session is empty.
THIS one is setting blank session.
Request C starts. Session is empty - not what I want.
Thats because B has set reset the session

It's possible this is because you are storing the user id as ":id" in the session object. :id may be a reserved key in the object. Try using a different name such as session[:user_id].
Good luck!

Related

Grails 3 -store session data in controller with scope='session'?

Somehow it seems like it might be a bad idea, but wondering if it recommended or not when you are using session scope in a controller to store session data in controller fields, say for example, as a kind of caching for user data so you have don't have to keep hitting the db to get frequently requested information for a particular user?
And, by the way, just wondering how long the server holds on to the controller instance in that case. If someone leaves the browser tab open for a week, not using it, does the controller instance for that session hang around indefinitely consuming resources on the server?
You could, use a controller like that, but why not just simply use a cache instead? There are lots of really good caches out there (Spring cache for instance) which will likely be more extensible than this approach.
Session management (and when they expire) is handled by your application container (e.g. Tomcat, JBoss, Websphere, etc.). In most cases without interaction with the server (e.g. hitting a URL or page) they expire after a default of 20 minutes. So once a session expires, the session scoped controller instance becomes a candidate for being cleaned up and removed.

Using session while sending set of AJAX requests

In my Rails application I make set of AJAX calls at once and that causes sending the same session cookie for each request.
The problem is that rails sets new session cookie in every response and therefore it expects that cookie value in the request after.
I'm looking for server-side solution because I don't want to chain those requests (they are time consuming).
Is it possible to change this behavior? And what security risks would come with it?
(I'm using Rails 4.1.0)
Many thanks
If the user doesn't already have a session cookie then there is nothing you can do.
If you can guarantee that the user already has a session (for example, if you require users to be logged in) then you may be able to do this with a server side session store.
With a server side session store the session cookie just contains an identifier - even if your overlapping ajax requests change values in the session they will not change the session cookie. In general this is better security wise: for example, old sessions can't be replayed after the user has logged out. Rails switched to the cookie store by default for performance reasons: no external data store needs to be accessed (however it does slightly increase the amount of data sent on each request)
Switching to a serverside session store isn't enough though and still leaves you open to race conditions. It is very easy to end up with a sequence along the lines of
Request A loads session
Request B loads session
Request B completes, saves session
Request A saves session and overwrites the session changes made by B
You need a session store that will attempt to merge any changes it has made with any changes that may have occurred from other requests.
I wrote such a session store some time ago. I haven't updated it for rails 4, since it isn't something i need anymore but you may be able to (or at least find inspiration in it)

What is the lifespan of each data storage area in ASP .net MVC

I've seen some explanations of these, but nothing that really compares where they start, end, or overlap, or good examples of their use.
What is the life span of each of the following data collections? And am I missing any?
Application
Session
ViewData
TempData
application: as long as your application is running. your application may be automatically shutdown and restarted by the server for various reasons
session: as long as the user is actively using your site. this is generally determined by cookies that ASP.NET sends down to give each user a unique ID that expires after a while. there are lots of ways to customize & tweak this to meet various needs
viewdata: as long as the current request is being processed. this is used for sending data from a controller to a view for immediate rendering and thus not persisted
tempdata: until the value is read back out OR until the end of processing the next request in the session OR when the session ends/expires - whichever is sooner. this is meant to be used for moving data from one controller to another when you are issuing a Redirect
Application : This get initiated at the time when an application start and end when the application stops the execution.If user leaves the application domain or application gets restarted then also the application based data is lost.
Session : This is application based storage. This ends when user leaves the current request or the session get expired. It can be stored in several modes like application cookie or client side cookie.
ViewBag & ViewData : This storage method hold the data for the current request. It transport the data between view and controller.
TempData : Lifespan of this storage type depends on, at which request the Tempdata is read. Once it is read by program it gets destroyed. But we can increase its lifespan using peek or keep methods.

what is the best way to cache user information in my basecontroller in asp.net mvc

on each controller call i have a code that gets some user properties from a webservice. I want to cache these for each user so i only hit the webservice once.
what is the best way to cache code in a controller method so it will allow me to avoid hitting the database on every URL request but also not cache one users info when another user logs on?
You could use the ASP.NET session to store per user values.
Check out the caching piece of the Enterprise library. We use it at work to cache lookups, so you only hit our WCF services once, instead of thousands of times for the exact same data.
You can also use Session, which I highly advise against unless your user is very small.
if (Session("user") == null)
{
Session("user") = CallWebService.GetUser(userId);
}
Why you should keep Session small, for this webpage:
Avoid storing too much data in session variables, and make sure your session timeout is reasonable. This can use a significant amount of server memory. Keep in mind that data stored in session variables can hang out long after the user closes the browser. Too many session variables can bring the server on its knees.

Rails action response should behave like a simple file response - no session or cookies

I have a rails controller I dont ever want to set a cookie. I production, all it's actions are basically page cached and served as static files. But in development it's responses are generated on each request so that we can change things on the fly and test it out.
The problem is that when we have parallel requests that change cookie data this falls apart. In the client coe that uses this API we are having a problem with session cookies if the requests are made in parallel. It's a race condition where the request that completes last sets it's cookie, overwriting whatever was there before.
req A starts for session creation
req B starts for static file
req A completes for session creates sets updated and authenticated session cookie
req B completes for static file, and in dev mode sets the cookie it started with overwriting the new session state from req A.
So I need to turn off sessions completely from the controller that serves req B.
I've tried session :off in the controller, but that seems to have been deprecated in rails 2.3 (what we are currently using). When I do a curl -I http://localhost:3000/my/path it still shows the Set-Cookie header in the response. The docs simply say that if you dont use the session, it wont load it. But it's still setting that cookie.
Long story short: I need a way to force my controller to NOT send a Set-Cookie header in it's response, ever, so that the controller's response in development mode better matches production behavior.
Thanks to tadman I discovered that my before filters were indeed messing with the session and mucking things up. So I added this line to my controller and allis well!
skip_filter filter_chain

Resources