package com.googlecode.jsonrpc4j.server; import com.fasterxml.jackson.databind.JsonNode; import com.googlecode.jsonrpc4j.ErrorResolver; import com.googlecode.jsonrpc4j.JsonRpcServer; import com.googlecode.jsonrpc4j.util.Util; import org.easymock.EasyMock; import org.easymock.EasyMockRunner; import org.easymock.Mock; import org.easymock.MockType; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import javax.servlet.http.HttpServletResponse; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import static com.googlecode.jsonrpc4j.JsonRpcBasicServer.ACCEPT_ENCODING; import static com.googlecode.jsonrpc4j.JsonRpcBasicServer.CONTENT_ENCODING; import static com.googlecode.jsonrpc4j.JsonRpcBasicServer.ID; import static com.googlecode.jsonrpc4j.JsonRpcBasicServer.RESULT; import static com.googlecode.jsonrpc4j.util.Util.decodeAnswer; import static com.googlecode.jsonrpc4j.util.Util.error; import static com.googlecode.jsonrpc4j.util.Util.errorCode; import static com.googlecode.jsonrpc4j.util.Util.toByteArrayOutputStream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @RunWith(EasyMockRunner.class) public class JsonRpcServerTest { @Mock(type = MockType.NICE) private ServiceInterface mockService; private JsonRpcServer jsonRpcServer; @Before public void setup() { jsonRpcServer = new JsonRpcServer(Util.mapper, mockService, ServiceInterface.class); } @Test public void testGetMethod_badRequest_corruptParams() throws Exception { EasyMock.expect(mockService.testMethod("Whirinaki")).andReturn("Forest"); EasyMock.replay(mockService); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test-get"); MockHttpServletResponse response = new MockHttpServletResponse(); request.addParameter("id", Integer.toString(123)); request.addParameter("method", "testMethod"); request.addParameter("params", "{BROKEN}"); jsonRpcServer.handle(request, response); assertTrue(MockHttpServletResponse.SC_BAD_REQUEST == response.getStatus()); JsonNode errorNode = error(toByteArrayOutputStream(response.getContentAsByteArray())); assertNotNull(errorNode); assertEquals(errorCode(errorNode).asLong(), (long) ErrorResolver.JsonError.PARSE_ERROR.code); } @Test public void testGetMethod_badRequest_noMethod() throws Exception { EasyMock.expect(mockService.testMethod("Whirinaki")).andReturn("Forest"); EasyMock.replay(mockService); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test-get"); MockHttpServletResponse response = new MockHttpServletResponse(); request.addParameter("id", Integer.toString(123)); // no method! request.addParameter("params", net.iharder.Base64.encodeBytes("[\"Whirinaki\"]".getBytes(StandardCharsets.UTF_8))); jsonRpcServer.handle(request, response); assertTrue(MockHttpServletResponse.SC_NOT_FOUND == response.getStatus()); JsonNode errorNode = error(toByteArrayOutputStream(response.getContentAsByteArray())); assertNotNull(errorNode); assertEquals(errorCode(errorNode).asLong(), (long) ErrorResolver.JsonError.METHOD_NOT_FOUND.code); } @Test public void test_contentType() throws Exception { EasyMock.expect(mockService.testMethod("Whir?inaki")).andReturn("For?est"); EasyMock.replay(mockService); MockHttpServletRequest request = new MockHttpServletRequest("POST", "/test-post"); MockHttpServletResponse response = new MockHttpServletResponse(); request.setContentType("application/json"); request.setContent("{\"jsonrpc\":\"2.0\",\"id\":123,\"method\":\"testMethod\",\"params\":[\"Whir?inaki\"]}".getBytes(StandardCharsets.UTF_8)); jsonRpcServer.setContentType("flip/flop"); jsonRpcServer.handle(request, response); assertTrue("flip/flop".equals(response.getContentType())); checkSuccessfulResponse(response); } private void checkSuccessfulResponse(MockHttpServletResponse response) throws IOException { assertTrue(HttpServletResponse.SC_OK == response.getStatus()); JsonNode responseEnvelope = decodeAnswer(toByteArrayOutputStream(response.getContentAsByteArray())); assertTrue(responseEnvelope.get(ID).isIntegralNumber()); assertEquals(responseEnvelope.get(ID).asLong(), 123L); assertTrue(responseEnvelope.get(RESULT).isTextual()); assertEquals(responseEnvelope.get(RESULT).asText(), "For?est"); } @Test public void testGetMethod_base64Params() throws Exception { EasyMock.expect(mockService.testMethod("Whir?inaki")).andReturn("For?est"); EasyMock.replay(mockService); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test-get"); MockHttpServletResponse response = new MockHttpServletResponse(); request.addParameter("id", Integer.toString(123)); request.addParameter("method", "testMethod"); request.addParameter("params", net.iharder.Base64.encodeBytes("[\"Whir?inaki\"]".getBytes(StandardCharsets.UTF_8))); jsonRpcServer.handle(request, response); assertTrue("application/json-rpc".equals(response.getContentType())); checkSuccessfulResponse(response); } @Test public void testGetMethod_unencodedParams() throws Exception { EasyMock.expect(mockService.testMethod("Whir?inaki")).andReturn("For?est"); EasyMock.replay(mockService); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test-get"); MockHttpServletResponse response = new MockHttpServletResponse(); request.addParameter("id", Integer.toString(123)); request.addParameter("method", "testMethod"); request.addParameter("params", "[\"Whir?inaki\"]"); jsonRpcServer.handle(request, response); assertTrue("application/json-rpc".equals(response.getContentType())); checkSuccessfulResponse(response); } @Test public void testNullRequest() throws Exception { MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test-get"); MockHttpServletResponse response = new MockHttpServletResponse(); jsonRpcServer.handle(request, response); assertTrue(MockHttpServletResponse.SC_BAD_REQUEST == response.getStatus()); } @Test public void testGzipResponse() throws IOException { MockHttpServletRequest request = new MockHttpServletRequest("POST", "/test-post"); request.addHeader(ACCEPT_ENCODING, "gzip"); request.setContentType("application/json"); request.setContent("{\"jsonrpc\":\"2.0\",\"id\":123,\"method\":\"testMethod\",\"params\":[\"Whir?inaki\"]}".getBytes(StandardCharsets.UTF_8)); MockHttpServletResponse response = new MockHttpServletResponse(); jsonRpcServer = new JsonRpcServer(Util.mapper, mockService, ServiceInterface.class, true); jsonRpcServer.handle(request, response); byte[] compressed = response.getContentAsByteArray(); String sb = getCompressedResponseContent(compressed); Assert.assertEquals(sb, "{\"jsonrpc\":\"2.0\",\"id\":123,\"result\":null}"); Assert.assertEquals("gzip", response.getHeader(CONTENT_ENCODING)); } private String getCompressedResponseContent(byte[] compressed) throws IOException { GZIPInputStream gzipInputStream = new GZIPInputStream(new ByteArrayInputStream(compressed)); InputStreamReader inputStreamReader = new InputStreamReader(gzipInputStream, StandardCharsets.UTF_8); BufferedReader bufferedReader = new BufferedReader(inputStreamReader, 2048); StringBuilder sb = new StringBuilder(); String readed; while ((readed = bufferedReader.readLine()) != null) { sb.append(readed); } return sb.toString(); } @Test public void testGzipRequest() throws IOException { MockHttpServletRequest request = new MockHttpServletRequest("POST", "/test-post"); request.addHeader(CONTENT_ENCODING, "gzip"); request.setContentType("application/json"); byte[] bytes = "{\"jsonrpc\":\"2.0\",\"id\":123,\"method\":\"testMethod\",\"params\":[\"Whir?inaki\"]}".getBytes(StandardCharsets.UTF_8); ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gos = new GZIPOutputStream(baos); gos.write(bytes); gos.close(); request.setContent(baos.toByteArray()); MockHttpServletResponse response = new MockHttpServletResponse(); jsonRpcServer = new JsonRpcServer(Util.mapper, mockService, ServiceInterface.class, true); jsonRpcServer.handle(request, response); String responseContent = new String(response.getContentAsByteArray(), StandardCharsets.UTF_8); Assert.assertEquals(responseContent, "{\"jsonrpc\":\"2.0\",\"id\":123,\"result\":null}\n"); Assert.assertNull(response.getHeader(CONTENT_ENCODING)); } @Test public void testGzipRequestAndResponse() throws IOException { MockHttpServletRequest request = new MockHttpServletRequest("POST", "/test-post"); request.addHeader(CONTENT_ENCODING, "gzip"); request.addHeader(ACCEPT_ENCODING, "gzip"); request.setContentType("application/json"); byte[] bytes = "{\"jsonrpc\":\"2.0\",\"id\":123,\"method\":\"testMethod\",\"params\":[\"Whir?inaki\"]}".getBytes(StandardCharsets.UTF_8); ByteArrayOutputStream baos = new ByteArrayOutputStream(); GZIPOutputStream gos = new GZIPOutputStream(baos); gos.write(bytes); gos.close(); request.setContent(baos.toByteArray()); MockHttpServletResponse response = new MockHttpServletResponse(); jsonRpcServer = new JsonRpcServer(Util.mapper, mockService, ServiceInterface.class, true); jsonRpcServer.handle(request, response); byte[] compressed = response.getContentAsByteArray(); String sb = getCompressedResponseContent(compressed); Assert.assertEquals(sb, "{\"jsonrpc\":\"2.0\",\"id\":123,\"result\":null}"); Assert.assertEquals("gzip", response.getHeader(CONTENT_ENCODING)); } // Service and service interfaces used in test public interface ServiceInterface { String testMethod(String param1); } }