Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id B029A200B7A for ; Mon, 5 Sep 2016 12:02:16 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id AEB8E160ACC; Mon, 5 Sep 2016 10:02:16 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 7BF82160ABC for ; Mon, 5 Sep 2016 12:02:15 +0200 (CEST) Received: (qmail 58878 invoked by uid 500); 5 Sep 2016 10:02:14 -0000 Mailing-List: contact commits-help@struts.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@struts.apache.org Delivered-To: mailing list commits@struts.apache.org Received: (qmail 58869 invoked by uid 99); 5 Sep 2016 10:02:14 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 05 Sep 2016 10:02:14 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 84F21DFD9F; Mon, 5 Sep 2016 10:02:14 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: lukaszlenart@apache.org To: commits@struts.apache.org Message-Id: <544c21be37eb4c3e9ad06c4e42b62928@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: struts git commit: WW-4684 Uses Content-Type to perform action based on defined type Date: Mon, 5 Sep 2016 10:02:14 +0000 (UTC) archived-at: Mon, 05 Sep 2016 10:02:16 -0000 Repository: struts Updated Branches: refs/heads/master 7dbe3ea8b -> 547718fcc WW-4684 Uses Content-Type to perform action based on defined type Project: http://git-wip-us.apache.org/repos/asf/struts/repo Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/547718fc Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/547718fc Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/547718fc Branch: refs/heads/master Commit: 547718fcc6e1d694cfd6ef5a65a5c42edb49a3dc Parents: 7dbe3ea Author: Lukasz Lenart Authored: Mon Sep 5 12:02:00 2016 +0200 Committer: Lukasz Lenart Committed: Mon Sep 5 12:02:00 2016 +0200 ---------------------------------------------------------------------- .../apache/struts2/json/JSONInterceptor.java | 180 ++++++++++--------- .../struts2/json/JSONInterceptorTest.java | 28 +-- 2 files changed, 112 insertions(+), 96 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/struts/blob/547718fc/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java ---------------------------------------------------------------------- diff --git a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java index b4ad4b7..d7836eb 100644 --- a/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java +++ b/plugins/json/src/main/java/org/apache/struts2/json/JSONInterceptor.java @@ -70,20 +70,17 @@ public class JSONInterceptor extends AbstractInterceptor { private boolean noCache = false; private boolean excludeNullProperties; private String callbackParameter; - private String accept; + private String jsonContentType = "application/json"; + private String jsonRpcContentType = "application/json-rpc"; @SuppressWarnings("unchecked") public String intercept(ActionInvocation invocation) throws Exception { HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); - //parameter wasn't set by the interceptor - if (accept == null) { - accept = request.getHeader("accept"); - } - - String[] accepts = accept.split(","); - + String requestContentType = readContentType(request); + String requestContentTypeEncoding = readContentTypeEncoding(request); + Object rootObject = null; final ValueStack stack = invocation.getStack(); if (this.root != null) { @@ -94,103 +91,118 @@ public class JSONInterceptor extends AbstractInterceptor { } } - for (String accept : accepts) { - if ((accept != null) && accept.equalsIgnoreCase("application/json")) { - // load JSON object - Object obj = JSONUtil.deserialize(request.getReader()); + if (jsonContentType.equalsIgnoreCase(requestContentType)) { + // load JSON object + Object obj = JSONUtil.deserialize(request.getReader()); - // JSON array (this.root cannot be null in this case) - if(obj instanceof List && this.root != null) { - String mapKey = this.root; - rootObject = null; + // JSON array (this.root cannot be null in this case) + if(obj instanceof List && this.root != null) { + String mapKey = this.root; + rootObject = null; - if(this.root.indexOf('.') != -1) { - mapKey = this.root.substring(this.root.lastIndexOf('.') + 1); + if(this.root.indexOf('.') != -1) { + mapKey = this.root.substring(this.root.lastIndexOf('.') + 1); - rootObject = stack.findValue(this.root.substring(0, this.root.lastIndexOf('.'))); - if (rootObject == null) { - throw new RuntimeException("JSON array: Invalid root expression: '" + this.root + "'."); - } + rootObject = stack.findValue(this.root.substring(0, this.root.lastIndexOf('.'))); + if (rootObject == null) { + throw new RuntimeException("JSON array: Invalid root expression: '" + this.root + "'."); } - - // create a map with a list inside - Map m = new HashMap(); - m.put(mapKey, new ArrayList((List) obj)); - obj = m; } - if (obj instanceof Map) { - Map json = (Map) obj; + // create a map with a list inside + Map m = new HashMap(); + m.put(mapKey, new ArrayList((List) obj)); + obj = m; + } - // clean up the values - if (dataCleaner != null) - dataCleaner.clean("", json); + if (obj instanceof Map) { + Map json = (Map) obj; - if (rootObject == null) // model overrides action - rootObject = invocation.getStack().peek(); + // clean up the values + if (dataCleaner != null) + dataCleaner.clean("", json); - // populate fields - populator.populateObject(rootObject, json); - } else { - LOG.error("Unable to deserialize JSON object from request"); - throw new JSONException("Unable to deserialize JSON object from request"); - } - } else if ((accept != null) && accept.equalsIgnoreCase("application/json-rpc")) { - Object result; - if (this.enableSMD) { - // load JSON object - Object obj = JSONUtil.deserialize(request.getReader()); - - if (obj instanceof Map) { - Map smd = (Map) obj; - - if (rootObject == null) { // model makes no sense when using RPC - rootObject = invocation.getAction(); - } - - // invoke method - try { - result = this.invoke(rootObject, smd); - } catch (Exception e) { - RPCResponse rpcResponse = new RPCResponse(); - rpcResponse.setId(smd.get("id").toString()); - rpcResponse.setError(new RPCError(e, RPCErrorCode.EXCEPTION, getDebug())); - - result = rpcResponse; - } - } else { - String message = "SMD request was not in the right format. See http://json-rpc.org"; + if (rootObject == null) // model overrides action + rootObject = invocation.getStack().peek(); + + // populate fields + populator.populateObject(rootObject, json); + } else { + LOG.error("Unable to deserialize JSON object from request"); + throw new JSONException("Unable to deserialize JSON object from request"); + } + } else if (jsonRpcContentType.equalsIgnoreCase(requestContentType)) { + Object result; + if (this.enableSMD) { + // load JSON object + Object obj = JSONUtil.deserialize(request.getReader()); + if (obj instanceof Map) { + Map smd = (Map) obj; + + if (rootObject == null) { // model makes no sense when using RPC + rootObject = invocation.getAction(); + } + + // invoke method + try { + result = this.invoke(rootObject, smd); + } catch (Exception e) { RPCResponse rpcResponse = new RPCResponse(); - rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL)); + rpcResponse.setId(smd.get("id").toString()); + rpcResponse.setError(new RPCError(e, RPCErrorCode.EXCEPTION, getDebug())); + result = rpcResponse; } } else { - String message = "Request with content type of 'application/json-rpc' was received but SMD is " - + "not enabled for this interceptor. Set 'enableSMD' to true to enable it"; + String message = "SMD request was not in the right format. See http://json-rpc.org"; RPCResponse rpcResponse = new RPCResponse(); - rpcResponse.setError(new RPCError(message, RPCErrorCode.SMD_DISABLED)); + rpcResponse.setError(new RPCError(message, RPCErrorCode.INVALID_PROCEDURE_CALL)); result = rpcResponse; } + } else { + String message = "Request with content type of 'application/json-rpc' was received but SMD is " + + "not enabled for this interceptor. Set 'enableSMD' to true to enable it"; - String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(), - ignoreHierarchy, excludeNullProperties); - json = addCallbackIfApplicable(request, json); - boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request); - JSONUtil.writeJSONToResponse(new SerializationParams(response, this.defaultEncoding, - this.wrapWithComments, json, true, writeGzip, noCache, -1, -1, prefix, "application/json")); - - return Action.NONE; - } else { - LOG.debug("Accept header parameter must be 'application/json' or 'application/json-rpc'. Ignoring request with accept ", accept); - break; + RPCResponse rpcResponse = new RPCResponse(); + rpcResponse.setError(new RPCError(message, RPCErrorCode.SMD_DISABLED)); + result = rpcResponse; } + + String json = JSONUtil.serialize(result, excludeProperties, getIncludeProperties(), + ignoreHierarchy, excludeNullProperties); + json = addCallbackIfApplicable(request, json); + boolean writeGzip = enableGZIP && JSONUtil.isGzipInRequest(request); + JSONUtil.writeJSONToResponse(new SerializationParams(response, requestContentTypeEncoding, + this.wrapWithComments, json, true, writeGzip, noCache, -1, -1, prefix, "application/json")); + + return Action.NONE; + } else { + LOG.debug("Accept header parameter must be '{}' or '{}'. Ignoring request with Content Type '{}'", jsonContentType, jsonRpcContentType, requestContentType); } return invocation.invoke(); } + protected String readContentType(HttpServletRequest request) { + String contentType = request.getHeader("Content-Type"); + if (contentType != null && contentType.contains(";")) { + contentType = contentType.substring(0, contentType.indexOf(";")); + } + return contentType; + } + + protected String readContentTypeEncoding(HttpServletRequest request) { + String contentTypeEncoding = request.getHeader("Content-Type"); + if (contentTypeEncoding != null && contentTypeEncoding.contains(";encoding=")) { + contentTypeEncoding = contentTypeEncoding.substring(contentTypeEncoding.indexOf(";encoding=") + ";encoding=".length()); + } else { + contentTypeEncoding = defaultEncoding; + } + return contentTypeEncoding; + } + @SuppressWarnings("unchecked") public RPCResponse invoke(Object object, Map data) throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, JSONException, InstantiationException, @@ -539,7 +551,11 @@ public class JSONInterceptor extends AbstractInterceptor { this.prefix = prefix; } - public void setAccept(String accept) { - this.accept = accept; + public void setJsonContentType(String jsonContentType) { + this.jsonContentType = jsonContentType; + } + + public void setJsonRpcContentType(String jsonRpcContentType) { + this.jsonRpcContentType = jsonRpcContentType; } } http://git-wip-us.apache.org/repos/asf/struts/blob/547718fc/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java ---------------------------------------------------------------------- diff --git a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java index 85e64ec..ac4c39b 100644 --- a/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java +++ b/plugins/json/src/test/java/org/apache/struts2/json/JSONInterceptorTest.java @@ -71,7 +71,7 @@ public class JSONInterceptorTest extends StrutsTestCase { private void tryBadJSON(String fileName) throws Exception { // request setRequestContent(fileName); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json;encoding=UTF-8"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -92,7 +92,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDDisabledSMD() throws Exception { // request setRequestContent("smd-3.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); SMDActionTest1 action = new SMDActionTest1(); @@ -111,7 +111,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDAliasedMethodCall1() throws Exception { // request setRequestContent("smd-14.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -129,7 +129,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDAliasedMethodCall2() throws Exception { // request setRequestContent("smd-15.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -147,7 +147,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDNoMethod() throws Exception { // request setRequestContent("smd-4.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -171,7 +171,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDMethodWithoutAnnotations() throws Exception { // request setRequestContent("smd-9.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -192,7 +192,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDPrimitivesNoResult() throws Exception { // request setRequestContent("smd-6.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -227,7 +227,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDReturnObject() throws Exception { // request setRequestContent("smd-10.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -252,7 +252,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testSMDObjectsNoResult() throws Exception { // request setRequestContent("smd-7.txt"); - this.request.addHeader("accept", "application/json-rpc, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json-rpc"); JSONInterceptor interceptor = new JSONInterceptor(); interceptor.setEnableSMD(true); @@ -300,7 +300,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testReadEmpty() throws Exception { // request setRequestContent("json-6.txt"); - this.request.addHeader("accept", "application/json, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -315,7 +315,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void test() throws Exception { // request setRequestContent("json-1.txt"); - this.request.addHeader("accept", "application/json, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -437,7 +437,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testRoot() throws Exception { setRequestContent("json-5.txt"); - this.request.addHeader("accept", "application/json, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -462,7 +462,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testJSONArray() throws Exception { setRequestContent("json-12.txt"); - this.request.addHeader("accept", "application/json, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json"); // interceptor JSONInterceptor interceptor = new JSONInterceptor(); @@ -488,7 +488,7 @@ public class JSONInterceptorTest extends StrutsTestCase { public void testJSONArray2() throws Exception { setRequestContent("json-12.txt"); - this.request.addHeader("accept", "application/json, text/plain, */*"); + this.request.addHeader("Content-Type", "application/json"); // interceptor JSONInterceptor interceptor = new JSONInterceptor();