You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by mf...@apache.org on 2010/03/30 23:25:12 UTC

svn commit: r929296 - in /myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces: application/PortletStateManagerImpl.java context/PortletExternalContextImpl.java

Author: mfreedman
Date: Tue Mar 30 21:25:11 2010
New Revision: 929296

URL: http://svn.apache.org/viewvc?rev=929296&view=rev
Log:
PORTLETBRIDGE-139: Bridge doesn't properly detect xml & escaping in QS
PORTLETBRIDGE-138: Bridge doesn't work correctly use of deprecated StateManager APIs

Modified:
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java
    myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java?rev=929296&r1=929295&r2=929296&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/application/PortletStateManagerImpl.java Tue Mar 30 21:25:11 2010
@@ -108,6 +108,46 @@ public class PortletStateManagerImpl
     
   }
   
+  public void writeState(FacesContext context, SerializedView state)
+    throws IOException
+  {
+    // Do nothing when not running in portlet request
+    if (!BridgeUtil.isPortletRequest())
+    {
+      super.writeState(context, state);
+      return;
+    }
+
+    // Replace current response writer so can grab what is written
+    ResponseWriter oldRW = context.getResponseWriter();
+    StringWriter stringWriter = new StringWriter(128);
+    ResponseWriter newRW = oldRW.cloneWithWriter(stringWriter);
+    context.setResponseWriter(newRW);
+    
+    super.writeState(context, state);
+    
+    // Restore real responsewriter
+    context.setResponseWriter(oldRW);
+    
+    // Get written state
+    newRW.flush();
+    String stateValue = new String(stringWriter.getBuffer());
+    
+
+    // Write it to the old response writer
+    oldRW.write(stateValue);
+    
+    // Now extract the parameter value from the buffer:
+    stateValue = extractViewStateParamValue(stateValue);
+    
+    if (stateValue != null) 
+    {
+      Map<String, Object> m = context.getExternalContext().getRequestMap();
+      m.put(BridgeImpl.UPDATED_VIEW_STATE_PARAM, stateValue);
+    }
+    
+  }
+  
   public StateManager getWrapped()
   {
     return mDelegatee;

Modified: myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java
URL: http://svn.apache.org/viewvc/myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java?rev=929296&r1=929295&r2=929296&view=diff
==============================================================================
--- myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java (original)
+++ myfaces/portlet-bridge/core/trunk/impl/src/main/java/org/apache/myfaces/portlet/faces/context/PortletExternalContextImpl.java Tue Mar 30 21:25:11 2010
@@ -463,15 +463,30 @@ public class PortletExternalContextImpl
           }
         }
       }
+      
+      url = actionURL.toString();
+      
+      // JSF expects encodeActionURL to not perturb any XML encoding (or lack thereof) of the url.
+      // I.e. the caller is responsible for either pre or post XML escaping the string sent/returned
+      // by encodeActionURL.  Unfortunately, the portlet 1.0 spec didn't define whether toString()
+      // returns an XML encoded string or not. Most containers behaved like the servlet environment and did not,
+      // however wsrp based containers had the option of encoding the consumer rewrite url either with & or &amp;.
+      // Some containers choose the later.
+      // 
+      //  So special care must be taken here to fix up the url returned by the container
+      //  to have the same encoding as what was sent in.
 
-      // If we weren't already Xhtml encoded (used &amp;) then renderkit will likely
-      // do it after us if it needs to do such encoding -- so undo any xml encoding the portlet URL might
-      // have done to avoid double encoding -- Otherwise if the string passed in was encoded the renderkit 
-      // is unlikely to reencode after the call -- so don't undo any encoding.
       if (!isStrictXhtmlEncoded)
       {
-        url = actionURL.toString();
-        url = url.replaceAll("\\&amp\\;", "&");
+        // If we weren't already Xhtml encoded (used &amp;) then renderkit will likely
+        // do it after us if it needs to do such encoding -- so undo any xml encoding the portlet URL might
+        // have done to avoid double encoding -- Otherwise if the string passed in was encoded the renderkit 
+        // is unlikely to reencode after the call -- so don't undo any encoding.
+        url = url.replace("&amp;", "&");
+      }
+      else if (!isStrictXhtmlEncoded(url)) // check the new url and process if its not xml encoded
+      {
+        url = xhtmlEncode(url);
       }
     }
     else
@@ -631,6 +646,8 @@ public class PortletExternalContextImpl
   
   private String encodeResourceURL(String s, boolean targetInApp)
   {
+    boolean isStrictXhtmlEncoded = isStrictXhtmlEncoded(s); // do here because replaceResourceQSMarkers changes
+    
     if (targetInApp)
     {
       s = normalizeResourcePath(s);
@@ -643,7 +660,7 @@ public class PortletExternalContextImpl
     // do it after us if it needs to do such encoding -- so undo any xml encoding the portlet URL might
     // have done to avoid double encoding -- Otherwise if the string passed in was encoded the renderkit 
     // is unlikely to reencode after the call -- so don't undo any encoding.
-    if (!isStrictXhtmlEncoded(s))
+    if (!isStrictXhtmlEncoded)
     {
     
       // Some portlet containers implementing wsrp choose to separate the 
@@ -651,11 +668,11 @@ public class PortletExternalContextImpl
       // spec allows for either that or &.  If the container has chosen to 
       // to do such -- undo it (use & instead) as faces renderkits/response writers
       // may reencode when writing XMl content.
-      return mPortletResponse.encodeURL(s).replaceAll("\\&amp\\;", "&");
+      return mPortletResponse.encodeURL(s).replace("&amp;", "&");
     }
     else
     {
-      return mPortletResponse.encodeURL(s); 
+      return xhtmlEncode(mPortletResponse.encodeURL(s)); 
     }
   }
   
@@ -1764,6 +1781,40 @@ public class PortletExternalContextImpl
     return url.toLowerCase().startsWith("portlet:");
   }
   
+  private String xhtmlEncode(String url)
+  {
+    StringBuffer sb = new StringBuffer(url.length());
+    
+    // check for use of &amp; in query string
+    int copyFrom = 0;
+    int currentPos = url.indexOf('?');
+
+    if (currentPos == -1) return url;
+    
+    while (true)
+    {
+      int ampPos = url.indexOf('&', currentPos);
+      int xhtmlAmpPos = url.indexOf("&amp;", currentPos);
+      // no more & to process -- so return current value of isStrict
+      if (ampPos == -1)
+      {
+        if (copyFrom < url.length())
+        {
+          sb.append(url, copyFrom, url.length());
+        }
+        return sb.toString();
+      }
+      // if the amp we found doesn't start an &amp; then its not strict
+      if (ampPos != xhtmlAmpPos)
+      {
+        sb.append(url, copyFrom, ampPos);
+        sb.append("&amp;");
+        copyFrom = ampPos + 1;
+      }
+      currentPos = ampPos + 1;
+    }    
+  }
+  
   private boolean isStrictXhtmlEncoded(String url)
   {
     // check for use of &amp; in query string
@@ -1775,7 +1826,7 @@ public class PortletExternalContextImpl
     while (true)
     {
       int ampPos = url.indexOf('&', currentPos);
-      int xhtmlAmpPos = url.indexOf("\\&amp\\;", currentPos);
+      int xhtmlAmpPos = url.indexOf("&amp;", currentPos);
       // no more & to process -- so return current value of isStrict
       if (ampPos == -1)
       {
@@ -1787,7 +1838,7 @@ public class PortletExternalContextImpl
         return false;
       }
       isStrict = true;
-      currentPos = ampPos;
+      currentPos = ampPos + 1;    
     }
   }