You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@wink.apache.org by bl...@apache.org on 2009/10/04 21:46:08 UTC
svn commit: r821592 - in /incubator/wink/trunk:
wink-common/src/main/java/org/apache/wink/common/internal/http/
wink-common/src/main/java/org/apache/wink/common/internal/providers/header/
wink-common/src/main/java/org/apache/wink/common/internal/runtim...
Author: bluk
Date: Sun Oct 4 19:46:08 2009
New Revision: 821592
URL: http://svn.apache.org/viewvc?rev=821592&view=rev
Log:
Consider Accept-Charset header in selectVariant
See [WINK-209]
Added:
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/http/AcceptCharset.java (with props)
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/header/AcceptCharsetHeaderDelegate.java (with props)
Modified:
incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/runtime/RuntimeDelegateImpl.java
incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/RequestImpl.java
incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java
incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/RequestsTest.java
Added: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/http/AcceptCharset.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/http/AcceptCharset.java?rev=821592&view=auto
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/http/AcceptCharset.java (added)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/http/AcceptCharset.java Sun Oct 4 19:46:08 2009
@@ -0,0 +1,156 @@
+/*
+ * 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.common.internal.http;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import javax.ws.rs.ext.RuntimeDelegate;
+import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
+
+/**
+ * Represent HTTP Accept-Charset header.
+ * <p>
+ * This version of the API does not support construction.
+ *
+ * @see <a href='http://tools.ietf.org/html/rfc2616#section-14.4'>RFC 2616
+ * 14.4</a>
+ */
+public class AcceptCharset {
+
+ public static final class ValuedCharset implements Comparable<ValuedCharset> {
+ public final double qValue;
+ public final String charset;
+
+ public ValuedCharset(double qValue, String charset) {
+ this.qValue = qValue;
+ this.charset = charset;
+ }
+
+ public int compareTo(ValuedCharset other) {
+ return Double.compare(qValue, other.qValue);
+ }
+
+ public boolean isWildcard() {
+ return charset == null;
+ }
+ }
+
+ private static final HeaderDelegate<AcceptCharset> delegate =
+ RuntimeDelegate
+ .getInstance()
+ .createHeaderDelegate(AcceptCharset.class);
+
+ private final String acceptCharsetHeader;
+ private final boolean anyAllowed;
+ private final List<String> acceptable;
+ private final List<String> banned;
+ private final List<AcceptCharset.ValuedCharset> valuedCharsets;
+
+ public AcceptCharset(String acceptCharset,
+ List<String> acceptableCharsets,
+ List<String> bannedCharsets,
+ boolean anyCharsetAllowed,
+ List<AcceptCharset.ValuedCharset> valuedCharsets) {
+ this.acceptCharsetHeader = acceptCharset;
+ this.anyAllowed = anyCharsetAllowed;
+ this.banned = Collections.unmodifiableList(bannedCharsets);
+ boolean isISO8859Explicit = false;
+ for (ValuedCharset vCharset : valuedCharsets) {
+ if ("ISO-8859-1".equalsIgnoreCase(vCharset.charset)) {
+ isISO8859Explicit = true;
+ break;
+ }
+ }
+ if (!isISO8859Explicit && !anyAllowed) {
+ ArrayList<String> acceptableCharsetsTemp = new ArrayList<String>(acceptableCharsets);
+ acceptableCharsetsTemp.add("ISO-8859-1");
+ this.acceptable = Collections.unmodifiableList(acceptableCharsetsTemp);
+
+ ArrayList<AcceptCharset.ValuedCharset> valuedCharsetsTemp =
+ new ArrayList<ValuedCharset>(valuedCharsets);
+ valuedCharsetsTemp.add(new AcceptCharset.ValuedCharset(1.0d, "ISO-8859-1"));
+ this.valuedCharsets = Collections.unmodifiableList(valuedCharsetsTemp);
+ } else {
+ this.acceptable = Collections.unmodifiableList(acceptableCharsets);
+ this.valuedCharsets = Collections.unmodifiableList(valuedCharsets);
+ }
+ }
+
+ /**
+ * Provide a list of character sets which are acceptable for the client. If
+ * any charset is acceptable with some non-zero priority (see
+ * {@link #isAnyCharsetAllowed()}), only character sets more preferable than
+ * wildcard are listed.
+ *
+ * @return unmodifiable list, never <code>null</code>; the list is sorted
+ * starting with the most preferable charset
+ */
+ public List<String> getAcceptableCharsets() {
+ return acceptable;
+ }
+
+ /**
+ * Is any character set acceptable? Note that expressions are listed by
+ * {@link #getBannedCharsets()}. This means that the value contains wildcard
+ * (with non-zero priority) of the header is not present at all.
+ *
+ * @return <code>true</code> if any character set is acceptable
+ */
+ public boolean isAnyCharsetAllowed() {
+ return anyAllowed;
+ }
+
+ /**
+ * A list of non-acceptable (q-value 0) character sets, i.e. exception of
+ * {@link #isAnyCharsetAllowed()}.
+ *
+ * @return never <code>null</code>; always empty if wildcard is not included
+ */
+ public List<String> getBannedCharsets() {
+ return banned;
+ }
+
+ /**
+ * Creates a new instance of AcceptCharset by parsing the supplied string.
+ *
+ * @param value the Accept-Charset string
+ * @return the newly created AcceptCharset
+ * @throws IllegalArgumentException if the supplied string cannot be parsed
+ */
+ public static AcceptCharset valueOf(String value) throws IllegalArgumentException {
+ return delegate.fromString(value);
+ }
+
+ public String getAcceptCharsetHeader() {
+ return acceptCharsetHeader;
+ }
+
+ public List<AcceptCharset.ValuedCharset> getValuedCharsets() {
+ return valuedCharsets;
+ }
+
+ @Override
+ public String toString() {
+ return delegate.toString(this);
+ }
+
+}
Propchange: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/http/AcceptCharset.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/header/AcceptCharsetHeaderDelegate.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/header/AcceptCharsetHeaderDelegate.java?rev=821592&view=auto
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/header/AcceptCharsetHeaderDelegate.java (added)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/header/AcceptCharsetHeaderDelegate.java Sun Oct 4 19:46:08 2009
@@ -0,0 +1,102 @@
+/*
+ * 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.common.internal.providers.header;
+
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
+
+import org.apache.wink.common.internal.http.AcceptCharset;
+
+public class AcceptCharsetHeaderDelegate implements HeaderDelegate<AcceptCharset> {
+
+ public AcceptCharset fromString(String value) throws IllegalArgumentException {
+ List<String> acceptable = new LinkedList<String>();
+ List<String> banned = new LinkedList<String>();
+ boolean anyAllowed = (value == null);
+
+ // parse the Accept-Encoding header
+ List<AcceptCharset.ValuedCharset> vCharsets = parseAcceptCharset(value);
+
+ for (AcceptCharset.ValuedCharset qCharset : vCharsets) {
+ if (anyAllowed) {
+ if (qCharset.qValue == 0 && !qCharset.isWildcard()) {
+ banned.add(qCharset.charset);
+ }
+ } else {
+ if (qCharset.qValue == 0) {
+ break; // gone through all acceptable languages
+ }
+ if (qCharset.isWildcard()) {
+ anyAllowed = true;
+ } else {
+ acceptable.add(qCharset.charset);
+ }
+ }
+ }
+ return new AcceptCharset(value, acceptable, banned, anyAllowed, vCharsets);
+ }
+
+ private List<AcceptCharset.ValuedCharset> parseAcceptCharset(String acceptableCharsetValue) {
+ List<AcceptCharset.ValuedCharset> qCharsets = new LinkedList<AcceptCharset.ValuedCharset>();
+ if (acceptableCharsetValue == null) {
+ return qCharsets;
+ }
+
+ for (String charsetRange : acceptableCharsetValue.split(",")) {
+ int semicolonIndex = charsetRange.indexOf(';');
+ double qValue;
+ String charsetSpec;
+ if (semicolonIndex == -1) {
+ qValue = 1.0d;
+ charsetSpec = charsetRange;
+ } else {
+ charsetSpec = charsetRange.substring(0, semicolonIndex);
+ int equalsIndex = charsetRange.indexOf('=', semicolonIndex + 1);
+ String qString =
+ charsetRange.substring(equalsIndex != -1 ? equalsIndex + 1 : charsetRange
+ .length());
+ try {
+ qValue = Double.parseDouble(qString.trim());
+ } catch (NumberFormatException nfe) {
+ // silently ignore incorrect q-specification and assume 1
+ qValue = 1.0d;
+ }
+ }
+ charsetSpec = charsetSpec.trim();
+ if (charsetSpec.length() == 0) {
+ // ignore empty encoding specifications
+ continue;
+ } else if (charsetSpec.equals("*")) {
+ qCharsets.add(new AcceptCharset.ValuedCharset(qValue, null));
+ } else {
+ qCharsets.add(new AcceptCharset.ValuedCharset(qValue, charsetSpec));
+ }
+ }
+ Collections.sort(qCharsets, Collections.reverseOrder());
+ return qCharsets;
+ }
+
+ public String toString(AcceptCharset value) {
+ return value.getAcceptCharsetHeader();
+ }
+}
Propchange: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/providers/header/AcceptCharsetHeaderDelegate.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/runtime/RuntimeDelegateImpl.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/runtime/RuntimeDelegateImpl.java?rev=821592&r1=821591&r2=821592&view=diff
==============================================================================
--- incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/runtime/RuntimeDelegateImpl.java (original)
+++ incubator/wink/trunk/wink-common/src/main/java/org/apache/wink/common/internal/runtime/RuntimeDelegateImpl.java Sun Oct 4 19:46:08 2009
@@ -38,10 +38,12 @@
import org.apache.wink.common.internal.UriBuilderImpl;
import org.apache.wink.common.internal.VariantListBuilderImpl;
import org.apache.wink.common.internal.http.Accept;
+import org.apache.wink.common.internal.http.AcceptCharset;
import org.apache.wink.common.internal.http.AcceptEncoding;
import org.apache.wink.common.internal.http.AcceptLanguage;
import org.apache.wink.common.internal.http.ContentDispositionHeader;
import org.apache.wink.common.internal.http.EntityTagMatchHeader;
+import org.apache.wink.common.internal.providers.header.AcceptCharsetHeaderDelegate;
import org.apache.wink.common.internal.providers.header.AcceptEncodingHeaderDelegate;
import org.apache.wink.common.internal.providers.header.AcceptHeaderDelegate;
import org.apache.wink.common.internal.providers.header.AcceptLanguageHeaderDelegate;
@@ -68,6 +70,7 @@
headerDelegates.put(EntityTag.class, new EntityTagHeaderDelegate());
headerDelegates.put(EntityTagMatchHeader.class, new EntityTagMatchHeaderDelegate());
headerDelegates.put(Accept.class, new AcceptHeaderDelegate());
+ headerDelegates.put(AcceptCharset.class, new AcceptCharsetHeaderDelegate());
headerDelegates.put(AcceptLanguage.class, new AcceptLanguageHeaderDelegate());
headerDelegates.put(AcceptEncoding.class, new AcceptEncodingHeaderDelegate());
headerDelegates.put(ContentDispositionHeader.class, new ContentDispositionHeaderDelegate());
Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/RequestImpl.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/RequestImpl.java?rev=821592&r1=821591&r2=821592&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/RequestImpl.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/contexts/RequestImpl.java Sun Oct 4 19:46:08 2009
@@ -38,9 +38,11 @@
import javax.ws.rs.ext.RuntimeDelegate;
import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate;
+import org.apache.wink.common.internal.http.AcceptCharset;
import org.apache.wink.common.internal.http.AcceptEncoding;
import org.apache.wink.common.internal.http.AcceptLanguage;
import org.apache.wink.common.internal.http.EntityTagMatchHeader;
+import org.apache.wink.common.utils.ProviderUtils;
import org.apache.wink.server.handlers.MessageContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -282,6 +284,20 @@
encodings = AcceptEncoding.valueOf(acceptEncodings);
}
+ List<String> acceptableCharsets =
+ msgContext.getHttpHeaders().getRequestHeader(HttpHeaders.ACCEPT_CHARSET);
+ AcceptCharset charsets = null;
+ if (acceptableCharsets != null) {
+ StringBuilder acceptCharsetsTemp = new StringBuilder();
+ acceptCharsetsTemp.append(acceptableCharsets.get(0));
+ for (int c = 1; c < acceptableCharsets.size(); ++c) {
+ acceptCharsetsTemp.append(",");
+ acceptCharsetsTemp.append(acceptableCharsets.get(c));
+ }
+ String acceptCharsets = acceptCharsetsTemp.toString();
+ charsets = AcceptCharset.valueOf(acceptCharsets);
+ }
+
VariantQChecked bestVariant = null;
boolean isIdentityEncodingChecked = false;
@@ -325,7 +341,6 @@
logger.debug("Accept Media Type: {} is compatible with q-factor {}",
mt,
acceptQFactor);
- break;
}
}
if (!isCompatible || !isAcceptable) {
@@ -381,6 +396,52 @@
}
}
+ double acceptCharsetQFactor = -1.0d;
+ String vCharset = ProviderUtils.getCharsetOrNull(v.getMediaType());
+ boolean hasCharSet = true;
+
+ if (vCharset == null) {
+ hasCharSet = false;
+ } else if (vCharset != null && charsets != null) {
+ boolean isCompatible = false;
+ logger.debug("Checking variant charset: {}", vCharset);
+ if (charsets.getBannedCharsets().contains(vCharset)) {
+ logger.debug("Variant charset {} was in unacceptable charsets", vCharset);
+ continue;
+ }
+ for (AcceptCharset.ValuedCharset charset : charsets.getValuedCharsets()) {
+ logger
+ .debug("Checking against Accept-Charset charset {} with quality factor {}",
+ charset.charset,
+ charset.qValue);
+ if (charset.isWildcard() || vCharset.equalsIgnoreCase(charset.charset)) {
+ logger.debug("Charset is compatible with {}", charset.charset);
+ isCompatible = true;
+ acceptCharsetQFactor = charset.qValue;
+ break;
+ }
+ }
+
+ if (!isCompatible) {
+ logger.debug("Variant charset is not compatible {}", vCharset);
+ /*
+ * do not remove this from the acceptable list even if not
+ * compatible but set to -1.0d for now. according to HTTP
+ * spec, it is "ok" to send
+ */
+ }
+ }
+
+ if (bestVariant != null) {
+ if (acceptCharsetQFactor < bestVariant.acceptCharsetQFactor && hasCharSet) {
+ logger
+ .debug("Best variant's charset {} q-factor {} is greater than current variant {} q-factor {}",
+ new Object[] {bestVariant.variant, bestVariant.acceptCharsetQFactor,
+ v, acceptCharsetQFactor});
+ continue;
+ }
+ }
+
double acceptEncodingQFactor = -1.0d;
String vEncoding = v.getEncoding();
if (vEncoding != null) {
@@ -441,8 +502,13 @@
}
}
- bestVariant =
- new VariantQChecked(v, acceptQFactor, acceptLanguageQFactor, acceptEncodingQFactor);
+ if (bestVariant == null || (acceptQFactor > bestVariant.acceptMediaTypeQFactor || acceptLanguageQFactor > bestVariant.acceptLanguageQFactor
+ || acceptEncodingQFactor > bestVariant.acceptEncodingQFactor
+ || (hasCharSet && acceptCharsetQFactor > bestVariant.acceptCharsetQFactor) || (hasCharSet && !bestVariant.hasCharset))) {
+ bestVariant =
+ new VariantQChecked(v, acceptQFactor, acceptLanguageQFactor,
+ acceptEncodingQFactor, acceptCharsetQFactor, hasCharSet);
+ }
}
if (bestVariant == null) {
@@ -469,6 +535,13 @@
varyHeaderValue.append(HttpHeaders.ACCEPT_ENCODING);
isValueWritten = true;
}
+ if (bestVariant.acceptCharsetQFactor > 0) {
+ if (isValueWritten) {
+ varyHeaderValue.append(", ");
+ }
+ varyHeaderValue.append(HttpHeaders.ACCEPT_CHARSET);
+ isValueWritten = true;
+ }
String varyHeaderValueStr = varyHeaderValue.toString().trim();
logger.debug("Vary Header value should be set to {}", varyHeaderValueStr);
msgContext.setAttribute(RequestImpl.VaryHeader.class, new VaryHeader(varyHeaderValueStr));
@@ -480,15 +553,21 @@
final double acceptMediaTypeQFactor;
final double acceptLanguageQFactor;
final double acceptEncodingQFactor;
+ final double acceptCharsetQFactor;
+ final boolean hasCharset;
public VariantQChecked(Variant v,
double acceptMediaType,
double acceptLanguage,
- double acceptEncoding) {
+ double acceptEncoding,
+ double acceptCharset,
+ boolean hasCharset) {
this.variant = v;
this.acceptMediaTypeQFactor = acceptMediaType;
this.acceptLanguageQFactor = acceptLanguage;
this.acceptEncodingQFactor = acceptEncoding;
+ this.acceptCharsetQFactor = acceptCharset;
+ this.hasCharset = hasCharset;
}
}
Modified: incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java?rev=821592&r1=821591&r2=821592&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java (original)
+++ incubator/wink/trunk/wink-server/src/main/java/org/apache/wink/server/internal/handlers/ServerMessageContext.java Sun Oct 4 19:46:08 2009
@@ -41,7 +41,6 @@
import org.apache.wink.common.internal.contexts.ProvidersImpl;
import org.apache.wink.common.internal.registry.ProvidersRegistry;
import org.apache.wink.common.internal.runtime.AbstractRuntimeContext;
-import org.apache.wink.common.internal.runtime.RuntimeContextTLS;
import org.apache.wink.server.handlers.MessageContext;
import org.apache.wink.server.internal.DeploymentConfiguration;
import org.apache.wink.server.internal.MediaTypeMapper;
Modified: incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/RequestsTest.java
URL: http://svn.apache.org/viewvc/incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/RequestsTest.java?rev=821592&r1=821591&r2=821592&view=diff
==============================================================================
--- incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/RequestsTest.java (original)
+++ incubator/wink/trunk/wink-server/src/test/java/org/apache/wink/server/internal/RequestsTest.java Sun Oct 4 19:46:08 2009
@@ -99,6 +99,21 @@
}
@GET
+ @Path("charset")
+ public Response getOnlyCharset(@Context Request request) {
+ List<Variant> responseVariants =
+ Variant.mediaTypes(MediaType.valueOf(MediaType.TEXT_PLAIN + ";charset=iso-8859-1"),
+ MediaType.valueOf(MediaType.TEXT_PLAIN + ";charset=UTF-8"),
+ MediaType.valueOf(MediaType.TEXT_PLAIN + ";charset=shift_jis"))
+ .add().build();
+ Variant bestResponseVariant = request.selectVariant(responseVariants);
+ if (bestResponseVariant != null) {
+ return Response.ok("Hello world!").variant(bestResponseVariant).build();
+ }
+ return Response.notAcceptable(responseVariants).build();
+ }
+
+ @GET
@Path("multipleheaders")
public Response getMultipleAcceptHeaders(@Context Request request) {
List<Variant> responseVariants =
@@ -114,6 +129,27 @@
}
return Response.notAcceptable(responseVariants).build();
}
+
+ @GET
+ @Path("moremultipleheaders")
+ public Response getMoreMultipleAcceptHeaders(@Context Request request) {
+ List<Variant> responseVariants =
+ Collections.unmodifiableList(Variant
+ .mediaTypes(MediaType.valueOf(MediaType.APPLICATION_JSON + ";charset=utf-8"),
+ MediaType.valueOf(MediaType.TEXT_PLAIN + ";charset=shift_jis"),
+ MediaType.valueOf(MediaType.APPLICATION_XML),
+ MediaType
+ .valueOf(MediaType.APPLICATION_JSON + ";charset=iso-8859-1"),
+ MediaType.valueOf(MediaType.TEXT_PLAIN + ";charset=iso-8859-1"))
+ .encodings("gzip", "identity", "deflate").languages(Locale.ENGLISH,
+ Locale.FRENCH,
+ Locale.US).add().build());
+ Variant bestResponseVariant = request.selectVariant(responseVariants);
+ if (bestResponseVariant != null) {
+ return Response.ok("Hello world!").variant(bestResponseVariant).build();
+ }
+ return Response.notAcceptable(responseVariants).build();
+ }
}
public void testSimpleMediaTypeSelect() throws Exception {
@@ -361,6 +397,78 @@
assertEquals(HttpHeaders.ACCEPT_ENCODING, response.getHeader(HttpHeaders.VARY));
}
+ public void testCharset() throws Exception {
+ // test that a null Accept-Charset means iso-8859-1 is automatically
+ // chosen
+ MockHttpServletRequest request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/charset",
+ MediaType.TEXT_PLAIN);
+ MockHttpServletResponse response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=iso-8859-1", response.getContentType());
+ assertEquals(HttpHeaders.ACCEPT, response.getHeader(HttpHeaders.VARY));
+
+ /*
+ * due to not mentioning of iso-8859-1 and no wildcard, iso-8859-1 is
+ * given a q-factor of 1.0 and since it is the first in the list of
+ * variants, should get chosen
+ */
+ request =
+ MockRequestConstructor.constructMockRequest("GET", "/root/charset", MediaType.WILDCARD);
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "shift_jis");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=iso-8859-1", response.getContentType());
+ assertEquals("Accept, Accept-Charset", response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET", "/root/charset", MediaType.WILDCARD);
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "shift_jis, *;q=0.5");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=shift_jis", response.getContentType());
+ assertEquals("Accept, Accept-Charset", response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET", "/root/charset", MediaType.WILDCARD);
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "SHIFT_jis, *;q=0.5");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=shift_jis", response.getContentType());
+ assertEquals("Accept, Accept-Charset", response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET", "/root/charset", MediaType.WILDCARD);
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "shift_jis, iso-8859-1;q=0.5");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=shift_jis", response.getContentType());
+ assertEquals("Accept, Accept-Charset", response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET", "/root/charset", MediaType.WILDCARD);
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "iso-8859-1");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=iso-8859-1", response.getContentType());
+ assertEquals("Accept, Accept-Charset", response.getHeader(HttpHeaders.VARY));
+
+ /*
+ * due to not mentioning of iso-8859-1 and no wildcard, iso-8859-1 is
+ * given a q-factor of 1.0
+ */
+ request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/charset",
+ MediaType.TEXT_PLAIN);
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "abcd");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=iso-8859-1", response.getContentType());
+ assertEquals("Accept, Accept-Charset", response.getHeader(HttpHeaders.VARY));
+ }
+
public void testSimpleMultipleAcceptHeaders() throws Exception {
MockHttpServletRequest request =
MockRequestConstructor.constructMockRequest("GET",
@@ -413,4 +521,114 @@
+ ", "
+ HttpHeaders.ACCEPT_ENCODING, response.getHeader(HttpHeaders.VARY));
}
+
+ public void testMoreSimpleMultipleAcceptHeaders() throws Exception {
+ MockHttpServletRequest request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/moremultipleheaders",
+ MediaType.TEXT_PLAIN + ";q=1.0,"
+ + MediaType.APPLICATION_XML
+ + ";q=0.8");
+ request.addHeader(HttpHeaders.ACCEPT_ENCODING, "gzip;q=0.8,deflate;q=0.7");
+ request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, "en-us");
+ MockHttpServletResponse response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=shift_jis", response.getContentType());
+ assertEquals("gzip", response.getHeader(HttpHeaders.CONTENT_ENCODING));
+ assertEquals("en_US", response.getHeader(HttpHeaders.CONTENT_LANGUAGE));
+ assertEquals(HttpHeaders.ACCEPT + ", "
+ + HttpHeaders.ACCEPT_LANGUAGE
+ + ", "
+ + HttpHeaders.ACCEPT_ENCODING, response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/moremultipleheaders",
+ MediaType.TEXT_PLAIN + ";q=0.9,"
+ + MediaType.APPLICATION_XML
+ + ";q=1.0");
+ request.addHeader(HttpHeaders.ACCEPT_ENCODING, "deflate;q=0.8,gzip;q=0.7");
+ request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, "en-us;q=0.9,fr;q=1.0");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.APPLICATION_XML, response.getContentType());
+ assertEquals("deflate", response.getHeader(HttpHeaders.CONTENT_ENCODING));
+ assertEquals("fr", response.getHeader(HttpHeaders.CONTENT_LANGUAGE));
+ assertEquals(HttpHeaders.ACCEPT + ", "
+ + HttpHeaders.ACCEPT_LANGUAGE
+ + ", "
+ + HttpHeaders.ACCEPT_ENCODING, response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/moremultipleheaders",
+ "text/*" + ";q=0.9,"
+ + MediaType.APPLICATION_XML
+ + ";q=1.0");
+ request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, "fr;q=1.0, en-us;q=0.9");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.APPLICATION_XML, response.getContentType());
+ assertEquals("fr", response.getHeader(HttpHeaders.CONTENT_LANGUAGE));
+ assertEquals(HttpHeaders.ACCEPT + ", "
+ + HttpHeaders.ACCEPT_LANGUAGE
+ + ", "
+ + HttpHeaders.ACCEPT_ENCODING, response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/moremultipleheaders",
+ "text/*" + ";q=0.9,"
+ + MediaType.APPLICATION_XML
+ + ";q=1.0");
+ request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, "fr;q=1.0, en-us;q=0.9");
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "shift_jis, *;q=0.8");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.APPLICATION_XML, response.getContentType());
+ assertEquals("fr", response.getHeader(HttpHeaders.CONTENT_LANGUAGE));
+ assertEquals(HttpHeaders.ACCEPT + ", "
+ + HttpHeaders.ACCEPT_LANGUAGE
+ + ", "
+ + HttpHeaders.ACCEPT_ENCODING, response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/moremultipleheaders",
+ "text/*" + ";q=0.9,"
+ + MediaType.APPLICATION_XML
+ + ";q=0.8");
+ request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, "fr;q=1.0, en-us;q=0.9");
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "shift_jis, *;q=0.8");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=shift_jis", response.getContentType());
+ assertEquals("fr", response.getHeader(HttpHeaders.CONTENT_LANGUAGE));
+ assertEquals(HttpHeaders.ACCEPT + ", "
+ + HttpHeaders.ACCEPT_LANGUAGE
+ + ", "
+ + HttpHeaders.ACCEPT_ENCODING
+ + ", "
+ + HttpHeaders.ACCEPT_CHARSET, response.getHeader(HttpHeaders.VARY));
+
+ request =
+ MockRequestConstructor.constructMockRequest("GET",
+ "/root/moremultipleheaders",
+ "text/*" + ";q=0.9,"
+ + MediaType.APPLICATION_XML
+ + ";q=0.8");
+ request.addHeader(HttpHeaders.ACCEPT_LANGUAGE, "fr;q=1.0, en-us;q=0.9");
+ request.addHeader(HttpHeaders.ACCEPT_CHARSET, "shift_jis;q=0.7");
+ response = invoke(request);
+ assertEquals(200, response.getStatus());
+ assertEquals(MediaType.TEXT_PLAIN + ";charset=iso-8859-1", response.getContentType());
+ assertEquals("fr", response.getHeader(HttpHeaders.CONTENT_LANGUAGE));
+ assertEquals(HttpHeaders.ACCEPT + ", "
+ + HttpHeaders.ACCEPT_LANGUAGE
+ + ", "
+ + HttpHeaders.ACCEPT_ENCODING
+ + ", "
+ + HttpHeaders.ACCEPT_CHARSET, response.getHeader(HttpHeaders.VARY));
+ }
+
}