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:54:58 UTC

[myfaces] branch 2.2.x 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=true in 2.2) 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 2.2.x
in repository https://gitbox.apache.org/repos/asf/myfaces.git


The following commit(s) were added to refs/heads/2.2.x by this push:
     new ef681d1  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=true in 2.2) is added to enable that behavior even if a view is transient or client side state saving is enabled.
     new 06edf01  Merge pull request #72 from wtlucy/MYFACES-4309_2.2.x
ef681d1 is described below

commit ef681d17bdd3089857216e00971294539948ba04
Author: Bill Lucy <wt...@gmail.com>
AuthorDate: Tue Nov 12 16:20:01 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=true in 2.2) is added to enable
    that behavior even if a view is transient or client side state saving
    is enabled.
---
 .../myfaces/lifecycle/RenderResponseExecutor.java  | 38 +++++++++++++++++++++-
 .../myfaces/shared/config/MyfacesConfig.java       | 32 ++++++++++++++++++
 2 files changed, 69 insertions(+), 1 deletion(-)

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 2281e99..d07ee56 100644
--- a/impl/src/main/java/org/apache/myfaces/lifecycle/RenderResponseExecutor.java
+++ b/impl/src/main/java/org/apache/myfaces/lifecycle/RenderResponseExecutor.java
@@ -34,6 +34,8 @@ import javax.faces.event.PhaseId;
 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)
  * 
@@ -44,6 +46,7 @@ class RenderResponseExecutor extends PhaseExecutor
 {
     
     private static final Logger log = Logger.getLogger(RenderResponseExecutor.class.getName());
+    private MyfacesConfig _myfacesConfig;
     
     public boolean execute(FacesContext facesContext)
     {
@@ -61,7 +64,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
@@ -154,4 +159,35 @@ 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) 
+        {
+            if (_myfacesConfig == null) 
+            {
+                _myfacesConfig = MyfacesConfig.getCurrentInstance(context.getExternalContext());
+            }
+            if (_myfacesConfig.isAlwaysForceSessionCreation() 
+                    || (!context.getViewRoot().isTransient() 
+                    && !context.getApplication().getStateManager().isSavingStateInClient(context))) 
+            {
+                context.getExternalContext().getSession(true);
+            }
+        }
+    }
 }
diff --git a/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java b/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
index 526d269..69d0954 100755
--- a/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
+++ b/shared/src/main/java/org/apache/myfaces/shared/config/MyfacesConfig.java
@@ -554,6 +554,19 @@ public class MyfacesConfig
             "org.apache.myfaces.STRICT_JSF_2_ORIGIN_HEADER_APP_PATH";
     public final static boolean STRICT_JSF_2_ORIGIN_HEADER_APP_PATH_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.2.13", defaultValue="true", 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 = true;
+
+
     private boolean _prettyHtml;
     private boolean _detectJavascript;
     private boolean _allowJavascript;
@@ -598,6 +611,7 @@ public class MyfacesConfig
     private Integer _numberOfFacesFlowClientWindowIdsInSession;
     private boolean _supportEL3ImportHandler;
     private boolean _strictJsf2OriginHeaderAppPath;
+    private boolean _alwaysForceSessionCreation;
 
     private static final boolean TOMAHAWK_AVAILABLE;
     private static final boolean MYFACES_IMPL_AVAILABLE;
@@ -712,6 +726,7 @@ public class MyfacesConfig
                         INIT_PARAM_NUMBER_OF_SEQUENTIAL_VIEWS_IN_SESSION_DEFAULT)+1);
         setSupportEL3ImportHandler(SUPPORT_EL_3_IMPORT_HANDLER_DEFAULT);
         setStrictJsf2OriginHeaderAppPath(STRICT_JSF_2_ORIGIN_HEADER_APP_PATH_DEFAULT);
+        setAlwaysForceSessionCreation(ALWAYS_FORCE_SESSION_CREATION_DEFAULT);
     }
 
     private static MyfacesConfig createAndInitializeMyFacesConfig(ExternalContext extCtx)
@@ -915,6 +930,10 @@ public class MyfacesConfig
         myfacesConfig.setStrictJsf2OriginHeaderAppPath(WebConfigParamUtils.getBooleanInitParameter(extCtx, 
                         STRICT_JSF_2_ORIGIN_HEADER_APP_PATH, 
                         STRICT_JSF_2_ORIGIN_HEADER_APP_PATH_DEFAULT));
+
+        myfacesConfig.setAlwaysForceSessionCreation(WebConfigParamUtils.getBooleanInitParameter(extCtx, 
+                        ALWAYS_FORCE_SESSION_CREATION, 
+                        ALWAYS_FORCE_SESSION_CREATION_DEFAULT));
         
         if (TOMAHAWK_AVAILABLE)
         {
@@ -1593,4 +1612,17 @@ public class MyfacesConfig
     {
         this._strictJsf2OriginHeaderAppPath = strictJsf2OriginHeaderAppPath;
     }
+
+    public boolean isAlwaysForceSessionCreation()
+    {
+        return _alwaysForceSessionCreation;
+    }
+    
+    /**
+     * @param alwaysForceSessionCreation the _alwaysForceSessionCreation to set
+     */
+    public void setAlwaysForceSessionCreation(boolean alwaysForceSessionCreation)
+    {
+        this._alwaysForceSessionCreation = alwaysForceSessionCreation;
+    }
 }