Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Make session loss handling more flexible for ajax and comet #1285

Merged
merged 7 commits into from

3 participants

@Shadowfiend
Owner

As per https://groups.google.com/forum/#!topic/liftweb/SVit97-RdCE , we add the ability to deal with ajax and comet session loss distinctly, while renaming the redirectAjaxOnSessionLoss variable to redirectAsyncOnSessionLoss so that it is more evident that it acts on both ajax and comet.

In particular, we add LiftRules.noCometSessionCmd and LiftRules.noAjaxSessionCmd, which are the JsCmds that are sent down when redirectAsyncOnSessionLoss is set to true and the session is lost. By default, these two invoke liftComet.lift_sessionLost and liftAjax.lift_sessionLost, respectively. By default, liftComet.lift_sessionLost is a redirect to the value of LiftRules.noCometSessionPage (which is now deprecated), while the default for liftAjax.lift_sessionLost is reloading the page (which is what I would like the default for the liftComet variant to be as well, were it not for the backwards compatibility concern of continuing to support LiftRules.noCometSessionPage).

Shadowfiend added some commits
@Shadowfiend Shadowfiend Rename redirectAjaxOnSessionLoss to redirectAsyncOnSessionLoss. bc5370d
@Shadowfiend Shadowfiend redirectAsyncOnSessionLoss calls client-side functions.
The client-side functions are called liftAjax.sessionLost and
liftComet.sessionLost, and can be overridden by the user. We still need
to hook noCometSessionPage into these somehow so we can have backwards
compatibility.
1f00e15
@Shadowfiend Shadowfiend Add LiftRules noCometSessionCmd/noAjaxSessionCmd.
These are the JsCmds that will be sent to the client when a session is
missing for a comet or ajax request, respectively. For comets, no comet
session is a state where a comet request comes in with no associated
session OR with a session that has no associated CometActors (typically
this happens on server reload).
b740ee8
@Shadowfiend Shadowfiend Use 2.8-compatible @deprecated call for redirectAjaxOnSessionLoss. 3ac4213
@Shadowfiend Shadowfiend Add default liftAjax. and liftComet.lift_sessionLoss.
The default implementation of liftComet.lift_sessionLoss uses
LiftRules.noCometSessionPage to do a redirect, while liftAjax's does a
page reload (which is what we'd rather have liftComet's do, but we need
to be backwards-compatible with noCometSessionPage).
8bb4e6d
@Shadowfiend Shadowfiend Rename sessionLoss to sessionLost for loss handlers. dae24b4
@fmpwizard
Owner

+1

@Shadowfiend Shadowfiend Add @deprecated for redirectOnAjaxSessionLoss assignment.
Before we had only deprecated the read, not the write.
fd3edcf
@fmpwizard
Owner

Let me know if/when you are done with this and #1283 . So I rebase them both and my #805 on one step. That would result in Cloudbees only running one build instead of 3 separate ones.

Thanks

Diego

@dpp dpp merged commit 03cab46 into from
@Shadowfiend
Owner

Hehe. I guess dpp took care of it :) I did consider them ready to rock, so we're set!

@dpp
Owner
dpp commented

Hey, if it's a pull request, I figure the author thinks it's good enough to go in.

@Shadowfiend
Owner

Sure did!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jun 20, 2012
  1. @Shadowfiend
Commits on Jun 21, 2012
  1. @Shadowfiend

    redirectAsyncOnSessionLoss calls client-side functions.

    Shadowfiend authored
    The client-side functions are called liftAjax.sessionLost and
    liftComet.sessionLost, and can be overridden by the user. We still need
    to hook noCometSessionPage into these somehow so we can have backwards
    compatibility.
Commits on Jun 25, 2012
  1. @Shadowfiend

    Add LiftRules noCometSessionCmd/noAjaxSessionCmd.

    Shadowfiend authored
    These are the JsCmds that will be sent to the client when a session is
    missing for a comet or ajax request, respectively. For comets, no comet
    session is a state where a comet request comes in with no associated
    session OR with a session that has no associated CometActors (typically
    this happens on server reload).
  2. @Shadowfiend
  3. @Shadowfiend

    Add default liftAjax. and liftComet.lift_sessionLoss.

    Shadowfiend authored
    The default implementation of liftComet.lift_sessionLoss uses
    LiftRules.noCometSessionPage to do a redirect, while liftAjax's does a
    page reload (which is what we'd rather have liftComet's do, but we need
    to be backwards-compatible with noCometSessionPage).
  4. @Shadowfiend
Commits on Jun 26, 2012
  1. @Shadowfiend

    Add @deprecated for redirectOnAjaxSessionLoss assignment.

    Shadowfiend authored
    Before we had only deprecated the read, not the write.
This page is out of date. Refresh to see the latest.
View
49 web/webkit/src/main/scala/net/liftweb/http/LiftRules.scala
@@ -599,11 +599,45 @@ class LiftRules() extends Factory with FormVendor with LazyLoggable {
@volatile var liftCoreResourceName = "i18n.lift-core"
/**
- * Where to send the user if there's no comet session
+ * Where to send the user if there's no comet session. Note that this is
+ * contingent on an unchanged LiftRules.noCometSessionCommand and on
+ * liftComet.lift_sessionLost not being overridden client-side.
*/
+ @scala.deprecated("Use LiftRules.noCometSessionCmd.")
@volatile var noCometSessionPage = "/"
/**
+ * The JsCmd to execute when the comet session is lost. The comet
+ * session is considered lost when either (a) a comet request comes
+ * in for a session that does not exist on the server or (b) a comet
+ * request comes in for a session that has no associated comet actors
+ * (this typically happens when the server restarts).
+ *
+ * By default, we invoke liftComet.lift_sessionLost, which can be
+ * overridden client-side for more complex work.
+ * liftComet.lift_sessionLost redirects to
+ * LiftRules.noCometSessionPage by default for now, though
+ * noCometSessionPage is deprecated and will be replaced by a
+ * default of reloading the current page.
+ */
+ val noCometSessionCmd = new FactoryMaker[JsCmd](
+ () => JsCmds.Run("liftComet.lift_sessionLost()")
+ ) {}
+
+ /**
+ * The JsCmd to execute when the ajax session is lost. The ajax
+ * session is considered lost when either an ajax request comes in for
+ * a session that does not exist on the server.
+ *
+ * By default, we invoke liftAjax.lift_sessionLost, which can be
+ * overridden client-side for more complex work.
+ * liftAjax.lift_sessionLost reloads the page by default.
+ */
+ val noAjaxSessionCmd = new FactoryMaker[JsCmd](
+ () => JsCmds.Run("liftAjax.lift_sessionLost()")
+ ) {}
+
+ /**
* Put a function that will calculate the request timeout based on the
* incoming request.
*/
@@ -1316,11 +1350,16 @@ class LiftRules() extends Factory with FormVendor with LazyLoggable {
private def logSnippetFailure(sf: SnippetFailure) = logger.info("Snippet Failure: " + sf)
/**
- * Set to false if you do not want Ajax/Comet requests that are not associated with a session
- * to cause a page reload
+ * Set to false if you do not want ajax/comet requests that are not
+ * associated with a session to call their respective session
+ * loss handlers (set via LiftRules.noAjaxSessionCmd and
+ * LiftRules.noCometSessionCmd).
*/
- @volatile var redirectAjaxOnSessionLoss = true
-
+ @volatile var redirectAsyncOnSessionLoss = true
+ @deprecated("Use redirectAsyncOnSessionLoss instead.")
+ def redirectAjaxOnSessionLoss = redirectAsyncOnSessionLoss
+ @deprecated("Use redirectAsyncOnSessionLoss instead.")
+ def redirectAjaxOnSessionLoss_=(updated:Boolean) = redirectAsyncOnSessionLoss = updated
/**
* The sequence of partial functions (pattern matching) for handling converting an exception to something to
View
47 web/webkit/src/main/scala/net/liftweb/http/LiftServlet.scala
@@ -214,22 +214,26 @@ class LiftServlet extends Loggable {
}.isDefined
}
- def isCometOrAjax(req: Req): Boolean = {
- val wp = req.path.wholePath
- val len = wp.length
-
- if (len < 2) false
+ val wp = req.path.wholePath
+ val pathLen = wp.length
+ def isComet: Boolean = {
+ if (pathLen < 2) false
else {
val kindaComet = wp.head == LiftRules.cometPath
- val cometScript = (len >= 3 && kindaComet &&
+ val cometScript = (pathLen >= 3 && kindaComet &&
wp(2) == LiftRules.cometScriptName())
+
+ (kindaComet && !cometScript) && req.acceptsJavaScript_?
+ }
+ }
+ def isAjax: Boolean = {
+ if (pathLen < 2) false
+ else {
val kindaAjax = wp.head == LiftRules.ajaxPath
- val ajaxScript = len >= 2 && kindaAjax &&
+ val ajaxScript = kindaAjax &&
wp(1) == LiftRules.ajaxScriptName()
-
- ((kindaComet && !cometScript) || (kindaAjax && !ajaxScript)) &&
- req.acceptsJavaScript_?
+ (kindaAjax && !ajaxScript) && req.acceptsJavaScript_?
}
}
@@ -241,20 +245,23 @@ class LiftServlet extends Loggable {
LiftRules.notFoundOrIgnore(req, Empty)
} else if (!authPassed_?(req)) {
Full(LiftRules.authentication.unauthorizedResponse)
- } else if (LiftRules.redirectAjaxOnSessionLoss && !hasSession(sessionIdCalc.id) && isCometOrAjax(req)) {
-
+ } else if (LiftRules.redirectAsyncOnSessionLoss && !hasSession(sessionIdCalc.id) && (isComet || isAjax)) {
val theId = sessionIdCalc.id
- // okay after 2 attempts to redirect, just
- // ignore calls to the comet URL
+
+ // okay after 2 attempts to redirect, just ignore calls to the
+ // async URL
if (recentlyChecked(theId) > 1) {
Empty
} else {
- Full(JavaScriptResponse(js.JE.JsRaw("window.location = " +
- (req.request.
- header("Referer") openOr
- "/").encJs).cmd, Nil, Nil, 200))
+ val cmd =
+ if (isComet)
+ js.JE.JsRaw(LiftRules.noCometSessionCmd.vend.toJsCmd + ";lift_toWatch = {};").cmd
+ else
+ js.JE.JsRaw(LiftRules.noAjaxSessionCmd.vend.toJsCmd).cmd
+
+ Full(new JsCommands(cmd :: Nil).toResponse)
}
- } else
+ }
// if the request is matched is defined in the stateless table, dispatch
if (S.statelessInit(req) {
tmpStatelessHolder = NamedPF.applyBox(req,
@@ -556,7 +563,7 @@ class LiftServlet extends Loggable {
sessionActor.getAsyncComponent(name).toList.map(c => (c, toLong(when)))
}
- if (actors.isEmpty) Left(Full(new JsCommands(new JE.JsRaw("lift_toWatch = {}") with JsCmd :: JsCmds.RedirectTo(LiftRules.noCometSessionPage) :: Nil).toResponse))
+ if (actors.isEmpty) Left(Full(new JsCommands(LiftRules.noCometSessionCmd.vend :: js.JE.JsRaw("lift_toWatch = {};").cmd :: Nil).toResponse))
else requestState.request.suspendResumeSupport_? match {
case true => {
setupContinuation(requestState, sessionActor, actors)
View
9 web/webkit/src/main/scala/net/liftweb/http/js/ScriptRenderer.scala
@@ -111,6 +111,11 @@ object ScriptRenderer {
"""
},
+
+ lift_sessionLost: function() {
+ location.reload();
+ },
+
lift_doAjaxCycle: function() {
if (liftAjax.lift_doCycleQueueCnt > 0) liftAjax.lift_doCycleQueueCnt--;
var queue = liftAjax.lift_ajaxQueue;
@@ -251,6 +256,10 @@ object ScriptRenderer {
setTimeout("liftComet.lift_cometEntry();",""" + LiftRules.cometFailureRetryTimeout + """);
},
+ lift_sessionLost: function() { """ +
+ JsCmds.RedirectTo(LiftRules.noCometSessionPage).toJsCmd +
+ """},
+
lift_cometEntry: function() {
var isEmpty = function(){for (var i in lift_toWatch) {return false} return true}();
if (!isEmpty) {
Something went wrong with that request. Please try again.