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

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


The following commit(s) were added to refs/heads/master by this push:
     new 5c762b6d6 try to workaround mojarra encodeRedirectURL bug
5c762b6d6 is described below

commit 5c762b6d61c81db714d29e83a5eeb39ffc50ac2f
Author: Thomas Andraschko <[email protected]>
AuthorDate: Wed Feb 28 11:49:48 2024 +0100

    try to workaround mojarra encodeRedirectURL bug
---
 .../impl/clientwindow/ClientSideClientWindow.java  |  15 +-
 .../jsf/impl/util/ClientWindowHelper.java          | 173 +++++++++++++++++++--
 2 files changed, 172 insertions(+), 16 deletions(-)

diff --git 
a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/clientwindow/ClientSideClientWindow.java
 
b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/clientwindow/ClientSideClientWindow.java
index f69a3388d..c9f0bba13 100644
--- 
a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/clientwindow/ClientSideClientWindow.java
+++ 
b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/clientwindow/ClientSideClientWindow.java
@@ -18,18 +18,19 @@
  */
 package org.apache.deltaspike.jsf.impl.clientwindow;
 
-import java.io.IOException;
-import java.io.OutputStream;
 import jakarta.faces.FacesException;
 import jakarta.faces.context.ExternalContext;
 import jakarta.faces.context.FacesContext;
 import jakarta.servlet.http.Cookie;
 import jakarta.servlet.http.HttpServletResponse;
-import java.util.Collections;
-import java.util.Map;
 import org.apache.deltaspike.jsf.impl.util.ClientWindowHelper;
 import org.apache.deltaspike.jsf.impl.util.JsfUtils;
 
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Map;
+
 public class ClientSideClientWindow extends DeltaSpikeClientWindow
 {
     /**
@@ -81,7 +82,7 @@ public class ClientSideClientWindow extends 
DeltaSpikeClientWindow
             if (id == null || newWindowIdRequested)
             {
                 // GET request without windowId - send 
windowhandlerfilter.html to get the windowId
-                sendWindowHandlerHtml(facesContext.getExternalContext(), id);
+                sendWindowHandlerHtml(facesContext, 
facesContext.getExternalContext(), id);
                 facesContext.responseComplete();
             }
         }
@@ -96,7 +97,7 @@ public class ClientSideClientWindow extends 
DeltaSpikeClientWindow
         return (noscript != null && "true".equals(noscript));
     }
 
-    protected void sendWindowHandlerHtml(ExternalContext externalContext, 
String windowId)
+    protected void sendWindowHandlerHtml(FacesContext facesContext, 
ExternalContext externalContext, String windowId)
     {
         HttpServletResponse httpResponse = (HttpServletResponse) 
externalContext.getResponse();
 
@@ -119,7 +120,7 @@ public class ClientSideClientWindow extends 
DeltaSpikeClientWindow
             // could be a different when using forwards
             windowHandlerHtml = 
windowHandlerHtml.replace(REQUEST_URL_REPLACE_PATTERN,
                                                           
org.owasp.encoder.Encode.forJavaScriptBlock(
-                                                              
ClientWindowHelper.constructRequestUrl(externalContext)));
+                                                              
ClientWindowHelper.constructRequestUrl(facesContext, externalContext)));
             // set the noscript-URL for users with no JavaScript
             windowHandlerHtml =
                 windowHandlerHtml.replace(NOSCRIPT_URL_REPLACE_PATTERN,
diff --git 
a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
 
b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
index 91799da12..62ce73bca 100644
--- 
a/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
+++ 
b/deltaspike/modules/jsf/impl/src/main/java/org/apache/deltaspike/jsf/impl/util/ClientWindowHelper.java
@@ -18,17 +18,27 @@
  */
 package org.apache.deltaspike.jsf.impl.util;
 
-import java.io.IOException;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
 import jakarta.enterprise.inject.Typed;
 import jakarta.faces.FacesException;
 import jakarta.faces.context.ExternalContext;
 import jakarta.faces.context.FacesContext;
+import jakarta.faces.lifecycle.ClientWindow;
 import jakarta.faces.render.ResponseStateManager;
-
+import jakarta.servlet.http.HttpServletResponse;
 import org.apache.deltaspike.jsf.api.config.base.JsfBaseConfig;
+import org.apache.myfaces.core.api.shared.lang.Assert;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
 
 @Typed()
 public abstract class ClientWindowHelper
@@ -48,7 +58,7 @@ public abstract class ClientWindowHelper
         public static final String REQUEST_WINDOW_ID_PREFIX = "dsrwid-";
     }
 
-    public static String constructRequestUrl(ExternalContext externalContext)
+    public static String constructRequestUrl(FacesContext facesContext, 
ExternalContext externalContext)
     {
         String url = externalContext.getRequestContextPath()
                 + externalContext.getRequestServletPath();
@@ -61,11 +71,156 @@ public abstract class ClientWindowHelper
         url = JsfUtils.addRequestParameters(externalContext, url, true);
         // always remove jfwid to force adding new jfwid as JSF impl otherwise 
just ignores it
         url = JsfUtils.removeUrlParameter(url, 
ResponseStateManager.CLIENT_WINDOW_URL_PARAM);
-        url = externalContext.encodeRedirectURL(url, null);
+
+        // TODO currently this is broken in Mojarra and will be fixed in 4.0.6
+        // url = externalContext.encodeRedirectURL(url, null);
+
+        // let's reuse the logic from MyFaces instead
+        HttpServletResponse servletResponse = (HttpServletResponse) 
externalContext.getResponse();
+        servletResponse.encodeRedirectURL(encodeURL(url, facesContext, 
servletResponse.getCharacterEncoding()));
 
         return url;
     }
-    
+
+    // copied from MyFaces
+    private static String encodeURL(String baseUrl, FacesContext facesContext, 
String encoding)
+    {
+        Assert.notNull(baseUrl, "url");
+
+        String fragment = null;
+        String queryString = null;
+        Map<String, List<String>> paramMap = null;
+
+        //extract any URL fragment
+        int index = baseUrl.indexOf('#');
+        if (index != -1)
+        {
+            fragment = baseUrl.substring(index + 1);
+            baseUrl = baseUrl.substring(0, index);
+        }
+
+        //extract the current query string and add the params to the paramMap
+        index = baseUrl.indexOf('?');
+        if (index != -1)
+        {
+            queryString = baseUrl.substring(index + 1);
+            baseUrl = baseUrl.substring(0, index);
+            String[] nameValuePairs = queryString.split("&");
+            for (int i = 0; i < nameValuePairs.length; i++)
+            {
+                String[] currentPair = nameValuePairs[i].split("=");
+                String currentName = currentPair[0];
+
+                if (paramMap == null)
+                {
+                    paramMap = new HashMap<>(5, 1f);
+                }
+
+                List<String> values = paramMap.get(currentName);
+                if (values == null)
+                {
+                    values = new ArrayList<>(1);
+                    paramMap.put(currentName, values);
+                }
+
+                try
+                {
+                    values.add(currentPair.length > 1
+                            ? URLDecoder.decode(currentPair[1], encoding)
+                            : "");
+                }
+                catch (UnsupportedEncodingException e)
+                {
+                    //shouldn't ever get here
+                    throw new UnsupportedOperationException("Encoding type=" + 
encoding
+                            + " not supported", e);
+                }
+            }
+        }
+
+        ClientWindow window = 
facesContext.getExternalContext().getClientWindow();
+        if (window != null && 
window.isClientWindowRenderModeEnabled(facesContext))
+        {
+            if (paramMap == null)
+            {
+                paramMap = new HashMap<>(5, 1f);
+            }
+
+            if 
(!paramMap.containsKey(ResponseStateManager.CLIENT_WINDOW_URL_PARAM))
+            {
+                paramMap.put(ResponseStateManager.CLIENT_WINDOW_URL_PARAM, 
Arrays.asList(window.getId()));
+            }
+
+            Map<String, String> additionalQueryURLParameters = 
window.getQueryURLParameters(facesContext);
+            if (additionalQueryURLParameters != null)
+            {
+                for (Map.Entry<String , String> entry : 
additionalQueryURLParameters.entrySet())
+                {
+                    paramMap.put(entry.getKey(), 
Arrays.asList(entry.getValue()));
+                }
+            }
+        }
+
+        boolean hasParams = paramMap != null && !paramMap.isEmpty();
+
+        if (!hasParams && fragment == null)
+        {
+            return baseUrl;
+        }
+
+        // start building the new URL
+        StringBuilder newUrl = new StringBuilder(baseUrl.length() + 10);
+        newUrl.append(baseUrl);
+
+        //now add the updated param list onto the url
+        if (hasParams)
+        {
+            boolean isFirstPair = true;
+            for (Map.Entry<String, List<String>> pair : paramMap.entrySet())
+            {
+                for (int i = 0; i < pair.getValue().size(); i++)
+                {
+                    String value = pair.getValue().get(i);
+
+                    if (!isFirstPair)
+                    {
+                        newUrl.append('&');
+                    }
+                    else
+                    {
+                        newUrl.append('?');
+                        isFirstPair = false;
+                    }
+
+                    newUrl.append(pair.getKey());
+                    newUrl.append('=');
+                    if (value != null)
+                    {
+                        try
+                        {
+                            newUrl.append(URLEncoder.encode(value, encoding));
+                        }
+                        catch (UnsupportedEncodingException e)
+                        {
+                            //shouldn't ever get here
+                            throw new UnsupportedOperationException("Encoding 
type=" + encoding
+                                    + " not supported", e);
+                        }
+                    }
+                }
+            }
+        }
+
+        //add the fragment back on (if any)
+        if (fragment != null)
+        {
+            newUrl.append('#');
+            newUrl.append(fragment);
+        }
+
+        return newUrl.toString();
+    }
+
     /**
      * Handles the initial redirect for the LAZY mode, if no windowId is 
available in the current request URL.
      *
@@ -80,7 +235,7 @@ public abstract class ClientWindowHelper
 
         ExternalContext externalContext = facesContext.getExternalContext();
 
-        String url = constructRequestUrl(externalContext);
+        String url = constructRequestUrl(facesContext, externalContext);
 
         // remember the initial redirect windowId till the next request - see 
#729
         addRequestWindowIdCookie(facesContext, newWindowId, newWindowId);

Reply via email to