@Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { if (! canServeRequests.get()) { logger.info("Not processing request, service not ready yet"); resp.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } try { //TODO: refactor and clean up. we should use codecs to abstract the encoding/decoding so that // there is one handler class without a bunch of duplication String contentType = req.getHeader(CONTENT_TYPE); logger.debug("Request content-type: {}", contentType); if (isProtobuf(contentType)) { protobufHandler.doPost(req, resp); } else if (isJson(contentType)) { jsonRpcHandler.doPost(req, resp); } else { resp.setStatus(HttpServletResponse.SC_BAD_REQUEST); } } catch (Exception ex) { logger.error("Uncaught exception handling POST", ex); } }
Span span = null; long startTime = System.nanoTime(); Map<String, String> headers = gatherHttpHeaders(req); OrangeContext context = new OrangeContext(headers); try { rpcRequest = parseRpcRequest(postedContent); } catch (IllegalArgumentException iaex) { logger.warn("Error parsing request: " + postedContent, iaex); JsonObject jsonResponse = new JsonObject(); jsonResponse.add(ERROR_FIELD, callException.toJson()); writeResponse(resp, HttpServletResponse.SC_BAD_REQUEST, jsonResponse.toString()); incrementFailureCounter("unknown", context.getRpcOriginService(), context.getRpcOriginMethod()); return; span = getSpan(methodName, headers, context); methodTimer = getMethodTimer(methodName, context.getRpcOriginService(), context.getRpcOriginMethod()); startTime = methodTimer.start(); context.setCorrelationId(rpcRequest.getIdAsString()); JsonRpcResponse finalResponse = dispatchJsonRpcRequest(rpcRequest, context); writeResponse(resp, finalResponse.getStatusCode(), finalResponse.toJson().toString()); incrementSuccessCounter(methodName, context.getRpcOriginService(), context.getRpcOriginMethod());
@Test public void parseRpcRequest_NoMethodNameGiven_ThrowIllegalArgumentExecption() { // given final String json = "{\"service\":\"x\",\"params\":[{\"data\":\"\"}],\"id\":\"dead-beef\"}"; // when Throwable thrown = catchThrowable(() -> { servlet.parseRpcRequest(json); }); // then assertThat(thrown).isInstanceOf(IllegalArgumentException.class); assertThat(thrown).hasMessage("Missing method name"); }
@Test public void doPost_NotValidJson_ErrorMessageBadRequestWithHttpExposed() throws IOException { // given final String json = "xxxx"; HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(MockHttpServletResponse.class); BufferedReader readerFromRequest = new BufferedReader(new StringReader(json)); when(request.getReader()).thenReturn(readerFromRequest); CharArrayWriter charArryWriter = new CharArrayWriter(512); PrintWriter writer = new PrintWriter(charArryWriter); when(response.getWriter()).thenReturn(writer); doCallRealMethod().when(response).setStatus(anyInt()); doCallRealMethod().when(response).getStatus(); // when ServiceProperties props = new ServiceProperties(); props.addProperty(FeatureFlags.FLAG_EXPOSE_ERRORS_HTTP, "true"); servlet = new JsonHandler(handlerDictionary, metricRegistry, handlerMetrics, props, null); servlet.doPost(request, response); // then final String responseAsString = charArryWriter.toString(); LOGGER.debug(responseAsString); assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_BAD_REQUEST); }
@SuppressWarnings("unchecked") private JsonRpcResponse dispatchJsonRpcRequest(JsonRpcRequest rpcRequest, OrangeContext cxt) { JsonRpcResponse jsonResponse = new JsonRpcResponse(rpcRequest.getId(), JsonNull.INSTANCE, JsonNull.INSTANCE, HttpServletResponse.SC_OK); try { ServiceMethodHandler handler = handlers.getMethodHandler(rpcRequest.getMethod()); Message innerRequest = convertJsonToProtobuf(handler, rpcRequest); JsonElement idElement = rpcRequest.getId(); if (idElement == null) { jsonResponse.setId(new JsonPrimitive(-1)); } Message innerResponse = invokeHandlerChain(rpcRequest.getMethod(), handler, innerRequest, cxt); jsonResponse.setResult(ProtobufUtil.protobufToJson(innerResponse)); } catch (RpcCallException rpcEx) { logger.debug("Error processing request", rpcEx); jsonResponse.setError(rpcEx.toJson()); jsonResponse.setStatusCode(rpcEx.getCategory().getHttpStatus()); } catch (Exception ex) { logger.warn("Error processing request", ex); if (ex.getMessage() != null) { jsonResponse.setError(new JsonPrimitive(ex.getMessage())); } jsonResponse.setStatusCode(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } return jsonResponse; }
@Before public void setup() throws RpcCallException { handlerDictionary = new MethodHandlerDictionary(); handlerDictionary.put("a", null); ServiceMethodHandlerUnderTest mockHandlerThrowsRpcCallEx = new ServiceMethodHandlerUnderTest(); handlerDictionary.put("jsonRpcWithException", mockHandlerThrowsRpcCallEx); metricRegistry = mock(MetricRegistry.class); when(metricRegistry.counter(anyString())).thenReturn(mock(Counter.class)); when(metricRegistry.timer(anyString())).thenReturn(mock(Timer.class)); handlerMetrics = mock(RpcHandlerMetrics.class); when(handlerMetrics.getMethodTimer(any(), any(), any())).thenReturn(mock(GoTimer.class)); servlet = new JsonHandler(handlerDictionary, metricRegistry, handlerMetrics, new ServiceProperties(), null); }
@Test public void testParseRpcRequestNumericId() { String input = "{\"service\":\"x\",\"method\":\"a\",\"params\":[{\"data\":\"\"}],\"id\":123456789}"; JsonRpcRequest request = servlet.parseRpcRequest(input); JsonElement idElement = request.getId(); assertThat(idElement.toString()).isEqualTo("123456789"); }
@Test public void testRpcCallExceptionJsonRpcWithHttpExposed() throws IOException { String input = "{\"service\":\"x\",\"method\":\"jsonRpcWithException\",\"params\":[{}],\"id\":\"dead-beef\"}"; HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(MockHttpServletResponse.class); BufferedReader readerFromRequest = new BufferedReader(new StringReader(input)); when(request.getReader()).thenReturn(readerFromRequest); CharArrayWriter charArryWriter = new CharArrayWriter(512); PrintWriter writer = new PrintWriter(charArryWriter); when(response.getWriter()).thenReturn(writer); doCallRealMethod().when(response).setStatus(anyInt()); doCallRealMethod().when(response).getStatus(); ServiceProperties props = new ServiceProperties(); props.addProperty(FeatureFlags.FLAG_EXPOSE_ERRORS_HTTP, "true"); servlet = new JsonHandler(handlerDictionary, metricRegistry, handlerMetrics, props, null); servlet.doPost(request, response); String responseAsString = charArryWriter.toString(); LOGGER.debug(responseAsString); assertThat(responseAsString).contains("no p4s5!"); assertThat(responseAsString).matches(Pattern.compile(".*retriable.+true.*")); assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); }
@Test public void testParseRpcRequestStringNumericId() { String input = "{\"service\":\"x\",\"method\":\"a\",\"params\":[{\"data\":\"\"}],\"id\":\"234234\"}"; JsonRpcRequest request = servlet.parseRpcRequest(input); JsonElement idElement = request.getId(); assertThat(idElement.toString()).isEqualTo("\"234234\""); }
@Test public void testRpcCallExceptionJsonRpc() throws IOException { String input = "{\"service\":\"x\",\"method\":\"jsonRpcWithException\",\"params\":[{}],\"id\":\"dead-beef\"}"; HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(MockHttpServletResponse.class); BufferedReader readerFromRequest = new BufferedReader(new StringReader(input)); when(request.getReader()).thenReturn(readerFromRequest); CharArrayWriter charArryWriter = new CharArrayWriter(512); PrintWriter writer = new PrintWriter(charArryWriter); when(response.getWriter()).thenReturn(writer); doCallRealMethod().when(response).setStatus(anyInt()); doCallRealMethod().when(response).getStatus(); servlet.doPost(request, response); String responseAsString = charArryWriter.toString(); LOGGER.debug(responseAsString); assertThat(responseAsString).contains("no p4s5!"); assertThat(responseAsString).matches(Pattern.compile(".*retriable.+true.*")); assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); }
@Test public void testParseRpcRequestStringId() { String input = "{\"service\":\"x\",\"method\":\"a\",\"params\":[{\"data\":\"\"}],\"id\":\"dead-beef\"}"; JsonRpcRequest request = servlet.parseRpcRequest(input); JsonElement idElement = request.getId(); assertThat(idElement.toString()).isEqualTo("\"dead-beef\""); }
@Test public void doPost_NotValidJson_ErrorMessageBadRequest() throws IOException { // given final String json = "xxxx"; HttpServletRequest request = mock(HttpServletRequest.class); HttpServletResponse response = mock(MockHttpServletResponse.class); BufferedReader readerFromRequest = new BufferedReader(new StringReader(json)); when(request.getReader()).thenReturn(readerFromRequest); CharArrayWriter charArryWriter = new CharArrayWriter(512); PrintWriter writer = new PrintWriter(charArryWriter); when(response.getWriter()).thenReturn(writer); doCallRealMethod().when(response).setStatus(anyInt()); doCallRealMethod().when(response).getStatus(); // when servlet.doPost(request, response); // then final String responseAsString = charArryWriter.toString(); LOGGER.debug(responseAsString); assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); }
@Test public void parseRpcRequest_NotJson_ThrowIllegalArgumentException() { // given final String json = "xxxx"; // when Throwable thrown = catchThrowable(() -> { servlet.parseRpcRequest(json); }); LOGGER.debug(thrown.getMessage()); // then assertThat(thrown).isInstanceOf(IllegalArgumentException.class); assertThat(thrown).hasMessageContaining("Not a JSON"); }
private void processRequest(Socket socket) throws IOException { MockHttpServletRequest request = new MockHttpServletRequest(socket); MockHttpServletResponse response = new MockHttpServletResponse(socket); try { String contentType = request.getContentType(); if (isProtobuf(contentType)) { protobufHandler.doPost(request, response); } else { jsonRpcHandler.doPost(request, response); } response.complete(); } catch (SocketException sockEx) { logger.warn("Caught SocketException processing request"); } catch (Exception ex) { logger.error("Uncaught exception handling POST", ex); } }
@Test public void parseRpcRequest_NotValidJson_ThrowIllegalArgumentException() { // given final String json = "xxxx}"; // when Throwable thrown = catchThrowable(() -> { servlet.parseRpcRequest(json); }); LOGGER.debug(thrown.getMessage()); // then assertThat(thrown).isInstanceOf(IllegalArgumentException.class); assertThat(thrown).hasMessageContaining("Malformed"); }
@Test public void testParseRpcRequestNoId() { String input = "{\"service\":\"x\",\"method\":\"a\",\"params\":[{\"data\":\"\"}]}"; JsonRpcRequest request = servlet.parseRpcRequest(input); assertThat(request.getId()).isNull(); }
@Test public void testParseRpcRequestNullId() { String input = "{\"service\":\"x\",\"method\":\"a\",\"params\":[{\"data\":\"\"}],\"id\":null}"; JsonRpcRequest request = servlet.parseRpcRequest(input); assertThat(request.getId()).isInstanceOf(JsonNull.class); }