diff --git a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/HTTPTransportUtils.java b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/HTTPTransportUtils.java index 86abb8c73f..bbd095abe8 100644 --- a/modules/transport/http/src/main/java/org/apache/axis2/transport/http/HTTPTransportUtils.java +++ b/modules/transport/http/src/main/java/org/apache/axis2/transport/http/HTTPTransportUtils.java @@ -372,6 +372,9 @@ public static boolean isRESTRequest(String contentType) { * This contains, * 1. application/json *
+ * Only the media type, the part before any parameters and the part the message + * builder is selected by, is compared, so "text/plain; x=application/json" is not + * a JSON request. * If the request does not contain a content type, this will return false. * * @param contentType content type to check @@ -381,7 +384,9 @@ public static boolean isJSONRequest(String contentType) { if (contentType == null || contentType.isEmpty()) { return false; } - return (contentType.toLowerCase().indexOf(HTTPConstants.MEDIA_TYPE_APPLICATION_JSON) != -1); + int index = contentType.indexOf(';'); + String mediaType = index >= 0 ? contentType.substring(0, index) : contentType; + return HTTPConstants.MEDIA_TYPE_APPLICATION_JSON.equalsIgnoreCase(mediaType); } public static EndpointReference[] getEPRsForService(ConfigurationContext configurationContext, diff --git a/modules/transport/http/src/test/java/org/apache/axis2/transport/http/AxisServletJSONOnlyTest.java b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/AxisServletJSONOnlyTest.java index e50da72fe8..f1b85deb06 100644 --- a/modules/transport/http/src/test/java/org/apache/axis2/transport/http/AxisServletJSONOnlyTest.java +++ b/modules/transport/http/src/test/java/org/apache/axis2/transport/http/AxisServletJSONOnlyTest.java @@ -177,6 +177,47 @@ public void testEnableJSONOnlyFalseAllowsNormalProcessing() throws Exception { } } + /** + * application/json in a parameter does not make a form-encoded POST a JSON request. + * The type is CORS-safelisted, so a cross-site page can send it without a preflight. + */ + public void testEnableJSONOnlyRejectsJSONInContentTypeParameter() throws Exception { + axisConfig.addParameter(new Parameter(Constants.Configuration.ENABLE_JSON_ONLY, "true")); + axisConfig.addMessageBuilder("application/x-www-form-urlencoded", + new org.apache.axis2.builder.XFormURLEncodedBuilder()); + + final int[] invocations = new int[1]; + axisConfig.getService("TestService").getOperation(new QName("testOperation")) + .setMessageReceiver(new org.apache.axis2.engine.MessageReceiver() { + public void receive(MessageContext messageContext) { + invocations[0]++; + } + }); + + String uri = "/axis2/services/TestService/testOperation"; + when(mockRequest.getRequestURI()).thenReturn(uri); + when(mockRequest.getRequestURL()).thenReturn(new StringBuffer("http://localhost:8080" + uri)); + when(mockRequest.getMethod()).thenReturn("POST"); + when(mockRequest.getContentType()).thenReturn("application/x-www-form-urlencoded; x=application/json"); + when(mockRequest.getInputStream()).thenReturn(new MockServletInputStream("value=1")); + + when(mockServletContext.getAttribute(AxisServlet.CONFIGURATION_CONTEXT)).thenReturn(configContext); + servlet.init(mockServletConfig); + servlet.doPost(mockRequest, mockResponse); + + assertEquals("the operation must not be reached", 0, invocations[0]); + assertTrue("Should return JSON error message", + responseOutputStream.toString().contains("application/json is mandatory")); + } + + public void testIsJSONRequestComparesTheMediaType() { + assertTrue(HTTPTransportUtils.isJSONRequest("application/json")); + assertTrue(HTTPTransportUtils.isJSONRequest("application/json; charset=UTF-8")); + assertTrue(HTTPTransportUtils.isJSONRequest("Application/JSON")); + assertFalse(HTTPTransportUtils.isJSONRequest("text/plain; x=application/json")); + assertFalse(HTTPTransportUtils.isJSONRequest("application/json-patch+json")); + } + /** * Test that non-JSON requests are rejected when enableJSONOnly=true. */