123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- /*
- @VaadinApache2LicenseForJavaFiles@
- */
-
- 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.terminal.gwt.client.Connector;
- import com.vaadin.ui.Root;
-
- /**
- * Application manager processes changes and paints for single application
- * instance.
- *
- * This class handles applications running as servlets.
- *
- * @see AbstractCommunicationManager
- *
- * @author Vaadin Ltd.
- * @version
- * @VERSION@
- * @since 5.0
- */
- @SuppressWarnings("serial")
- public class CommunicationManager extends AbstractCommunicationManager {
-
- /**
- * @deprecated use {@link #CommunicationManager(Application)} instead
- * @param application
- * @param applicationServlet
- */
- @Deprecated
- public CommunicationManager(Application application,
- AbstractApplicationServlet applicationServlet) {
- super(application);
- }
-
- /**
- * TODO New constructor - document me!
- *
- * @param application
- */
- public CommunicationManager(Application application) {
- 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(Root root, WrappedRequest request,
- WrappedResponse response) throws IOException,
- InvalidUIDLSecurityKeyException {
-
- /*
- * URI pattern: APP/UPLOAD/[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("/", 3); // 0 = pid, 1= name, 2 = sec key
- String variableName = parts[1];
- String connectorId = parts[0];
-
- StreamVariable streamVariable = pidToNameToStreamVariable.get(
- connectorId).get(variableName);
- String secKey = streamVariableToSeckey.get(streamVariable);
- if (secKey.equals(parts[2])) {
-
- Connector 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!");
- }
-
- }
-
- @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
- String getStreamVariableTargetUrl(Connector owner, String name,
- StreamVariable value) {
- /*
- * We will use the same APP/* URI space as ApplicationResources but
- * prefix url with UPLOAD
- *
- * eg. APP/UPLOAD/[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();
- String key = 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
- protected void cleanStreamVariable(Connector 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() {
- @Override
- protected String getApplicationId(BootstrapContext context) {
- String appUrl = getAppUri(context);
-
- String appId = appUrl;
- if ("".equals(appUrl)) {
- appId = "ROOT";
- }
- appId = appId.replaceAll("[^a-zA-Z0-9]", "");
- // Add hashCode to the end, so that it is still (sort of)
- // predictable, but indicates that it should not be used in CSS
- // and
- // such:
- int hashCode = appId.hashCode();
- if (hashCode < 0) {
- hashCode = -hashCode;
- }
- appId = appId + "-" + hashCode;
- return appId;
- }
-
- @Override
- protected String getAppUri(BootstrapContext context) {
- /* Fetch relative url to application */
- // don't use server and port in uri. It may cause problems with
- // some
- // virtual server configurations which lose the server name
- Application application = context.getApplication();
- URL url = application.getURL();
- String appUrl = url.getPath();
- if (appUrl.endsWith("/")) {
- appUrl = appUrl.substring(0, appUrl.length() - 1);
- }
- return appUrl;
- }
-
- @Override
- public String getThemeName(BootstrapContext context) {
- String themeName = context.getRequest().getParameter(
- AbstractApplicationServlet.URL_PARAMETER_THEME);
- if (themeName == null) {
- themeName = super.getThemeName(context);
- }
- return themeName;
- }
-
- @Override
- protected String getInitialUIDL(WrappedRequest request, Root root)
- throws PaintException, JSONException {
- return CommunicationManager.this.getInitialUIDL(request, root);
- }
- };
- }
-
- @Override
- protected InputStream getThemeResourceAsStream(Root root, String themeName,
- String resource) {
- WebApplicationContext context = (WebApplicationContext) root
- .getApplication().getContext();
- ServletContext servletContext = context.getHttpSession()
- .getServletContext();
- return servletContext.getResourceAsStream("/"
- + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName
- + "/" + resource);
- }
- }
|