[Refactor] XContentType to parse Accept or Content-Type headers (#3077)
Refactors XContentType.fromMediaTypeOrFormat to fromMediaType so Accept headers and Content-Type headers can be parsed separately. This helps in reusing the same parse logic in for REST Versioning API support. Signed-off-by: Nicholas Walter Knize <nknize@apache.org>
This commit is contained in:
parent
da8077de44
commit
d86c88fe59
|
@ -2073,7 +2073,7 @@ public class RestHighLevelClient implements Closeable {
|
|||
if (entity.getContentType() == null) {
|
||||
throw new IllegalStateException("OpenSearch didn't return the [Content-Type] header, unable to parse response body");
|
||||
}
|
||||
XContentType xContentType = XContentType.fromMediaTypeOrFormat(entity.getContentType().getValue());
|
||||
XContentType xContentType = XContentType.fromMediaType(entity.getContentType().getValue());
|
||||
if (xContentType == null) {
|
||||
throw new IllegalStateException("Unsupported Content-Type: " + entity.getContentType().getValue());
|
||||
}
|
||||
|
|
|
@ -806,7 +806,7 @@ public class RequestConvertersTests extends OpenSearchTestCase {
|
|||
|
||||
UpdateRequest parsedUpdateRequest = new UpdateRequest();
|
||||
|
||||
XContentType entityContentType = XContentType.fromMediaTypeOrFormat(entity.getContentType().getValue());
|
||||
XContentType entityContentType = XContentType.fromMediaType(entity.getContentType().getValue());
|
||||
try (XContentParser parser = createParser(entityContentType.xContent(), entity.getContent())) {
|
||||
parsedUpdateRequest.fromXContent(parser);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
package org.opensearch.common.xcontent;
|
||||
|
||||
/**
|
||||
* Abstracts a <a href="http://en.wikipedia.org/wiki/Internet_media_type">Media Type</a> and a format parameter.
|
||||
* Media types are used as values on Content-Type and Accept headers
|
||||
* format is an URL parameter, specifies response media type.
|
||||
*/
|
||||
public interface MediaType {
|
||||
/**
|
||||
* Returns a type part of a MediaType
|
||||
* i.e. application for application/json
|
||||
*/
|
||||
String type();
|
||||
|
||||
/**
|
||||
* Returns a subtype part of a MediaType.
|
||||
* i.e. json for application/json
|
||||
*/
|
||||
String subtype();
|
||||
|
||||
/**
|
||||
* Returns a corresponding format for a MediaType. i.e. json for application/json media type
|
||||
* Can differ from the MediaType's subtype i.e plain/text has a subtype of text but format is txt
|
||||
*/
|
||||
String format();
|
||||
|
||||
/**
|
||||
* returns a string representation of a media type.
|
||||
*/
|
||||
default String typeWithSubtype() {
|
||||
return type() + "/" + subtype();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
package org.opensearch.common.xcontent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
public class MediaTypeParser<T extends MediaType> {
|
||||
private final Map<String, T> formatToMediaType;
|
||||
private final Map<String, T> typeWithSubtypeToMediaType;
|
||||
|
||||
public MediaTypeParser(T[] acceptedMediaTypes) {
|
||||
this(acceptedMediaTypes, Map.of());
|
||||
}
|
||||
|
||||
public MediaTypeParser(T[] acceptedMediaTypes, Map<String, T> additionalMediaTypes) {
|
||||
final int size = acceptedMediaTypes.length + additionalMediaTypes.size();
|
||||
Map<String, T> formatMap = new HashMap<>(size);
|
||||
Map<String, T> typeMap = new HashMap<>(size);
|
||||
for (T mediaType : acceptedMediaTypes) {
|
||||
typeMap.put(mediaType.typeWithSubtype(), mediaType);
|
||||
formatMap.put(mediaType.format(), mediaType);
|
||||
}
|
||||
for (Map.Entry<String, T> entry : additionalMediaTypes.entrySet()) {
|
||||
String typeWithSubtype = entry.getKey();
|
||||
T mediaType = entry.getValue();
|
||||
|
||||
typeMap.put(typeWithSubtype.toLowerCase(Locale.ROOT), mediaType);
|
||||
formatMap.put(mediaType.format(), mediaType);
|
||||
}
|
||||
|
||||
this.formatToMediaType = Map.copyOf(formatMap);
|
||||
this.typeWithSubtypeToMediaType = Map.copyOf(typeMap);
|
||||
}
|
||||
|
||||
public T fromMediaType(String mediaType) {
|
||||
ParsedMediaType parsedMediaType = parseMediaType(mediaType);
|
||||
return parsedMediaType != null ? parsedMediaType.getMediaType() : null;
|
||||
}
|
||||
|
||||
public T fromFormat(String format) {
|
||||
if (format == null) {
|
||||
return null;
|
||||
}
|
||||
return formatToMediaType.get(format.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
/**
|
||||
* parsing media type that follows https://tools.ietf.org/html/rfc7231#section-3.1.1.1
|
||||
* @param headerValue a header value from Accept or Content-Type
|
||||
* @return a parsed media-type
|
||||
*/
|
||||
public ParsedMediaType parseMediaType(String headerValue) {
|
||||
if (headerValue != null) {
|
||||
String[] split = headerValue.toLowerCase(Locale.ROOT).split(";");
|
||||
|
||||
String[] typeSubtype = split[0].trim().split("/");
|
||||
if (typeSubtype.length == 2) {
|
||||
String type = typeSubtype[0];
|
||||
String subtype = typeSubtype[1];
|
||||
T xContentType = typeWithSubtypeToMediaType.get(type + "/" + subtype);
|
||||
if (xContentType != null) {
|
||||
Map<String, String> parameters = new HashMap<>();
|
||||
for (int i = 1; i < split.length; i++) {
|
||||
// spaces are allowed between parameters, but not between '=' sign
|
||||
String[] keyValueParam = split[i].trim().split("=");
|
||||
if (keyValueParam.length != 2 || hasSpaces(keyValueParam[0]) || hasSpaces(keyValueParam[1])) {
|
||||
return null;
|
||||
}
|
||||
parameters.put(keyValueParam[0], keyValueParam[1]);
|
||||
}
|
||||
return new ParsedMediaType(xContentType, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hasSpaces(String s) {
|
||||
return s.trim().equals(s) == false;
|
||||
}
|
||||
|
||||
/**
|
||||
* A media type object that contains all the information provided on a Content-Type or Accept header
|
||||
*/
|
||||
public class ParsedMediaType {
|
||||
private final Map<String, String> parameters;
|
||||
private final T mediaType;
|
||||
|
||||
public ParsedMediaType(T mediaType, Map<String, String> parameters) {
|
||||
this.parameters = parameters;
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
|
||||
public T getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public Map<String, String> getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -38,12 +38,12 @@ import org.opensearch.common.xcontent.smile.SmileXContent;
|
|||
import org.opensearch.common.xcontent.yaml.YamlXContent;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The content type of {@link org.opensearch.common.xcontent.XContent}.
|
||||
*/
|
||||
public enum XContentType {
|
||||
public enum XContentType implements MediaType {
|
||||
|
||||
/**
|
||||
* A JSON based content type.
|
||||
|
@ -60,7 +60,7 @@ public enum XContentType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String shortName() {
|
||||
public String subtype() {
|
||||
return "json";
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ public enum XContentType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String shortName() {
|
||||
public String subtype() {
|
||||
return "smile";
|
||||
}
|
||||
|
||||
|
@ -98,7 +98,7 @@ public enum XContentType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String shortName() {
|
||||
public String subtype() {
|
||||
return "yaml";
|
||||
}
|
||||
|
||||
|
@ -117,7 +117,7 @@ public enum XContentType {
|
|||
}
|
||||
|
||||
@Override
|
||||
public String shortName() {
|
||||
public String subtype() {
|
||||
return "cbor";
|
||||
}
|
||||
|
||||
|
@ -127,34 +127,42 @@ public enum XContentType {
|
|||
}
|
||||
};
|
||||
|
||||
/** a parser of media types */
|
||||
private static final MediaTypeParser<XContentType> MEDIA_TYPE_PARSER = new MediaTypeParser<>(
|
||||
XContentType.values(),
|
||||
Map.of("application/*", JSON, "application/x-ndjson", JSON)
|
||||
);
|
||||
|
||||
/** gets the {@link MediaTypeParser} singleton for use outside class */
|
||||
@SuppressWarnings("rawtypes")
|
||||
public static MediaTypeParser getMediaTypeParser() {
|
||||
return MEDIA_TYPE_PARSER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Accepts either a format string, which is equivalent to {@link XContentType#shortName()} or a media type that optionally has
|
||||
* parameters and attempts to match the value to an {@link XContentType}. The comparisons are done in lower case format and this method
|
||||
* also supports a wildcard accept for {@code application/*}. This method can be used to parse the {@code Accept} HTTP header or a
|
||||
* format query string parameter. This method will return {@code null} if no match is found
|
||||
* Accepts a format string, which is most of the time is equivalent to {@link XContentType#subtype()}
|
||||
* and attempts to match the value to an {@link XContentType}.
|
||||
* The comparisons are done in lower case format.
|
||||
* This method will return {@code null} if no match is found
|
||||
*/
|
||||
public static XContentType fromMediaTypeOrFormat(String mediaType) {
|
||||
if (mediaType == null) {
|
||||
return null;
|
||||
}
|
||||
public static XContentType fromFormat(String mediaType) {
|
||||
return MEDIA_TYPE_PARSER.fromFormat(mediaType);
|
||||
}
|
||||
|
||||
mediaType = removeVersionInMediaType(mediaType);
|
||||
for (XContentType type : values()) {
|
||||
if (isSameMediaTypeOrFormatAs(mediaType, type)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
final String lowercaseMediaType = mediaType.toLowerCase(Locale.ROOT);
|
||||
if (lowercaseMediaType.startsWith("application/*")) {
|
||||
return JSON;
|
||||
}
|
||||
|
||||
return null;
|
||||
/**
|
||||
* Attempts to match the given media type with the known {@link XContentType} values. This match is done in a case-insensitive manner.
|
||||
* The provided media type can optionally has parameters.
|
||||
* This method is suitable for parsing of the {@code Content-Type} and {@code Accept} HTTP headers.
|
||||
* This method will return {@code null} if no match is found
|
||||
*/
|
||||
public static XContentType fromMediaType(String mediaTypeHeaderValue) {
|
||||
mediaTypeHeaderValue = removeVersionInMediaType(mediaTypeHeaderValue);
|
||||
return MEDIA_TYPE_PARSER.fromMediaType(mediaTypeHeaderValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clients compatible with ES 7.x might start sending media types with versioned media type
|
||||
* in a form of application/vnd.opensearch+json;compatible-with=7.
|
||||
* in a form of application/vnd.elasticsearch+json;compatible-with=7.
|
||||
* This has to be removed in order to be used in 7.x server.
|
||||
* The same client connecting using that media type will be able to communicate with ES 8 thanks to compatible API.
|
||||
* @param mediaType - a media type used on Content-Type header, might contain versioned media type.
|
||||
|
@ -162,38 +170,12 @@ public enum XContentType {
|
|||
* @return a media type string without
|
||||
*/
|
||||
private static String removeVersionInMediaType(String mediaType) {
|
||||
if (mediaType.contains("vnd.opensearch")) {
|
||||
if (mediaType != null && (mediaType = mediaType.toLowerCase(Locale.ROOT)).contains("vnd.opensearch")) {
|
||||
return mediaType.replaceAll("vnd.opensearch\\+", "").replaceAll("\\s*;\\s*compatible-with=\\d+", "");
|
||||
}
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to match the given media type with the known {@link XContentType} values. This match is done in a case-insensitive manner.
|
||||
* The provided media type should not include any parameters. This method is suitable for parsing part of the {@code Content-Type}
|
||||
* HTTP header. This method will return {@code null} if no match is found
|
||||
*/
|
||||
public static XContentType fromMediaType(String mediaType) {
|
||||
final String lowercaseMediaType = Objects.requireNonNull(mediaType, "mediaType cannot be null").toLowerCase(Locale.ROOT);
|
||||
for (XContentType type : values()) {
|
||||
if (type.mediaTypeWithoutParameters().equals(lowercaseMediaType)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
// we also support newline delimited JSON: http://specs.okfnlabs.org/ndjson/
|
||||
if (lowercaseMediaType.toLowerCase(Locale.ROOT).equals("application/x-ndjson")) {
|
||||
return XContentType.JSON;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isSameMediaTypeOrFormatAs(String stringType, XContentType type) {
|
||||
return type.mediaTypeWithoutParameters().equalsIgnoreCase(stringType)
|
||||
|| stringType.toLowerCase(Locale.ROOT).startsWith(type.mediaTypeWithoutParameters().toLowerCase(Locale.ROOT) + ";")
|
||||
|| type.shortName().equalsIgnoreCase(stringType);
|
||||
}
|
||||
|
||||
private int index;
|
||||
|
||||
XContentType(int index) {
|
||||
|
@ -208,10 +190,17 @@ public enum XContentType {
|
|||
return mediaTypeWithoutParameters();
|
||||
}
|
||||
|
||||
public abstract String shortName();
|
||||
|
||||
public abstract XContent xContent();
|
||||
|
||||
public abstract String mediaTypeWithoutParameters();
|
||||
|
||||
@Override
|
||||
public String type() {
|
||||
return "application";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String format() {
|
||||
return subtype();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* The OpenSearch Contributors require contributions made to
|
||||
* this file be licensed under the Apache-2.0 license or a
|
||||
* compatible open source license.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Licensed to Elasticsearch under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modifications Copyright OpenSearch Contributors. See
|
||||
* GitHub history for details.
|
||||
*/
|
||||
|
||||
package org.opensearch.common.xcontent;
|
||||
|
||||
import org.opensearch.test.OpenSearchTestCase;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class MediaTypeParserTests extends OpenSearchTestCase {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
MediaTypeParser<XContentType> mediaTypeParser = XContentType.getMediaTypeParser();
|
||||
|
||||
public void testJsonWithParameters() throws Exception {
|
||||
String mediaType = "application/json";
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType).getParameters(), equalTo(Collections.emptyMap()));
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType + ";").getParameters(), equalTo(Collections.emptyMap()));
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType + "; charset=UTF-8").getParameters(), equalTo(Map.of("charset", "utf-8")));
|
||||
assertThat(
|
||||
mediaTypeParser.parseMediaType(mediaType + "; custom=123;charset=UTF-8").getParameters(),
|
||||
equalTo(Map.of("charset", "utf-8", "custom", "123"))
|
||||
);
|
||||
}
|
||||
|
||||
public void testWhiteSpaceInTypeSubtype() {
|
||||
String mediaType = " application/json ";
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType).getMediaType(), equalTo(XContentType.JSON));
|
||||
|
||||
assertThat(
|
||||
mediaTypeParser.parseMediaType(mediaType + "; custom=123; charset=UTF-8").getParameters(),
|
||||
equalTo(Map.of("charset", "utf-8", "custom", "123"))
|
||||
);
|
||||
assertThat(
|
||||
mediaTypeParser.parseMediaType(mediaType + "; custom=123;\n charset=UTF-8").getParameters(),
|
||||
equalTo(Map.of("charset", "utf-8", "custom", "123"))
|
||||
);
|
||||
|
||||
mediaType = " application / json ";
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType), is(nullValue()));
|
||||
}
|
||||
|
||||
public void testInvalidParameters() {
|
||||
String mediaType = "application/json";
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType + "; keyvalueNoEqualsSign"), is(nullValue()));
|
||||
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType + "; key = value"), is(nullValue()));
|
||||
assertThat(mediaTypeParser.parseMediaType(mediaType + "; key="), is(nullValue()));
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@ public abstract class AbstractRestChannel implements RestChannel {
|
|||
private final String filterPath;
|
||||
private final boolean pretty;
|
||||
private final boolean human;
|
||||
private final String acceptHeader;
|
||||
|
||||
private BytesStreamOutput bytesOut;
|
||||
|
||||
|
@ -71,7 +72,8 @@ public abstract class AbstractRestChannel implements RestChannel {
|
|||
protected AbstractRestChannel(RestRequest request, boolean detailedErrorsEnabled) {
|
||||
this.request = request;
|
||||
this.detailedErrorsEnabled = detailedErrorsEnabled;
|
||||
this.format = request.param("format", request.header("Accept"));
|
||||
this.format = request.param("format");
|
||||
this.acceptHeader = request.header("Accept");
|
||||
this.filterPath = request.param("filter_path", null);
|
||||
this.pretty = request.paramAsBoolean("pretty", false);
|
||||
this.human = request.paramAsBoolean("human", false);
|
||||
|
@ -112,7 +114,11 @@ public abstract class AbstractRestChannel implements RestChannel {
|
|||
boolean useFiltering
|
||||
) throws IOException {
|
||||
if (responseContentType == null) {
|
||||
responseContentType = XContentType.fromMediaTypeOrFormat(format);
|
||||
// TODO should format vs acceptHeader always be the same, do we allow overriding?
|
||||
responseContentType = XContentType.fromFormat(format);
|
||||
if (responseContentType == null) {
|
||||
responseContentType = XContentType.fromMediaType(acceptHeader);
|
||||
}
|
||||
}
|
||||
// try to determine the response content type from the media type or the format query string parameter, with the format parameter
|
||||
// taking precedence over the Accept header
|
||||
|
|
|
@ -64,13 +64,20 @@ public class RestTable {
|
|||
|
||||
public static RestResponse buildResponse(Table table, RestChannel channel) throws Exception {
|
||||
RestRequest request = channel.request();
|
||||
XContentType xContentType = XContentType.fromMediaTypeOrFormat(request.param("format", request.header("Accept")));
|
||||
XContentType xContentType = getXContentType(request);
|
||||
if (xContentType != null) {
|
||||
return buildXContentBuilder(table, channel);
|
||||
}
|
||||
return buildTextPlainResponse(table, channel);
|
||||
}
|
||||
|
||||
private static XContentType getXContentType(RestRequest request) {
|
||||
if (request.hasParam("format")) {
|
||||
return XContentType.fromFormat(request.param("format"));
|
||||
}
|
||||
return XContentType.fromMediaType(request.header("Accept"));
|
||||
}
|
||||
|
||||
public static RestResponse buildXContentBuilder(Table table, RestChannel channel) throws Exception {
|
||||
RestRequest request = channel.request();
|
||||
XContentBuilder builder = channel.newBuilder();
|
||||
|
|
|
@ -43,72 +43,80 @@ public class XContentTypeTests extends OpenSearchTestCase {
|
|||
public void testFromJson() throws Exception {
|
||||
String mediaType = "application/json";
|
||||
XContentType expectedXContentType = XContentType.JSON;
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + "; charset=UTF-8"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + "; charset=UTF-8"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromNdJson() throws Exception {
|
||||
String mediaType = "application/x-ndjson";
|
||||
XContentType expectedXContentType = XContentType.JSON;
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + "; charset=UTF-8"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromJsonUppercase() throws Exception {
|
||||
String mediaType = "application/json".toUpperCase(Locale.ROOT);
|
||||
XContentType expectedXContentType = XContentType.JSON;
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + "; charset=UTF-8"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + "; charset=UTF-8"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromYaml() throws Exception {
|
||||
String mediaType = "application/yaml";
|
||||
XContentType expectedXContentType = XContentType.YAML;
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + "; charset=UTF-8"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + "; charset=UTF-8"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromSmile() throws Exception {
|
||||
String mediaType = "application/smile";
|
||||
XContentType expectedXContentType = XContentType.SMILE;
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromCbor() throws Exception {
|
||||
String mediaType = "application/cbor";
|
||||
XContentType expectedXContentType = XContentType.CBOR;
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromWildcard() throws Exception {
|
||||
String mediaType = "application/*";
|
||||
XContentType expectedXContentType = XContentType.JSON;
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromWildcardUppercase() throws Exception {
|
||||
String mediaType = "APPLICATION/*";
|
||||
XContentType expectedXContentType = XContentType.JSON;
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(mediaType + ";"), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType), equalTo(expectedXContentType));
|
||||
assertThat(XContentType.fromMediaType(mediaType + ";"), equalTo(expectedXContentType));
|
||||
}
|
||||
|
||||
public void testFromRubbish() throws Exception {
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(null), nullValue());
|
||||
assertThat(XContentType.fromMediaTypeOrFormat(""), nullValue());
|
||||
assertThat(XContentType.fromMediaTypeOrFormat("text/plain"), nullValue());
|
||||
assertThat(XContentType.fromMediaTypeOrFormat("gobbly;goop"), nullValue());
|
||||
assertThat(XContentType.fromMediaType(null), nullValue());
|
||||
assertThat(XContentType.fromMediaType(""), nullValue());
|
||||
assertThat(XContentType.fromMediaType("text/plain"), nullValue());
|
||||
assertThat(XContentType.fromMediaType("gobbly;goop"), nullValue());
|
||||
}
|
||||
|
||||
public void testVersionedMediaType() throws Exception {
|
||||
assertThat(XContentType.fromMediaTypeOrFormat("application/vnd.opensearch+json;compatible-with=7"), equalTo(XContentType.JSON));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat("application/vnd.opensearch+yaml;compatible-with=7"), equalTo(XContentType.YAML));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat("application/vnd.opensearch+cbor;compatible-with=7"), equalTo(XContentType.CBOR));
|
||||
assertThat(XContentType.fromMediaTypeOrFormat("application/vnd.opensearch+smile;compatible-with=7"), equalTo(XContentType.SMILE));
|
||||
assertThat(XContentType.fromMediaType("application/vnd.opensearch+json;compatible-with=7"), equalTo(XContentType.JSON));
|
||||
assertThat(XContentType.fromMediaType("application/vnd.opensearch+yaml;compatible-with=7"), equalTo(XContentType.YAML));
|
||||
assertThat(XContentType.fromMediaType("application/vnd.opensearch+cbor;compatible-with=7"), equalTo(XContentType.CBOR));
|
||||
assertThat(XContentType.fromMediaType("application/vnd.opensearch+smile;compatible-with=7"), equalTo(XContentType.SMILE));
|
||||
|
||||
assertThat(XContentType.fromMediaTypeOrFormat("application/vnd.opensearch+json ;compatible-with=7"), equalTo(XContentType.JSON));
|
||||
assertThat(
|
||||
XContentType.fromMediaTypeOrFormat("application/vnd.opensearch+json ;compatible-with=7;charset=utf-8"),
|
||||
equalTo(XContentType.JSON)
|
||||
);
|
||||
assertThat(XContentType.fromMediaType("application/vnd.opensearch+json ;compatible-with=7"), equalTo(XContentType.JSON));
|
||||
|
||||
String mthv = "application/vnd.opensearch+json ;compatible-with=7;charset=utf-8";
|
||||
assertThat(XContentType.fromMediaType(mthv), equalTo(XContentType.JSON));
|
||||
assertThat(XContentType.fromMediaType(mthv.toUpperCase(Locale.ROOT)), equalTo(XContentType.JSON));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,7 +325,7 @@ public class BytesRestResponseTests extends OpenSearchTestCase {
|
|||
|
||||
final XContentType xContentType = randomFrom(XContentType.values());
|
||||
|
||||
Map<String, String> params = Collections.singletonMap("format", xContentType.mediaType());
|
||||
Map<String, String> params = Collections.singletonMap("format", xContentType.format());
|
||||
RestRequest request = new FakeRestRequest.Builder(xContentRegistry()).withParams(params).build();
|
||||
RestChannel channel = detailed ? new DetailedExceptionRestChannel(request) : new SimpleExceptionRestChannel(request);
|
||||
|
||||
|
|
|
@ -136,7 +136,7 @@ public abstract class OpenSearchRestTestCase extends OpenSearchTestCase {
|
|||
* Convert the entity from a {@link Response} into a map of maps.
|
||||
*/
|
||||
public static Map<String, Object> entityAsMap(Response response) throws IOException {
|
||||
XContentType xContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue());
|
||||
XContentType xContentType = XContentType.fromMediaType(response.getEntity().getContentType().getValue());
|
||||
// EMPTY and THROW are fine here because `.map` doesn't use named x content or deprecation
|
||||
try (
|
||||
XContentParser parser = xContentType.xContent()
|
||||
|
@ -154,7 +154,7 @@ public abstract class OpenSearchRestTestCase extends OpenSearchTestCase {
|
|||
* Convert the entity from a {@link Response} into a list of maps.
|
||||
*/
|
||||
public static List<Object> entityAsList(Response response) throws IOException {
|
||||
XContentType xContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue());
|
||||
XContentType xContentType = XContentType.fromMediaType(response.getEntity().getContentType().getValue());
|
||||
// EMPTY and THROW are fine here because `.map` doesn't use named x content or deprecation
|
||||
try (
|
||||
XContentParser parser = xContentType.xContent()
|
||||
|
@ -1082,7 +1082,7 @@ public abstract class OpenSearchRestTestCase extends OpenSearchTestCase {
|
|||
}
|
||||
|
||||
protected static Map<String, Object> responseAsMap(Response response) throws IOException {
|
||||
XContentType entityContentType = XContentType.fromMediaTypeOrFormat(response.getEntity().getContentType().getValue());
|
||||
XContentType entityContentType = XContentType.fromMediaType(response.getEntity().getContentType().getValue());
|
||||
Map<String, Object> responseEntity = XContentHelper.convertToMap(
|
||||
entityContentType.xContent(),
|
||||
response.getEntity().getContent(),
|
||||
|
|
|
@ -66,7 +66,7 @@ public class ClientYamlTestResponse {
|
|||
this.response = response;
|
||||
if (response.getEntity() != null) {
|
||||
String contentType = response.getHeader("Content-Type");
|
||||
this.bodyContentType = XContentType.fromMediaTypeOrFormat(contentType);
|
||||
this.bodyContentType = XContentType.fromMediaType(contentType);
|
||||
try {
|
||||
byte[] bytes = EntityUtils.toByteArray(response.getEntity());
|
||||
// skip parsing if we got text back (e.g. if we called _cat apis)
|
||||
|
|
|
@ -57,7 +57,7 @@ public class ObjectPath {
|
|||
public static ObjectPath createFromResponse(Response response) throws IOException {
|
||||
byte[] bytes = EntityUtils.toByteArray(response.getEntity());
|
||||
String contentType = response.getHeader("Content-Type");
|
||||
XContentType xContentType = XContentType.fromMediaTypeOrFormat(contentType);
|
||||
XContentType xContentType = XContentType.fromMediaType(contentType);
|
||||
return ObjectPath.createFromXContent(xContentType.xContent(), new BytesArray(bytes));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue