From 70c7aadb977f3f98cec8761683b33eeca3adb9e2 Mon Sep 17 00:00:00 2001 From: Eric Dahl Date: Mon, 1 Sep 2014 17:36:25 -0700 Subject: [PATCH] Update Accept header content negotiation to not echo back the user's accept entry (including the quality flag) but instead use the actual content-type. --- .../PopulateResponseMediaTypeHandler.java | 10 +- .../PopulateResponseMediaTypeHandlerTest.java | 145 ++++++++++++++++++ 2 files changed, 147 insertions(+), 8 deletions(-) create mode 100644 wink-server/src/test/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandlerTest.java diff --git a/wink-server/src/main/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandler.java b/wink-server/src/main/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandler.java index 752d8b69..c5b02b46 100644 --- a/wink-server/src/main/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandler.java +++ b/wink-server/src/main/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandler.java @@ -132,18 +132,12 @@ public void handleResponse(MessageContext context) throws Throwable { logger.trace("Comparing {} to {}", acceptableMediaType, mediaType); //$NON-NLS-1$ } if (mediaType.isCompatible(acceptableMediaType)) { - MediaType candidateMediaType = null; - if (MediaTypeUtils.compareTo(mediaType, acceptableMediaType) > 0) { - candidateMediaType = mediaType; - } else { - candidateMediaType = acceptableMediaType; - } if (debug) { - logger.trace("MediaType compatible so using candidate type {}", candidateMediaType); //$NON-NLS-1$ + logger.trace("MediaType compatible so using candidate type {}", mediaType); //$NON-NLS-1$ } String q = acceptableMediaType.getParameters().get("q"); //$NON-NLS-1$ CandidateMediaType candidate = - new CandidateMediaType(candidateMediaType, q); + new CandidateMediaType(mediaType, q); if (Double.compare(candidate.q, 0.0) != 0) { if (debug) { logger.trace("Candidate {} has q value {} so adding to possible candidates", candidate.getMediaType(), q); //$NON-NLS-1$ diff --git a/wink-server/src/test/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandlerTest.java b/wink-server/src/test/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandlerTest.java new file mode 100644 index 00000000..273722b4 --- /dev/null +++ b/wink-server/src/test/java/org/apache/wink/server/internal/handlers/PopulateResponseMediaTypeHandlerTest.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.apache.wink.server.internal.handlers; + +import org.apache.wink.server.internal.servlet.MockServletInvocationTest; +import org.apache.wink.test.mock.MockRequestConstructor; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + +public class PopulateResponseMediaTypeHandlerTest extends MockServletInvocationTest { + + + @Path("/") + public static class MyResource { + + @GET + @Path("/hellotext") + @Produces(MediaType.TEXT_PLAIN) + public String getText() { + return "hello text"; + } + + @GET + @Path("/hello") + public String get() { + return "hello"; + } + } + + @Override + protected Class[] getClasses() { + return new Class[] {MyResource.class}; + } + + public void testAcceptableContentType() throws Exception { + MockHttpServletResponse response = invoke(MediaType.TEXT_PLAIN); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN, response.getContentType()); + } + + public void testNoAcceptableContentType() throws Exception { + MockHttpServletResponse response = invoke(MediaType.APPLICATION_JSON); + assertEquals(406, response.getStatus()); + } + + public void testFindBestContentType() throws Exception { + StringBuilder acceptHeader = new StringBuilder(); + acceptHeader.append(MediaType.APPLICATION_JSON).append(","); // 1.0 quality (implicit) + acceptHeader.append(MediaType.APPLICATION_XML).append(";q=0.8").append(","); + acceptHeader.append(MediaType.TEXT_PLAIN).append(";q=0.5"); + + MockHttpServletResponse response = invoke(acceptHeader.toString()); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN, response.getContentType()); + } + + public void testSkipGeneralContentType() throws Exception { + StringBuilder acceptHeader = new StringBuilder(); + acceptHeader.append(MediaType.WILDCARD).append(";q=0.1").append(","); + acceptHeader.append(MediaType.TEXT_PLAIN).append(";q=0.5"); + + MockHttpServletResponse response = invoke(acceptHeader.toString()); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN, response.getContentType()); + } + + public void testMultipleSameQuality() throws Exception { + StringBuilder acceptHeader = new StringBuilder(); + acceptHeader.append(MediaType.APPLICATION_JSON).append(";q=0.5").append(","); + acceptHeader.append(MediaType.TEXT_PLAIN).append(";q=0.5"); + + MockHttpServletResponse response = invoke(acceptHeader.toString()); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN, response.getContentType()); + } + + public void testMalformedAccept() throws Exception { + assertEquals(400, invoke("text\nplain").getStatus()); + assertEquals(400, invoke("sure").getStatus()); + assertEquals(400, invoke("text/plain,text/xml,text////").getStatus()); + assertEquals(400, invoke("text/plain,text/xml;q=yes").getStatus()); + assertEquals(400, invoke("text/plain,text/xml;q=Inf").getStatus()); +// assertEquals(400, invoke("text/plain,text/xml;q=NaN").getStatus()); // TODO investigate (returns 200) + assertEquals(400, invoke("text/plain,text/xml;q=33").getStatus()); + } + + public void testWildcardSubtype() throws Exception { + StringBuilder acceptHeader = new StringBuilder(); + acceptHeader.append("text/*").append(";q=0.5"); + + MockHttpServletResponse response = invoke(acceptHeader.toString()); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN, response.getContentType()); + } + + public void testSkipWildcardSubtype() throws Exception { + StringBuilder acceptHeader = new StringBuilder(); + acceptHeader.append("text/*").append(";q=0.3").append(","); + acceptHeader.append(MediaType.TEXT_HTML).append(";q=0.3").append(","); + acceptHeader.append(MediaType.TEXT_PLAIN).append(";q=0.1"); + + MockHttpServletResponse response = invoke(acceptHeader.toString()); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.TEXT_PLAIN, response.getContentType()); + } + + public void testNoProduces() throws Exception { + MockHttpServletResponse response = pathInvoke("/hello", MediaType.TEXT_PLAIN); + assertEquals(200, response.getStatus()); + assertEquals(MediaType.APPLICATION_OCTET_STREAM, response.getContentType()); + } + + private MockHttpServletResponse invoke(String acceptHeader) throws Exception { + MockHttpServletRequest mockRequest = + MockRequestConstructor.constructMockRequest("GET", "/hellotext", acceptHeader); + return invoke(mockRequest); + } + + private MockHttpServletResponse pathInvoke(String path, String acceptHeader) throws Exception { + MockHttpServletRequest mockRequest = + MockRequestConstructor.constructMockRequest("GET", path, acceptHeader); + return invoke(mockRequest); + } +}