]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactor Portlet URL handling based on Servlet URLs (#9168)
authorLeif Åstrand <leif@vaadin.com>
Thu, 26 Jul 2012 12:03:28 +0000 (15:03 +0300)
committerLeif Åstrand <leif@vaadin.com>
Thu, 26 Jul 2012 13:29:13 +0000 (16:29 +0300)
src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
src/com/vaadin/terminal/gwt/server/CommunicationManager.java
src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java
src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java

index 877f2a70b8fc70bac0a63650a37cf0f2184518b8..71707e723a7f0aa3f33c1c0c680dbd179e8f0a7e 100644 (file)
@@ -23,6 +23,8 @@ import com.vaadin.terminal.gwt.client.ui.UnknownComponentConnector;
 
 public class ApplicationConfiguration implements EntryPoint {
 
+    public static final String PORTLET_RESOUCE_URL_BASE = "portletAppURLBase";
+
     /**
      * Helper class for reading configuration options from the bootstap
      * javascript
@@ -205,8 +207,6 @@ public class ApplicationConfiguration implements EntryPoint {
     private ErrorMessage communicationError;
     private ErrorMessage authorizationError;
     private boolean useDebugIdInDom = true;
-    private boolean usePortletURLs = false;
-    private String portletUidlURLBase;
 
     private HashMap<Integer, String> unknownComponents;
 
@@ -226,11 +226,12 @@ public class ApplicationConfiguration implements EntryPoint {
     private Map<Integer, String> tagToServerSideClassName = new HashMap<Integer, String>();
 
     public boolean usePortletURLs() {
-        return usePortletURLs;
+        return getPortletResourceUrl() != null;
     }
 
-    public String getPortletUidlURLBase() {
-        return portletUidlURLBase;
+    public String getPortletResourceUrl() {
+        return getJsoConfiguration(id)
+                .getConfigString(PORTLET_RESOUCE_URL_BASE);
     }
 
     public String getRootPanelId() {
@@ -318,12 +319,6 @@ public class ApplicationConfiguration implements EntryPoint {
         // null -> true
         useDebugIdInDom = jsoConfiguration.getConfigBoolean("useDebugIdInDom") != Boolean.FALSE;
 
-        // null -> false
-        usePortletURLs = jsoConfiguration.getConfigBoolean("usePortletURLs") == Boolean.TRUE;
-
-        portletUidlURLBase = jsoConfiguration
-                .getConfigString("portletUidlURLBase");
-
         // null -> false
         standalone = jsoConfiguration.getConfigBoolean("standalone") == Boolean.TRUE;
 
index 5db7221bdbea13e5a1cc239f4ab38bf9fcd8af06..0647f2fe96fc7d49c51bfc8ab39fb6c7b21580c6 100644 (file)
@@ -27,6 +27,7 @@ import com.google.gwt.http.client.RequestBuilder;
 import com.google.gwt.http.client.RequestCallback;
 import com.google.gwt.http.client.RequestException;
 import com.google.gwt.http.client.Response;
+import com.google.gwt.http.client.URL;
 import com.google.gwt.json.client.JSONArray;
 import com.google.gwt.json.client.JSONObject;
 import com.google.gwt.json.client.JSONString;
@@ -76,6 +77,8 @@ import com.vaadin.terminal.gwt.server.AbstractCommunicationManager;
  * Entry point classes (widgetsets) define <code>onModuleLoad()</code>.
  */
 public class ApplicationConnection {
+    public static final String V_RESOURCE_PATH = "v-resourcePath";
+
     private static final String CONNECTOR_PROTOCOL_PREFIX = "connector://";
 
     public static final String CONNECTOR_RESOURCE_PREFIX = "APP/CONNECTOR";
@@ -511,12 +514,7 @@ public class ApplicationConnection {
         final String payload = uidlSecurityKey + VAR_BURST_SEPARATOR
                 + requestData;
         VConsole.log("Making UIDL Request with params: " + payload);
-        String uri;
-        if (configuration.usePortletURLs()) {
-            uri = configuration.getPortletUidlURLBase();
-        } else {
-            uri = getAppUri() + "UIDL";
-        }
+        String uri = translateVaadinUri("app://UIDL");
 
         if (extraParams != null && extraParams.length() > 0) {
             uri = addGetParameters(uri, extraParams);
@@ -2298,7 +2296,28 @@ public class ApplicationConnection {
             uidlUri = themeUri + uidlUri.substring(7);
         }
         if (uidlUri.startsWith("app://")) {
-            uidlUri = getAppUri() + uidlUri.substring(6);
+            String relativeUrl = uidlUri.substring(6);
+            if (getConfiguration().usePortletURLs()) {
+                // Should put path in v-resourcePath parameter and append query
+                // params to base portlet url
+                String[] parts = relativeUrl.split("\\?", 2);
+                String path = parts[0];
+
+                String url = getConfiguration().getPortletResourceUrl();
+                if (parts.length > 1) {
+                    String appUrlParams = parts[1];
+                    url = addGetParameters(url, appUrlParams);
+                }
+                if (!path.startsWith("/")) {
+                    path = '/' + path;
+                }
+                String pathParam = V_RESOURCE_PATH + "="
+                        + URL.encodeQueryString(path);
+                url = addGetParameters(url, pathParam);
+                uidlUri = url;
+            } else {
+                uidlUri = getAppUri() + relativeUrl;
+            }
         } else if (uidlUri.startsWith(CONNECTOR_PROTOCOL_PREFIX)) {
             // getAppUri *should* always end with /
             // substring *should* always start with / (connector:///foo.bar
index 3fcd61036fc01cf1ca1e259963bbb82e3336f3a0..978738a1d87a8e83303878206bb5e729746ed6b2 100644 (file)
@@ -25,7 +25,6 @@ import javax.portlet.ActionResponse;
 import javax.portlet.EventRequest;
 import javax.portlet.EventResponse;
 import javax.portlet.GenericPortlet;
-import javax.portlet.MimeResponse;
 import javax.portlet.PortletConfig;
 import javax.portlet.PortletContext;
 import javax.portlet.PortletException;
@@ -64,6 +63,8 @@ import com.vaadin.ui.Root;
 public abstract class AbstractApplicationPortlet extends GenericPortlet
         implements Constants {
 
+    public static final String RESOURCE_URL_ID = "APP";
+
     public static class WrappedHttpAndPortletRequest extends
             WrappedPortletRequest {
 
@@ -179,12 +180,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
         public void criticalNotification(WrappedRequest request,
                 WrappedResponse response, String cap, String msg,
                 String details, String outOfSyncURL) throws IOException {
-            PortletRequest portletRequest = WrappedPortletRequest.cast(request)
-                    .getPortletRequest();
-            PortletResponse portletResponse = ((WrappedPortletResponse) response)
-                    .getPortletResponse();
-            portlet.criticalNotification(portletRequest,
-                    (MimeResponse) portletResponse, cap, msg, details,
+            portlet.criticalNotification(WrappedPortletRequest.cast(request),
+                    (WrappedPortletResponse) response, cap, msg, details,
                     outOfSyncURL);
         }
     }
@@ -440,18 +437,20 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
         FILE_UPLOAD, UIDL, RENDER, STATIC_FILE, APPLICATION_RESOURCE, DUMMY, EVENT, ACTION, UNKNOWN, BROWSER_DETAILS;
     }
 
-    protected RequestType getRequestType(PortletRequest request) {
+    protected RequestType getRequestType(WrappedPortletRequest wrappedRequest) {
+        PortletRequest request = wrappedRequest.getPortletRequest();
         if (request instanceof RenderRequest) {
             return RequestType.RENDER;
         } else if (request instanceof ResourceRequest) {
             ResourceRequest resourceRequest = (ResourceRequest) request;
-            if (isUIDLRequest(resourceRequest)) {
+            if (ServletPortletHelper.isUIDLRequest(wrappedRequest)) {
                 return RequestType.UIDL;
             } else if (isBrowserDetailsRequeset(resourceRequest)) {
                 return RequestType.BROWSER_DETAILS;
-            } else if (isFileUploadRequest(resourceRequest)) {
+            } else if (ServletPortletHelper.isFileUploadRequest(wrappedRequest)) {
                 return RequestType.FILE_UPLOAD;
-            } else if (isApplicationResourceRequest(resourceRequest)) {
+            } else if (ServletPortletHelper
+                    .isApplicationResourceRequest(wrappedRequest)) {
                 return RequestType.APPLICATION_RESOURCE;
             } else if (isDummyRequest(resourceRequest)) {
                 return RequestType.DUMMY;
@@ -471,25 +470,11 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
                 && request.getResourceID().equals("browserDetails");
     }
 
-    private boolean isApplicationResourceRequest(ResourceRequest request) {
-        return request.getResourceID() != null
-                && request.getResourceID().startsWith("APP");
-    }
-
-    private boolean isUIDLRequest(ResourceRequest request) {
-        return request.getResourceID() != null
-                && request.getResourceID().equals("UIDL");
-    }
-
     private boolean isDummyRequest(ResourceRequest request) {
         return request.getResourceID() != null
                 && request.getResourceID().equals("DUMMY");
     }
 
-    private boolean isFileUploadRequest(ResourceRequest request) {
-        return "UPLOAD".equals(request.getResourceID());
-    }
-
     /**
      * Returns true if the servlet is running in production mode. Production
      * mode disables all debug facilities.
@@ -513,7 +498,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
         WrappedPortletResponse wrappedResponse = new WrappedPortletResponse(
                 response, getDeploymentConfiguration());
 
-        RequestType requestType = getRequestType(request);
+        RequestType requestType = getRequestType(wrappedRequest);
 
         if (requestType == RequestType.UNKNOWN) {
             handleUnknownRequest(request, response);
@@ -682,7 +667,8 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
                 getLogger()
                         .fine("General security exception, the security key was probably incorrect.");
             } catch (final Throwable e) {
-                handleServiceException(request, response, application, e);
+                handleServiceException(wrappedRequest, wrappedResponse,
+                        application, e);
             } finally {
                 // Notifies transaction end
                 try {
@@ -1040,16 +1026,16 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
         return Application.getSystemMessages();
     }
 
-    private void handleServiceException(PortletRequest request,
-            PortletResponse response, Application application, Throwable e)
-            throws IOException, PortletException {
+    private void handleServiceException(WrappedPortletRequest request,
+            WrappedPortletResponse response, Application application,
+            Throwable e) throws IOException, PortletException {
         // TODO Check that this error handler is working when running inside a
         // portlet
 
         // if this was an UIDL request, response UIDL back to client
         if (getRequestType(request) == RequestType.UIDL) {
             Application.SystemMessages ci = getSystemMessages();
-            criticalNotification(request, (ResourceResponse) response,
+            criticalNotification(request, response,
                     ci.getInternalErrorCaption(), ci.getInternalErrorMessage(),
                     null, ci.getInternalErrorURL());
             if (application != null) {
@@ -1103,9 +1089,9 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
      * @throws IOException
      *             if the writing failed due to input/output error.
      */
-    void criticalNotification(PortletRequest request, MimeResponse response,
-            String caption, String message, String details, String url)
-            throws IOException {
+    void criticalNotification(WrappedPortletRequest request,
+            WrappedPortletResponse response, String caption, String message,
+            String details, String url) throws IOException {
 
         // clients JS app is still running, but server application either
         // no longer exists or it might fail to perform reasonably.
@@ -1131,7 +1117,7 @@ public abstract class AbstractApplicationPortlet extends GenericPortlet
 
         // Set the response type
         response.setContentType("application/json; charset=UTF-8");
-        final OutputStream out = response.getPortletOutputStream();
+        final OutputStream out = response.getOutputStream();
         final PrintWriter outWriter = new PrintWriter(new BufferedWriter(
                 new OutputStreamWriter(out, "UTF-8")));
         outWriter.print("for(;;);[{\"changes\":[], \"meta\" : {"
index 3c8fc596d1f455018d2427b09dfe1b9b714b9ce8..f0b8c7e3b112cadcffc6ac777e8fc64baa8c9e16 100644 (file)
@@ -141,8 +141,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
         }
     };
 
-    static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/";
-
     /**
      * Called by the servlet container to indicate to a servlet that the servlet
      * is being placed into service.
@@ -556,8 +554,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
      * @throws IOException
      */
     private boolean ensureCookiesEnabled(RequestType requestType,
-            HttpServletRequest request, HttpServletResponse response)
-            throws IOException {
+            WrappedHttpServletRequest request,
+            WrappedHttpServletResponse response) throws IOException {
         if (requestType == RequestType.UIDL && !isRepaintAll(request)) {
             // In all other but the first UIDL request a cookie should be
             // returned by the browser.
@@ -622,11 +620,11 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
      * @throws IOException
      *             if the writing failed due to input/output error.
      */
-    protected void criticalNotification(HttpServletRequest request,
+    protected void criticalNotification(WrappedHttpServletRequest request,
             HttpServletResponse response, String caption, String message,
             String details, String url) throws IOException {
 
-        if (isUIDLRequest(request)) {
+        if (ServletPortletHelper.isUIDLRequest(request)) {
 
             if (caption != null) {
                 caption = "\"" + JsonPaintTarget.escapeJSON(caption) + "\"";
@@ -848,9 +846,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
         return newApplication;
     }
 
-    private void handleServiceException(HttpServletRequest request,
-            HttpServletResponse response, Application application, Throwable e)
-            throws IOException, ServletException {
+    private void handleServiceException(WrappedHttpServletRequest request,
+            WrappedHttpServletResponse response, Application application,
+            Throwable e) throws IOException, ServletException {
         // if this was an UIDL request, response UIDL back to client
         if (getRequestType(request) == RequestType.UIDL) {
             Application.SystemMessages ci = getSystemMessages();
@@ -903,8 +901,9 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
         return DEFAULT_THEME_NAME;
     }
 
-    void handleServiceSessionExpired(HttpServletRequest request,
-            HttpServletResponse response) throws IOException, ServletException {
+    void handleServiceSessionExpired(WrappedHttpServletRequest request,
+            WrappedHttpServletResponse response) throws IOException,
+            ServletException {
 
         if (isOnUnloadRequest(request)) {
             /*
@@ -944,8 +943,10 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
 
     }
 
-    private void handleServiceSecurityException(HttpServletRequest request,
-            HttpServletResponse response) throws IOException, ServletException {
+    private void handleServiceSecurityException(
+            WrappedHttpServletRequest request,
+            WrappedHttpServletResponse response) throws IOException,
+            ServletException {
         if (isOnUnloadRequest(request)) {
             /*
              * Request was an unload request (e.g. window close event) and the
@@ -1273,18 +1274,18 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
         FILE_UPLOAD, BROWSER_DETAILS, UIDL, OTHER, STATIC_FILE, APPLICATION_RESOURCE, CONNECTOR_RESOURCE;
     }
 
-    protected RequestType getRequestType(HttpServletRequest request) {
-        if (isFileUploadRequest(request)) {
+    protected RequestType getRequestType(WrappedHttpServletRequest request) {
+        if (ServletPortletHelper.isFileUploadRequest(request)) {
             return RequestType.FILE_UPLOAD;
-        } else if (isConnectorResourceRequest(request)) {
+        } else if (ServletPortletHelper.isConnectorResourceRequest(request)) {
             return RequestType.CONNECTOR_RESOURCE;
         } else if (isBrowserDetailsRequest(request)) {
             return RequestType.BROWSER_DETAILS;
-        } else if (isUIDLRequest(request)) {
+        } else if (ServletPortletHelper.isUIDLRequest(request)) {
             return RequestType.UIDL;
         } else if (isStaticResourceRequest(request)) {
             return RequestType.STATIC_FILE;
-        } else if (isApplicationRequest(request)) {
+        } else if (ServletPortletHelper.isApplicationResourceRequest(request)) {
             return RequestType.APPLICATION_RESOURCE;
         }
         return RequestType.OTHER;
@@ -1296,23 +1297,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
                 && request.getParameter("browserDetails") != null;
     }
 
-    private boolean isConnectorResourceRequest(HttpServletRequest request) {
-        String path = getRequestPathInfo(request);
-        if (path != null
-                && path.startsWith('/' + ApplicationConnection.CONNECTOR_RESOURCE_PREFIX + '/')) {
-            return true;
-        }
-        return false;
-    }
-
-    private boolean isApplicationRequest(HttpServletRequest request) {
-        String path = getRequestPathInfo(request);
-        if (path != null && path.startsWith("/APP/")) {
-            return true;
-        }
-        return false;
-    }
-
     private boolean isStaticResourceRequest(HttpServletRequest request) {
         String pathInfo = request.getPathInfo();
         if (pathInfo == null || pathInfo.length() <= 10) {
@@ -1330,37 +1314,6 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
         return false;
     }
 
-    private boolean isUIDLRequest(HttpServletRequest request) {
-        String pathInfo = getRequestPathInfo(request);
-
-        if (pathInfo == null) {
-            return false;
-        }
-
-        String compare = AJAX_UIDL_URI;
-
-        if (pathInfo.startsWith(compare + "/") || pathInfo.endsWith(compare)) {
-            return true;
-        }
-
-        return false;
-    }
-
-    private boolean isFileUploadRequest(HttpServletRequest request) {
-        String pathInfo = getRequestPathInfo(request);
-
-        if (pathInfo == null) {
-            return false;
-        }
-
-        if (pathInfo.startsWith("/" + UPLOAD_URL_PREFIX)) {
-            return true;
-        }
-
-        return false;
-
-    }
-
     private boolean isOnUnloadRequest(HttpServletRequest request) {
         return request.getParameter(ApplicationConnection.PARAM_UNLOADBURST) != null;
     }
index 76dab13502a46379696275cff0a59807e757d3cc..bf69d3bae09d36d8f54d550948068fcf6f32fe1d 100644 (file)
@@ -162,6 +162,10 @@ public abstract class AbstractCommunicationManager implements Serializable {
 
     private Map<String, Class<?>> connectorResourceContexts = new HashMap<String, Class<?>>();
 
+    private Map<String, Map<String, StreamVariable>> pidToNameToStreamVariable;
+
+    private Map<StreamVariable, String> streamVariableToSeckey;
+
     /**
      * TODO New constructor - document me!
      * 
@@ -634,6 +638,23 @@ public abstract class AbstractCommunicationManager implements Serializable {
         // Remove connectors that have been detached from the application during
         // handling of the request
         root.getConnectorTracker().cleanConnectorMap();
+
+        if (pidToNameToStreamVariable != null) {
+            Iterator<String> iterator = pidToNameToStreamVariable.keySet()
+                    .iterator();
+            while (iterator.hasNext()) {
+                String connectorId = iterator.next();
+                if (root.getConnectorTracker().getConnector(connectorId) == null) {
+                    // Owner is no longer attached to the application
+                    Map<String, StreamVariable> removed = pidToNameToStreamVariable
+                            .get(connectorId);
+                    for (String key : removed.keySet()) {
+                        streamVariableToSeckey.remove(removed.get(key));
+                    }
+                    iterator.remove();
+                }
+            }
+        }
     }
 
     protected void highlightConnector(Connector highlightedConnector) {
@@ -2281,11 +2302,57 @@ public abstract class AbstractCommunicationManager implements Serializable {
 
     }
 
-    abstract String getStreamVariableTargetUrl(ClientConnector owner,
-            String name, StreamVariable value);
+    public String getStreamVariableTargetUrl(ClientConnector owner,
+            String name, StreamVariable value) {
+        /*
+         * We will use the same APP/* URI space as ApplicationResources but
+         * prefix url with UPLOAD
+         * 
+         * eg. APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY]
+         * 
+         * SECKEY is created on each paint to make URL's unpredictable (to
+         * prevent CSRF attacks).
+         * 
+         * NAME and PID from URI forms a key to fetch StreamVariable when
+         * handling post
+         */
+        String paintableId = owner.getConnectorId();
+        int rootId = owner.getRoot().getRootId();
+        String key = rootId + "/" + paintableId + "/" + name;
 
-    abstract protected void cleanStreamVariable(ClientConnector owner,
-            String name);
+        if (pidToNameToStreamVariable == null) {
+            pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>();
+        }
+        Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable
+                .get(paintableId);
+        if (nameToStreamVariable == null) {
+            nameToStreamVariable = new HashMap<String, StreamVariable>();
+            pidToNameToStreamVariable.put(paintableId, nameToStreamVariable);
+        }
+        nameToStreamVariable.put(name, value);
+
+        if (streamVariableToSeckey == null) {
+            streamVariableToSeckey = new HashMap<StreamVariable, String>();
+        }
+        String seckey = streamVariableToSeckey.get(value);
+        if (seckey == null) {
+            seckey = UUID.randomUUID().toString();
+            streamVariableToSeckey.put(value, seckey);
+        }
+
+        return "app://" + ServletPortletHelper.UPLOAD_URL_PREFIX + key + "/"
+                + seckey;
+
+    }
+
+    public void cleanStreamVariable(ClientConnector owner, String name) {
+        Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable
+                .get(owner.getConnectorId());
+        nameToStreamVar.remove(name);
+        if (nameToStreamVar.isEmpty()) {
+            pidToNameToStreamVariable.remove(owner.getConnectorId());
+        }
+    }
 
     /**
      * Gets the bootstrap handler that should be used for generating the pages
@@ -2485,6 +2552,78 @@ public abstract class AbstractCommunicationManager implements Serializable {
         }
     }
 
+    /**
+     * Handles file upload request submitted via Upload component.
+     * 
+     * @param root
+     *            The root for this request
+     * 
+     * @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable)
+     * 
+     * @param request
+     * @param response
+     * @throws IOException
+     * @throws InvalidUIDLSecurityKeyException
+     */
+    public void handleFileUpload(Application application,
+            WrappedRequest request, WrappedResponse response)
+            throws IOException, InvalidUIDLSecurityKeyException {
+
+        /*
+         * URI pattern: APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY] See
+         * #createReceiverUrl
+         */
+
+        String pathInfo = request.getRequestPathInfo();
+        // strip away part until the data we are interested starts
+        int startOfData = pathInfo
+                .indexOf(ServletPortletHelper.UPLOAD_URL_PREFIX)
+                + ServletPortletHelper.UPLOAD_URL_PREFIX.length();
+        String uppUri = pathInfo.substring(startOfData);
+        String[] parts = uppUri.split("/", 4); // 0= rootid, 1 = cid, 2= name, 3
+                                               // = sec key
+        String rootId = parts[0];
+        String connectorId = parts[1];
+        String variableName = parts[2];
+        Root root = application.getRootById(Integer.parseInt(rootId));
+        Root.setCurrent(root);
+
+        StreamVariable streamVariable = getStreamVariable(connectorId,
+                variableName);
+        String secKey = streamVariableToSeckey.get(streamVariable);
+        if (secKey.equals(parts[3])) {
+
+            ClientConnector source = getConnector(root, connectorId);
+            String contentType = request.getContentType();
+            if (contentType.contains("boundary")) {
+                // Multipart requests contain boundary string
+                doHandleSimpleMultipartFileUpload(request, response,
+                        streamVariable, variableName, source,
+                        contentType.split("boundary=")[1]);
+            } else {
+                // if boundary string does not exist, the posted file is from
+                // XHR2.post(File)
+                doHandleXhrFilePost(request, response, streamVariable,
+                        variableName, source, request.getContentLength());
+            }
+        } else {
+            throw new InvalidUIDLSecurityKeyException(
+                    "Security key in upload post did not match!");
+        }
+
+    }
+
+    public StreamVariable getStreamVariable(String connectorId,
+            String variableName) {
+        Map<String, StreamVariable> map = pidToNameToStreamVariable
+                .get(connectorId);
+        if (map == null) {
+            return null;
+        }
+        StreamVariable streamVariable = map.get(variableName);
+        return streamVariable;
+    }
+
     /**
      * Stream that extracts content from another stream until the boundary
      * string is encountered.
index f083252897e43af025cb017e0b2018f329d42203..3cc3a8cb646392a6cb6f66f68e1ae57fc9557178 100644 (file)
@@ -4,22 +4,15 @@
 
 package com.vaadin.terminal.gwt.server;
 
-import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.UUID;
 
 import javax.servlet.ServletContext;
 
 import com.vaadin.Application;
 import com.vaadin.external.json.JSONException;
 import com.vaadin.terminal.PaintException;
-import com.vaadin.terminal.StreamVariable;
 import com.vaadin.terminal.WrappedRequest;
-import com.vaadin.terminal.WrappedResponse;
 import com.vaadin.ui.Root;
 
 /**
@@ -58,170 +51,6 @@ public class CommunicationManager extends AbstractCommunicationManager {
         super(application);
     }
 
-    /**
-     * Handles file upload request submitted via Upload component.
-     * 
-     * @param root
-     *            The root for this request
-     * 
-     * @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable)
-     * 
-     * @param request
-     * @param response
-     * @throws IOException
-     * @throws InvalidUIDLSecurityKeyException
-     */
-    public void handleFileUpload(Application application,
-            WrappedRequest request, WrappedResponse response)
-            throws IOException, InvalidUIDLSecurityKeyException {
-
-        /*
-         * URI pattern: APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY] See
-         * #createReceiverUrl
-         */
-
-        String pathInfo = request.getRequestPathInfo();
-        // strip away part until the data we are interested starts
-        int startOfData = pathInfo
-                .indexOf(AbstractApplicationServlet.UPLOAD_URL_PREFIX)
-                + AbstractApplicationServlet.UPLOAD_URL_PREFIX.length();
-        String uppUri = pathInfo.substring(startOfData);
-        String[] parts = uppUri.split("/", 4); // 0= rootid, 1 = cid, 2= name, 3
-                                               // = sec key
-        String rootId = parts[0];
-        String connectorId = parts[1];
-        String variableName = parts[2];
-        Root root = application.getRootById(Integer.parseInt(rootId));
-        Root.setCurrent(root);
-
-        StreamVariable streamVariable = getStreamVariable(connectorId,
-                variableName);
-        String secKey = streamVariableToSeckey.get(streamVariable);
-        if (secKey.equals(parts[3])) {
-
-            ClientConnector source = getConnector(root, connectorId);
-            String contentType = request.getContentType();
-            if (contentType.contains("boundary")) {
-                // Multipart requests contain boundary string
-                doHandleSimpleMultipartFileUpload(request, response,
-                        streamVariable, variableName, source,
-                        contentType.split("boundary=")[1]);
-            } else {
-                // if boundary string does not exist, the posted file is from
-                // XHR2.post(File)
-                doHandleXhrFilePost(request, response, streamVariable,
-                        variableName, source, request.getContentLength());
-            }
-        } else {
-            throw new InvalidUIDLSecurityKeyException(
-                    "Security key in upload post did not match!");
-        }
-
-    }
-
-    /**
-     * Gets a stream variable based on paintable id and variable name. Returns
-     * <code>null</code> if no matching variable has been registered.
-     * 
-     * @param paintableId
-     *            id of paintable to get variable for
-     * @param variableName
-     *            name of the stream variable
-     * @return the corresponding stream variable, or <code>null</code> if not
-     *         found
-     */
-    public StreamVariable getStreamVariable(String paintableId,
-            String variableName) {
-        Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable
-                .get(paintableId);
-        if (nameToStreamVariable == null) {
-            return null;
-        }
-        StreamVariable streamVariable = nameToStreamVariable.get(variableName);
-        return streamVariable;
-    }
-
-    @Override
-    protected void postPaint(Root root) {
-        super.postPaint(root);
-
-        if (pidToNameToStreamVariable != null) {
-            Iterator<String> iterator = pidToNameToStreamVariable.keySet()
-                    .iterator();
-            while (iterator.hasNext()) {
-                String connectorId = iterator.next();
-                if (root.getConnectorTracker().getConnector(connectorId) == null) {
-                    // Owner is no longer attached to the application
-                    Map<String, StreamVariable> removed = pidToNameToStreamVariable
-                            .get(connectorId);
-                    for (String key : removed.keySet()) {
-                        streamVariableToSeckey.remove(removed.get(key));
-                    }
-                    iterator.remove();
-                }
-            }
-        }
-
-    }
-
-    private Map<String, Map<String, StreamVariable>> pidToNameToStreamVariable;
-
-    private Map<StreamVariable, String> streamVariableToSeckey;
-
-    @Override
-    public String getStreamVariableTargetUrl(ClientConnector owner,
-            String name, StreamVariable value) {
-        /*
-         * We will use the same APP/* URI space as ApplicationResources but
-         * prefix url with UPLOAD
-         * 
-         * eg. APP/UPLOAD/[ROOTID]/[PID]/[NAME]/[SECKEY]
-         * 
-         * SECKEY is created on each paint to make URL's unpredictable (to
-         * prevent CSRF attacks).
-         * 
-         * NAME and PID from URI forms a key to fetch StreamVariable when
-         * handling post
-         */
-        String paintableId = owner.getConnectorId();
-        int rootId = owner.getRoot().getRootId();
-        String key = rootId + "/" + paintableId + "/" + name;
-
-        if (pidToNameToStreamVariable == null) {
-            pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>();
-        }
-        Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable
-                .get(paintableId);
-        if (nameToStreamVariable == null) {
-            nameToStreamVariable = new HashMap<String, StreamVariable>();
-            pidToNameToStreamVariable.put(paintableId, nameToStreamVariable);
-        }
-        nameToStreamVariable.put(name, value);
-
-        if (streamVariableToSeckey == null) {
-            streamVariableToSeckey = new HashMap<StreamVariable, String>();
-        }
-        String seckey = streamVariableToSeckey.get(value);
-        if (seckey == null) {
-            seckey = UUID.randomUUID().toString();
-            streamVariableToSeckey.put(value, seckey);
-        }
-
-        return "app://" + AbstractApplicationServlet.UPLOAD_URL_PREFIX + key
-                + "/" + seckey;
-
-    }
-
-    @Override
-    public void cleanStreamVariable(ClientConnector owner, String name) {
-        Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable
-                .get(owner.getConnectorId());
-        nameToStreamVar.remove(name);
-        if (nameToStreamVar.isEmpty()) {
-            pidToNameToStreamVariable.remove(owner.getConnectorId());
-        }
-    }
-
     @Override
     protected BootstrapHandler createBootstrapHandler() {
         return new BootstrapHandler() {
index a6032fa98dccd7a03fdd74215a335aee54da6467..cc12c9cc4327db706d500286ca3506c44e08c4b3 100644 (file)
@@ -121,8 +121,9 @@ public class GAEApplicationServlet extends ApplicationServlet {
     // appengine session expires-parameter
     private static final String PROPERTY_APPENGINE_EXPIRES = "_expires";
 
-    protected void sendDeadlineExceededNotification(HttpServletRequest request,
-            HttpServletResponse response) throws IOException {
+    protected void sendDeadlineExceededNotification(
+            WrappedHttpServletRequest request,
+            WrappedHttpServletResponse response) throws IOException {
         criticalNotification(
                 request,
                 response,
@@ -131,8 +132,9 @@ public class GAEApplicationServlet extends ApplicationServlet {
                 "", null);
     }
 
-    protected void sendNotSerializableNotification(HttpServletRequest request,
-            HttpServletResponse response) throws IOException {
+    protected void sendNotSerializableNotification(
+            WrappedHttpServletRequest request,
+            WrappedHttpServletResponse response) throws IOException {
         criticalNotification(
                 request,
                 response,
@@ -142,8 +144,9 @@ public class GAEApplicationServlet extends ApplicationServlet {
                         + "?restartApplication");
     }
 
-    protected void sendCriticalErrorNotification(HttpServletRequest request,
-            HttpServletResponse response) throws IOException {
+    protected void sendCriticalErrorNotification(
+            WrappedHttpServletRequest request,
+            WrappedHttpServletResponse response) throws IOException {
         criticalNotification(
                 request,
                 response,
@@ -154,8 +157,13 @@ public class GAEApplicationServlet extends ApplicationServlet {
     }
 
     @Override
-    protected void service(HttpServletRequest request,
-            HttpServletResponse response) throws ServletException, IOException {
+    protected void service(HttpServletRequest unwrappedRequest,
+            HttpServletResponse unwrappedResponse) throws ServletException,
+            IOException {
+        WrappedHttpServletRequest request = new WrappedHttpServletRequest(
+                unwrappedRequest, getDeploymentConfiguration());
+        WrappedHttpServletResponse response = new WrappedHttpServletResponse(
+                unwrappedResponse, getDeploymentConfiguration());
 
         if (isCleanupRequest(request)) {
             cleanDatastore();
index b888ad8e2d3f3190267658050c295db1e6eb14fd..0214cb2b3539d7ff534a038dbdce6c8dca52ea1c 100644 (file)
@@ -28,13 +28,11 @@ import javax.portlet.RenderRequest;
 import javax.portlet.RenderResponse;
 import javax.portlet.ResourceRequest;
 import javax.portlet.ResourceResponse;
-import javax.portlet.ResourceURL;
 import javax.portlet.StateAwareResponse;
 import javax.servlet.http.HttpSessionBindingListener;
 import javax.xml.namespace.QName;
 
 import com.vaadin.Application;
-import com.vaadin.terminal.ApplicationResource;
 import com.vaadin.ui.Root;
 
 /**
@@ -254,27 +252,6 @@ public class PortletApplicationContext2 extends AbstractWebApplicationContext {
         this.response = response;
     }
 
-    @Override
-    public String generateApplicationResourceURL(ApplicationResource resource,
-            String mapKey) {
-        if (response instanceof MimeResponse) {
-            ResourceURL resourceURL = ((MimeResponse) response)
-                    .createResourceURL();
-            final String filename = resource.getFilename();
-            if (filename == null) {
-                resourceURL.setResourceID("APP/" + mapKey + "/");
-            } else {
-                resourceURL.setResourceID("APP/" + mapKey + "/"
-                        + urlEncode(filename));
-            }
-            return resourceURL.toString();
-        } else {
-            // in a background thread or otherwise outside a request
-            // TODO exception ??
-            return null;
-        }
-    }
-
     /**
      * Creates a new action URL.
      * 
index d45e652110b928d2d61f20ef85e41160e41c2403..edd970a31ffb36d1f67bfc37e8bffc5cb0600415 100644 (file)
@@ -5,9 +5,6 @@ package com.vaadin.terminal.gwt.server;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
 
 import javax.portlet.MimeResponse;
 import javax.portlet.PortletContext;
@@ -22,10 +19,9 @@ import com.vaadin.external.json.JSONException;
 import com.vaadin.external.json.JSONObject;
 import com.vaadin.terminal.DeploymentConfiguration;
 import com.vaadin.terminal.PaintException;
-import com.vaadin.terminal.StreamVariable;
 import com.vaadin.terminal.WrappedRequest;
 import com.vaadin.terminal.WrappedResponse;
-import com.vaadin.terminal.gwt.client.Connector;
+import com.vaadin.terminal.gwt.client.ApplicationConfiguration;
 import com.vaadin.ui.Root;
 
 /**
@@ -37,140 +33,10 @@ import com.vaadin.ui.Root;
 @SuppressWarnings("serial")
 public class PortletCommunicationManager extends AbstractCommunicationManager {
 
-    private transient MimeResponse currentMimeResponse;
-
     public PortletCommunicationManager(Application application) {
         super(application);
     }
 
-    public void handleFileUpload(Application application,
-            WrappedRequest request, WrappedResponse response)
-            throws IOException {
-        String contentType = request.getContentType();
-        String name = request.getParameter("name");
-        String ownerId = request.getParameter("rec-owner");
-        String rootId = request.getParameter("rootId");
-
-        Root root = application.getRootById(Integer.parseInt(rootId));
-        Root.setCurrent(root);
-
-        ClientConnector owner = getConnector(root, ownerId);
-
-        StreamVariable streamVariable = ownerToNameToStreamVariable.get(owner)
-                .get(name);
-
-        if (contentType.contains("boundary")) {
-            doHandleSimpleMultipartFileUpload(request, response,
-                    streamVariable, name, owner,
-                    contentType.split("boundary=")[1]);
-        } else {
-            doHandleXhrFilePost(request, response, streamVariable, name, owner,
-                    request.getContentLength());
-        }
-
-    }
-
-    @Override
-    protected void postPaint(Root root) {
-        super.postPaint(root);
-
-        Application application = root.getApplication();
-        if (ownerToNameToStreamVariable != null) {
-            Iterator<Connector> iterator = ownerToNameToStreamVariable.keySet()
-                    .iterator();
-            while (iterator.hasNext()) {
-                Connector owner = iterator.next();
-                if (getConnector(root, owner.getConnectorId()) == null) {
-                    // Owner is no longer attached to the application
-                    iterator.remove();
-                }
-            }
-        }
-    }
-
-    @Override
-    protected boolean handleApplicationRequest(WrappedRequest request,
-            WrappedResponse response) throws IOException {
-        setCurrentMimeReponse(response);
-        try {
-            return super.handleApplicationRequest(request, response);
-        } finally {
-            currentMimeResponse = null;
-        }
-    }
-
-    private void setCurrentMimeReponse(WrappedResponse response) {
-        PortletResponse portletResponse = ((WrappedPortletResponse) response)
-                .getPortletResponse();
-        if (portletResponse instanceof MimeResponse) {
-            currentMimeResponse = (MimeResponse) portletResponse;
-        }
-
-    }
-
-    @Override
-    public void handleUidlRequest(WrappedRequest request,
-            WrappedResponse response, Callback callback, Root root)
-            throws IOException, InvalidUIDLSecurityKeyException, JSONException {
-        setCurrentMimeReponse(response);
-        super.handleUidlRequest(request, response, callback, root);
-        currentMimeResponse = null;
-    }
-
-    @Override
-    public void handleBrowserDetailsRequest(WrappedRequest request,
-            WrappedResponse response, Application application)
-            throws IOException {
-        setCurrentMimeReponse(response);
-        super.handleBrowserDetailsRequest(request, response, application);
-        currentMimeResponse = null;
-
-    }
-
-    private Map<Connector, Map<String, StreamVariable>> ownerToNameToStreamVariable;
-
-    @Override
-    String getStreamVariableTargetUrl(ClientConnector owner, String name,
-            StreamVariable value) {
-        if (ownerToNameToStreamVariable == null) {
-            ownerToNameToStreamVariable = new HashMap<Connector, Map<String, StreamVariable>>();
-        }
-        Map<String, StreamVariable> nameToReceiver = ownerToNameToStreamVariable
-                .get(owner);
-        if (nameToReceiver == null) {
-            nameToReceiver = new HashMap<String, StreamVariable>();
-            ownerToNameToStreamVariable.put(owner, nameToReceiver);
-        }
-        nameToReceiver.put(name, value);
-        ResourceURL resurl = createResourceURL();
-        resurl.setResourceID("UPLOAD");
-        resurl.setParameter("name", name);
-        resurl.setParameter("rec-owner", owner.getConnectorId());
-        resurl.setParameter("rootId", "" + owner.getRoot().getRootId());
-        resurl.setProperty("name", name);
-        resurl.setProperty("rec-owner", owner.getConnectorId());
-        resurl.setProperty("rootId", "" + owner.getRoot().getRootId());
-        return resurl.toString();
-    }
-
-    private ResourceURL createResourceURL() {
-        if (currentMimeResponse == null) {
-            throw new RuntimeException(
-                    "No reponse object available. Cannot create a resource URL");
-        }
-        return currentMimeResponse.createResourceURL();
-    }
-
-    @Override
-    protected void cleanStreamVariable(ClientConnector owner, String name) {
-        Map<String, StreamVariable> map = ownerToNameToStreamVariable
-                .get(owner);
-        map.remove(name);
-        if (map.isEmpty()) {
-            ownerToNameToStreamVariable.remove(owner);
-        }
-    }
-
     @Override
     protected BootstrapHandler createBootstrapHandler() {
         return new BootstrapHandler() {
@@ -220,12 +86,14 @@ public class PortletCommunicationManager extends AbstractCommunicationManager {
                  * some other things
                  */
                 JSONObject defaults = super.getDefaultParameters(context);
-                defaults.put("usePortletURLs", true);
 
-                ResourceURL uidlUrlBase = getRenderResponse(context)
+                ResourceURL portletResourceUrl = getRenderResponse(context)
                         .createResourceURL();
-                uidlUrlBase.setResourceID("UIDL");
-                defaults.put("portletUidlURLBase", uidlUrlBase.toString());
+                portletResourceUrl
+                        .setResourceID(AbstractApplicationPortlet.RESOURCE_URL_ID);
+                defaults.put(ApplicationConfiguration.PORTLET_RESOUCE_URL_BASE,
+                        portletResourceUrl.toString());
+
                 defaults.put("pathInfo", "");
 
                 return defaults;
index 9b1e60e6214d08fd825d6759b2f11bac20469978..55f27566047fe664340d66c12f292786529f896b 100644 (file)
@@ -3,6 +3,8 @@ package com.vaadin.terminal.gwt.server;
 import java.io.Serializable;
 
 import com.vaadin.Application;
+import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
 import com.vaadin.ui.Root;
 
 /*
@@ -10,6 +12,8 @@ import com.vaadin.ui.Root;
  */
 
 class ServletPortletHelper implements Serializable {
+    public static final String UPLOAD_URL_PREFIX = "APP/UPLOAD/";
+
     public static class ApplicationClassException extends Exception {
 
         public ApplicationClassException(String message, Throwable cause) {
@@ -70,4 +74,40 @@ class ServletPortletHelper implements Serializable {
                     + " doesn't have a public no-args constructor");
         }
     }
+
+    private static boolean hasPathPrefix(WrappedRequest request, String prefix) {
+        String pathInfo = request.getRequestPathInfo();
+
+        if (pathInfo == null) {
+            return false;
+        }
+
+        if (!prefix.startsWith("/")) {
+            prefix = '/' + prefix;
+        }
+
+        if (pathInfo.startsWith(prefix)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    public static boolean isFileUploadRequest(WrappedRequest request) {
+        return hasPathPrefix(request, UPLOAD_URL_PREFIX);
+    }
+
+    public static boolean isConnectorResourceRequest(WrappedRequest request) {
+        return hasPathPrefix(request,
+                ApplicationConnection.CONNECTOR_RESOURCE_PREFIX + "/");
+    }
+
+    public static boolean isUIDLRequest(WrappedRequest request) {
+        return hasPathPrefix(request, Constants.AJAX_UIDL_URI);
+    }
+
+    public static boolean isApplicationResourceRequest(WrappedRequest request) {
+        return hasPathPrefix(request, "APP/");
+    }
+
 }
index 44858b3e102b293a43b3379fc4974bbadca8dd9a..a3fa172034b97fe727300ba25d332bf90027edbc 100644 (file)
@@ -17,6 +17,7 @@ import com.vaadin.Application;
 import com.vaadin.terminal.CombinedRequest;
 import com.vaadin.terminal.DeploymentConfiguration;
 import com.vaadin.terminal.WrappedRequest;
+import com.vaadin.terminal.gwt.client.ApplicationConnection;
 
 /**
  * Wrapper for {@link PortletRequest} and its subclasses.
@@ -89,7 +90,14 @@ public class WrappedPortletRequest implements WrappedRequest {
     @Override
     public String getRequestPathInfo() {
         if (request instanceof ResourceRequest) {
-            return ((ResourceRequest) request).getResourceID();
+            ResourceRequest resourceRequest = (ResourceRequest) request;
+            String resourceID = resourceRequest.getResourceID();
+            if (AbstractApplicationPortlet.RESOURCE_URL_ID.equals(resourceID)) {
+                String resourcePath = resourceRequest
+                        .getParameter(ApplicationConnection.V_RESOURCE_PATH);
+                return resourcePath;
+            }
+            return resourceID;
         } else {
             return null;
         }