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);