You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by wt...@apache.org on 2019/11/12 21:55:09 UTC

[myfaces] branch master updated: MYFACES-4309: create session in render response if needed If a given view is not transient and server side state saving is used, we should always create a session since some scopes need one. A new parm ALWAYS_FORCE_SESSION_CREATION (default=false in 3.0) is added to enable that behavior even if a view is transient or client side state saving is enabled.

This is an automated email from the ASF dual-hosted git repository.

wtlucy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/master by this push:
     new 8155657  MYFACES-4309: create session in render response if needed If a given view is not transient and server side state saving is used, we should always create a session since some scopes need one.  A new parm ALWAYS_FORCE_SESSION_CREATION (default=false in 3.0) is added to enable that behavior even if a view is transient or client side state saving is enabled.
     new 23765d9  Merge pull request #73 from wtlucy/MYFACES-4309
8155657 is described below

commit 81556575698ab3b06619a86534165e44e85b0aaa
Author: Bill Lucy <wt...@gmail.com>
AuthorDate: Thu Nov 7 14:49:22 2019 -0500

    MYFACES-4309: create session in render response if needed
    If a given view is not transient and server side state saving is used, we
    should always create a session since some scopes need one.  A new parm
    ALWAYS_FORCE_SESSION_CREATION (default=false in 3.0) is added to enable
    that behavior even if a view is transient or client side state saving
    is enabled.
---
 .../org/apache/myfaces/config/MyfacesConfig.java   | 20 +++++++++++++
 .../myfaces/lifecycle/RenderResponseExecutor.java  | 35 +++++++++++++++++++++-
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java b/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java
index 0e3300a..c680d4a 100755
--- a/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java
+++ b/impl/src/main/java/org/apache/myfaces/config/MyfacesConfig.java
@@ -806,6 +806,17 @@ public class MyfacesConfig
     public static final String RENDER_CLIENTBEHAVIOR_SCRIPTS_AS_STRING = "org.apache.myfaces.RENDER_CLIENTBEHAVIOR_SCRIPTS_AS_STRING";
     public static final boolean RENDER_CLIENTBEHAVIOR_SCRIPTS_AS_STRING_DEFAULT = false;
     
+    /**
+     * Defines if a session should be created (if one does not exist) before response rendering.
+     * When this parameter is set to true, a session will be created even when client side state 
+     * saving or stateless views are used, which can lead to unintended resource consumption.
+     * When this parameter is set to false, a session will only be created before response 
+     * rendering if a view is not transient and server side state saving is in use.     
+     */
+    @JSFWebConfigParam(since="2.3.6", defaultValue="false", expectedValues="true,false")
+    protected static final String ALWAYS_FORCE_SESSION_CREATION = 
+            "org.apache.myfaces.ALWAYS_FORCE_SESSION_CREATION";
+    public final static boolean ALWAYS_FORCE_SESSION_CREATION_DEFAULT = false;
     
     // we need it, applicationImpl not ready probably
     private ProjectStage projectStage = ProjectStage.Production;
@@ -886,6 +897,7 @@ public class MyfacesConfig
     private boolean logWebContextParams = false;
     private int websocketMaxConnections = WEBSOCKET_MAX_CONNECTIONS_DEFAULT;
     private boolean renderClientBehaviorScriptsAsString = RENDER_CLIENTBEHAVIOR_SCRIPTS_AS_STRING_DEFAULT;
+    private boolean alwaysForceSessionCreation = ALWAYS_FORCE_SESSION_CREATION_DEFAULT;
     
     private static final boolean MYFACES_IMPL_AVAILABLE;
     private static final boolean RI_IMPL_AVAILABLE;
@@ -1297,6 +1309,9 @@ public class MyfacesConfig
         cfg.renderClientBehaviorScriptsAsString = getBoolean(extCtx, RENDER_CLIENTBEHAVIOR_SCRIPTS_AS_STRING,
                 RENDER_CLIENTBEHAVIOR_SCRIPTS_AS_STRING_DEFAULT);
 
+        cfg.alwaysForceSessionCreation = getBoolean(extCtx, ALWAYS_FORCE_SESSION_CREATION,
+                ALWAYS_FORCE_SESSION_CREATION_DEFAULT);
+
         return cfg;
     }
 
@@ -1756,5 +1771,10 @@ public class MyfacesConfig
     {
         return renderClientBehaviorScriptsAsString;
     }
+
+    public boolean isAlwaysForceSessionCreation()
+    {
+        return alwaysForceSessionCreation;
+    }
 }
 
diff --git a/impl/src/main/java/org/apache/myfaces/lifecycle/RenderResponseExecutor.java b/impl/src/main/java/org/apache/myfaces/lifecycle/RenderResponseExecutor.java
index 1ecf911..6a89c90 100644
--- a/impl/src/main/java/org/apache/myfaces/lifecycle/RenderResponseExecutor.java
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/RenderResponseExecutor.java
@@ -29,12 +29,15 @@ import javax.faces.application.FacesMessage;
 import javax.faces.application.ProjectStage;
 import javax.faces.application.ViewHandler;
 import javax.faces.component.UIViewRoot;
+import javax.faces.context.ExternalContext;
 import javax.faces.context.FacesContext;
 import javax.faces.event.PhaseId;
 import javax.faces.event.PostRenderViewEvent;
 import javax.faces.event.PreRenderViewEvent;
 import javax.faces.view.ViewDeclarationLanguage;
 
+import org.apache.myfaces.shared.config.MyfacesConfig;
+
 /**
  * Implements the render response phase (JSF Spec 2.2.6)
  * 
@@ -62,7 +65,9 @@ class RenderResponseExecutor extends PhaseExecutor
         {
             throw new ViewNotFoundException("A view is required to execute "+facesContext.getCurrentPhaseId());
         }
-        
+
+        forceSessionCreation(facesContext);
+
         try
         {
             // do-while, because the view might change in PreRenderViewEvent-listeners
@@ -157,4 +162,32 @@ class RenderResponseExecutor extends PhaseExecutor
     {
         return PhaseId.RENDER_RESPONSE;
     }
+
+    /**
+     * Create a session if the ALWAYS_FORCE_SESSION_CREATION param is set to true, or if the
+     * current view is not transient and server side state saving is in use.
+     * 
+     * Note: if the current view is transient or client side state saving is in use, it is 
+     * not technically correct to create a session here, since a session should not be
+     * required for those cases and creating one will cause undesirable memory usage.  
+     * However, if we do not create a session before rendering begins and view or session
+     * scope beans are created later on, then the response might be committed before those 
+     * scopes have a chance to create a session and so the session cookie will not be set.
+     * See MYFACES-4309
+     * 
+     * @param FacesContext
+     */
+    private void forceSessionCreation(FacesContext context) 
+    {
+        if (context.getExternalContext().getSession(false) == null) 
+        {
+            ExternalContext ec = context.getExternalContext();
+            if (MyfacesConfig.getCurrentInstance(ec).isAlwaysForceSessionCreation() 
+                    || (!context.getViewRoot().isTransient() 
+                    && !context.getApplication().getStateManager().isSavingStateInClient(context))) 
+            {
+                context.getExternalContext().getSession(true);
+            }
+        }
+    }
 }