您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

CommunicationManager.java 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. /*
  2. @VaadinApache2LicenseForJavaFiles@
  3. */
  4. package com.vaadin.terminal.gwt.server;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.net.URL;
  8. import java.util.HashMap;
  9. import java.util.Iterator;
  10. import java.util.Map;
  11. import java.util.UUID;
  12. import javax.servlet.ServletContext;
  13. import com.vaadin.Application;
  14. import com.vaadin.external.json.JSONException;
  15. import com.vaadin.terminal.PaintException;
  16. import com.vaadin.terminal.StreamVariable;
  17. import com.vaadin.terminal.WrappedRequest;
  18. import com.vaadin.terminal.WrappedResponse;
  19. import com.vaadin.terminal.gwt.client.Connector;
  20. import com.vaadin.ui.Root;
  21. /**
  22. * Application manager processes changes and paints for single application
  23. * instance.
  24. *
  25. * This class handles applications running as servlets.
  26. *
  27. * @see AbstractCommunicationManager
  28. *
  29. * @author Vaadin Ltd.
  30. * @version
  31. * @VERSION@
  32. * @since 5.0
  33. */
  34. @SuppressWarnings("serial")
  35. public class CommunicationManager extends AbstractCommunicationManager {
  36. /**
  37. * @deprecated use {@link #CommunicationManager(Application)} instead
  38. * @param application
  39. * @param applicationServlet
  40. */
  41. @Deprecated
  42. public CommunicationManager(Application application,
  43. AbstractApplicationServlet applicationServlet) {
  44. super(application);
  45. }
  46. /**
  47. * TODO New constructor - document me!
  48. *
  49. * @param application
  50. */
  51. public CommunicationManager(Application application) {
  52. super(application);
  53. }
  54. /**
  55. * Handles file upload request submitted via Upload component.
  56. *
  57. * @param root
  58. * The root for this request
  59. *
  60. * @see #getStreamVariableTargetUrl(ReceiverOwner, String, StreamVariable)
  61. *
  62. * @param request
  63. * @param response
  64. * @throws IOException
  65. * @throws InvalidUIDLSecurityKeyException
  66. */
  67. public void handleFileUpload(Root root, WrappedRequest request,
  68. WrappedResponse response) throws IOException,
  69. InvalidUIDLSecurityKeyException {
  70. /*
  71. * URI pattern: APP/UPLOAD/[PID]/[NAME]/[SECKEY] See #createReceiverUrl
  72. */
  73. String pathInfo = request.getRequestPathInfo();
  74. // strip away part until the data we are interested starts
  75. int startOfData = pathInfo
  76. .indexOf(AbstractApplicationServlet.UPLOAD_URL_PREFIX)
  77. + AbstractApplicationServlet.UPLOAD_URL_PREFIX.length();
  78. String uppUri = pathInfo.substring(startOfData);
  79. String[] parts = uppUri.split("/", 3); // 0 = pid, 1= name, 2 = sec key
  80. String variableName = parts[1];
  81. String connectorId = parts[0];
  82. StreamVariable streamVariable = pidToNameToStreamVariable.get(
  83. connectorId).get(variableName);
  84. String secKey = streamVariableToSeckey.get(streamVariable);
  85. if (secKey.equals(parts[2])) {
  86. Connector source = getConnector(root, connectorId);
  87. String contentType = request.getContentType();
  88. if (contentType.contains("boundary")) {
  89. // Multipart requests contain boundary string
  90. doHandleSimpleMultipartFileUpload(request, response,
  91. streamVariable, variableName, source,
  92. contentType.split("boundary=")[1]);
  93. } else {
  94. // if boundary string does not exist, the posted file is from
  95. // XHR2.post(File)
  96. doHandleXhrFilePost(request, response, streamVariable,
  97. variableName, source, request.getContentLength());
  98. }
  99. } else {
  100. throw new InvalidUIDLSecurityKeyException(
  101. "Security key in upload post did not match!");
  102. }
  103. }
  104. @Override
  105. protected void postPaint(Root root) {
  106. super.postPaint(root);
  107. if (pidToNameToStreamVariable != null) {
  108. Iterator<String> iterator = pidToNameToStreamVariable.keySet()
  109. .iterator();
  110. while (iterator.hasNext()) {
  111. String connectorId = iterator.next();
  112. if (root.getConnectorTracker().getConnector(connectorId) == null) {
  113. // Owner is no longer attached to the application
  114. Map<String, StreamVariable> removed = pidToNameToStreamVariable
  115. .get(connectorId);
  116. for (String key : removed.keySet()) {
  117. streamVariableToSeckey.remove(removed.get(key));
  118. }
  119. iterator.remove();
  120. }
  121. }
  122. }
  123. }
  124. private Map<String, Map<String, StreamVariable>> pidToNameToStreamVariable;
  125. private Map<StreamVariable, String> streamVariableToSeckey;
  126. @Override
  127. String getStreamVariableTargetUrl(Connector owner, String name,
  128. StreamVariable value) {
  129. /*
  130. * We will use the same APP/* URI space as ApplicationResources but
  131. * prefix url with UPLOAD
  132. *
  133. * eg. APP/UPLOAD/[PID]/[NAME]/[SECKEY]
  134. *
  135. * SECKEY is created on each paint to make URL's unpredictable (to
  136. * prevent CSRF attacks).
  137. *
  138. * NAME and PID from URI forms a key to fetch StreamVariable when
  139. * handling post
  140. */
  141. String paintableId = owner.getConnectorId();
  142. String key = paintableId + "/" + name;
  143. if (pidToNameToStreamVariable == null) {
  144. pidToNameToStreamVariable = new HashMap<String, Map<String, StreamVariable>>();
  145. }
  146. Map<String, StreamVariable> nameToStreamVariable = pidToNameToStreamVariable
  147. .get(paintableId);
  148. if (nameToStreamVariable == null) {
  149. nameToStreamVariable = new HashMap<String, StreamVariable>();
  150. pidToNameToStreamVariable.put(paintableId, nameToStreamVariable);
  151. }
  152. nameToStreamVariable.put(name, value);
  153. if (streamVariableToSeckey == null) {
  154. streamVariableToSeckey = new HashMap<StreamVariable, String>();
  155. }
  156. String seckey = streamVariableToSeckey.get(value);
  157. if (seckey == null) {
  158. seckey = UUID.randomUUID().toString();
  159. streamVariableToSeckey.put(value, seckey);
  160. }
  161. return "app://" + AbstractApplicationServlet.UPLOAD_URL_PREFIX + key
  162. + "/" + seckey;
  163. }
  164. @Override
  165. protected void cleanStreamVariable(Connector owner, String name) {
  166. Map<String, StreamVariable> nameToStreamVar = pidToNameToStreamVariable
  167. .get(owner.getConnectorId());
  168. nameToStreamVar.remove("name");
  169. if (nameToStreamVar.isEmpty()) {
  170. pidToNameToStreamVariable.remove(owner.getConnectorId());
  171. }
  172. }
  173. @Override
  174. protected BootstrapHandler createBootstrapHandler() {
  175. return new BootstrapHandler() {
  176. @Override
  177. protected String getApplicationId(BootstrapContext context) {
  178. String appUrl = getAppUri(context);
  179. String appId = appUrl;
  180. if ("".equals(appUrl)) {
  181. appId = "ROOT";
  182. }
  183. appId = appId.replaceAll("[^a-zA-Z0-9]", "");
  184. // Add hashCode to the end, so that it is still (sort of)
  185. // predictable, but indicates that it should not be used in CSS
  186. // and
  187. // such:
  188. int hashCode = appId.hashCode();
  189. if (hashCode < 0) {
  190. hashCode = -hashCode;
  191. }
  192. appId = appId + "-" + hashCode;
  193. return appId;
  194. }
  195. @Override
  196. protected String getAppUri(BootstrapContext context) {
  197. /* Fetch relative url to application */
  198. // don't use server and port in uri. It may cause problems with
  199. // some
  200. // virtual server configurations which lose the server name
  201. Application application = context.getApplication();
  202. URL url = application.getURL();
  203. String appUrl = url.getPath();
  204. if (appUrl.endsWith("/")) {
  205. appUrl = appUrl.substring(0, appUrl.length() - 1);
  206. }
  207. return appUrl;
  208. }
  209. @Override
  210. public String getThemeName(BootstrapContext context) {
  211. String themeName = context.getRequest().getParameter(
  212. AbstractApplicationServlet.URL_PARAMETER_THEME);
  213. if (themeName == null) {
  214. themeName = super.getThemeName(context);
  215. }
  216. return themeName;
  217. }
  218. @Override
  219. protected String getInitialUIDL(WrappedRequest request, Root root)
  220. throws PaintException, JSONException {
  221. return CommunicationManager.this.getInitialUIDL(request, root);
  222. }
  223. };
  224. }
  225. @Override
  226. protected InputStream getThemeResourceAsStream(Root root, String themeName,
  227. String resource) {
  228. WebApplicationContext context = (WebApplicationContext) root
  229. .getApplication().getContext();
  230. ServletContext servletContext = context.getHttpSession()
  231. .getServletContext();
  232. return servletContext.getResourceAsStream("/"
  233. + AbstractApplicationServlet.THEME_DIRECTORY_PATH + themeName
  234. + "/" + resource);
  235. }
  236. }