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 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. * Copyright 2000-2016 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.LegacyCommunicationManager.InvalidUIDLSecurityKeyException;
  23. import com.vaadin.server.ServletPortletHelper;
  24. import com.vaadin.server.SessionExpiredHandler;
  25. import com.vaadin.server.SynchronizedRequestHandler;
  26. import com.vaadin.server.SystemMessages;
  27. import com.vaadin.server.VaadinRequest;
  28. import com.vaadin.server.VaadinResponse;
  29. import com.vaadin.server.VaadinService;
  30. import com.vaadin.server.VaadinSession;
  31. import com.vaadin.shared.JsonConstants;
  32. import com.vaadin.ui.UI;
  33. import elemental.json.JsonException;
  34. /**
  35. * Processes a UIDL request from the client.
  36. *
  37. * Uses {@link ServerRpcHandler} to execute client-to-server RPC invocations and
  38. * {@link UidlWriter} to write state changes and client RPC calls back to the
  39. * client.
  40. *
  41. * @author Vaadin Ltd
  42. * @since 7.1
  43. */
  44. public class UidlRequestHandler extends SynchronizedRequestHandler
  45. implements SessionExpiredHandler {
  46. public static final String UIDL_PATH = "UIDL/";
  47. private final ServerRpcHandler rpcHandler;
  48. public UidlRequestHandler() {
  49. rpcHandler = createRpcHandler();
  50. }
  51. /**
  52. * Creates the ServerRpcHandler to use
  53. *
  54. * @since 7.7
  55. * @return the ServerRpcHandler to use
  56. */
  57. protected ServerRpcHandler createRpcHandler() {
  58. return new ServerRpcHandler();
  59. }
  60. @Override
  61. protected boolean canHandleRequest(VaadinRequest request) {
  62. return ServletPortletHelper.isUIDLRequest(request);
  63. }
  64. @Override
  65. public boolean synchronizedHandleRequest(VaadinSession session,
  66. VaadinRequest request, VaadinResponse response) throws IOException {
  67. UI uI = session.getService().findUI(request);
  68. if (uI == null) {
  69. // This should not happen but it will if the UI has been closed. We
  70. // really don't want to see it in the server logs though
  71. UIInitHandler.commitJsonResponse(request, response,
  72. getUINotFoundErrorJSON(session.getService(), request));
  73. return true;
  74. }
  75. StringWriter stringWriter = new StringWriter();
  76. try {
  77. rpcHandler.handleRpc(uI, request.getReader(), request);
  78. writeUidl(request, response, uI, stringWriter);
  79. } catch (JsonException e) {
  80. getLogger().log(Level.SEVERE, "Error writing JSON to response", e);
  81. // Refresh on client side
  82. writeRefresh(request, response);
  83. return true;
  84. } catch (InvalidUIDLSecurityKeyException e) {
  85. getLogger().log(Level.WARNING,
  86. "Invalid security key received from {0}",
  87. request.getRemoteHost());
  88. // Refresh on client side
  89. writeRefresh(request, response);
  90. return true;
  91. } finally {
  92. stringWriter.close();
  93. }
  94. return UIInitHandler.commitJsonResponse(request, response,
  95. stringWriter.toString());
  96. }
  97. private void writeRefresh(VaadinRequest request, VaadinResponse response)
  98. throws IOException {
  99. String json = VaadinService.createCriticalNotificationJSON(null, null,
  100. null, null);
  101. UIInitHandler.commitJsonResponse(request, response, json);
  102. }
  103. private void writeUidl(VaadinRequest request, VaadinResponse response,
  104. UI ui, Writer writer) throws IOException {
  105. openJsonMessage(writer, response);
  106. new UidlWriter().write(ui, writer, false);
  107. closeJsonMessage(writer);
  108. }
  109. protected void closeJsonMessage(Writer outWriter) throws IOException {
  110. outWriter.write("}]");
  111. }
  112. /**
  113. * Writes the opening of JSON message to be sent to client.
  114. *
  115. * @param outWriter
  116. * @param response
  117. * @throws IOException
  118. */
  119. protected void openJsonMessage(Writer outWriter, VaadinResponse response)
  120. throws IOException {
  121. // some dirt to prevent cross site scripting
  122. outWriter.write("for(;;);[{");
  123. }
  124. private static final Logger getLogger() {
  125. return Logger.getLogger(UidlRequestHandler.class.getName());
  126. }
  127. /*
  128. * (non-Javadoc)
  129. *
  130. * @see
  131. * com.vaadin.server.SessionExpiredHandler#handleSessionExpired(com.vaadin
  132. * .server.VaadinRequest, com.vaadin.server.VaadinResponse)
  133. */
  134. @Override
  135. public boolean handleSessionExpired(VaadinRequest request,
  136. VaadinResponse response) throws IOException {
  137. if (!ServletPortletHelper.isUIDLRequest(request)) {
  138. return false;
  139. }
  140. VaadinService service = request.getService();
  141. SystemMessages systemMessages = service.getSystemMessages(
  142. ServletPortletHelper.findLocale(null, null, request), request);
  143. service.writeStringResponse(response, JsonConstants.JSON_CONTENT_TYPE,
  144. VaadinService.createCriticalNotificationJSON(
  145. systemMessages.getSessionExpiredCaption(),
  146. systemMessages.getSessionExpiredMessage(), null,
  147. systemMessages.getSessionExpiredURL()));
  148. return true;
  149. }
  150. /**
  151. * Returns the JSON which should be returned to the client when a request
  152. * for a non-existent UI arrives.
  153. *
  154. * @param service
  155. * The VaadinService
  156. * @param vaadinRequest
  157. * The request which triggered this, or null if not available
  158. * @since 7.1
  159. * @return A JSON string
  160. */
  161. static String getUINotFoundErrorJSON(VaadinService service,
  162. VaadinRequest vaadinRequest) {
  163. SystemMessages ci = service.getSystemMessages(vaadinRequest.getLocale(),
  164. vaadinRequest);
  165. // Session Expired is not really the correct message as the
  166. // session exists but the requested UI does not.
  167. // Using Communication Error for now.
  168. String json = VaadinService.createCriticalNotificationJSON(
  169. ci.getCommunicationErrorCaption(),
  170. ci.getCommunicationErrorMessage(), null,
  171. ci.getCommunicationErrorURL());
  172. return json;
  173. }
  174. }