Why doesn't container create the instance of HTTPSession when it receives first request, the way it does it for ServletContext or ServletConfig?
Since sessions are managed by container, it would be logical to create session instance when it receives the first request, isn't it?
Why don't we have simple getSession() method only i.e. why would someone need to invoke getSessin(false) in this fashion.
Creating a session has an impact on the response: it sets a cookie, and causes every properly encoded URL to have an additional jsessionid inside. You might not want that (for SEO reasons, etc.).
It also has an impact on the server: a session object is created and kept in memory for every user visiting the application. You might not want that. Suppose for example that a bot sends a request every second to your application, and rejects the cookie set by the application server. Your webapp, after 30 minutes, would have 108000 useless sessions in memory.
So starting a session is a deliberate choice by the programmer. If you need one, you create it. If you don't need it, you don't create it.
Related
I have a scenario where I receive a request, and based on that request I have to do a few web service calls to a backend system. All is done in an orchestration. The backend system is session based, so first I perform a login and then I want to do my stuff. The login operation replies with a Set-Cookie header, I want to place that value in the Cookie header in the subsequent calls. However, when trying to do this in a Message assignment shape:
msg_request2(HTTP.HttpCookie) = msg_loginresponse(HTTP.HttpCookie)
I get an error in the event viewer:
Inner exception: There is no value associated with the property 'HTTP.HttpCookie' in the message.
Exception type: MissingPropertyException
Source: Microsoft.XLANGs.BizTalk.Engine
I've also tried accessing the HTTP.InboundHttpHeaders of msg_loginresponse, same error message. I can see the InboundHttpHeaders context property in the suspended message that results, so i "know" that it's there.
Adding a reference to Microsoft.BizTalk.GlobalPropertySchemas.dll in my project did not help.
Any clever suggestions?
After you have informed your management that the Trading Partner is using a very old and unusual pattern for which you are going to have to spend extra time, meaning money, to accommodate (this problem is 100% created by the Trading Partner), it should be pretty simple.
For the Adapter, Set-Cookie does not result in an actual cookie since the Adapter has no notion of sessions.
You need to parse the cookie value out of HTTP.InboundHttpHeaders, then use that value to set the cookie by either HTTP.HttpCookie or HTTP.UserHttpHeaders.
BTW, since token auth in 99.9% of scenarios is silly and unnecessary, I always avoid maintaining the token and just 'auth' every time. No reason for you to make you app more complicated. The only exception would be if the same calls are performed in the same sequence every time, then you can hold the token in the Orchestration.
I'm wondering if ServletResponse.reset() is the extra step I need to block non-logged-in users from accessing servlets, or if there are risks or downsides to it.
Background:
The way my website works, initially users can only see certain pages after they create an account and login with those credentials. The problem I was initially having was, even though I used session.invalidate(), when a user logged-out, they could re-send the request (for example, via the back button) and were able to access restricted contents from the unauthorized state. Assuming the session is expired, as per above, I'm not sure how that's even possible or what can properly be done to prevent it.
Through experimentation, as a workaround, I tried ServletResponse.reset(), and that seemed to resolve it, but I don't understand why it works, and hence, I'm not confident it is a robust viable solution.
My specific questions are:
Is resetting the response buffer (including header and http status code) a safe or recommended practice, or is there a better way to do it?
How can I manage logging in with the session object as opposed to using a session cookie?
I don't think ServletResponse.reset() will hurt anything but it isn't standard operating procedure and it shouldn't be necessary. Just make sure you're doing the right things both invalidating and validating sessions.
Invalidating session:
Call session.invalidate() to remove session attributes bound to a session, but also be sure your code explicitly removes it's own stale references to the previous session state. Session cookies can be explicitly removed by locating the cookie with exact matching criteria and setting its maximum age to 0.
Validating session:
When authenticating, you can check whether getSession(false) returns null to determine if there is an active session. If so you can invalidate it then, and you can also check request.isRequestedSessionIdValid(), or explicitly check for the presence any specific attributes you've used in your session management scheme. That will let you verify the state of the session properly.
From the JavaDocs:
ServletResponse
void reset()
Clears any data that exists in the buffer as well as the status code and headers. If the response has been
committed, this method throws an IllegalStateException.
void invalidate()
Invalidates this session then unbinds any objects bound to it.
ServletRequest
boolean isRequestedSessionIdValid()
Checks whether the requested session ID is still valid.
HttpSession getSession(boolean create)
Returns the current HttpSession associated with this request or, if there is no current session and create is true,
returns a new session. If create is false and the request has no valid HttpSession, this method returns null.
To make sure the session is properly maintained, you must call this method before the response is committed.
is using cookies to maintain session integrity and is asked to create a new session when the response is
committed, an IllegalStateException is thrown.
I'm using Spring MVC 3 + Tiles for a webapp. I have a slow operation, and I'd like a please wait page.
There are two main approaches to please wait pages, that I know of:
Long-lived requests: render and flush the "please wait" bit of the page, but don't complete the request until the action has finished, at which point you can stream out the rest of the response with some javascript to redirect away or update the page.
Return immediately, and start processing on a background thread. The client polls the server (in javascript, or via page refreshes), and redirects away when the background thread finishes.
(1) is nice as it keeps the action all single-threaded, but doesn't seem possible with Tiles, as each JSP must complete rendering in full before the page is assembled and returned to the client.
So I've started implementing (2). In my implementation, the first request starts the operation on a background thread, using Spring's #Async annotation, which returns a Future<Result>. It then returns a "please wait" page to the user, which refreshes every few seconds.
When the please wait page is refreshed, the controller needs to check on the progress of the background thread. What is the best way of doing this?
If I put the Future object in the Session directly, then the poll request threads can pull it out and check on the thread's progress. However, doesn't this mean my Sessions are not serializable, so my app can't be deployed with more than one web server (without requiring sticky sessions)?
I could put some kind of status flag in the Session, and have the background thread update the Session when it is finished. I'm very concerned that passing an HttpSession object to a non-request thread will result in hard to debug errors. Is this allowed? Can anyone cite any documentation either way? It works fine when the sessions are in-memory, of course, but what if the sessions are stored in a database? What if I have more than one web server?
I could put some kind of status flag in my database, keyed on the session id, or some other aspect of the slow operation. It seems weird to have session data in my domain database, and not in the session, but at least I know the database is thread-safe.
Is there another option I have missed?
The Spring MVC part of your question is rather easy, since the problem has nothing to do with Spring MVC. See a possible solution in this answer: https://stackoverflow.com/a/4427922/734687
As you can see in the code, the author is using a tokenService to store the future. The implementation is not included and here the problems begin, as you are already aware of, when you want failover.
It is not possible to serialize the future and let it jump to a second server instance. The thread is executed within a certain instance and therefore has to stay there. So session storage is no option.
As in the example link you could use a token service. This is normally just a HashMap where you can store your object and access it later again via the token (the String identifier). But again, this works only within the same web application, when the tokenService is a singleton.
The solution is not to save the future, but instead the state of the work (in work, finished, failed with result). Even when the querying session and the executing threads are on different machines, the state should be accessible and serialize able. But how would you do that? This could be implemented by storing it in a database or on the file system (the example above you could check if the zip file is available) or in a key/value store or in a cache or in a common object store (Terracota), ...
In fact, every batch framework (Spring Batch for example) works this way. It stores the current state of the jobs in the database. You are concerned that you mix domain data with operation data. But most applications do. On large applications there is the possibility to use two database instances, operational data and domain data.
So I recommend that you save the state and the result of the work in a database.
Hope that helps.
I have to send some private data once from server to browser. I want to store it in a cookie. This data will be using later in Javascript code. But I want to send never(!) this private data to server when the browser does HTTP Request (because of security).
I know that I can set "path" value in cookie (to i.e. some abstract path) but then I won't be able to read this cookie (I'll be able to read from this abstract path, but if so, the browser send this cookie to server once - but as I said this data can't be sent to server).
So, my question is: is it somehow possible not to send a cookie with HTTP Request?
If you're sending this private data from server to browser then it is being exposed anyway. I don't think it matters much that it will be included in subsequent requests.
In general you should never place private data in cookies, at least not unless encrypted. So either a) do all of this over https or b) encrypt the data. But I'm guessing that b) will be a problem as you'll have to decrypt on the client side.
To be honest it sounds like you need to rethink your strategy here.
I don't think you'll be able to force the browser not to resend the cookie up if it's valid for that request.
Perhaps a better way would be to delete the cookie within the JS once you've read your data from it:
http://techpatterns.com/downloads/javascript_cookies.php
If you need to have it back in the JS again on the next response, just have the server re-send it, and delete it again on the client side.
I should say that sending data which you would deem to be 'private' in this way does not seem entirely appropriate on the face of it - as this information could easily be viewed using a proxy of some type sat between the browser and the server.
As Richard H mentioned, data in cookies is visible to the user if they know where to look. So this is not a good place to store secrets.
That said, I had a different application which needed to store lots of data client-side and ran into this same problem. (In my application, I needed to make the application able to run offline and keep the user actions if the PC crashes or website is down.) The solution is pretty simple:
1) Store the cookie data in a JavaScript variable. (Or maintain it in a variable already.)
2) Remove the cookies. Here's a function that can erase a cookie:
function cookieErase (name) {
document.cookie = name+'=; Max-Age=-99999999;path=/';
}
If you have more than one cookie (as was my case), you have to run the above function for every cookie you have stored. There is code to iterate each cookie, but in practice you probably know the names of the large cookies already and you might not want to delete other cookies your website is relying on.
3) Send the request as you would normally.
4) Restore the cookie data from the saved variables.
Here are some optimizations you can use:
1) Only trigger this code on a status 400 bad request (which is what you get back if the cookie data is too large). Sometimes, your data isn't too big, so deleting is unnecessary.
2) Restore the cookie data after a timeout if it isn't needed immediately. In this way, you can make multiple requests and only restore the data if there is idle time. This means your users can have a fast experience when actively using your website.
3) The moment you can, try to get any data moved to the server-side so the burden on the client/communication is less. In my case, the moment that the connection is back up, all actions are synchronized as soon as possible.
Our asp.net 2.0 application has a very long process (synchronized) before sending response back to client. I observed that a second request, exactly same the initial one, was sent after client IE8 waited response for a long period of time while our application was still processing the first request.
I use page session with predefined key to store a flag when the initial request arrives and then starts long process while client IE waits for the response, so if second request comes in, our application checks the session value. After our application sets the session flag and starts processing, I use Fiddler “Abort Session” to abort the initial request, right away the second request (same as the first one) is sent automatically, but session value set earlier seems no longer exist.
Any thoughts?
When the second request comes in during your ongoing process isn't it overwritting your current request's value since it is only storing one item? Assuming both requests are coming in under the same session.
Maybe consider storing a list of items so that you can add the second item to your list of flags and then find any previous items and delete them.
Maybe kill the request currently in the session before starting the second requests session?
I don't really understand your problem / solution all that well but hopefully that helps.
Edit based on your comment:
If it no longer exists it's probably due to your session timing out and wiping the values so the second one wouldn't be able to access it. Is the second connection coming in under the exact same session? Compare the Session IDs in both cases. Also check your timeout.
You could also store this information in your application Cache that has a real long expiry. Have a dictionary with the key being the session ID or even the user if you only want one process per user and then store your value. This when the second request comes in by the same user, you will be able to find it regardless of session ID. Just make sure you are clearing once your process is complete.