ICEfaces
  1. ICEfaces
  2. ICE-8540

ACE Data Exporter components fail on Liferay when request is not localhost

    Details

    • Type: Bug Bug
    • Status: Closed
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: EE-3.0.0.GA, EE-3.0.0.GA_P01
    • Fix Version/s: EE-3.0.0.GA_P01, 3.2
    • Component/s: ACE-Components, Sample Apps
    • Labels:
      None
    • Environment:
      Liferay Portal Portlet ACE Data Exporter Component

      Description

      In testing the showcase-portlet examples on Liferay (any of 5.2.3, 6.0, 6.1), the following behaviour was observed when using IE. It exists in the EE-3.0.0.GA release as well as on the current maintenance branch.

      When running any of the Data Exporter examples, after clicking the "Export File" button, the operation appears to simply silently fail. There were no client or server-side errors detected.

        Activity

        Deryk Sinotte created issue -
        Deryk Sinotte made changes -
        Field Original Value New Value
        Salesforce Case []
        Assignee Arturo Zambrano [ artzambrano ]
        Ken Fyten made changes -
        Salesforce Case []
        Assignee Priority P1
        Hide
        Deryk Sinotte added a comment -

        Looks like it's not an IE problem specifically. The reason it only showed up on IE is that it was the only browser that I was testing with that wasn't using http://localhost:8080. Running Chrome from a remote machine shows the same issue.

        The problem seems to stem from the initial update that comes back. When you go to the initial portal page from a browser on a different machine, the initial address might look something like:

        http://myRemoteHostAddress:8080/web/guest/exporter

        When you click the export button, the URL for the request looks something like:

        http://myRemoteHostAddress:8080/web/guest/exporter?_dataExporter_WAR_showcaseportlet__facesViewId=%2Fportlet-view.xhtml&p_p_col_count=1&p_p_col_id=column-2&p_p_id=dataExporter_WAR_showcaseportlet&p_p_lifecycle=2

        The response that comes back includes a script that needs to be run to actually fetch the resource. It looks like this (formatted a bit for readability):

        <update id="A9102:form1:dataExporter_script">
        <![CDATA[<span id="A9102:form1:dataExporter_script">
        <script type="text/javascript">
        ice.ace.jq(ice.ace.escapeClientId('A9102:form1:dataExporter')).button();
        if (ice.ace.DataExporters['A9102:form1:dataExporter'])
        ice.ace.DataExporters['A9102:form1:dataExporter'].url('http://localhost:8080/web/guest/exporter?_dataExporter_WAR_showcaseportlet_javax.faces.resource=s8040c1d4-6309-4ee5-8f0d-a44cf4bae1a7&p_p_col_count=1&p_p_col_id=column-2&p_p_id=dataExporter_WAR_showcaseportlet&p_p_lifecycle=2');

        </script>
        </span>]]>
        </update>

        The interesting part to note is the URL it's constructed that contains the resource id it'll be looking for. It starts with "http://localhost:8080/web/guest/exporter?...". So it's trying to make a request to localhost even though the original request was not localhost. This explains why it works when testing it locally.

        Show
        Deryk Sinotte added a comment - Looks like it's not an IE problem specifically. The reason it only showed up on IE is that it was the only browser that I was testing with that wasn't using http://localhost:8080 . Running Chrome from a remote machine shows the same issue. The problem seems to stem from the initial update that comes back. When you go to the initial portal page from a browser on a different machine, the initial address might look something like: http://myRemoteHostAddress:8080/web/guest/exporter When you click the export button, the URL for the request looks something like: http://myRemoteHostAddress:8080/web/guest/exporter?_dataExporter_WAR_showcaseportlet__facesViewId=%2Fportlet-view.xhtml&p_p_col_count=1&p_p_col_id=column-2&p_p_id=dataExporter_WAR_showcaseportlet&p_p_lifecycle=2 The response that comes back includes a script that needs to be run to actually fetch the resource. It looks like this (formatted a bit for readability): <update id="A9102:form1:dataExporter_script"> <![CDATA[<span id="A9102:form1:dataExporter_script"> <script type="text/javascript"> ice.ace.jq(ice.ace.escapeClientId('A9102:form1:dataExporter')).button(); if (ice.ace.DataExporters ['A9102:form1:dataExporter'] ) ice.ace.DataExporters ['A9102:form1:dataExporter'] .url('http://localhost:8080/web/guest/exporter?_dataExporter_WAR_showcaseportlet_javax.faces.resource=s8040c1d4-6309-4ee5-8f0d-a44cf4bae1a7&p_p_col_count=1&p_p_col_id=column-2&p_p_id=dataExporter_WAR_showcaseportlet&p_p_lifecycle=2'); </script> </span>]]> </update> The interesting part to note is the URL it's constructed that contains the resource id it'll be looking for. It starts with "http://localhost:8080/web/guest/exporter?...". So it's trying to make a request to localhost even though the original request was not localhost. This explains why it works when testing it locally.
        Hide
        Deryk Sinotte added a comment -

        Editing description to better reflect actual issue.

        Show
        Deryk Sinotte added a comment - Editing description to better reflect actual issue.
        Deryk Sinotte made changes -
        Summary ACE Data Exporter components fail on Liferay with IE ACE Data Exporter components fail on Liferay when request is not localhost
        Salesforce Case []
        Hide
        Deryk Sinotte added a comment -

        Turns out you can more easily reproduce the problem simply by making the first portlet export a file from one host (e.g. http://localhost:8080/) and then a subsequent export using a different host (e.g. http://192.168.5.1:8080). They can even be on the same machine.

        In ResourceRegistry.addResource(), there is the following bit of logic:

        ...
        String[] pathTemplate = EnvUtils.getPathTemplate();
        String path = pathTemplate[0] + key + pathTemplate[1];
        path = FacesContext.getCurrentInstance().getExternalContext().encodeResourceURL(path);
        return path;

        The path template provides a way to get the proper bits for building up a valid URL with the key being the id of resource in the registry. The entire path is then encoded and returned.

        The EnvUtils.getPathTemplate() does the following:

        public static String[] getPathTemplate() {
        FacesContext facesContext = FacesContext.getCurrentInstance();
        Map applicationMap = facesContext.getExternalContext()
        .getApplicationMap();
        String[] pathTemplate = (String[]) applicationMap.get(PATH_TEMPLATE);
        ...

        First it checks to see if a path template already exists and uses that. In our testing with portlets, if you first export some files from "localhost", that's what gets stored in the application map as the path template and used from then on.

        The reason it doesn't fail in non-portlet mode is that the path template ends up being a relative path (no host or port information). But with portlets, the entire URL is used as a template, leading to failures when subsequent requests come from a different host.

        In other words, when getPathTemplate() generates a path using a "dummy" resource:

        PORTLET: http://localhost:8080/web/guest/exporter?_dataExporter_WAR_showcaseportlet_javax.faces.resource=bridge.js&p_p_col_count=1&p_p_col_id=column-2&p_p_id=dataExporter_WAR_showcaseportlet&p_p_lifecycle=2

        NON-PORTLET:
        /showcase/javax.faces.resource/bridge.js.jsf

        The likely fix is to disable the optimization for storing the path template in the application map when running in a portal.

        Show
        Deryk Sinotte added a comment - Turns out you can more easily reproduce the problem simply by making the first portlet export a file from one host (e.g. http://localhost:8080/ ) and then a subsequent export using a different host (e.g. http://192.168.5.1:8080 ). They can even be on the same machine. In ResourceRegistry.addResource(), there is the following bit of logic: ... String[] pathTemplate = EnvUtils.getPathTemplate(); String path = pathTemplate [0] + key + pathTemplate [1] ; path = FacesContext.getCurrentInstance().getExternalContext().encodeResourceURL(path); return path; The path template provides a way to get the proper bits for building up a valid URL with the key being the id of resource in the registry. The entire path is then encoded and returned. The EnvUtils.getPathTemplate() does the following: public static String[] getPathTemplate() { FacesContext facesContext = FacesContext.getCurrentInstance(); Map applicationMap = facesContext.getExternalContext() .getApplicationMap(); String[] pathTemplate = (String[]) applicationMap.get(PATH_TEMPLATE); ... First it checks to see if a path template already exists and uses that. In our testing with portlets, if you first export some files from "localhost", that's what gets stored in the application map as the path template and used from then on. The reason it doesn't fail in non-portlet mode is that the path template ends up being a relative path (no host or port information). But with portlets, the entire URL is used as a template, leading to failures when subsequent requests come from a different host. In other words, when getPathTemplate() generates a path using a "dummy" resource: PORTLET: http://localhost:8080/web/guest/exporter?_dataExporter_WAR_showcaseportlet_javax.faces.resource=bridge.js&p_p_col_count=1&p_p_col_id=column-2&p_p_id=dataExporter_WAR_showcaseportlet&p_p_lifecycle=2 NON-PORTLET: /showcase/javax.faces.resource/bridge.js.jsf The likely fix is to disable the optimization for storing the path template in the application map when running in a portal.
        Repository Revision Date User Message
        ICEsoft Public SVN Repository #30709 Thu Sep 06 10:09:32 MDT 2012 deryk.sinotte ICE-8540: disable optmization of application scope storage of paths when running in portals
        Files Changed
        Commit graph MODIFY /icefaces3/trunk/icefaces/core/src/main/java/org/icefaces/util/EnvUtils.java
        Repository Revision Date User Message
        ICEsoft Public SVN Repository #30710 Thu Sep 06 10:09:43 MDT 2012 deryk.sinotte ICE-8540: disable optmization of application scope storage of paths when running in portals
        Files Changed
        Commit graph MODIFY /icefaces3/branches/icefaces-3.0.x-maintenance/icefaces/core/src/main/java/org/icefaces/util/EnvUtils.java
        Ken Fyten made changes -
        Assignee Arturo Zambrano [ artzambrano ] Deryk Sinotte [ deryk.sinotte ]
        Deryk Sinotte made changes -
        Salesforce Case []
        Fix Version/s 3.2 [ 10338 ]
        Hide
        Deryk Sinotte added a comment -

        Checked in a fix to both the maintenance branch and the trunk that avoids caching the path of the dummy resource when running in a portal. The optimization is still there for non-portal platforms but with portals the path will be calculated for each resource.

        Show
        Deryk Sinotte added a comment - Checked in a fix to both the maintenance branch and the trunk that avoids caching the path of the dummy resource when running in a portal. The optimization is still there for non-portal platforms but with portals the path will be calculated for each resource.
        Deryk Sinotte made changes -
        Status Open [ 1 ] Resolved [ 5 ]
        Resolution Fixed [ 1 ]
        Ken Fyten made changes -
        Status Resolved [ 5 ] Closed [ 6 ]
        Assignee Priority P1 [ 10010 ]

          People

          • Assignee:
            Deryk Sinotte
            Reporter:
            Deryk Sinotte
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: