summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeif Åstrand <leif@vaadin.com>2012-07-26 15:03:28 +0300
committerLeif Åstrand <leif@vaadin.com>2012-07-26 16:29:13 +0300
commita1be41f0fcba31c20234b223e36678a8e9a30bf0 (patch)
treed86ecbe6ac594f6970056fb1e6526e7c23208c58
parente0ae6b9f65bd5fdc0432604f4376e99960b29ce9 (diff)
downloadvaadin-framework-a1be41f0fcba31c20234b223e36678a8e9a30bf0.tar.gz
vaadin-framework-a1be41f0fcba31c20234b223e36678a8e9a30bf0.zip
Refactor Portlet URL handling based on Servlet URLs (#9168)
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java17
-rw-r--r--src/com/vaadin/terminal/gwt/client/ApplicationConnection.java33
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java56
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java85
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java147
-rw-r--r--src/com/vaadin/terminal/gwt/server/CommunicationManager.java171
-rw-r--r--src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java24
-rw-r--r--src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java23
-rw-r--r--src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java146
-rw-r--r--src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java40
-rw-r--r--src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java10
11 files changed, 287 insertions, 465 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
index 877f2a70b8..71707e723a 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConfiguration.java
@@ -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() {
@@ -319,12 +320,6 @@ public class ApplicationConfiguration implements EntryPoint {
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;
communicationError = jsoConfiguration.getConfigError("comErrMsg");
diff --git a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
index 5db7221bdb..0647f2fe96 100644
--- a/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
+++ b/src/com/vaadin/terminal/gwt/client/ApplicationConnection.java
@@ -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
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
index 3fcd61036f..978738a1d8 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationPortlet.java
@@ -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\" : {"
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index 3c8fc596d1..f0b8c7e3b1 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -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;
}
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index 76dab13502..bf69d3bae0 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -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
@@ -2486,6 +2553,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.
*
diff --git a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
index f083252897..3cc3a8cb64 100644
--- a/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/CommunicationManager.java
@@ -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() {
diff --git a/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java
index a6032fa98d..cc12c9cc43 100644
--- a/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/GAEApplicationServlet.java
@@ -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();
diff --git a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
index b888ad8e2d..0214cb2b35 100644
--- a/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
+++ b/src/com/vaadin/terminal/gwt/server/PortletApplicationContext2.java
@@ -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.
*
diff --git a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
index d45e652110..edd970a31f 100644
--- a/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/PortletCommunicationManager.java
@@ -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;
diff --git a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
index 9b1e60e621..55f2756604 100644
--- a/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
+++ b/src/com/vaadin/terminal/gwt/server/ServletPortletHelper.java
@@ -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/");
+ }
+
}
diff --git a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
index 44858b3e10..a3fa172034 100644
--- a/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
+++ b/src/com/vaadin/terminal/gwt/server/WrappedPortletRequest.java
@@ -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;
}