2

I have a JSF 2.0 web application running on glassfish 3.1 that is working fine on IE, FF, Safari and Chrome.

When I added the url of my website inside a iframe of another website then I am getting ViewExpiredException after clicking any button inside iframe - This happens only on Safari, works fine in IE, FF, Chrome.

<iframe style="width: 100%; height: 800px" src="url_of_my_website" frameBorder="0"></iframe>

Following are my observations

  1. Deployed the same application on glassfish 3.0.1 and the problem doesn't happen
  2. If I open my website without frame, it works fine irrespective of browser
  3. Developed the same application using JSF1.2 and RF 3.3.3 and the problem doesn't happen

As per my understanding, we get ViewExpiredException when any action is performed on a page whose session is expired. But in this particular case it happens just after the website gets load loaded.

I'm not sure about what's causing it. Is it Safari/JSF 2.0/GF 3.1/IFRAME?

Update: I found an interesting problem. On my home page, I have a h:commandLink that redirects me to a new page. Also, I have a href link to redirect to some other page. When I click on the commandLink, I'm getting ViewExpiredException but when I click on href link, I'm not getting any exceptions and the page is redirected and I can proceed with further operations as session cookie is getting established.

Praneeth
  • 1,457
  • 5
  • 23
  • 36
  • As per your update: that's normal. The commandlink submits a hidden form and effectively fires a POST request which thus requires the request to be fired within the same session. A normal link fires a GET request which doesn't require the request to be fired within the same session. Simply a new session will be created whenever necessary. If you don't need to submit additional POST data, then you don't need a commandlink at all. – BalusC Aug 15 '11 at 15:33

2 Answers2

3

This is indeed a known problem. Safari does not allow crossdomain cookies. Any cookies delivered by an iframe will just be ignored by this browser. The HTTP session is backed by a cookie. So it won't be maintained as well. Thus, when you submit a JSF form inside an iframe, then Safari won't send the session cookie back and the server side will implicitly create a new session and thus the view which was set in the initial session is completely lost. Hence the ViewExpiredException.

In theory, this can be solved to include the JSESSIONID fragment in the action URL of the JSF-generated HTML <form> element. E.g.

<form action="/context/page.xhtml;JSESSIONID=1234567890ABCDEF">

However, JSF already does that. It uses under the covers HttpServletResponse#encodeURL() for that. That it didn't work for you on JSF 2 while it apparently worked on JSF 1.2 is for me a mystery. But you have now at least something to concentrate on. Did HttpServletResponse#encodeURL() return the properly encoded URL with JSESSIONID inside? Does the generated HTML <form> include the JSESSIONID? Etc. When using Mojarra, start with FormRenderer#getActionStr() method while debugging.

Anyway, another solution is to use JavaScript for this. Do something like the following during onload of the JSF page which is to be displayed inside an iframe. The following script kickoff example should be embedded inside the JSF page so that #{} will be evaluated.

window.onload = function() {
    if (top != self) { // If true, then page is been requested inside an iframe.
        var jsessionid = '#{session.id}';
        var forms = document.forms;

        for (var i = 0; i < forms.length; i++) {
            forms[i].action += ';JSESSIONID=' + jsessionid;
        }
    }
}

This should not harm browsers other than Safari.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thanks for the response. I tried the javascript, but it didn't work for me. All of my pages uses a template, so I added the javascript there. FYI, in the doFilter() method of my Filter, I'm checking HttpServletRequest#isRequestSessionIdFromURL(), if it is true then I'm redirecting user to home page. Will that be a problem if the workaround javascript works? – Praneeth Aug 12 '11 at 18:59
0

I experienced the same issue for IE and Safari. This is because third party cookies are not allowed by default in those browsers. Thus session id could not be passed via cookie.

To fix it in IE is enough to add response header P3P with value CP="This site does not have a p3p policy.":

ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
extContext.addResponseHeader("P3P", "CP=\"This site does not have a p3p policy.\"");

To fix it in Safari is enough to transfer session id in url but not in cookie. This is known as url rewriting. For application server supporting Servlet 3.0 it could be done using web.xml :

<session-config>
    <tracking-mode>URL</tracking-mode> 
</session-config>