ServerRpcHandler implements Serializable { public void handleRpc(UI ui, Reader reader, VaadinRequest request) throws IOException, InvalidUIDLSecurityKeyException { ui.getSession().setLastRequestTimestamp(System.currentTimeMillis()); String changeMessage = getMessage(reader); if (changeMessage == null || changeMessage.equals("")) { return; } RpcRequest rpcRequest = new RpcRequest(changeMessage, request); if (!VaadinService.isCsrfTokenValid(ui, rpcRequest.getCsrfToken())) { throw new InvalidUIDLSecurityKeyException(); } String hashMessage = changeMessage; if (hashMessage.length() > 64 * 1024) { hashMessage = changeMessage.substring(0, 64 * 1024); } byte[] messageHash = MessageDigestUtil.sha256(hashMessage); int expectedId = ui.getInternals().getLastProcessedClientToServerId() + 1; int requestId = rpcRequest.getClientToServerId(); if (requestId != -1 && requestId != expectedId) { if (requestId == expectedId - 1 && Arrays.equals(messageHash, ui.getInternals().getLastProcessedMessageHash())) { getLogger().info( "Ignoring old duplicate message from the client. Expected: " + expectedId + ", got: " + requestId); } else { String messageStart = changeMessage; if (messageStart.length() > 1000) { messageStart = messageStart.substring(0, 1000); } throw new UnsupportedOperationException( "Unexpected message id from the client." + " Expected sync id: " + expectedId + ", got " + requestId + ". Message start: " + messageStart); } } else { ui.getInternals().setLastProcessedClientToServerId(expectedId, messageHash); handleInvocations(ui, rpcRequest.getRpcInvocationsData()); } if (rpcRequest.isResynchronize()) { getLogger().warn("Resynchronizing UI by client's request. Under " + "normal operations this should not happen and may " + "indicate a bug in Vaadin platform. If you see this " + "message regularly please open a bug report at " + "https: ui.getInternals().getStateTree().prepareForResync(); ui.getInternals().getDependencyList().clearPendingSendToClient(); throw new ResynchronizationRequiredException(); } }  void handleRpc(UI ui, Reader reader, VaadinRequest request);  }
@Test public void handleRpc_resynchronize_throwsExceptionAndDirtiesTreeAndClearsDependenciesSent() throws IOException, ServerRpcHandler.InvalidUIDLSecurityKeyException { StringReader reader = new StringReader("{\"csrfToken\": \"" + csrfToken + "\", \"rpc\":[], \"resynchronize\": true, \"clientId\":1}"); uiTree.collectChanges(c -> { }); thrown.expect( ServerRpcHandler.ResynchronizationRequiredException.class); serverRpcHandler.handleRpc(ui, reader, request); Assert.assertTrue(uiTree.hasDirtyNodes()); Mockito.verify(dependencyList).clearPendingSendToClient(); }
@Test public void handleRpc_duplicateMessage_doNotThrow() throws InvalidUIDLSecurityKeyException, IOException { String msg = "{\"" + ApplicationConstants.CLIENT_TO_SERVER_ID + "\":1}"; ServerRpcHandler handler = new ServerRpcHandler() { @Override protected String getMessage(Reader reader) throws IOException { return msg; }; }; ui = new UI(); ui.getInternals().setSession(session); ui.getInternals().setLastProcessedClientToServerId(1, MessageDigestUtil.sha256(msg)); handler.handleRpc(ui, Mockito.mock(Reader.class), request); }
@Test(expected = UnsupportedOperationException.class) public void handleRpc_unexpectedMessage_throw() throws InvalidUIDLSecurityKeyException, IOException { ServerRpcHandler handler = new ServerRpcHandler() { @Override protected String getMessage(Reader reader) throws IOException { return "{\"" + ApplicationConstants.CLIENT_TO_SERVER_ID + "\":1}"; }; }; ui = new UI(); ui.getInternals().setSession(session); handler.handleRpc(ui, Mockito.mock(Reader.class), request); }