You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UidlRequestHandler.java 7.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. /*
  2. * Copyright 2000-2014 Vaadin Ltd.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not
  5. * use this file except in compliance with the License. You may obtain a copy of
  6. * the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. * License for the specific language governing permissions and limitations under
  14. * the License.
  15. */
  16. package com.vaadin.server.communication;
  17. import java.io.IOException;
  18. import java.io.StringWriter;
  19. import java.io.Writer;
  20. import java.util.logging.Level;
  21. import java.util.logging.Logger;
  22. import com.vaadin.server.Constants;
  23. import com.vaadin.server.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
  24. import com.vaadin.server.ServletPortletHelper;
  25. import com.vaadin.server.SessionExpiredHandler;
  26. import com.vaadin.server.SynchronizedRequestHandler;
  27. import com.vaadin.server.SystemMessages;
  28. import com.vaadin.server.VaadinRequest;
  29. import com.vaadin.server.VaadinResponse;
  30. import com.vaadin.server.VaadinService;
  31. import com.vaadin.server.VaadinSession;
  32. import com.vaadin.shared.ApplicationConstants;
  33. import com.vaadin.shared.JsonConstants;
  34. import com.vaadin.shared.Version;
  35. import com.vaadin.ui.UI;
  36. import elemental.json.JsonException;
  37. /**
  38. * Processes a UIDL request from the client.
  39. *
  40. * Uses {@link ServerRpcHandler} to execute client-to-server RPC invocations and
  41. * {@link UidlWriter} to write state changes and client RPC calls back to the
  42. * client.
  43. *
  44. * @author Vaadin Ltd
  45. * @since 7.1
  46. */
  47. public class UidlRequestHandler extends SynchronizedRequestHandler implements
  48. SessionExpiredHandler {
  49. public static final String UIDL_PATH = "UIDL/";
  50. private ServerRpcHandler rpcHandler = new ServerRpcHandler();
  51. public UidlRequestHandler() {
  52. }
  53. @Override
  54. protected boolean canHandleRequest(VaadinRequest request) {
  55. return ServletPortletHelper.isUIDLRequest(request);
  56. }
  57. @Override
  58. public boolean synchronizedHandleRequest(VaadinSession session,
  59. VaadinRequest request, VaadinResponse response) throws IOException {
  60. UI uI = session.getService().findUI(request);
  61. if (uI == null) {
  62. // This should not happen but it will if the UI has been closed. We
  63. // really don't want to see it in the server logs though
  64. response.getWriter().write(
  65. getUINotFoundErrorJSON(session.getService(), request));
  66. return true;
  67. }
  68. checkWidgetsetVersion(request);
  69. // repaint requested or session has timed out and new one is created
  70. boolean repaintAll;
  71. // TODO PUSH repaintAll, analyzeLayouts should be
  72. // part of the message payload to make the functionality transport
  73. // agnostic
  74. repaintAll = (request
  75. .getParameter(ApplicationConstants.URL_PARAMETER_REPAINT_ALL) != null);
  76. StringWriter stringWriter = new StringWriter();
  77. try {
  78. rpcHandler.handleRpc(uI, request.getReader(), request);
  79. if (repaintAll) {
  80. session.getCommunicationManager().repaintAll(uI);
  81. }
  82. writeUidl(request, response, uI, stringWriter, repaintAll);
  83. } catch (JsonException e) {
  84. getLogger().log(Level.SEVERE, "Error writing JSON to response", e);
  85. // Refresh on client side
  86. response.getWriter().write(
  87. VaadinService.createCriticalNotificationJSON(null, null,
  88. null, null));
  89. return true;
  90. } catch (InvalidUIDLSecurityKeyException e) {
  91. getLogger().log(Level.WARNING,
  92. "Invalid security key received from {0}",
  93. request.getRemoteHost());
  94. // Refresh on client side
  95. response.getWriter().write(
  96. VaadinService.createCriticalNotificationJSON(null, null,
  97. null, null));
  98. return true;
  99. } finally {
  100. stringWriter.close();
  101. }
  102. return UIInitHandler.commitJsonResponse(request, response,
  103. stringWriter.toString());
  104. }
  105. /**
  106. * Checks that the version reported by the client (widgetset) matches that
  107. * of the server.
  108. *
  109. * @param request
  110. */
  111. private void checkWidgetsetVersion(VaadinRequest request) {
  112. String widgetsetVersion = request.getParameter("v-wsver");
  113. if (widgetsetVersion == null) {
  114. // Only check when the widgetset version is reported. It is reported
  115. // in the first UIDL request (not the initial request as it is a
  116. // plain GET /)
  117. return;
  118. }
  119. if (!Version.getFullVersion().equals(widgetsetVersion)) {
  120. getLogger().warning(
  121. String.format(Constants.WIDGETSET_MISMATCH_INFO,
  122. Version.getFullVersion(), widgetsetVersion));
  123. }
  124. }
  125. private void writeUidl(VaadinRequest request, VaadinResponse response,
  126. UI ui, Writer writer, boolean repaintAll) throws IOException {
  127. openJsonMessage(writer, response);
  128. new UidlWriter().write(ui, writer, repaintAll, false);
  129. closeJsonMessage(writer);
  130. }
  131. protected void closeJsonMessage(Writer outWriter) throws IOException {
  132. outWriter.write("}]");
  133. }
  134. /**
  135. * Writes the opening of JSON message to be sent to client.
  136. *
  137. * @param outWriter
  138. * @param response
  139. * @throws IOException
  140. */
  141. protected void openJsonMessage(Writer outWriter, VaadinResponse response)
  142. throws IOException {
  143. // some dirt to prevent cross site scripting
  144. outWriter.write("for(;;);[{");
  145. }
  146. private static final Logger getLogger() {
  147. return Logger.getLogger(UidlRequestHandler.class.getName());
  148. }
  149. /*
  150. * (non-Javadoc)
  151. *
  152. * @see
  153. * com.vaadin.server.SessionExpiredHandler#handleSessionExpired(com.vaadin
  154. * .server.VaadinRequest, com.vaadin.server.VaadinResponse)
  155. */
  156. @Override
  157. public boolean handleSessionExpired(VaadinRequest request,
  158. VaadinResponse response) throws IOException {
  159. if (!ServletPortletHelper.isUIDLRequest(request)) {
  160. return false;
  161. }
  162. VaadinService service = request.getService();
  163. SystemMessages systemMessages = service.getSystemMessages(
  164. ServletPortletHelper.findLocale(null, null, request), request);
  165. service.writeStringResponse(response, JsonConstants.JSON_CONTENT_TYPE,
  166. VaadinService.createCriticalNotificationJSON(
  167. systemMessages.getSessionExpiredCaption(),
  168. systemMessages.getSessionExpiredMessage(), null,
  169. systemMessages.getSessionExpiredURL()));
  170. return true;
  171. }
  172. /**
  173. * Returns the JSON which should be returned to the client when a request
  174. * for a non-existent UI arrives.
  175. *
  176. * @param service
  177. * The VaadinService
  178. * @param vaadinRequest
  179. * The request which triggered this, or null if not available
  180. * @since 7.1
  181. * @return A JSON string
  182. */
  183. static String getUINotFoundErrorJSON(VaadinService service,
  184. VaadinRequest vaadinRequest) {
  185. SystemMessages ci = service.getSystemMessages(
  186. vaadinRequest.getLocale(), vaadinRequest);
  187. // Session Expired is not really the correct message as the
  188. // session exists but the requested UI does not.
  189. // Using Communication Error for now.
  190. String json = VaadinService.createCriticalNotificationJSON(
  191. ci.getCommunicationErrorCaption(),
  192. ci.getCommunicationErrorMessage(), null,
  193. ci.getCommunicationErrorURL());
  194. return json;
  195. }
  196. }