Optionally require a valid content type for all rest requests with content (#22691)

This change adds a strict mode for xcontent parsing on the rest layer. The strict mode will be off by default for 5.x and in a separate commit will be enabled by default for 6.0. The strict mode, which can be enabled by setting `http.content_type.required: true` in 5.x, will require that all incoming rest requests have a valid and supported content type header before the request is dispatched. In the non-strict mode, the Content-Type header will be inspected and if it is not present or not valid, we will continue with auto detection of content like we have done previously.

The content type header is parsed to the matching XContentType value with the only exception being for plain text requests. This value is then passed on with the content bytes so that we can reduce the number of places where we need to auto-detect the content type.

As part of this, many transport requests and builders were updated to provide methods that
accepted the XContentType along with the bytes and the methods that would rely on auto-detection have been deprecated.

In the non-strict mode, deprecation warnings are issued whenever a request with body doesn't provide the Content-Type header.

See #19388
This commit is contained in:
Jay Modi 2017-02-02 14:07:13 -05:00 committed by GitHub
parent b41d5747f0
commit 7520a107be
252 changed files with 3705 additions and 1031 deletions

View File

@ -28,6 +28,7 @@ import org.elasticsearch.client.benchmark.ops.search.SearchRequestExecutor;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.TransportAddress;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugin.noop.NoopPlugin;
import org.elasticsearch.plugin.noop.action.bulk.NoopBulkAction;
@ -80,7 +81,7 @@ public final class TransportClientBenchmark extends AbstractBenchmark<TransportC
public boolean bulkIndex(List<String> bulkData) {
NoopBulkRequestBuilder builder = NoopBulkAction.INSTANCE.newRequestBuilder(client);
for (String bulkItem : bulkData) {
builder.add(new IndexRequest(indexName, typeName).source(bulkItem.getBytes(StandardCharsets.UTF_8)));
builder.add(new IndexRequest(indexName, typeName).source(bulkItem.getBytes(StandardCharsets.UTF_8), XContentType.JSON));
}
BulkResponse bulkResponse;
try {

View File

@ -33,6 +33,7 @@ import org.elasticsearch.action.update.UpdateRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
public class NoopBulkRequestBuilder extends ActionRequestBuilder<BulkRequest, BulkResponse, NoopBulkRequestBuilder>
implements WriteRequestBuilder<NoopBulkRequestBuilder> {
@ -95,17 +96,17 @@ public class NoopBulkRequestBuilder extends ActionRequestBuilder<BulkRequest, Bu
/**
* Adds a framed data in binary format
*/
public NoopBulkRequestBuilder add(byte[] data, int from, int length) throws Exception {
request.add(data, from, length, null, null);
public NoopBulkRequestBuilder add(byte[] data, int from, int length, XContentType xContentType) throws Exception {
request.add(data, from, length, null, null, xContentType);
return this;
}
/**
* Adds a framed data in binary format
*/
public NoopBulkRequestBuilder add(byte[] data, int from, int length, @Nullable String defaultIndex, @Nullable String defaultType)
throws Exception {
request.add(data, from, length, defaultIndex, defaultType);
public NoopBulkRequestBuilder add(byte[] data, int from, int length, @Nullable String defaultIndex, @Nullable String defaultType,
XContentType xContentType) throws Exception {
request.add(data, from, length, defaultIndex, defaultType, xContentType);
return this;
}

View File

@ -73,7 +73,8 @@ public class RestNoopBulkAction extends BaseRestHandler {
}
bulkRequest.timeout(request.paramAsTime("timeout", BulkShardRequest.DEFAULT_TIMEOUT));
bulkRequest.setRefreshPolicy(request.param("refresh"));
bulkRequest.add(request.content(), defaultIndex, defaultType, defaultRouting, defaultFields, null, defaultPipeline, null, true);
bulkRequest.add(request.content(), defaultIndex, defaultType, defaultRouting, defaultFields, null, defaultPipeline, null, true,
request.getXContentType());
// short circuit the call to the transport layer
return channel -> {

View File

@ -142,14 +142,28 @@ public class PutRepositoryRequest extends AcknowledgedRequest<PutRepositoryReque
/**
* Sets the repository settings.
*
* @param source repository settings in json, yaml or properties format
* @param source repository settings in json or yaml format
* @return this request
* @deprecated use {@link #settings(String, XContentType)} to avoid content type auto-detection
*/
@Deprecated
public PutRepositoryRequest settings(String source) {
this.settings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* Sets the repository settings.
*
* @param source repository settings in json or yaml format
* @param xContentType the content type of the source
* @return this request
*/
public PutRepositoryRequest settings(String source, XContentType xContentType) {
this.settings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Sets the repository settings.
*
@ -160,7 +174,7 @@ public class PutRepositoryRequest extends AcknowledgedRequest<PutRepositoryReque
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
settings(builder.string());
settings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.action.admin.cluster.repositories.put;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import java.util.Map;
@ -89,16 +90,30 @@ public class PutRepositoryRequestBuilder extends AcknowledgedRequestBuilder<PutR
}
/**
* Sets the repository settings in Json, Yaml or properties format
* Sets the repository settings in Json or Yaml format
*
* @param source repository settings
* @return this builder
* @deprecated use {@link #setSettings(String, XContentType)} instead to avoid content type auto detection
*/
@Deprecated
public PutRepositoryRequestBuilder setSettings(String source) {
request.settings(source);
return this;
}
/**
* Sets the repository settings in Json or Yaml format
*
* @param source repository settings
* @param xContentType the contenty type of the source
* @return this builder
*/
public PutRepositoryRequestBuilder setSettings(String source, XContentType xContentType) {
request.settings(source, xContentType);
return this;
}
/**
* Sets the repository settings
*

View File

@ -83,12 +83,22 @@ public class ClusterUpdateSettingsRequest extends AcknowledgedRequest<ClusterUpd
/**
* Sets the source containing the transient settings to be updated. They will not survive a full cluster restart
* @deprecated use {@link #transientSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public ClusterUpdateSettingsRequest transientSettings(String source) {
this.transientSettings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* Sets the source containing the transient settings to be updated. They will not survive a full cluster restart
*/
public ClusterUpdateSettingsRequest transientSettings(String source, XContentType xContentType) {
this.transientSettings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Sets the transient settings to be updated. They will not survive a full cluster restart
*/
@ -97,7 +107,7 @@ public class ClusterUpdateSettingsRequest extends AcknowledgedRequest<ClusterUpd
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
transientSettings(builder.string());
transientSettings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
@ -122,12 +132,22 @@ public class ClusterUpdateSettingsRequest extends AcknowledgedRequest<ClusterUpd
/**
* Sets the source containing the persistent settings to be updated. They will get applied cross restarts
* @deprecated use {@link #persistentSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public ClusterUpdateSettingsRequest persistentSettings(String source) {
this.persistentSettings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* Sets the source containing the persistent settings to be updated. They will get applied cross restarts
*/
public ClusterUpdateSettingsRequest persistentSettings(String source, XContentType xContentType) {
this.persistentSettings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Sets the persistent settings to be updated. They will get applied cross restarts
*/
@ -136,7 +156,7 @@ public class ClusterUpdateSettingsRequest extends AcknowledgedRequest<ClusterUpd
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
persistentSettings(builder.string());
persistentSettings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.action.admin.cluster.settings;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import java.util.Map;
@ -52,12 +53,22 @@ public class ClusterUpdateSettingsRequestBuilder extends AcknowledgedRequestBuil
/**
* Sets the source containing the transient settings to be updated. They will not survive a full cluster restart
* @deprecated use {@link #setTransientSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public ClusterUpdateSettingsRequestBuilder setTransientSettings(String settings) {
request.transientSettings(settings);
return this;
}
/**
* Sets the source containing the transient settings to be updated. They will not survive a full cluster restart
*/
public ClusterUpdateSettingsRequestBuilder setTransientSettings(String settings, XContentType xContentType) {
request.transientSettings(settings, xContentType);
return this;
}
/**
* Sets the transient settings to be updated. They will not survive a full cluster restart
*/
@ -84,12 +95,22 @@ public class ClusterUpdateSettingsRequestBuilder extends AcknowledgedRequestBuil
/**
* Sets the source containing the persistent settings to be updated. They will get applied cross restarts
* @deprecated use {@link #setPersistentSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public ClusterUpdateSettingsRequestBuilder setPersistentSettings(String settings) {
request.persistentSettings(settings);
return this;
}
/**
* Sets the source containing the persistent settings to be updated. They will get applied cross restarts
*/
public ClusterUpdateSettingsRequestBuilder setPersistentSettings(String settings, XContentType xContentType) {
request.persistentSettings(settings, xContentType);
return this;
}
/**
* Sets the persistent settings to be updated. They will get applied cross restarts
*/

View File

@ -288,18 +288,34 @@ public class CreateSnapshotRequest extends MasterNodeRequest<CreateSnapshotReque
}
/**
* Sets repository-specific snapshot settings in JSON, YAML or properties format
* Sets repository-specific snapshot settings in JSON or YAML format
* <p>
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @return this request
* @deprecated use {@link #settings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public CreateSnapshotRequest settings(String source) {
this.settings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* Sets repository-specific snapshot settings in JSON or YAML format
* <p>
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @param xContentType the content type of the source
* @return this request
*/
public CreateSnapshotRequest settings(String source, XContentType xContentType) {
this.settings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Sets repository-specific snapshot settings.
* <p>
@ -312,7 +328,7 @@ public class CreateSnapshotRequest extends MasterNodeRequest<CreateSnapshotReque
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
settings(builder.string());
settings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}

View File

@ -23,6 +23,7 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import java.util.Map;
@ -147,12 +148,28 @@ public class CreateSnapshotRequestBuilder extends MasterNodeOperationRequestBuil
*
* @param source repository-specific snapshot settings
* @return this builder
* @deprecated use {@link #setSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public CreateSnapshotRequestBuilder setSettings(String source) {
request.settings(source);
return this;
}
/**
* Sets repository-specific snapshot settings in YAML or JSON format
* <p>
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @param xContentType the content type of the source
* @return this builder
*/
public CreateSnapshotRequestBuilder setSettings(String source, XContentType xContentType) {
request.settings(source, xContentType);
return this;
}
/**
* Sets repository-specific snapshot settings.
* <p>

View File

@ -313,18 +313,34 @@ public class RestoreSnapshotRequest extends MasterNodeRequest<RestoreSnapshotReq
}
/**
* Sets repository-specific restore settings in JSON, YAML or properties format
* Sets repository-specific restore settings in JSON or YAML format
* <p>
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @return this request
* @deprecated use {@link #settings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public RestoreSnapshotRequest settings(String source) {
this.settings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* Sets repository-specific restore settings in JSON or YAML format
* <p>
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @param xContentType the content type of the source
* @return this request
*/
public RestoreSnapshotRequest settings(String source, XContentType xContentType) {
this.settings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Sets repository-specific restore settings
* <p>
@ -337,7 +353,7 @@ public class RestoreSnapshotRequest extends MasterNodeRequest<RestoreSnapshotReq
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
settings(builder.string());
settings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
@ -436,12 +452,22 @@ public class RestoreSnapshotRequest extends MasterNodeRequest<RestoreSnapshotReq
/**
* Sets settings that should be added/changed in all restored indices
* @deprecated use {@link #indexSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public RestoreSnapshotRequest indexSettings(String source) {
this.indexSettings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* Sets settings that should be added/changed in all restored indices
*/
public RestoreSnapshotRequest indexSettings(String source, XContentType xContentType) {
this.indexSettings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Sets settings that should be added/changed in all restored indices
*/
@ -449,7 +475,7 @@ public class RestoreSnapshotRequest extends MasterNodeRequest<RestoreSnapshotReq
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
indexSettings(builder.string());
indexSettings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}

View File

@ -23,6 +23,7 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.MasterNodeOperationRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import java.util.List;
import java.util.Map;
@ -153,18 +154,34 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui
}
/**
* Sets repository-specific restore settings in JSON, YAML or properties format
* Sets repository-specific restore settings in JSON or YAML format
* <p>
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @return this builder
* @deprecated use {@link #setSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public RestoreSnapshotRequestBuilder setSettings(String source) {
request.settings(source);
return this;
}
/**
* Sets repository-specific restore settings in JSON or YAML format
* <p>
* See repository documentation for more information.
*
* @param source repository-specific snapshot settings
* @param xContentType the content type of the source
* @return this builder
*/
public RestoreSnapshotRequestBuilder setSettings(String source, XContentType xContentType) {
request.settings(source, xContentType);
return this;
}
/**
* Sets repository-specific restore settings
* <p>
@ -251,12 +268,26 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui
*
* @param source index settings
* @return this builder
* @deprecated use {@link #setIndexSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public RestoreSnapshotRequestBuilder setIndexSettings(String source) {
request.indexSettings(source);
return this;
}
/**
* Sets index settings that should be added or replaced during restore
*
* @param source index settings
* @param xContentType the content type of the source
* @return this builder
*/
public RestoreSnapshotRequestBuilder setIndexSettings(String source, XContentType xContentType) {
request.indexSettings(source, xContentType);
return this;
}
/**
* Sets index settings that should be added or replaced during restore
*

View File

@ -19,14 +19,18 @@
package org.elasticsearch.action.admin.cluster.storedscripts;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.AcknowledgedRequest;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.Objects;
import static org.elasticsearch.action.ValidateActions.addValidationError;
@ -35,17 +39,23 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
private String id;
private String lang;
private BytesReference content;
private XContentType xContentType;
public PutStoredScriptRequest() {
super();
}
@Deprecated
public PutStoredScriptRequest(String id, String lang, BytesReference content) {
super();
this(id, lang, content, XContentFactory.xContentType(content));
}
public PutStoredScriptRequest(String id, String lang, BytesReference content, XContentType xContentType) {
super();
this.id = id;
this.lang = lang;
this.content = content;
this.xContentType = Objects.requireNonNull(xContentType);
}
@Override
@ -93,9 +103,25 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
return content;
}
public PutStoredScriptRequest content(BytesReference content) {
this.content = content;
public XContentType xContentType() {
return xContentType;
}
/**
* Set the script source using bytes.
* @deprecated this method is deprecated as it relies on content type detection. Use {@link #content(BytesReference, XContentType)}
*/
@Deprecated
public PutStoredScriptRequest content(BytesReference content) {
return content(content, XContentFactory.xContentType(content));
}
/**
* Set the script source and the content type of the bytes.
*/
public PutStoredScriptRequest content(BytesReference content, XContentType xContentType) {
this.content = content;
this.xContentType = Objects.requireNonNull(xContentType);
return this;
}
@ -111,6 +137,11 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
id = in.readOptionalString();
content = in.readBytesReference();
if (in.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType = XContentType.readFrom(in);
} else {
xContentType = XContentFactory.xContentType(content);
}
}
@Override
@ -120,6 +151,9 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
out.writeString(lang == null ? "" : lang);
out.writeOptionalString(id);
out.writeBytesReference(content);
if (out.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType.writeTo(out);
}
}
@Override
@ -127,8 +161,8 @@ public class PutStoredScriptRequest extends AcknowledgedRequest<PutStoredScriptR
String source = "_na_";
try {
source = XContentHelper.convertToJson(content, false);
} catch (Exception exception) {
source = XContentHelper.convertToJson(content, false, xContentType);
} catch (Exception e) {
// ignore
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.action.admin.cluster.storedscripts;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentType;
public class PutStoredScriptRequestBuilder extends AcknowledgedRequestBuilder<PutStoredScriptRequest,
PutStoredScriptResponse, PutStoredScriptRequestBuilder> {
@ -32,19 +33,29 @@ public class PutStoredScriptRequestBuilder extends AcknowledgedRequestBuilder<Pu
public PutStoredScriptRequestBuilder setId(String id) {
request.id(id);
return this;
}
/**
* Set the source of the script.
* @deprecated this method requires content type detection. Use {@link #setContent(BytesReference, XContentType)} instead
*/
@Deprecated
public PutStoredScriptRequestBuilder setContent(BytesReference content) {
request.content(content);
return this;
}
/**
* Set the source of the script along with the content type of the source
*/
public PutStoredScriptRequestBuilder setContent(BytesReference source, XContentType xContentType) {
request.content(source, xContentType);
return this;
}
public PutStoredScriptRequestBuilder setLang(String lang) {
request.lang(lang);
return this;
}
public PutStoredScriptRequestBuilder setContent(BytesReference content) {
request.content(content);
return this;
}
}

View File

@ -75,7 +75,7 @@ public class AnalyzeRequest extends SingleShardRequest<AnalyzeRequest> {
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(definition);
this.definition = Settings.builder().loadFromSource(builder.string()).build();
this.definition = Settings.builder().loadFromSource(builder.string(), builder.contentType()).build();
} catch (IOException e) {
throw new IllegalArgumentException("Failed to parse [" + definition + "]", e);
}

View File

@ -21,6 +21,7 @@ package org.elasticsearch.action.admin.indices.create;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.admin.indices.alias.Alias;
@ -43,10 +44,11 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.io.UncheckedIOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static org.elasticsearch.action.ValidateActions.addValidationError;
@ -169,19 +171,29 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
}
/**
* The settings to create the index with (either json/yaml/properties format)
* The settings to create the index with (either json or yaml format)
* @deprecated use {@link #source(String, XContentType)} instead to avoid content type detection
*/
@Deprecated
public CreateIndexRequest settings(String source) {
this.settings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* The settings to create the index with (either json or yaml format)
*/
public CreateIndexRequest settings(String source, XContentType xContentType) {
this.settings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Allows to set the settings using a json builder.
*/
public CreateIndexRequest settings(XContentBuilder builder) {
try {
settings(builder.string());
settings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate json settings from builder", e);
}
@ -196,7 +208,7 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
settings(builder.string());
settings(builder.string(), XContentType.JSON);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
@ -208,13 +220,42 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
*
* @param type The mapping type
* @param source The mapping source
* @deprecated use {@link #mapping(String, String, XContentType)} to avoid content type detection
*/
@Deprecated
public CreateIndexRequest mapping(String type, String source) {
return mapping(type, new BytesArray(source), XContentFactory.xContentType(source));
}
/**
* Adds mapping that will be added when the index gets created.
*
* @param type The mapping type
* @param source The mapping source
* @param xContentType The content type of the source
*/
public CreateIndexRequest mapping(String type, String source, XContentType xContentType) {
return mapping(type, new BytesArray(source), xContentType);
}
/**
* Adds mapping that will be added when the index gets created.
*
* @param type The mapping type
* @param source The mapping source
* @param xContentType the content type of the mapping source
*/
private CreateIndexRequest mapping(String type, BytesReference source, XContentType xContentType) {
if (mappings.containsKey(type)) {
throw new IllegalStateException("mappings for type \"" + type + "\" were already defined");
}
mappings.put(type, source);
return this;
Objects.requireNonNull(xContentType);
try {
mappings.put(type, XContentHelper.convertToJson(source, false, false, xContentType));
return this;
} catch (IOException e) {
throw new UncheckedIOException("failed to convert to json", e);
}
}
/**
@ -232,15 +273,7 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
* @param source The mapping source
*/
public CreateIndexRequest mapping(String type, XContentBuilder source) {
if (mappings.containsKey(type)) {
throw new IllegalStateException("mappings for type \"" + type + "\" were already defined");
}
try {
mappings.put(type, source.string());
} catch (IOException e) {
throw new IllegalArgumentException("Failed to build json for mapping request", e);
}
return this;
return mapping(type, source.bytes(), source.contentType());
}
/**
@ -261,7 +294,7 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
return mapping(type, builder.string());
return mapping(type, builder);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
@ -331,9 +364,18 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #source(String, XContentType)}
*/
@Deprecated
public CreateIndexRequest source(String source) {
return source(source.getBytes(StandardCharsets.UTF_8));
return source(new BytesArray(source));
}
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequest source(String source, XContentType xContentType) {
return source(new BytesArray(source), xContentType);
}
/**
@ -345,7 +387,9 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #source(byte[], XContentType)}
*/
@Deprecated
public CreateIndexRequest source(byte[] source) {
return source(source, 0, source.length);
}
@ -353,6 +397,15 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequest source(byte[] source, XContentType xContentType) {
return source(source, 0, source.length, xContentType);
}
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #source(byte[], int, int, XContentType)}
*/
@Deprecated
public CreateIndexRequest source(byte[] source, int offset, int length) {
return source(new BytesArray(source, offset, length));
}
@ -360,13 +413,27 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequest source(byte[] source, int offset, int length, XContentType xContentType) {
return source(new BytesArray(source, offset, length), xContentType);
}
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #source(BytesReference, XContentType)}
*/
@Deprecated
public CreateIndexRequest source(BytesReference source) {
XContentType xContentType = XContentFactory.xContentType(source);
if (xContentType != null) {
source(XContentHelper.convertToMap(source, false).v2());
} else {
settings(source.utf8ToString());
}
source(source, xContentType);
return this;
}
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequest source(BytesReference source, XContentType xContentType) {
Objects.requireNonNull(xContentType);
source(XContentHelper.convertToMap(source, false, xContentType).v2());
return this;
}
@ -483,7 +550,13 @@ public class CreateIndexRequest extends AcknowledgedRequest<CreateIndexRequest>
readTimeout(in);
int size = in.readVInt();
for (int i = 0; i < size; i++) {
mappings.put(in.readString(), in.readString());
final String type = in.readString();
String source = in.readString();
if (in.getVersion().before(Version.V_6_0_0_alpha1_UNRELEASED)) { // TODO change to 5.3.0 after backport
// we do not know the content type that comes from earlier versions so we autodetect and convert
source = XContentHelper.convertToJson(new BytesArray(source), false, false, XContentFactory.xContentType(source));
}
mappings.put(type, source);
}
int customSize = in.readVInt();
for (int i = 0; i < customSize; i++) {

View File

@ -27,6 +27,7 @@ import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import java.util.Map;
@ -76,13 +77,23 @@ public class CreateIndexRequestBuilder extends AcknowledgedRequestBuilder<Create
}
/**
* The settings to create the index with (either json/yaml/properties format)
* The settings to create the index with (either json or yaml format)
* @deprecated use {@link #setSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public CreateIndexRequestBuilder setSettings(String source) {
request.settings(source);
return this;
}
/**
* The settings to create the index with (either json or yaml format)
*/
public CreateIndexRequestBuilder setSettings(String source, XContentType xContentType) {
request.settings(source, xContentType);
return this;
}
/**
* A simplified version of settings that takes key value pairs settings.
*/
@ -104,12 +115,26 @@ public class CreateIndexRequestBuilder extends AcknowledgedRequestBuilder<Create
*
* @param type The mapping type
* @param source The mapping source
* @deprecated use {@link #addMapping(String, String, XContentType)} to avoid content type auto-detection
*/
@Deprecated
public CreateIndexRequestBuilder addMapping(String type, String source) {
request.mapping(type, source);
return this;
}
/**
* Adds mapping that will be added when the index gets created.
*
* @param type The mapping type
* @param source The mapping source
* @param xContentType The content type of the source
*/
public CreateIndexRequestBuilder addMapping(String type, String source, XContentType xContentType) {
request.mapping(type, source, xContentType);
return this;
}
/**
* The cause for this index creation.
*/
@ -191,7 +216,9 @@ public class CreateIndexRequestBuilder extends AcknowledgedRequestBuilder<Create
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #setSource(String, XContentType)}
*/
@Deprecated
public CreateIndexRequestBuilder setSource(String source) {
request.source(source);
return this;
@ -200,6 +227,16 @@ public class CreateIndexRequestBuilder extends AcknowledgedRequestBuilder<Create
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequestBuilder setSource(String source, XContentType xContentType) {
request.source(source, xContentType);
return this;
}
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #setSource(BytesReference, XContentType)}
*/
@Deprecated
public CreateIndexRequestBuilder setSource(BytesReference source) {
request.source(source);
return this;
@ -208,6 +245,16 @@ public class CreateIndexRequestBuilder extends AcknowledgedRequestBuilder<Create
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequestBuilder setSource(BytesReference source, XContentType xContentType) {
request.source(source, xContentType);
return this;
}
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #setSource(byte[], XContentType)}
*/
@Deprecated
public CreateIndexRequestBuilder setSource(byte[] source) {
request.source(source);
return this;
@ -216,11 +263,29 @@ public class CreateIndexRequestBuilder extends AcknowledgedRequestBuilder<Create
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequestBuilder setSource(byte[] source, XContentType xContentType) {
request.source(source, xContentType);
return this;
}
/**
* Sets the settings and mappings as a single source.
* @deprecated use {@link #setSource(byte[], int, int, XContentType)}
*/
@Deprecated
public CreateIndexRequestBuilder setSource(byte[] source, int offset, int length) {
request.source(source, offset, length);
return this;
}
/**
* Sets the settings and mappings as a single source.
*/
public CreateIndexRequestBuilder setSource(byte[] source, int offset, int length, XContentType xContentType) {
request.source(source, offset, length, xContentType);
return this;
}
/**
* Sets the settings and mappings as a single source.
*/

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.Mapper;
import java.io.IOException;
@ -108,20 +109,25 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
/** Returns the mappings as a map. Note that the returned map has a single key which is always the field's {@link Mapper#name}. */
public Map<String, Object> sourceAsMap() {
return XContentHelper.convertToMap(source, true).v2();
return XContentHelper.convertToMap(source, true, XContentType.JSON).v2();
}
public boolean isNull() {
return NULL.fullName().equals(fullName) && NULL.source.length() == source.length();
}
//pkg-private for testing
BytesReference getSource() {
return source;
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.field("full_name", fullName);
if (params.paramAsBoolean("pretty", false)) {
builder.field("mapping", sourceAsMap());
} else {
builder.rawField("mapping", source);
builder.rawField("mapping", source, XContentType.JSON);
}
return builder;
}

View File

@ -220,4 +220,4 @@ public class TransportGetFieldMappingsIndexAction extends TransportSingleShardAc
}
}
}
}

View File

@ -22,19 +22,24 @@ package org.elasticsearch.action.admin.indices.mapping.put;
import com.carrotsearch.hppc.ObjectHashSet;
import org.elasticsearch.ElasticsearchGenerationException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.IndicesRequest;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
@ -245,7 +250,7 @@ public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> im
*/
public PutMappingRequest source(XContentBuilder mappingBuilder) {
try {
return source(mappingBuilder.string());
return source(mappingBuilder.string(), mappingBuilder.contentType());
} catch (IOException e) {
throw new IllegalArgumentException("Failed to build json for mapping request", e);
}
@ -259,7 +264,7 @@ public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> im
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(mappingSource);
return source(builder.string());
return source(builder.string(), XContentType.JSON);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + mappingSource + "]", e);
}
@ -267,10 +272,31 @@ public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> im
/**
* The mapping source definition.
* @deprecated use {@link #source(String, XContentType)}
*/
@Deprecated
public PutMappingRequest source(String mappingSource) {
this.source = mappingSource;
return this;
return source(mappingSource, XContentFactory.xContentType(mappingSource));
}
/**
* The mapping source definition.
*/
public PutMappingRequest source(String mappingSource, XContentType xContentType) {
return source(new BytesArray(mappingSource), xContentType);
}
/**
* The mapping source definition.
*/
public PutMappingRequest source(BytesReference mappingSource, XContentType xContentType) {
Objects.requireNonNull(xContentType);
try {
this.source = XContentHelper.convertToJson(mappingSource, false, false, xContentType);
return this;
} catch (IOException e) {
throw new UncheckedIOException("failed to convert source to json", e);
}
}
/** True if all fields that span multiple types should be updated, false otherwise */
@ -291,6 +317,10 @@ public class PutMappingRequest extends AcknowledgedRequest<PutMappingRequest> im
indicesOptions = IndicesOptions.readIndicesOptions(in);
type = in.readOptionalString();
source = in.readString();
if (in.getVersion().before(Version.V_6_0_0_alpha1_UNRELEASED)) { // TODO change to V_5_3 once backported
// we do not know the format from earlier versions so convert if necessary
source = XContentHelper.convertToJson(new BytesArray(source), false, false, XContentFactory.xContentType(source));
}
updateAllTypes = in.readBoolean();
readTimeout(in);
concreteIndex = in.readOptionalWriteable(Index::new);

View File

@ -23,6 +23,7 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.Index;
import java.util.Map;
@ -82,12 +83,22 @@ public class PutMappingRequestBuilder extends AcknowledgedRequestBuilder<PutMapp
/**
* The mapping source definition.
* @deprecated use {@link #setSource(String, XContentType)}
*/
@Deprecated
public PutMappingRequestBuilder setSource(String mappingSource) {
request.source(mappingSource);
return this;
}
/**
* The mapping source definition.
*/
public PutMappingRequestBuilder setSource(String mappingSource, XContentType xContentType) {
request.source(mappingSource, xContentType);
return this;
}
/**
* A specialized simplified mapping source method, takes the form of simple properties definition:
* ("field1", "type=string,store=true").

View File

@ -121,13 +121,23 @@ public class UpdateSettingsRequest extends AcknowledgedRequest<UpdateSettingsReq
}
/**
* Sets the settings to be updated (either json/yaml/properties format)
* Sets the settings to be updated (either json or yaml format)
* @deprecated use {@link #settings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public UpdateSettingsRequest settings(String source) {
this.settings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* Sets the settings to be updated (either json or yaml format)
*/
public UpdateSettingsRequest settings(String source, XContentType xContentType) {
this.settings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* Returns <code>true</code> iff the settings update should only add but not update settings. If the setting already exists
* it should not be overwritten by this update. The default is <code>false</code>
@ -146,14 +156,14 @@ public class UpdateSettingsRequest extends AcknowledgedRequest<UpdateSettingsReq
}
/**
* Sets the settings to be updated (either json/yaml/properties format)
* Sets the settings to be updated (either json or yaml format)
*/
@SuppressWarnings("unchecked")
public UpdateSettingsRequest settings(Map source) {
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
settings(builder.string());
settings(builder.string(), builder.contentType());
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}

View File

@ -23,6 +23,7 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.action.support.master.AcknowledgedRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import java.util.Map;
@ -70,15 +71,25 @@ public class UpdateSettingsRequestBuilder extends AcknowledgedRequestBuilder<Upd
}
/**
* Sets the settings to be updated (either json/yaml/properties format)
* Sets the settings to be updated (either json or yaml format)
* @deprecated use {@link #setSettings(String, XContentType)} to avoid content type detection
*/
@Deprecated
public UpdateSettingsRequestBuilder setSettings(String source) {
request.settings(source);
return this;
}
/**
* Sets the settings to be updated (either json/yaml/properties format)
* Sets the settings to be updated (either json or yaml format)
*/
public UpdateSettingsRequestBuilder setSettings(String source, XContentType xContentType) {
request.settings(source, xContentType);
return this;
}
/**
* Sets the settings to be updated
*/
public UpdateSettingsRequestBuilder setSettings(Map<String, Object> source) {
request.settings(source);

View File

@ -45,11 +45,13 @@ import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@ -179,21 +181,31 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
}
/**
* The settings to create the index template with (either json/yaml/properties format).
* The settings to create the index template with (either json/yaml format).
* @deprecated use {@link #settings(String, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequest settings(String source) {
this.settings = Settings.builder().loadFromSource(source).build();
return this;
}
/**
* The settings to crete the index template with (either json/yaml/properties format).
* The settings to create the index template with (either json/yaml format).
*/
public PutIndexTemplateRequest settings(String source, XContentType xContentType) {
this.settings = Settings.builder().loadFromSource(source, xContentType).build();
return this;
}
/**
* The settings to create the index template with (either json or yaml format).
*/
public PutIndexTemplateRequest settings(Map<String, Object> source) {
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
settings(builder.string());
settings(builder.string(), XContentType.JSON);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
@ -209,10 +221,23 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
*
* @param type The mapping type
* @param source The mapping source
* @deprecated use {@link #mapping(String, String, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequest mapping(String type, String source) {
mappings.put(type, source);
return this;
XContentType xContentType = XContentFactory.xContentType(source);
return mapping(type, source, xContentType);
}
/**
* Adds mapping that will be added when the index gets created.
*
* @param type The mapping type
* @param source The mapping source
* @param xContentType The type of content contained within the source
*/
public PutIndexTemplateRequest mapping(String type, String source, XContentType xContentType) {
return mapping(type, new BytesArray(source), xContentType);
}
/**
@ -234,12 +259,24 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
* @param source The mapping source
*/
public PutIndexTemplateRequest mapping(String type, XContentBuilder source) {
return mapping(type, source.bytes(), source.contentType());
}
/**
* Adds mapping that will be added when the index gets created.
*
* @param type The mapping type
* @param source The mapping source
* @param xContentType the source content type
*/
public PutIndexTemplateRequest mapping(String type, BytesReference source, XContentType xContentType) {
Objects.requireNonNull(xContentType);
try {
mappings.put(type, source.string());
mappings.put(type, XContentHelper.convertToJson(source, false, false, xContentType));
return this;
} catch (IOException e) {
throw new IllegalArgumentException("Failed to build json for mapping request", e);
throw new UncheckedIOException("failed to convert source to json", e);
}
return this;
}
/**
@ -256,7 +293,7 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.map(source);
return mapping(type, builder.string());
return mapping(type, builder);
} catch (IOException e) {
throw new ElasticsearchGenerationException("Failed to generate [" + source + "]", e);
}
@ -280,7 +317,7 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
*/
public PutIndexTemplateRequest source(XContentBuilder templateBuilder) {
try {
return source(templateBuilder.bytes());
return source(templateBuilder.bytes(), templateBuilder.contentType());
} catch (Exception e) {
throw new IllegalArgumentException("Failed to build json for template request", e);
}
@ -350,7 +387,9 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
/**
* The template source definition.
* @deprecated use {@link #source(String, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequest source(String templateSource) {
return source(XContentHelper.convertToMap(XContentFactory.xContent(templateSource), templateSource, true));
}
@ -358,6 +397,15 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
/**
* The template source definition.
*/
public PutIndexTemplateRequest source(String templateSource, XContentType xContentType) {
return source(XContentHelper.convertToMap(xContentType.xContent(), templateSource, true));
}
/**
* The template source definition.
* @deprecated use {@link #source(byte[], XContentType)}
*/
@Deprecated
public PutIndexTemplateRequest source(byte[] source) {
return source(source, 0, source.length);
}
@ -365,6 +413,15 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
/**
* The template source definition.
*/
public PutIndexTemplateRequest source(byte[] source, XContentType xContentType) {
return source(source, 0, source.length, xContentType);
}
/**
* The template source definition.
* @deprecated use {@link #source(byte[], int, int, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequest source(byte[] source, int offset, int length) {
return source(new BytesArray(source, offset, length));
}
@ -372,10 +429,26 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
/**
* The template source definition.
*/
public PutIndexTemplateRequest source(byte[] source, int offset, int length, XContentType xContentType) {
return source(new BytesArray(source, offset, length), xContentType);
}
/**
* The template source definition.
* @deprecated use {@link #source(BytesReference, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequest source(BytesReference source) {
return source(XContentHelper.convertToMap(source, true).v2());
}
/**
* The template source definition.
*/
public PutIndexTemplateRequest source(BytesReference source, XContentType xContentType) {
return source(XContentHelper.convertToMap(source, true, xContentType).v2());
}
public PutIndexTemplateRequest custom(IndexMetaData.Custom custom) {
customs.put(custom.type(), custom);
return this;
@ -471,7 +544,14 @@ public class PutIndexTemplateRequest extends MasterNodeRequest<PutIndexTemplateR
settings = readSettingsFromStream(in);
int size = in.readVInt();
for (int i = 0; i < size; i++) {
mappings.put(in.readString(), in.readString());
final String type = in.readString();
String mappingSource = in.readString();
if (in.getVersion().before(Version.V_6_0_0_alpha1_UNRELEASED)) { // TODO change to V_5_3_0 once backported
// we do not know the incoming type so convert it if needed
mappingSource =
XContentHelper.convertToJson(new BytesArray(mappingSource), false, false, XContentFactory.xContentType(mappingSource));
}
mappings.put(type, mappingSource);
}
int customSize = in.readVInt();
for (int i = 0; i < customSize; i++) {

View File

@ -24,6 +24,7 @@ import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import java.util.Collections;
import java.util.List;
@ -100,15 +101,25 @@ public class PutIndexTemplateRequestBuilder
}
/**
* The settings to crete the index template with (either json/yaml/properties format)
* The settings to crete the index template with (either json or yaml format)
* @deprecated use {@link #setSettings(String, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequestBuilder setSettings(String source) {
request.settings(source);
return this;
}
/**
* The settings to crete the index template with (either json/yaml/properties format)
* The settings to crete the index template with (either json or yaml format)
*/
public PutIndexTemplateRequestBuilder setSettings(String source, XContentType xContentType) {
request.settings(source, xContentType);
return this;
}
/**
* The settings to crete the index template with (either json or yaml format)
*/
public PutIndexTemplateRequestBuilder setSettings(Map<String, Object> source) {
request.settings(source);
@ -120,12 +131,26 @@ public class PutIndexTemplateRequestBuilder
*
* @param type The mapping type
* @param source The mapping source
* @deprecated use {@link #addMapping(String, String, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequestBuilder addMapping(String type, String source) {
request.mapping(type, source);
return this;
}
/**
* Adds mapping that will be added when the index template gets created.
*
* @param type The mapping type
* @param source The mapping source
* @param xContentType The type/format of the source
*/
public PutIndexTemplateRequestBuilder addMapping(String type, String source, XContentType xContentType) {
request.mapping(type, source, xContentType);
return this;
}
/**
* A specialized simplified mapping source method, takes the form of simple properties definition:
* ("field1", "type=string,store=true").
@ -226,7 +251,9 @@ public class PutIndexTemplateRequestBuilder
/**
* The template source definition.
* @deprecated use {@link #setSource(BytesReference, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequestBuilder setSource(String templateSource) {
request.source(templateSource);
return this;
@ -235,6 +262,16 @@ public class PutIndexTemplateRequestBuilder
/**
* The template source definition.
*/
public PutIndexTemplateRequestBuilder setSource(BytesReference templateSource, XContentType xContentType) {
request.source(templateSource, xContentType);
return this;
}
/**
* The template source definition.
* @deprecated use {@link #setSource(BytesReference, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequestBuilder setSource(BytesReference templateSource) {
request.source(templateSource);
return this;
@ -242,7 +279,9 @@ public class PutIndexTemplateRequestBuilder
/**
* The template source definition.
* @deprecated use {@link #setSource(byte[], XContentType)}
*/
@Deprecated
public PutIndexTemplateRequestBuilder setSource(byte[] templateSource) {
request.source(templateSource);
return this;
@ -251,8 +290,26 @@ public class PutIndexTemplateRequestBuilder
/**
* The template source definition.
*/
public PutIndexTemplateRequestBuilder setSource(byte[] templateSource, XContentType xContentType) {
request.source(templateSource, xContentType);
return this;
}
/**
* The template source definition.
* @deprecated use {@link #setSource(byte[], int, int, XContentType)}
*/
@Deprecated
public PutIndexTemplateRequestBuilder setSource(byte[] templateSource, int offset, int length) {
request.source(templateSource, offset, length);
return this;
}
/**
* The template source definition.
*/
public PutIndexTemplateRequestBuilder setSource(byte[] templateSource, int offset, int length, XContentType xContentType) {
request.source(templateSource, offset, length, xContentType);
return this;
}
}

View File

@ -43,6 +43,7 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
@ -244,7 +245,9 @@ public class BulkRequest extends ActionRequest implements CompositeIndicesReques
/**
* Adds a framed data in binary format
* @deprecated use {@link #add(byte[], int, int, XContentType)}
*/
@Deprecated
public BulkRequest add(byte[] data, int from, int length) throws IOException {
return add(data, from, length, null, null);
}
@ -252,6 +255,15 @@ public class BulkRequest extends ActionRequest implements CompositeIndicesReques
/**
* Adds a framed data in binary format
*/
public BulkRequest add(byte[] data, int from, int length, XContentType xContentType) throws IOException {
return add(data, from, length, null, null, xContentType);
}
/**
* Adds a framed data in binary format
* @deprecated use {@link #add(byte[], int, int, String, String, XContentType)}
*/
@Deprecated
public BulkRequest add(byte[] data, int from, int length, @Nullable String defaultIndex, @Nullable String defaultType) throws IOException {
return add(new BytesArray(data, from, length), defaultIndex, defaultType);
}
@ -259,6 +271,17 @@ public class BulkRequest extends ActionRequest implements CompositeIndicesReques
/**
* Adds a framed data in binary format
*/
public BulkRequest add(byte[] data, int from, int length, @Nullable String defaultIndex, @Nullable String defaultType,
XContentType xContentType) throws IOException {
return add(new BytesArray(data, from, length), defaultIndex, defaultType, xContentType);
}
/**
* Adds a framed data in binary format
*
* @deprecated use {@link #add(BytesReference, String, String, XContentType)}
*/
@Deprecated
public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Nullable String defaultType) throws IOException {
return add(data, defaultIndex, defaultType, null, null, null, null, null, true);
}
@ -266,12 +289,40 @@ public class BulkRequest extends ActionRequest implements CompositeIndicesReques
/**
* Adds a framed data in binary format
*/
public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Nullable String defaultType,
XContentType xContentType) throws IOException {
return add(data, defaultIndex, defaultType, null, null, null, null, null, true, xContentType);
}
/**
* Adds a framed data in binary format
*
* @deprecated use {@link #add(BytesReference, String, String, boolean, XContentType)}
*/
@Deprecated
public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Nullable String defaultType, boolean allowExplicitIndex) throws IOException {
return add(data, defaultIndex, defaultType, null, null, null, null, null, allowExplicitIndex);
}
/**
* Adds a framed data in binary format
*/
public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Nullable String defaultType, boolean allowExplicitIndex,
XContentType xContentType) throws IOException {
return add(data, defaultIndex, defaultType, null, null, null, null, null, allowExplicitIndex, xContentType);
}
@Deprecated
public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Nullable String defaultType, @Nullable String defaultRouting, @Nullable String[] defaultFields, @Nullable FetchSourceContext defaultFetchSourceContext, @Nullable String defaultPipeline, @Nullable Object payload, boolean allowExplicitIndex) throws IOException {
XContent xContent = XContentFactory.xContent(data);
XContentType xContentType = XContentFactory.xContentType(data);
return add(data, defaultIndex, defaultType, defaultRouting, defaultFields, defaultFetchSourceContext, defaultPipeline, payload,
allowExplicitIndex, xContentType);
}
public BulkRequest add(BytesReference data, @Nullable String defaultIndex, @Nullable String defaultType, @Nullable String
defaultRouting, @Nullable String[] defaultFields, @Nullable FetchSourceContext defaultFetchSourceContext, @Nullable String
defaultPipeline, @Nullable Object payload, boolean allowExplicitIndex, XContentType xContentType) throws IOException {
XContent xContent = xContentType.xContent();
int line = 0;
int from = 0;
int length = data.length();
@ -387,16 +438,16 @@ public class BulkRequest extends ActionRequest implements CompositeIndicesReques
if ("index".equals(action)) {
if (opType == null) {
internalAdd(new IndexRequest(index, type, id).routing(routing).parent(parent).version(version).versionType(versionType)
.setPipeline(pipeline).source(data.slice(from, nextMarker - from)), payload);
.setPipeline(pipeline).source(data.slice(from, nextMarker - from), xContentType), payload);
} else {
internalAdd(new IndexRequest(index, type, id).routing(routing).parent(parent).version(version).versionType(versionType)
.create("create".equals(opType)).setPipeline(pipeline)
.source(data.slice(from, nextMarker - from)), payload);
.source(data.slice(from, nextMarker - from), xContentType), payload);
}
} else if ("create".equals(action)) {
internalAdd(new IndexRequest(index, type, id).routing(routing).parent(parent).version(version).versionType(versionType)
.create(true).setPipeline(pipeline)
.source(data.slice(from, nextMarker - from)), payload);
.source(data.slice(from, nextMarker - from), xContentType), payload);
} else if ("update".equals(action)) {
UpdateRequest updateRequest = new UpdateRequest(index, type, id).routing(routing).parent(parent).retryOnConflict(retryOnConflict)
.version(version).versionType(versionType)

View File

@ -32,6 +32,7 @@ import org.elasticsearch.action.update.UpdateRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
/**
* A bulk request holds an ordered {@link IndexRequest}s and {@link DeleteRequest}s and allows to executes
@ -97,7 +98,9 @@ public class BulkRequestBuilder extends ActionRequestBuilder<BulkRequest, BulkRe
/**
* Adds a framed data in binary format
* @deprecated use {@link #add(byte[], int, int, XContentType)}
*/
@Deprecated
public BulkRequestBuilder add(byte[] data, int from, int length) throws Exception {
request.add(data, from, length, null, null);
return this;
@ -106,11 +109,30 @@ public class BulkRequestBuilder extends ActionRequestBuilder<BulkRequest, BulkRe
/**
* Adds a framed data in binary format
*/
public BulkRequestBuilder add(byte[] data, int from, int length, XContentType xContentType) throws Exception {
request.add(data, from, length, null, null, xContentType);
return this;
}
/**
* Adds a framed data in binary format
* @deprecated use {@link #add(byte[], int, int, String, String, XContentType)}
*/
@Deprecated
public BulkRequestBuilder add(byte[] data, int from, int length, @Nullable String defaultIndex, @Nullable String defaultType) throws Exception {
request.add(data, from, length, defaultIndex, defaultType);
return this;
}
/**
* Adds a framed data in binary format
*/
public BulkRequestBuilder add(byte[] data, int from, int length, @Nullable String defaultIndex, @Nullable String defaultType,
XContentType xContentType) throws Exception {
request.add(data, from, length, defaultIndex, defaultType, xContentType);
return this;
}
/**
* Sets the number of shard copies that must be active before proceeding with the write.
* See {@link ReplicationRequest#waitForActiveShards(ActiveShardCount)} for details.

View File

@ -328,7 +328,7 @@ public class TransportShardBulkAction extends TransportWriteAction<BulkShardRequ
if ((updateRequest.fetchSource() != null && updateRequest.fetchSource().fetchSource()) ||
(updateRequest.fields() != null && updateRequest.fields().length > 0)) {
Tuple<XContentType, Map<String, Object>> sourceAndContent =
XContentHelper.convertToMap(indexSourceAsBytes, true);
XContentHelper.convertToMap(indexSourceAsBytes, true, updateIndexRequest.getContentType());
updateResponse.setGetResult(updateHelper.extractGetResult(updateRequest, request.index(),
indexResponse.getVersion(), sourceAndContent.v2(), sourceAndContent.v1(), indexSourceAsBytes));
}
@ -427,8 +427,9 @@ public class TransportShardBulkAction extends TransportWriteAction<BulkShardRequ
*/
public static Engine.IndexResult executeIndexRequestOnReplica(IndexRequest request, IndexShard replica) throws IOException {
final ShardId shardId = replica.shardId();
SourceToParse sourceToParse = SourceToParse.source(SourceToParse.Origin.REPLICA, shardId.getIndexName(), request.type(), request.id(), request.source())
.routing(request.routing()).parent(request.parent());
SourceToParse sourceToParse =
SourceToParse.source(SourceToParse.Origin.REPLICA, shardId.getIndexName(), request.type(), request.id(), request.source(),
request.getContentType()).routing(request.routing()).parent(request.parent());
final Engine.Index operation;
try {
@ -445,8 +446,9 @@ public class TransportShardBulkAction extends TransportWriteAction<BulkShardRequ
/** Utility method to prepare an index operation on primary shards */
static Engine.Index prepareIndexOperationOnPrimary(IndexRequest request, IndexShard primary) {
SourceToParse sourceToParse = SourceToParse.source(SourceToParse.Origin.PRIMARY, request.index(), request.type(), request.id(), request.source())
.routing(request.routing()).parent(request.parent());
SourceToParse sourceToParse =
SourceToParse.source(SourceToParse.Origin.PRIMARY, request.index(), request.type(), request.id(), request.source(),
request.getContentType()).routing(request.routing()).parent(request.parent());
return primary.prepareIndexOnPrimary(sourceToParse, request.version(), request.versionType(), request.getAutoGeneratedTimestamp(), request.isRetry());
}

View File

@ -37,6 +37,8 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.util.concurrent.AbstractRunnable;
import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.ParentFieldMapper;
import org.elasticsearch.index.mapper.RoutingFieldMapper;
import org.elasticsearch.search.SearchHit;
@ -232,6 +234,10 @@ public class ClientScrollableHitSource extends ScrollableHitSource {
return source;
}
@Override
public XContentType getXContentType() {
return XContentFactory.xContentType(source);
}
@Override
public long getVersion() {
return delegate.getVersion();

View File

@ -32,6 +32,7 @@ import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.threadpool.ThreadPool;
@ -80,7 +81,7 @@ public abstract class ScrollableHitSource implements Closeable {
});
}
protected abstract void doStartNextScroll(String scrollId, TimeValue extraKeepAlive, Consumer<? super Response> onResponse);
@Override
public final void close() {
String scrollId = this.scrollId.get();
@ -189,6 +190,10 @@ public abstract class ScrollableHitSource implements Closeable {
* all.
*/
@Nullable BytesReference getSource();
/**
* The content type of the hit source. Returns null if the source didn't come back from the search.
*/
@Nullable XContentType getXContentType();
/**
* The document id of the parent of the hit if there is a parent or null if there isn't.
*/
@ -209,6 +214,7 @@ public abstract class ScrollableHitSource implements Closeable {
private final long version;
private BytesReference source;
private XContentType xContentType;
private String parent;
private String routing;
@ -244,8 +250,14 @@ public abstract class ScrollableHitSource implements Closeable {
return source;
}
public BasicHit setSource(BytesReference source) {
@Override
public XContentType getXContentType() {
return xContentType;
}
public BasicHit setSource(BytesReference source, XContentType xContentType) {
this.source = source;
this.xContentType = xContentType;
return this;
}

View File

@ -47,6 +47,7 @@ import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.action.ValidateActions.addValidationError;
@ -55,10 +56,10 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
* created using {@link org.elasticsearch.client.Requests#indexRequest(String)}.
*
* The index requires the {@link #index()}, {@link #type(String)}, {@link #id(String)} and
* {@link #source(byte[])} to be set.
* {@link #source(byte[], XContentType)} to be set.
*
* The source (content to index) can be set in its bytes form using ({@link #source(byte[])}),
* its string form ({@link #source(String)}) or using a {@link org.elasticsearch.common.xcontent.XContentBuilder}
* The source (content to index) can be set in its bytes form using ({@link #source(byte[], XContentType)}),
* its string form ({@link #source(String, XContentType)}) or using a {@link org.elasticsearch.common.xcontent.XContentBuilder}
* ({@link #source(org.elasticsearch.common.xcontent.XContentBuilder)}).
*
* If the {@link #id(String)} is not set, it will be automatically generated.
@ -83,7 +84,7 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
private long version = Versions.MATCH_ANY;
private VersionType versionType = VersionType.INTERNAL;
private XContentType contentType = Requests.INDEX_CONTENT_TYPE;
private XContentType contentType;
private String pipeline;
@ -103,7 +104,7 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
/**
* Constructs a new index request against the specific index. The {@link #type(String)}
* {@link #source(byte[])} must be set.
* {@link #source(byte[], XContentType)} must be set.
*/
public IndexRequest(String index) {
this.index = index;
@ -140,7 +141,9 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
if (source == null) {
validationException = addValidationError("source is missing", validationException);
}
if (contentType == null) {
validationException = addValidationError("content type is missing", validationException);
}
final long resolvedVersion = resolveVersionDefaults();
if (opType() == OpType.CREATE) {
if (versionType != VersionType.INTERNAL) {
@ -179,20 +182,13 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
}
/**
* The content type that will be used when generating a document from user provided objects like Maps.
* The content type. This will be used when generating a document from user provided objects like Maps and when parsing the
* source at index time
*/
public XContentType getContentType() {
return contentType;
}
/**
* Sets the content type that will be used when generating a document from user provided objects (like Map).
*/
public IndexRequest contentType(XContentType contentType) {
this.contentType = contentType;
return this;
}
/**
* The type of the indexed document.
*/
@ -284,16 +280,16 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
}
public Map<String, Object> sourceAsMap() {
return XContentHelper.convertToMap(source, false).v2();
return XContentHelper.convertToMap(source, false, contentType).v2();
}
/**
* Index the Map as a {@link org.elasticsearch.client.Requests#INDEX_CONTENT_TYPE}.
* Index the Map in {@link Requests#INDEX_CONTENT_TYPE} format
*
* @param source The map to index
*/
public IndexRequest source(Map source) throws ElasticsearchGenerationException {
return source(source, contentType);
return source(source, Requests.INDEX_CONTENT_TYPE);
}
/**
@ -314,24 +310,32 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
/**
* Sets the document source to index.
*
* Note, its preferable to either set it using {@link #source(org.elasticsearch.common.xcontent.XContentBuilder)}
* or using the {@link #source(byte[])}.
* @deprecated use {@link #source(String, XContentType)}
*/
@Deprecated
public IndexRequest source(String source) {
this.source = new BytesArray(source.getBytes(StandardCharsets.UTF_8));
return this;
return source(new BytesArray(source), XContentFactory.xContentType(source));
}
/**
* Sets the document source to index.
*
* Note, its preferable to either set it using {@link #source(org.elasticsearch.common.xcontent.XContentBuilder)}
* or using the {@link #source(byte[], XContentType)}.
*/
public IndexRequest source(String source, XContentType xContentType) {
return source(new BytesArray(source), xContentType);
}
/**
* Sets the content source to index.
*/
public IndexRequest source(XContentBuilder sourceBuilder) {
source = sourceBuilder.bytes();
return this;
return source(sourceBuilder.bytes(), sourceBuilder.contentType());
}
/**
* Sets the content source to index.
* Sets the content source to index using the default content type ({@link Requests#INDEX_CONTENT_TYPE})
* <p>
* <b>Note: the number of objects passed to this method must be an even
* number. Also the first argument in each pair (the field name) must have a
@ -339,6 +343,18 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
* </p>
*/
public IndexRequest source(Object... source) {
return source(Requests.INDEX_CONTENT_TYPE, source);
}
/**
* Sets the content source to index.
* <p>
* <b>Note: the number of objects passed to this method as varargs must be an even
* number. Also the first argument in each pair (the field name) must have a
* valid String representation.</b>
* </p>
*/
public IndexRequest source(XContentType xContentType, Object... source) {
if (source.length % 2 != 0) {
throw new IllegalArgumentException("The number of object passed must be even but was [" + source.length + "]");
}
@ -346,7 +362,7 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
throw new IllegalArgumentException("you are using the removed method for source with bytes and unsafe flag, the unsafe flag was removed, please just use source(BytesReference)");
}
try {
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
XContentBuilder builder = XContentFactory.contentBuilder(xContentType);
builder.startObject();
for (int i = 0; i < source.length; i++) {
builder.field(source[i++].toString(), source[i]);
@ -360,19 +376,53 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
/**
* Sets the document to index in bytes form.
* @deprecated use {@link #source(BytesReference, XContentType)}
*/
@Deprecated
public IndexRequest source(BytesReference source) {
this.source = source;
return this;
return source(source, XContentFactory.xContentType(source));
}
/**
* Sets the document to index in bytes form.
*/
public IndexRequest source(BytesReference source, XContentType xContentType) {
this.source = Objects.requireNonNull(source);
this.contentType = Objects.requireNonNull(xContentType);
return this;
}
/**
* Sets the document to index in bytes form.
* @deprecated use {@link #source(byte[], XContentType)}
*/
@Deprecated
public IndexRequest source(byte[] source) {
return source(source, 0, source.length);
}
/**
* Sets the document to index in bytes form.
*/
public IndexRequest source(byte[] source, XContentType xContentType) {
return source(source, 0, source.length, xContentType);
}
/**
* Sets the document to index in bytes form (assumed to be safe to be used from different
* threads).
*
* @param source The source to index
* @param offset The offset in the byte array
* @param length The length of the data
* @deprecated use {@link #source(byte[], int, int, XContentType)}
*/
@Deprecated
public IndexRequest source(byte[] source, int offset, int length) {
return source(new BytesArray(source, offset, length), XContentFactory.xContentType(source));
}
/**
* Sets the document to index in bytes form (assumed to be safe to be used from different
* threads).
@ -381,9 +431,8 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
* @param offset The offset in the byte array
* @param length The length of the data
*/
public IndexRequest source(byte[] source, int offset, int length) {
this.source = new BytesArray(source, offset, length);
return this;
public IndexRequest source(byte[] source, int offset, int length, XContentType xContentType) {
return source(new BytesArray(source, offset, length), xContentType);
}
/**
@ -515,6 +564,11 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
pipeline = in.readOptionalString();
isRetry = in.readBoolean();
autoGeneratedTimestamp = in.readLong();
if (in.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
contentType = in.readOptionalWriteable(XContentType::readFrom);
} else {
contentType = XContentFactory.xContentType(source);
}
}
@Override
@ -543,6 +597,9 @@ public class IndexRequest extends ReplicatedWriteRequest<IndexRequest> implement
out.writeOptionalString(pipeline);
out.writeBoolean(isRetry);
out.writeLong(autoGeneratedTimestamp);
if (out.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
out.writeOptionalWriteable(contentType);
}
}
@Override

View File

@ -82,12 +82,22 @@ public class IndexRequestBuilder extends ReplicationRequestBuilder<IndexRequest,
/**
* Sets the source.
* @deprecated use {@link #setSource(BytesReference, XContentType)}
*/
@Deprecated
public IndexRequestBuilder setSource(BytesReference source) {
request.source(source);
return this;
}
/**
* Sets the source.
*/
public IndexRequestBuilder setSource(BytesReference source, XContentType xContentType) {
request.source(source, xContentType);
return this;
}
/**
* Index the Map as a JSON.
*
@ -112,13 +122,26 @@ public class IndexRequestBuilder extends ReplicationRequestBuilder<IndexRequest,
* Sets the document source to index.
* <p>
* Note, its preferable to either set it using {@link #setSource(org.elasticsearch.common.xcontent.XContentBuilder)}
* or using the {@link #setSource(byte[])}.
* or using the {@link #setSource(byte[], XContentType)}.
* @deprecated use {@link #setSource(String, XContentType)}
*/
@Deprecated
public IndexRequestBuilder setSource(String source) {
request.source(source);
return this;
}
/**
* Sets the document source to index.
* <p>
* Note, its preferable to either set it using {@link #setSource(org.elasticsearch.common.xcontent.XContentBuilder)}
* or using the {@link #setSource(byte[], XContentType)}.
*/
public IndexRequestBuilder setSource(String source, XContentType xContentType) {
request.source(source, xContentType);
return this;
}
/**
* Sets the content source to index.
*/
@ -129,12 +152,22 @@ public class IndexRequestBuilder extends ReplicationRequestBuilder<IndexRequest,
/**
* Sets the document to index in bytes form.
* @deprecated use {@link #setSource(byte[], XContentType)}
*/
@Deprecated
public IndexRequestBuilder setSource(byte[] source) {
request.source(source);
return this;
}
/**
* Sets the document to index in bytes form.
*/
public IndexRequestBuilder setSource(byte[] source, XContentType xContentType) {
request.source(source, xContentType);
return this;
}
/**
* Sets the document to index in bytes form (assumed to be safe to be used from different
* threads).
@ -142,12 +175,28 @@ public class IndexRequestBuilder extends ReplicationRequestBuilder<IndexRequest,
* @param source The source to index
* @param offset The offset in the byte array
* @param length The length of the data
* @deprecated use {@link #setSource(byte[], int, int, XContentType)}
*/
@Deprecated
public IndexRequestBuilder setSource(byte[] source, int offset, int length) {
request.source(source, offset, length);
return this;
}
/**
* Sets the document to index in bytes form (assumed to be safe to be used from different
* threads).
*
* @param source The source to index
* @param offset The offset in the byte array
* @param length The length of the data
* @param xContentType The type/format of the source
*/
public IndexRequestBuilder setSource(byte[] source, int offset, int length, XContentType xContentType) {
request.source(source, offset, length, xContentType);
return this;
}
/**
* Constructs a simple document with a field name and value pairs.
* <p>
@ -162,10 +211,15 @@ public class IndexRequestBuilder extends ReplicationRequestBuilder<IndexRequest,
}
/**
* The content type that will be used to generate a document from user provided objects (like Map).
* Constructs a simple document with a field name and value pairs.
* <p>
* <b>Note: the number of objects passed as varargs to this method must be an even
* number. Also the first argument in each pair (the field name) must have a
* valid String representation.</b>
* </p>
*/
public IndexRequestBuilder setContentType(XContentType contentType) {
request.contentType(contentType);
public IndexRequestBuilder setSource(XContentType xContentType, Object... source) {
request.source(xContentType, source);
return this;
}

View File

@ -19,32 +19,40 @@
package org.elasticsearch.action.ingest;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.AcknowledgedRequest;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.Objects;
import static org.elasticsearch.action.ValidateActions.addValidationError;
public class PutPipelineRequest extends AcknowledgedRequest<PutPipelineRequest> {
private String id;
private BytesReference source;
private XContentType xContentType;
/**
* Create a new pipeline request
* @deprecated use {@link #PutPipelineRequest(String, BytesReference, XContentType)} to avoid content type auto-detection
*/
@Deprecated
public PutPipelineRequest(String id, BytesReference source) {
if (id == null) {
throw new IllegalArgumentException("id is missing");
}
if (source == null) {
throw new IllegalArgumentException("source is missing");
}
this(id, source, XContentFactory.xContentType(source));
}
this.id = id;
this.source = source;
/**
* Create a new pipeline request with the id and source along with the content type of the source
*/
public PutPipelineRequest(String id, BytesReference source, XContentType xContentType) {
this.id = Objects.requireNonNull(id);
this.source = Objects.requireNonNull(source);
this.xContentType = Objects.requireNonNull(xContentType);
}
PutPipelineRequest() {
@ -63,11 +71,20 @@ public class PutPipelineRequest extends AcknowledgedRequest<PutPipelineRequest>
return source;
}
public XContentType getXContentType() {
return xContentType;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
id = in.readString();
source = in.readBytesReference();
if (in.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType = XContentType.readFrom(in);
} else {
xContentType = XContentFactory.xContentType(source);
}
}
@Override
@ -75,5 +92,8 @@ public class PutPipelineRequest extends AcknowledgedRequest<PutPipelineRequest>
super.writeTo(out);
out.writeString(id);
out.writeBytesReference(source);
if (out.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType.writeTo(out);
}
}
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.action.ingest;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentType;
public class PutPipelineRequestBuilder extends ActionRequestBuilder<PutPipelineRequest, WritePipelineResponse, PutPipelineRequestBuilder> {
@ -29,8 +30,13 @@ public class PutPipelineRequestBuilder extends ActionRequestBuilder<PutPipelineR
super(client, action, new PutPipelineRequest());
}
@Deprecated
public PutPipelineRequestBuilder(ElasticsearchClient client, PutPipelineAction action, String id, BytesReference source) {
super(client, action, new PutPipelineRequest(id, source));
}
public PutPipelineRequestBuilder(ElasticsearchClient client, PutPipelineAction action, String id, BytesReference source,
XContentType xContentType) {
super(client, action, new PutPipelineRequest(id, source, xContentType));
}
}

View File

@ -19,11 +19,14 @@
package org.elasticsearch.action.ingest;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequest;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.ingest.ConfigurationUtils;
import org.elasticsearch.ingest.IngestDocument;
import org.elasticsearch.ingest.Pipeline;
@ -34,6 +37,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static org.elasticsearch.ingest.IngestDocument.MetaData;
@ -42,12 +46,23 @@ public class SimulatePipelineRequest extends ActionRequest {
private String id;
private boolean verbose;
private BytesReference source;
private XContentType xContentType;
/**
* Create a new request
* @deprecated use {@link #SimulatePipelineRequest(BytesReference, XContentType)} that does not attempt content autodetection
*/
@Deprecated
public SimulatePipelineRequest(BytesReference source) {
if (source == null) {
throw new IllegalArgumentException("source is missing");
}
this.source = source;
this(source, XContentFactory.xContentType(source));
}
/**
* Creates a new request with the given source and its content type
*/
public SimulatePipelineRequest(BytesReference source, XContentType xContentType) {
this.source = Objects.requireNonNull(source);
this.xContentType = Objects.requireNonNull(xContentType);
}
SimulatePipelineRequest() {
@ -78,12 +93,21 @@ public class SimulatePipelineRequest extends ActionRequest {
return source;
}
public XContentType getXContentType() {
return xContentType;
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
id = in.readOptionalString();
verbose = in.readBoolean();
source = in.readBytesReference();
if (in.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType = XContentType.readFrom(in);
} else {
xContentType = XContentFactory.xContentType(source);
}
}
@Override
@ -92,6 +116,9 @@ public class SimulatePipelineRequest extends ActionRequest {
out.writeOptionalString(id);
out.writeBoolean(verbose);
out.writeBytesReference(source);
if (out.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType.writeTo(out);
}
}
public static final class Fields {

View File

@ -22,22 +22,46 @@ package org.elasticsearch.action.ingest;
import org.elasticsearch.action.ActionRequestBuilder;
import org.elasticsearch.client.ElasticsearchClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentType;
public class SimulatePipelineRequestBuilder extends ActionRequestBuilder<SimulatePipelineRequest, SimulatePipelineResponse, SimulatePipelineRequestBuilder> {
/**
* Create a new builder for {@link SimulatePipelineRequest}s
*/
public SimulatePipelineRequestBuilder(ElasticsearchClient client, SimulatePipelineAction action) {
super(client, action, new SimulatePipelineRequest());
}
/**
* Create a new builder for {@link SimulatePipelineRequest}s
* @deprecated use {@link #SimulatePipelineRequestBuilder(ElasticsearchClient, SimulatePipelineAction, BytesReference, XContentType)} to
* avoid content type auto-detection on the source bytes
*/
@Deprecated
public SimulatePipelineRequestBuilder(ElasticsearchClient client, SimulatePipelineAction action, BytesReference source) {
super(client, action, new SimulatePipelineRequest(source));
}
/**
* Create a new builder for {@link SimulatePipelineRequest}s
*/
public SimulatePipelineRequestBuilder(ElasticsearchClient client, SimulatePipelineAction action, BytesReference source,
XContentType xContentType) {
super(client, action, new SimulatePipelineRequest(source, xContentType));
}
/**
* Set the id for the pipeline to simulate
*/
public SimulatePipelineRequestBuilder setId(String id) {
request.setId(id);
return this;
}
/**
* Enable or disable verbose mode
*/
public SimulatePipelineRequestBuilder setVerbose(boolean verbose) {
request.setVerbose(verbose);
return this;

View File

@ -47,7 +47,7 @@ public class SimulatePipelineTransportAction extends HandledTransportAction<Simu
@Override
protected void doExecute(SimulatePipelineRequest request, ActionListener<SimulatePipelineResponse> listener) {
final Map<String, Object> source = XContentHelper.convertToMap(request.getSource(), false).v2();
final Map<String, Object> source = XContentHelper.convertToMap(request.getSource(), false, request.getXContentType()).v2();
final SimulatePipelineRequest.Parsed simulateRequest;
try {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.action.termvectors;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.RealtimeRequest;
import org.elasticsearch.action.ValidateActions;
@ -33,7 +34,9 @@ import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.VersionType;
import java.io.IOException;
@ -63,6 +66,8 @@ public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> i
private BytesReference doc;
private XContentType xContentType;
private String routing;
private String parent;
@ -156,8 +161,9 @@ public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> i
super(other.index());
this.id = other.id();
this.type = other.type();
if (this.doc != null) {
if (other.doc != null) {
this.doc = new BytesArray(other.doc().toBytesRef(), true);
this.xContentType = other.xContentType;
}
this.flagsEnum = other.getFlags().clone();
this.preference = other.preference();
@ -225,22 +231,36 @@ public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> i
return doc;
}
/**
* Sets an artificial document from which term vectors are requested for.
*/
public TermVectorsRequest doc(XContentBuilder documentBuilder) {
return this.doc(documentBuilder.bytes(), true);
public XContentType xContentType() {
return xContentType;
}
/**
* Sets an artificial document from which term vectors are requested for.
*/
public TermVectorsRequest doc(XContentBuilder documentBuilder) {
return this.doc(documentBuilder.bytes(), true, documentBuilder.contentType());
}
/**
* Sets an artificial document from which term vectors are requested for.
* @deprecated use {@link #doc(BytesReference, boolean, XContentType)} to avoid content auto detection
*/
@Deprecated
public TermVectorsRequest doc(BytesReference doc, boolean generateRandomId) {
return this.doc(doc, generateRandomId, XContentFactory.xContentType(doc));
}
/**
* Sets an artificial document from which term vectors are requested for.
*/
public TermVectorsRequest doc(BytesReference doc, boolean generateRandomId, XContentType xContentType) {
// assign a random id to this artificial document, for routing
if (generateRandomId) {
this.id(String.valueOf(randomInt.getAndAdd(1)));
}
this.doc = doc;
this.xContentType = xContentType;
return this;
}
@ -479,6 +499,11 @@ public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> i
if (in.readBoolean()) {
doc = in.readBytesReference();
if (in.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType = XContentType.readFrom(in);
} else {
xContentType = XContentFactory.xContentType(doc);
}
}
routing = in.readOptionalString();
parent = in.readOptionalString();
@ -519,6 +544,9 @@ public class TermVectorsRequest extends SingleShardRequest<TermVectorsRequest> i
out.writeBoolean(doc != null);
if (doc != null) {
out.writeBytesReference(doc);
if (out.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType.writeTo(out);
}
}
out.writeOptionalString(routing);
out.writeOptionalString(parent);

View File

@ -186,7 +186,8 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
UpdateResponse update = new UpdateResponse(response.getShardInfo(), response.getShardId(), response.getType(), response.getId(), response.getSeqNo(), response.getVersion(), response.getResult());
if ((request.fetchSource() != null && request.fetchSource().fetchSource()) ||
(request.fields() != null && request.fields().length > 0)) {
Tuple<XContentType, Map<String, Object>> sourceAndContent = XContentHelper.convertToMap(upsertSourceBytes, true);
Tuple<XContentType, Map<String, Object>> sourceAndContent =
XContentHelper.convertToMap(upsertSourceBytes, true, upsertRequest.getContentType());
update.setGetResult(updateHelper.extractGetResult(request, request.concreteIndex(), response.getVersion(), sourceAndContent.v2(), sourceAndContent.v1(), upsertSourceBytes));
} else {
update.setGetResult(null);

View File

@ -29,8 +29,6 @@ import org.elasticsearch.action.support.single.instance.InstanceShardOperationRe
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
@ -52,8 +50,6 @@ import static org.elasticsearch.action.ValidateActions.addValidationError;
public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
implements DocWriteRequest<UpdateRequest>, WriteRequest<UpdateRequest> {
private static final DeprecationLogger DEPRECATION_LOGGER =
new DeprecationLogger(Loggers.getLogger(UpdateRequest.class));
private String type;
private String id;
@ -559,7 +555,9 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
/**
* Sets the doc to use for updates when a script is not specified.
* @deprecated use {@link #doc(String, XContentType)}
*/
@Deprecated
public UpdateRequest doc(String source) {
safeDoc().source(source);
return this;
@ -568,6 +566,16 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
/**
* Sets the doc to use for updates when a script is not specified.
*/
public UpdateRequest doc(String source, XContentType xContentType) {
safeDoc().source(source, xContentType);
return this;
}
/**
* Sets the doc to use for updates when a script is not specified.
* @deprecated use {@link #doc(byte[], XContentType)}
*/
@Deprecated
public UpdateRequest doc(byte[] source) {
safeDoc().source(source);
return this;
@ -576,11 +584,29 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
/**
* Sets the doc to use for updates when a script is not specified.
*/
public UpdateRequest doc(byte[] source, XContentType xContentType) {
safeDoc().source(source, xContentType);
return this;
}
/**
* Sets the doc to use for updates when a script is not specified.
* @deprecated use {@link #doc(byte[], int, int, XContentType)}
*/
@Deprecated
public UpdateRequest doc(byte[] source, int offset, int length) {
safeDoc().source(source, offset, length);
return this;
}
/**
* Sets the doc to use for updates when a script is not specified.
*/
public UpdateRequest doc(byte[] source, int offset, int length, XContentType xContentType) {
safeDoc().source(source, offset, length, xContentType);
return this;
}
/**
* Sets the doc to use for updates when a script is not specified, the doc provided
* is a field and value pairs.
@ -591,10 +617,11 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
}
/**
* Sets the doc to use for updates when a script is not specified.
* Sets the doc to use for updates when a script is not specified, the doc provided
* is a field and value pairs.
*/
public UpdateRequest doc(String field, Object value) {
safeDoc().source(field, value);
public UpdateRequest doc(XContentType xContentType, Object... source) {
safeDoc().source(xContentType, source);
return this;
}
@ -644,7 +671,9 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
/**
* Sets the doc source of the update request to be used when the document does not exists.
* @deprecated use {@link #upsert(String, XContentType)}
*/
@Deprecated
public UpdateRequest upsert(String source) {
safeUpsertRequest().source(source);
return this;
@ -653,6 +682,16 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
/**
* Sets the doc source of the update request to be used when the document does not exists.
*/
public UpdateRequest upsert(String source, XContentType xContentType) {
safeUpsertRequest().source(source, xContentType);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists.
* @deprecated use {@link #upsert(byte[], XContentType)}
*/
@Deprecated
public UpdateRequest upsert(byte[] source) {
safeUpsertRequest().source(source);
return this;
@ -661,11 +700,29 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
/**
* Sets the doc source of the update request to be used when the document does not exists.
*/
public UpdateRequest upsert(byte[] source, XContentType xContentType) {
safeUpsertRequest().source(source, xContentType);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists.
* @deprecated use {@link #upsert(byte[], int, int, XContentType)}
*/
@Deprecated
public UpdateRequest upsert(byte[] source, int offset, int length) {
safeUpsertRequest().source(source, offset, length);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists.
*/
public UpdateRequest upsert(byte[] source, int offset, int length, XContentType xContentType) {
safeUpsertRequest().source(source, offset, length, xContentType);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists. The doc
* includes field and value pairs.
@ -675,6 +732,15 @@ public class UpdateRequest extends InstanceShardOperationRequest<UpdateRequest>
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists. The doc
* includes field and value pairs.
*/
public UpdateRequest upsert(XContentType xContentType, Object... source) {
safeUpsertRequest().source(xContentType, source);
return this;
}
public IndexRequest upsertRequest() {
return this.upsertRequest;
}

View File

@ -223,7 +223,9 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
/**
* Sets the doc to use for updates when a script is not specified.
* @deprecated use {@link #setDoc(String, XContentType)}
*/
@Deprecated
public UpdateRequestBuilder setDoc(String source) {
request.doc(source);
return this;
@ -232,6 +234,16 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
/**
* Sets the doc to use for updates when a script is not specified.
*/
public UpdateRequestBuilder setDoc(String source, XContentType xContentType) {
request.doc(source, xContentType);
return this;
}
/**
* Sets the doc to use for updates when a script is not specified.
* @deprecated use {@link #setDoc(byte[], XContentType)}
*/
@Deprecated
public UpdateRequestBuilder setDoc(byte[] source) {
request.doc(source);
return this;
@ -240,6 +252,16 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
/**
* Sets the doc to use for updates when a script is not specified.
*/
public UpdateRequestBuilder setDoc(byte[] source, XContentType xContentType) {
request.doc(source, xContentType);
return this;
}
/**
* Sets the doc to use for updates when a script is not specified.
* @deprecated use {@link #setDoc(byte[], int, int, XContentType)}
*/
@Deprecated
public UpdateRequestBuilder setDoc(byte[] source, int offset, int length) {
request.doc(source, offset, length);
return this;
@ -248,8 +270,8 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
/**
* Sets the doc to use for updates when a script is not specified.
*/
public UpdateRequestBuilder setDoc(String field, Object value) {
request.doc(field, value);
public UpdateRequestBuilder setDoc(byte[] source, int offset, int length, XContentType xContentType) {
request.doc(source, offset, length, xContentType);
return this;
}
@ -262,6 +284,15 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
return this;
}
/**
* Sets the doc to use for updates when a script is not specified, the doc provided
* is a field and value pairs.
*/
public UpdateRequestBuilder setDoc(XContentType xContentType, Object... source) {
request.doc(xContentType, source);
return this;
}
/**
* Sets the index request to be used if the document does not exists. Otherwise, a {@link org.elasticsearch.index.engine.DocumentMissingException}
* is thrown.
@ -297,7 +328,9 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
/**
* Sets the doc source of the update request to be used when the document does not exists.
* @deprecated use {@link #setUpsert(String, XContentType)}
*/
@Deprecated
public UpdateRequestBuilder setUpsert(String source) {
request.upsert(source);
return this;
@ -306,6 +339,16 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
/**
* Sets the doc source of the update request to be used when the document does not exists.
*/
public UpdateRequestBuilder setUpsert(String source, XContentType xContentType) {
request.upsert(source, xContentType);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists.
* @deprecated use {@link #setDoc(byte[], XContentType)}
*/
@Deprecated
public UpdateRequestBuilder setUpsert(byte[] source) {
request.upsert(source);
return this;
@ -314,11 +357,29 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
/**
* Sets the doc source of the update request to be used when the document does not exists.
*/
public UpdateRequestBuilder setUpsert(byte[] source, XContentType xContentType) {
request.upsert(source, xContentType);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists.
* @deprecated use {@link #setUpsert(byte[], int, int, XContentType)}
*/
@Deprecated
public UpdateRequestBuilder setUpsert(byte[] source, int offset, int length) {
request.upsert(source, offset, length);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists.
*/
public UpdateRequestBuilder setUpsert(byte[] source, int offset, int length, XContentType xContentType) {
request.upsert(source, offset, length, xContentType);
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists. The doc
* includes field and value pairs.
@ -328,6 +389,15 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
return this;
}
/**
* Sets the doc source of the update request to be used when the document does not exists. The doc
* includes field and value pairs.
*/
public UpdateRequestBuilder setUpsert(XContentType xContentType, Object... source) {
request.upsert(xContentType, source);
return this;
}
/**
* Sets whether the specified doc parameter should be used as upsert document.
*/

View File

@ -112,6 +112,7 @@ import org.elasticsearch.action.ingest.SimulatePipelineResponse;
import org.elasticsearch.action.ingest.WritePipelineResponse;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.tasks.TaskId;
/**
@ -545,9 +546,16 @@ public interface ClusterAdminClient extends ElasticsearchClient {
/**
* Stores an ingest pipeline
* @deprecated use {@link #preparePutPipeline(String, BytesReference, XContentType)}
*/
@Deprecated
PutPipelineRequestBuilder preparePutPipeline(String id, BytesReference source);
/**
* Stores an ingest pipeline
*/
PutPipelineRequestBuilder preparePutPipeline(String id, BytesReference source, XContentType xContentType);
/**
* Deletes a stored ingest pipeline
*/
@ -596,8 +604,14 @@ public interface ClusterAdminClient extends ElasticsearchClient {
/**
* Simulates an ingest pipeline
*/
@Deprecated
SimulatePipelineRequestBuilder prepareSimulatePipeline(BytesReference source);
/**
* Simulates an ingest pipeline
*/
SimulatePipelineRequestBuilder prepareSimulatePipeline(BytesReference source, XContentType xContentType);
/**
* Explain the allocation of a shard
*/

View File

@ -343,6 +343,7 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.tasks.TaskId;
import org.elasticsearch.threadpool.ThreadPool;
@ -1081,6 +1082,11 @@ public abstract class AbstractClient extends AbstractComponent implements Client
return new PutPipelineRequestBuilder(this, PutPipelineAction.INSTANCE, id, source);
}
@Override
public PutPipelineRequestBuilder preparePutPipeline(String id, BytesReference source, XContentType xContentType) {
return new PutPipelineRequestBuilder(this, PutPipelineAction.INSTANCE, id, source, xContentType);
}
@Override
public void deletePipeline(DeletePipelineRequest request, ActionListener<WritePipelineResponse> listener) {
execute(DeletePipelineAction.INSTANCE, request, listener);
@ -1131,6 +1137,11 @@ public abstract class AbstractClient extends AbstractComponent implements Client
return new SimulatePipelineRequestBuilder(this, SimulatePipelineAction.INSTANCE, source);
}
@Override
public SimulatePipelineRequestBuilder prepareSimulatePipeline(BytesReference source, XContentType xContentType) {
return new SimulatePipelineRequestBuilder(this, SimulatePipelineAction.INSTANCE, source, xContentType);
}
@Override
public void allocationExplain(ClusterAllocationExplainRequest request, ActionListener<ClusterAllocationExplainResponse> listener) {
execute(ClusterAllocationExplainAction.INSTANCE, request, listener);

View File

@ -26,6 +26,7 @@ import org.elasticsearch.cluster.AbstractDiffable;
import org.elasticsearch.cluster.Diff;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.compress.CompressedXContent;

View File

@ -265,11 +265,13 @@ public class MetaDataCreateIndexService extends AbstractComponent {
for (IndexTemplateMetaData template : templates) {
templateNames.add(template.getName());
for (ObjectObjectCursor<String, CompressedXContent> cursor : template.mappings()) {
String mappingString = cursor.value.string();
if (mappings.containsKey(cursor.key)) {
XContentHelper.mergeDefaults(mappings.get(cursor.key),
MapperService.parseMapping(xContentRegistry, cursor.value.string()));
MapperService.parseMapping(xContentRegistry, mappingString));
} else {
mappings.put(cursor.key, MapperService.parseMapping(xContentRegistry, cursor.value.string()));
mappings.put(cursor.key,
MapperService.parseMapping(xContentRegistry, mappingString));
}
}
// handle custom

View File

@ -237,6 +237,7 @@ public final class ClusterSettings extends AbstractScopedSettings {
HttpTransportSettings.SETTING_CORS_ALLOW_METHODS,
HttpTransportSettings.SETTING_CORS_ALLOW_HEADERS,
HttpTransportSettings.SETTING_HTTP_DETAILED_ERRORS_ENABLED,
HttpTransportSettings.SETTING_HTTP_CONTENT_TYPE_REQUIRED,
HttpTransportSettings.SETTING_HTTP_MAX_CONTENT_LENGTH,
HttpTransportSettings.SETTING_HTTP_MAX_CHUNK_SIZE,
HttpTransportSettings.SETTING_HTTP_MAX_HEADER_SIZE,

View File

@ -37,6 +37,7 @@ import org.elasticsearch.common.unit.SizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.io.InputStream;
@ -960,7 +961,9 @@ public final class Settings implements ToXContent {
/**
* Loads settings from the actual string content that represents them using the
* {@link SettingsLoaderFactory#loaderFromSource(String)}.
* @deprecated use {@link #loadFromSource(String, XContentType)} to avoid content type detection
*/
@Deprecated
public Builder loadFromSource(String source) {
SettingsLoader settingsLoader = SettingsLoaderFactory.loaderFromSource(source);
try {
@ -972,9 +975,24 @@ public final class Settings implements ToXContent {
return this;
}
/**
* Loads settings from the actual string content that represents them using the
* {@link SettingsLoaderFactory#loaderFromXContentType(XContentType)} method to obtain a loader
*/
public Builder loadFromSource(String source, XContentType xContentType) {
SettingsLoader settingsLoader = SettingsLoaderFactory.loaderFromXContentType(xContentType);
try {
Map<String, String> loadedSettings = settingsLoader.load(source);
put(loadedSettings);
} catch (Exception e) {
throw new SettingsException("Failed to load settings from [" + source + "]", e);
}
return this;
}
/**
* Loads settings from a url that represents them using the
* {@link SettingsLoaderFactory#loaderFromSource(String)}.
* {@link SettingsLoaderFactory#loaderFromResource(String)}.
*/
public Builder loadFromPath(Path path) throws IOException {
// NOTE: loadFromStream will close the input stream
@ -983,7 +1001,7 @@ public final class Settings implements ToXContent {
/**
* Loads settings from a stream that represents them using the
* {@link SettingsLoaderFactory#loaderFromSource(String)}.
* {@link SettingsLoaderFactory#loaderFromResource(String)}.
*/
public Builder loadFromStream(String resourceName, InputStream is) throws IOException {
SettingsLoader settingsLoader = SettingsLoaderFactory.loaderFromResource(resourceName);

View File

@ -19,6 +19,8 @@
package org.elasticsearch.common.settings.loader;
import org.elasticsearch.common.xcontent.XContentType;
/**
* A class holding factory methods for settings loaders that attempts
* to infer the type of the underlying settings content.
@ -33,9 +35,7 @@ public final class SettingsLoaderFactory {
* name. This factory method assumes that if the resource name ends
* with ".json" then the content should be parsed as JSON, else if
* the resource name ends with ".yml" or ".yaml" then the content
* should be parsed as YAML, else if the resource name ends with
* ".properties" then the content should be parsed as properties,
* otherwise default to attempting to parse as JSON. Note that the
* should be parsed as YAML, otherwise throws an exception. Note that the
* parsers returned by this method will not accept null-valued
* keys.
*
@ -59,13 +59,15 @@ public final class SettingsLoaderFactory {
* contains an opening and closing brace ('{' and '}') then the
* content should be parsed as JSON, else if the underlying content
* fails this condition but contains a ':' then the content should
* be parsed as YAML, and otherwise should be parsed as properties.
* be parsed as YAML, and otherwise throws an exception.
* Note that the JSON and YAML parsers returned by this method will
* accept null-valued keys.
*
* @param source The underlying settings content.
* @return A settings loader.
* @deprecated use {@link #loaderFromXContentType(XContentType)} instead
*/
@Deprecated
public static SettingsLoader loaderFromSource(String source) {
if (source.indexOf('{') != -1 && source.indexOf('}') != -1) {
return new JsonSettingsLoader(true);
@ -76,4 +78,20 @@ public final class SettingsLoaderFactory {
}
}
/**
* Returns a {@link SettingsLoader} based on the {@link XContentType}. Note only {@link XContentType#JSON} and
* {@link XContentType#YAML} are supported
*
* @param xContentType The content type
* @return A settings loader.
*/
public static SettingsLoader loaderFromXContentType(XContentType xContentType) {
if (xContentType == XContentType.JSON) {
return new JsonSettingsLoader(true);
} else if (xContentType == XContentType.YAML) {
return new YamlSettingsLoader(true);
} else {
throw new IllegalArgumentException("unsupported content type [" + xContentType + "]");
}
}
}

View File

@ -964,21 +964,60 @@ public final class XContentBuilder implements BytesStream, Releasable, Flushable
// Raw fields
//////////////////////////////////
/**
* Writes a raw field with the value taken from the bytes in the stream
* @deprecated use {@link #rawField(String, InputStream, XContentType)} to avoid content type auto-detection
*/
@Deprecated
public XContentBuilder rawField(String name, InputStream value) throws IOException {
generator.writeRawField(name, value);
return this;
}
/**
* Writes a raw field with the value taken from the bytes in the stream
*/
public XContentBuilder rawField(String name, InputStream value, XContentType contentType) throws IOException {
generator.writeRawField(name, value, contentType);
return this;
}
/**
* Writes a raw field with the given bytes as the value
* @deprecated use {@link #rawField(String name, BytesReference, XContentType)} to avoid content type auto-detection
*/
@Deprecated
public XContentBuilder rawField(String name, BytesReference value) throws IOException {
generator.writeRawField(name, value);
return this;
}
/**
* Writes a raw field with the given bytes as the value
*/
public XContentBuilder rawField(String name, BytesReference value, XContentType contentType) throws IOException {
generator.writeRawField(name, value, contentType);
return this;
}
/**
* Writes a value with the source coming directly from the bytes
* @deprecated use {@link #rawValue(BytesReference, XContentType)} to avoid content type auto-detection
*/
@Deprecated
public XContentBuilder rawValue(BytesReference value) throws IOException {
generator.writeRawValue(value);
return this;
}
/**
* Writes a value with the source coming directly from the bytes
*/
public XContentBuilder rawValue(BytesReference value, XContentType contentType) throws IOException {
generator.writeRawValue(value, contentType);
return this;
}
public XContentBuilder copyCurrentStructure(XContentParser parser) throws IOException {
generator.copyCurrentStructure(parser);
return this;

View File

@ -86,12 +86,42 @@ public interface XContentGenerator extends Closeable, Flushable {
void writeBinary(byte[] value, int offset, int length) throws IOException;
/**
* Writes a raw field with the value taken from the bytes in the stream
* @deprecated use {@link #writeRawField(String, InputStream, XContentType)} to avoid content type auto-detection
*/
@Deprecated
void writeRawField(String name, InputStream value) throws IOException;
/**
* Writes a raw field with the value taken from the bytes in the stream
*/
void writeRawField(String name, InputStream value, XContentType xContentType) throws IOException;
/**
* Writes a raw field with the given bytes as the value
* @deprecated use {@link #writeRawField(String, BytesReference, XContentType)} to avoid content type auto-detection
*/
@Deprecated
void writeRawField(String name, BytesReference value) throws IOException;
/**
* Writes a raw field with the given bytes as the value
*/
void writeRawField(String name, BytesReference value, XContentType xContentType) throws IOException;
/**
* Writes a value with the source coming directly from the bytes
* @deprecated use {@link #writeRawValue(BytesReference, XContentType)} to avoid content type auto-detection
*/
@Deprecated
void writeRawValue(BytesReference value) throws IOException;
/**
* Writes a value with the source coming directly from the bytes
*/
void writeRawValue(BytesReference value, XContentType xContentType) throws IOException;
void copyCurrentStructure(XContentParser parser) throws IOException;
/**

View File

@ -41,6 +41,11 @@ import static org.elasticsearch.common.xcontent.ToXContent.EMPTY_PARAMS;
@SuppressWarnings("unchecked")
public class XContentHelper {
/**
* Creates a parser based on the bytes provided
* @deprecated use {@link #createParser(NamedXContentRegistry, BytesReference, XContentType)} to avoid content type auto-detection
*/
@Deprecated
public static XContentParser createParser(NamedXContentRegistry xContentRegistry, BytesReference bytes) throws IOException {
Compressor compressor = CompressorFactory.compressor(bytes);
if (compressor != null) {
@ -48,17 +53,49 @@ public class XContentHelper {
if (compressedInput.markSupported() == false) {
compressedInput = new BufferedInputStream(compressedInput);
}
XContentType contentType = XContentFactory.xContentType(compressedInput);
final XContentType contentType = XContentFactory.xContentType(compressedInput);
return XContentFactory.xContent(contentType).createParser(xContentRegistry, compressedInput);
} else {
return XContentFactory.xContent(bytes).createParser(xContentRegistry, bytes.streamInput());
}
}
/**
* Creates a parser for the bytes using the supplied content-type
*/
public static XContentParser createParser(NamedXContentRegistry xContentRegistry, BytesReference bytes,
XContentType xContentType) throws IOException {
Objects.requireNonNull(xContentType);
Compressor compressor = CompressorFactory.compressor(bytes);
if (compressor != null) {
InputStream compressedInput = compressor.streamInput(bytes.streamInput());
if (compressedInput.markSupported() == false) {
compressedInput = new BufferedInputStream(compressedInput);
}
return XContentFactory.xContent(xContentType).createParser(xContentRegistry, compressedInput);
} else {
return xContentType.xContent().createParser(xContentRegistry, bytes.streamInput());
}
}
/**
* Converts the given bytes into a map that is optionally ordered.
* @deprecated this method relies on auto-detection of content type. Use {@link #convertToMap(BytesReference, boolean, XContentType)}
* instead with the proper {@link XContentType}
*/
@Deprecated
public static Tuple<XContentType, Map<String, Object>> convertToMap(BytesReference bytes, boolean ordered)
throws ElasticsearchParseException {
return convertToMap(bytes, ordered, null);
}
/**
* Converts the given bytes into a map that is optionally ordered. The provided {@link XContentType} must be non-null.
*/
public static Tuple<XContentType, Map<String, Object>> convertToMap(BytesReference bytes, boolean ordered, XContentType xContentType)
throws ElasticsearchParseException {
try {
XContentType contentType;
final XContentType contentType;
InputStream input;
Compressor compressor = CompressorFactory.compressor(bytes);
if (compressor != null) {
@ -66,13 +103,12 @@ public class XContentHelper {
if (compressedStreamInput.markSupported() == false) {
compressedStreamInput = new BufferedInputStream(compressedStreamInput);
}
contentType = XContentFactory.xContentType(compressedStreamInput);
input = compressedStreamInput;
} else {
contentType = XContentFactory.xContentType(bytes);
input = bytes.streamInput();
}
return new Tuple<>(contentType, convertToMap(XContentFactory.xContent(contentType), input, ordered));
contentType = xContentType != null ? xContentType : XContentFactory.xContentType(input);
return new Tuple<>(Objects.requireNonNull(contentType), convertToMap(XContentFactory.xContent(contentType), input, ordered));
} catch (IOException e) {
throw new ElasticsearchParseException("Failed to parse content to map", e);
}
@ -105,15 +141,27 @@ public class XContentHelper {
}
}
@Deprecated
public static String convertToJson(BytesReference bytes, boolean reformatJson) throws IOException {
return convertToJson(bytes, reformatJson, false);
}
@Deprecated
public static String convertToJson(BytesReference bytes, boolean reformatJson, boolean prettyPrint) throws IOException {
XContentType xContentType = XContentFactory.xContentType(bytes);
return convertToJson(bytes, reformatJson, prettyPrint, XContentFactory.xContentType(bytes));
}
public static String convertToJson(BytesReference bytes, boolean reformatJson, XContentType xContentType) throws IOException {
return convertToJson(bytes, reformatJson, false, xContentType);
}
public static String convertToJson(BytesReference bytes, boolean reformatJson, boolean prettyPrint, XContentType xContentType)
throws IOException {
Objects.requireNonNull(xContentType);
if (xContentType == XContentType.JSON && !reformatJson) {
return bytes.utf8ToString();
}
// It is safe to use EMPTY here because this never uses namedObject
try (XContentParser parser = XContentFactory.xContent(xContentType).createParser(NamedXContentRegistry.EMPTY,
bytes.streamInput())) {
@ -365,7 +413,10 @@ public class XContentHelper {
/**
* Writes a "raw" (bytes) field, handling cases where the bytes are compressed, and tries to optimize writing using
* {@link XContentBuilder#rawField(String, org.elasticsearch.common.bytes.BytesReference)}.
* @deprecated use {@link #writeRawField(String, BytesReference, XContentType, XContentBuilder, Params)} to avoid content type
* auto-detection
*/
@Deprecated
public static void writeRawField(String field, BytesReference source, XContentBuilder builder, ToXContent.Params params) throws IOException {
Compressor compressor = CompressorFactory.compressor(source);
if (compressor != null) {
@ -376,6 +427,22 @@ public class XContentHelper {
}
}
/**
* Writes a "raw" (bytes) field, handling cases where the bytes are compressed, and tries to optimize writing using
* {@link XContentBuilder#rawField(String, org.elasticsearch.common.bytes.BytesReference, XContentType)}.
*/
public static void writeRawField(String field, BytesReference source, XContentType xContentType, XContentBuilder builder,
ToXContent.Params params) throws IOException {
Objects.requireNonNull(xContentType);
Compressor compressor = CompressorFactory.compressor(source);
if (compressor != null) {
InputStream compressedStreamInput = compressor.streamInput(source.streamInput());
builder.rawField(field, compressedStreamInput, xContentType);
} else {
builder.rawField(field, source, xContentType);
}
}
/**
* Returns the bytes that represent the XContent output of the provided {@link ToXContent} object, using the provided
* {@link XContentType}. Wraps the output into a new anonymous object.

View File

@ -29,6 +29,7 @@ import org.elasticsearch.common.xcontent.yaml.YamlXContent;
import java.io.IOException;
import java.util.Locale;
import java.util.Objects;
/**
* The content type of {@link org.elasticsearch.common.xcontent.XContent}.
@ -40,7 +41,7 @@ public enum XContentType implements Writeable {
*/
JSON(0) {
@Override
protected String mediaTypeWithoutParameters() {
public String mediaTypeWithoutParameters() {
return "application/json";
}
@ -64,7 +65,7 @@ public enum XContentType implements Writeable {
*/
SMILE(1) {
@Override
protected String mediaTypeWithoutParameters() {
public String mediaTypeWithoutParameters() {
return "application/smile";
}
@ -83,7 +84,7 @@ public enum XContentType implements Writeable {
*/
YAML(2) {
@Override
protected String mediaTypeWithoutParameters() {
public String mediaTypeWithoutParameters() {
return "application/yaml";
}
@ -102,7 +103,7 @@ public enum XContentType implements Writeable {
*/
CBOR(3) {
@Override
protected String mediaTypeWithoutParameters() {
public String mediaTypeWithoutParameters() {
return "application/cbor";
}
@ -117,12 +118,18 @@ public enum XContentType implements Writeable {
}
};
/**
* 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
*/
public static XContentType fromMediaTypeOrFormat(String mediaType) {
if (mediaType == null) {
return null;
}
for (XContentType type : values()) {
if (isSameMediaTypeAs(mediaType, type)) {
if (isSameMediaTypeOrFormatAs(mediaType, type)) {
return type;
}
}
@ -133,7 +140,22 @@ public enum XContentType implements Writeable {
return null;
}
private static boolean isSameMediaTypeAs(String stringType, XContentType type) {
/**
* 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;
}
}
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);
@ -157,7 +179,7 @@ public enum XContentType implements Writeable {
public abstract XContent xContent();
protected abstract String mediaTypeWithoutParameters();
public abstract String mediaTypeWithoutParameters();
public static XContentType readFrom(StreamInput in) throws IOException {
int index = in.readVInt();

View File

@ -307,6 +307,11 @@ public class JsonXContentGenerator implements XContentGenerator {
if (contentType == null) {
throw new IllegalArgumentException("Can't write raw bytes whose xcontent-type can't be guessed");
}
writeRawField(name, content, contentType);
}
@Override
public void writeRawField(String name, InputStream content, XContentType contentType) throws IOException {
if (mayWriteRawData(contentType) == false) {
// EMPTY is safe here because we never call namedObject when writing raw data
try (XContentParser parser = XContentFactory.xContent(contentType).createParser(NamedXContentRegistry.EMPTY, content)) {
@ -328,6 +333,11 @@ public class JsonXContentGenerator implements XContentGenerator {
if (contentType == null) {
throw new IllegalArgumentException("Can't write raw bytes whose xcontent-type can't be guessed");
}
writeRawField(name, content, contentType);
}
@Override
public final void writeRawField(String name, BytesReference content, XContentType contentType) throws IOException {
if (mayWriteRawData(contentType) == false) {
writeFieldName(name);
copyRawValue(content, contentType.xContent());
@ -345,6 +355,11 @@ public class JsonXContentGenerator implements XContentGenerator {
if (contentType == null) {
throw new IllegalArgumentException("Can't write raw bytes whose xcontent-type can't be guessed");
}
writeRawValue(content, contentType);
}
@Override
public final void writeRawValue(BytesReference content, XContentType contentType) throws IOException {
if (mayWriteRawData(contentType) == false) {
copyRawValue(content, contentType.xContent());
} else {

View File

@ -68,6 +68,8 @@ public final class HttpTransportSettings {
Setting.intSetting("http.publish_port", -1, -1, Property.NodeScope);
public static final Setting<Boolean> SETTING_HTTP_DETAILED_ERRORS_ENABLED =
Setting.boolSetting("http.detailed_errors.enabled", true, Property.NodeScope);
public static final Setting<Boolean> SETTING_HTTP_CONTENT_TYPE_REQUIRED =
Setting.boolSetting("http.content_type.required", false, Property.NodeScope);
public static final Setting<ByteSizeValue> SETTING_HTTP_MAX_CONTENT_LENGTH =
Setting.byteSizeSetting("http.max_content_length", new ByteSizeValue(100, ByteSizeUnit.MB), Property.NodeScope);
public static final Setting<ByteSizeValue> SETTING_HTTP_MAX_CHUNK_SIZE =

View File

@ -190,7 +190,7 @@ public final class IndexingSlowLog implements IndexingOperationListener {
return sb.toString();
}
try {
String source = XContentHelper.convertToJson(doc.source(), reformat);
String source = XContentHelper.convertToJson(doc.source(), reformat, doc.getXContentType());
sb.append(", source[").append(Strings.cleanTruncate(source, maxSourceCharsToLog)).append("]");
} catch (IOException e) {
sb.append(", source[_failed_to_convert_]");

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.IndexAnalyzers;
@ -256,8 +257,9 @@ public class DocumentMapper implements ToXContent {
return this.objectMappers;
}
// TODO this method looks like it is only used in tests...
public ParsedDocument parse(String index, String type, String id, BytesReference source) throws MapperParsingException {
return parse(SourceToParse.source(index, type, id, source));
return parse(SourceToParse.source(index, type, id, source, XContentType.JSON));
}
public ParsedDocument parse(SourceToParse source) throws MapperParsingException {

View File

@ -24,9 +24,9 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.IndexAnalyzers;
import org.elasticsearch.index.query.QueryShardContext;
@ -80,7 +80,7 @@ public class DocumentMapperParser {
public DocumentMapper parse(@Nullable String type, CompressedXContent source, String defaultSource) throws MapperParsingException {
Map<String, Object> mapping = null;
if (source != null) {
Map<String, Object> root = XContentHelper.convertToMap(source.compressedReference(), true).v2();
Map<String, Object> root = XContentHelper.convertToMap(source.compressedReference(), true, XContentType.JSON).v2();
Tuple<String, Map<String, Object>> t = extractMapping(type, root);
type = t.v1();
mapping = t.v2();
@ -162,7 +162,7 @@ public class DocumentMapperParser {
private Tuple<String, Map<String, Object>> extractMapping(String type, String source) throws MapperParsingException {
Map<String, Object> root;
try (XContentParser parser = XContentFactory.xContent(source).createParser(xContentRegistry, source)) {
try (XContentParser parser = XContentType.JSON.xContent().createParser(xContentRegistry, source)) {
root = parser.mapOrdered();
} catch (Exception e) {
throw new MapperParsingException("failed to parse mapping definition", e);

View File

@ -154,6 +154,7 @@ final class DocumentParser {
source.routing(),
context.docs(),
context.sourceToParse().source(),
context.sourceToParse().getXContentType(),
update
).parent(source.parent());
}

View File

@ -30,6 +30,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressedXContent;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Setting;
@ -37,6 +38,7 @@ import org.elasticsearch.common.settings.Setting.Property;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.AbstractIndexComponent;
import org.elasticsearch.index.IndexSettings;
import org.elasticsearch.index.analysis.IndexAnalyzers;
@ -189,8 +191,11 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
return this.documentParser;
}
/**
* Parses the mappings (formatted as JSON) into a map
*/
public static Map<String, Object> parseMapping(NamedXContentRegistry xContentRegistry, String mappingSource) throws Exception {
try (XContentParser parser = XContentFactory.xContent(mappingSource).createParser(xContentRegistry, mappingSource)) {
try (XContentParser parser = XContentType.JSON.xContent().createParser(xContentRegistry, mappingSource)) {
return parser.map();
}
}
@ -318,7 +323,8 @@ public class MapperService extends AbstractIndexComponent implements Closeable {
&& mappers.containsKey(type) == false;
try {
DocumentMapper documentMapper = documentParser.parse(type, entry.getValue(), applyDefault ? defaultMappingSourceOrLastStored : null);
DocumentMapper documentMapper =
documentParser.parse(type, entry.getValue(), applyDefault ? defaultMappingSourceOrLastStored : null);
documentMappers.add(documentMapper);
} catch (Exception e) {
throw new MapperParsingException("Failed to parse mapping [{}]: {}", e, entry.getKey(), e.getMessage());

View File

@ -22,8 +22,8 @@ package org.elasticsearch.index.mapper;
import org.apache.lucene.document.Field;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.ParseContext.Document;
import org.elasticsearch.index.mapper.SeqNoFieldMapper;
import java.util.List;
@ -43,6 +43,7 @@ public class ParsedDocument {
private final List<Document> documents;
private BytesReference source;
private XContentType xContentType;
private Mapping dynamicMappingsUpdate;
@ -55,6 +56,7 @@ public class ParsedDocument {
String routing,
List<Document> documents,
BytesReference source,
XContentType xContentType,
Mapping dynamicMappingsUpdate) {
this.version = version;
this.seqID = seqID;
@ -65,6 +67,7 @@ public class ParsedDocument {
this.documents = documents;
this.source = source;
this.dynamicMappingsUpdate = dynamicMappingsUpdate;
this.xContentType = xContentType;
}
public BytesRef uid() {
@ -105,8 +108,13 @@ public class ParsedDocument {
return this.source;
}
public void setSource(BytesReference source) {
public XContentType getXContentType() {
return this.xContentType;
}
public void setSource(BytesReference source, XContentType xContentType) {
this.source = source;
this.xContentType = xContentType;
}
public ParsedDocument parent(String parent) {

View File

@ -241,7 +241,8 @@ public class SourceFieldMapper extends MetadataFieldMapper {
if (filter != null) {
// we don't update the context source if we filter, we want to keep it as is...
Tuple<XContentType, Map<String, Object>> mapTuple = XContentHelper.convertToMap(source, true);
Tuple<XContentType, Map<String, Object>> mapTuple =
XContentHelper.convertToMap(source, true, context.sourceToParse().getXContentType());
Map<String, Object> filteredSource = filter.apply(mapTuple.v2());
BytesStreamOutput bStream = new BytesStreamOutput();
XContentType contentType = mapTuple.v1();

View File

@ -23,15 +23,18 @@ import java.util.Objects;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
public class SourceToParse {
public static SourceToParse source(String index, String type, String id, BytesReference source) {
return source(Origin.PRIMARY, index, type, id, source);
public static SourceToParse source(String index, String type, String id, BytesReference source, XContentType contentType) {
return source(Origin.PRIMARY, index, type, id, source, contentType);
}
public static SourceToParse source(Origin origin, String index, String type, String id, BytesReference source) {
return new SourceToParse(origin, index, type, id, source);
public static SourceToParse source(Origin origin, String index, String type, String id, BytesReference source,
XContentType contentType) {
return new SourceToParse(origin, index, type, id, source, contentType);
}
private final Origin origin;
@ -48,14 +51,17 @@ public class SourceToParse {
private String parentId;
private SourceToParse(Origin origin, String index, String type, String id, BytesReference source) {
private XContentType xContentType;
private SourceToParse(Origin origin, String index, String type, String id, BytesReference source, XContentType xContentType) {
this.origin = Objects.requireNonNull(origin);
this.index = Objects.requireNonNull(index);
this.type = Objects.requireNonNull(type);
this.id = Objects.requireNonNull(id);
// we always convert back to byte array, since we store it and Field only supports bytes..
// so, we might as well do it here, and improve the performance of working with direct byte arrays
this.source = new BytesArray(source.toBytesRef());
this.source = new BytesArray(Objects.requireNonNull(source).toBytesRef());
this.xContentType = Objects.requireNonNull(xContentType);
}
public Origin origin() {
@ -91,6 +97,10 @@ public class SourceToParse {
return this.routing;
}
public XContentType getXContentType() {
return this.xContentType;
}
public SourceToParse routing(String routing) {
this.routing = routing;
return this;

View File

@ -28,6 +28,7 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.util.BytesRef;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.Version;
import org.elasticsearch.action.termvectors.MultiTermVectorsItemResponse;
import org.elasticsearch.action.termvectors.MultiTermVectorsRequest;
import org.elasticsearch.action.termvectors.MultiTermVectorsResponse;
@ -161,6 +162,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
private String type;
private String id;
private BytesReference doc;
private XContentType xContentType;
private String[] fields;
private Map<String, String> perFieldAnalyzer;
private String routing;
@ -178,6 +180,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
this.type = copy.type;
this.id = copy.id;
this.doc = copy.doc;
this.xContentType = copy.xContentType;
this.fields = copy.fields;
this.perFieldAnalyzer = copy.perFieldAnalyzer;
this.version = copy.version;
@ -214,6 +217,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
this.index = index;
this.type = type;
this.doc = doc.bytes();
this.xContentType = doc.contentType();
}
/**
@ -224,6 +228,11 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
type = in.readOptionalString();
if (in.readBoolean()) {
doc = (BytesReference) in.readGenericValue();
if (in.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType = XContentType.readFrom(in);
} else {
xContentType = XContentFactory.xContentType(doc);
}
} else {
id = in.readString();
}
@ -241,6 +250,9 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
out.writeBoolean(doc != null);
if (doc != null) {
out.writeGenericValue(doc);
if (out.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType.writeTo(out);
}
} else {
out.writeString(id);
}
@ -325,6 +337,10 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
return this;
}
XContentType xContentType() {
return xContentType;
}
/**
* Convert this to a {@link TermVectorsRequest} for fetching the terms of the document.
*/
@ -342,7 +358,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
.termStatistics(false);
// for artificial docs to make sure that the id has changed in the item too
if (doc != null) {
termVectorsRequest.doc(doc, true);
termVectorsRequest.doc(doc, true, xContentType);
this.id = termVectorsRequest.id();
}
return termVectorsRequest;
@ -366,6 +382,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
item.id = parser.text();
} else if (Field.DOC.match(currentFieldName)) {
item.doc = jsonBuilder().copyCurrentStructure(parser).bytes();
item.xContentType = XContentType.JSON;
} else if (Field.FIELDS.match(currentFieldName)) {
if (token == XContentParser.Token.START_ARRAY) {
List<String> fields = new ArrayList<>();
@ -416,12 +433,7 @@ public class MoreLikeThisQueryBuilder extends AbstractQueryBuilder<MoreLikeThisQ
builder.field(Field.ID.getPreferredName(), this.id);
}
if (this.doc != null) {
XContentType contentType = XContentFactory.xContentType(this.doc);
if (contentType == builder.contentType()) {
builder.rawField(Field.DOC.getPreferredName(), this.doc);
} else {
builder.rawField(Field.DOC.getPreferredName(), doc);
}
builder.rawField(Field.DOC.getPreferredName(), this.doc, xContentType);
}
if (this.fields != null) {
builder.array(Field.FIELDS.getPreferredName(), this.fields);

View File

@ -22,6 +22,7 @@ import org.apache.logging.log4j.Logger;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.VersionType;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.engine.IgnoreOnRecoveryEngineException;
@ -157,7 +158,8 @@ public class TranslogRecoveryPerformer {
Translog.Index index = (Translog.Index) operation;
// we set canHaveDuplicates to true all the time such that we de-optimze the translog case and ensure that all
// autoGeneratedID docs that are coming from the primary are updated correctly.
Engine.Index engineIndex = IndexShard.prepareIndex(docMapper(index.type()), source(shardId.getIndexName(), index.type(), index.id(), index.source())
Engine.Index engineIndex = IndexShard.prepareIndex(docMapper(index.type()),
source(shardId.getIndexName(), index.type(), index.id(), index.source(), XContentFactory.xContentType(index.source()))
.routing(index.routing()).parent(index.parent()), index.seqNo(), index.primaryTerm(),
index.version(), index.versionType().versionTypeForReplicationAndRecovery(), origin, index.getAutoGeneratedIdTimestamp(), true);
maybeAddMappingUpdate(engineIndex.type(), engineIndex.parsedDoc().dynamicMappingsUpdate(), engineIndex.id(), allowMappingUpdates);

View File

@ -36,6 +36,7 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.support.XContentMapValues;
import org.elasticsearch.index.engine.Engine;
import org.elasticsearch.index.get.GetField;
@ -270,7 +271,8 @@ public class TermVectorsService {
private static Fields generateTermVectorsFromDoc(IndexShard indexShard, TermVectorsRequest request) throws IOException {
// parse the document, at the moment we do update the mapping, just like percolate
ParsedDocument parsedDocument = parseDocument(indexShard, indexShard.shardId().getIndexName(), request.type(), request.doc());
ParsedDocument parsedDocument =
parseDocument(indexShard, indexShard.shardId().getIndexName(), request.type(), request.doc(), request.xContentType());
// select the right fields and generate term vectors
ParseContext.Document doc = parsedDocument.rootDoc();
@ -293,13 +295,15 @@ public class TermVectorsService {
String[] values = doc.getValues(field.name());
getFields.add(new GetField(field.name(), Arrays.asList((Object[]) values)));
}
return generateTermVectors(indexShard, XContentHelper.convertToMap(parsedDocument.source(), true).v2(), getFields, request.offsets(), request.perFieldAnalyzer(), seenFields);
return generateTermVectors(indexShard, XContentHelper.convertToMap(parsedDocument.source(), true, request.xContentType()).v2(),
getFields, request.offsets(), request.perFieldAnalyzer(), seenFields);
}
private static ParsedDocument parseDocument(IndexShard indexShard, String index, String type, BytesReference doc) {
private static ParsedDocument parseDocument(IndexShard indexShard, String index, String type, BytesReference doc,
XContentType xContentType) {
MapperService mapperService = indexShard.mapperService();
DocumentMapperForType docMapper = mapperService.documentMapperWithAutoCreate(type);
ParsedDocument parsedDocument = docMapper.getDocumentMapper().parse(source(index, type, "_id_for_tv_api", doc));
ParsedDocument parsedDocument = docMapper.getDocumentMapper().parse(source(index, type, "_id_for_tv_api", doc, xContentType));
if (docMapper.getMapping() != null) {
parsedDocument.addDynamicMappingsUpdate(docMapper.getMapping());
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.ingest;
import org.elasticsearch.Version;
import org.elasticsearch.cluster.AbstractDiffable;
import org.elasticsearch.cluster.Diff;
import org.elasticsearch.common.ParseField;
@ -29,10 +30,13 @@ import org.elasticsearch.common.xcontent.ContextParser;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.util.Map;
import java.util.Objects;
/**
* Encapsulates a pipeline's id and configuration as a blob
@ -45,8 +49,9 @@ public final class PipelineConfiguration extends AbstractDiffable<PipelineConfig
PARSER.declareField((parser, builder, aVoid) -> {
XContentBuilder contentBuilder = XContentBuilder.builder(parser.contentType().xContent());
XContentHelper.copyCurrentStructure(contentBuilder.generator(), parser);
builder.setConfig(contentBuilder.bytes());
builder.setConfig(contentBuilder.bytes(), contentBuilder.contentType());
}, new ParseField("config"), ObjectParser.ValueType.OBJECT);
}
public static ContextParser<Void, PipelineConfiguration> getParser() {
@ -56,17 +61,19 @@ public final class PipelineConfiguration extends AbstractDiffable<PipelineConfig
private String id;
private BytesReference config;
private XContentType xContentType;
void setId(String id) {
this.id = id;
}
void setConfig(BytesReference config) {
void setConfig(BytesReference config, XContentType xContentType) {
this.config = config;
this.xContentType = xContentType;
}
PipelineConfiguration build() {
return new PipelineConfiguration(id, config);
return new PipelineConfiguration(id, config, xContentType);
}
}
@ -75,10 +82,12 @@ public final class PipelineConfiguration extends AbstractDiffable<PipelineConfig
// and the way the map of maps config is read requires a deep copy (it removes instead of gets entries to check for unused options)
// also the get pipeline api just directly returns this to the caller
private final BytesReference config;
private final XContentType xContentType;
public PipelineConfiguration(String id, BytesReference config) {
this.id = id;
this.config = config;
public PipelineConfiguration(String id, BytesReference config, XContentType xContentType) {
this.id = Objects.requireNonNull(id);
this.config = Objects.requireNonNull(config);
this.xContentType = Objects.requireNonNull(xContentType);
}
public String getId() {
@ -86,7 +95,17 @@ public final class PipelineConfiguration extends AbstractDiffable<PipelineConfig
}
public Map<String, Object> getConfigAsMap() {
return XContentHelper.convertToMap(config, true).v2();
return XContentHelper.convertToMap(config, true, xContentType).v2();
}
// pkg-private for tests
XContentType getXContentType() {
return xContentType;
}
// pkg-private for tests
BytesReference getConfig() {
return config;
}
@Override
@ -99,7 +118,13 @@ public final class PipelineConfiguration extends AbstractDiffable<PipelineConfig
}
public static PipelineConfiguration readFrom(StreamInput in) throws IOException {
return new PipelineConfiguration(in.readString(), in.readBytesReference());
if (in.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
return new PipelineConfiguration(in.readString(), in.readBytesReference(), XContentType.readFrom(in));
} else {
final String id = in.readString();
final BytesReference config = in.readBytesReference();
return new PipelineConfiguration(id, config, XContentFactory.xContentType(config));
}
}
public static Diff<PipelineConfiguration> readDiffFrom(StreamInput in) throws IOException {
@ -110,6 +135,9 @@ public final class PipelineConfiguration extends AbstractDiffable<PipelineConfig
public void writeTo(StreamOutput out) throws IOException {
out.writeString(id);
out.writeBytesReference(config);
if (out.getVersion().after(Version.V_5_3_0_UNRELEASED)) { // TODO update to onOrAfter after backporting
xContentType.writeTo(out);
}
}
@Override

View File

@ -162,7 +162,7 @@ public class PipelineStore extends AbstractComponent implements ClusterStateAppl
throw new IllegalStateException("Ingest info is empty");
}
Map<String, Object> pipelineConfig = XContentHelper.convertToMap(request.getSource(), false).v2();
Map<String, Object> pipelineConfig = XContentHelper.convertToMap(request.getSource(), false, request.getXContentType()).v2();
Pipeline pipeline = factory.create(request.getId(), pipelineConfig, processorFactories);
List<IllegalArgumentException> exceptions = new ArrayList<>();
for (Processor processor : pipeline.flattenAllProcessors()) {
@ -185,7 +185,7 @@ public class PipelineStore extends AbstractComponent implements ClusterStateAppl
pipelines = new HashMap<>();
}
pipelines.put(request.getId(), new PipelineConfiguration(request.getId(), request.getSource()));
pipelines.put(request.getId(), new PipelineConfiguration(request.getId(), request.getSource(), request.getXContentType()));
ClusterState.Builder newState = ClusterState.builder(currentState);
newState.metaData(MetaData.builder(currentState.getMetaData())
.putCustom(IngestMetadata.TYPE, new IngestMetadata(pipelines))

View File

@ -20,7 +20,6 @@ package org.elasticsearch.rest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
@ -58,28 +57,37 @@ public abstract class AbstractRestChannel implements RestChannel {
@Override
public XContentBuilder newBuilder() throws IOException {
return newBuilder(request.hasContent() ? request.content() : null, true);
return newBuilder(request.getXContentType(), true);
}
@Override
public XContentBuilder newErrorBuilder() throws IOException {
// Disable filtering when building error responses
return newBuilder(request.hasContent() ? request.content() : null, false);
return newBuilder(request.getXContentType(), false);
}
/**
* Creates a new {@link XContentBuilder} for a response to be sent using this channel. The builder's type is determined by the following
* logic. If the request has a format parameter that will be used to attempt to map to an {@link XContentType}. If there is no format
* parameter, the HTTP Accept header is checked to see if it can be matched to a {@link XContentType}. If this first attempt to map
* fails, the request content type will be used if the value is not {@code null}; if the value is {@code null} the output format falls
* back to JSON.
*/
@Override
public XContentBuilder newBuilder(@Nullable BytesReference autoDetectSource, boolean useFiltering) throws IOException {
XContentType contentType = XContentType.fromMediaTypeOrFormat(format);
if (contentType == null) {
// try and guess it from the auto detect source
if (autoDetectSource != null) {
contentType = XContentFactory.xContentType(autoDetectSource);
public XContentBuilder newBuilder(@Nullable XContentType requestContentType, boolean useFiltering) throws IOException {
// 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
XContentType responseContentType = XContentType.fromMediaTypeOrFormat(format);
if (responseContentType == null) {
if (requestContentType != null) {
// if there was a parsed content-type for the incoming request use that since no format was specified using the query
// string parameter or the HTTP Accept header
responseContentType = requestContentType;
} else {
// default to JSON output when all else fails
responseContentType = XContentType.JSON;
}
}
if (contentType == null) {
// default to JSON
contentType = XContentType.JSON;
}
Set<String> includes = Collections.emptySet();
Set<String> excludes = Collections.emptySet();
@ -89,7 +97,7 @@ public abstract class AbstractRestChannel implements RestChannel {
excludes = filters.stream().filter(EXCLUDE_FILTER).map(f -> f.substring(1)).collect(toSet());
}
XContentBuilder builder = new XContentBuilder(XContentFactory.xContent(contentType), bytesOutput(), includes, excludes);
XContentBuilder builder = new XContentBuilder(XContentFactory.xContent(responseContentType), bytesOutput(), includes, excludes);
if (pretty) {
builder.prettyPrint().lfAtEnd();
}
@ -125,5 +133,4 @@ public abstract class AbstractRestChannel implements RestChannel {
public boolean detailedErrorsEnabled() {
return detailedErrorsEnabled;
}
}

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.common.xcontent.XContentParser;
import java.io.IOException;
@ -146,6 +147,13 @@ public class BytesRestResponse extends RestResponse {
return builder;
}
static BytesRestResponse createSimpleErrorResponse(RestStatus status, String errorMessage) throws IOException {
return new BytesRestResponse(status, JsonXContent.contentBuilder().startObject()
.field("error", errorMessage)
.field("status", status.getStatus())
.endObject());
}
public static ElasticsearchStatusException errorFromXContent(XContentParser parser) throws IOException {
XContentParser.Token token = parser.nextToken();
ensureExpectedToken(XContentParser.Token.START_OBJECT, token, parser::getTokenLocation);

View File

@ -20,9 +20,9 @@
package org.elasticsearch.rest;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
@ -35,7 +35,7 @@ public interface RestChannel {
XContentBuilder newErrorBuilder() throws IOException;
XContentBuilder newBuilder(@Nullable BytesReference autoDetectSource, boolean useFiltering) throws IOException;
XContentBuilder newBuilder(@Nullable XContentType xContentType, boolean useFiltering) throws IOException;
BytesStreamOutput bytesOutput();
@ -47,5 +47,4 @@ public interface RestChannel {
boolean detailedErrorsEnabled();
void sendResponse(RestResponse response);
}

View File

@ -22,18 +22,19 @@ package org.elasticsearch.rest;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.function.UnaryOperator;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.logging.log4j.util.Supplier;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.breaker.CircuitBreaker;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.component.AbstractComponent;
import org.elasticsearch.common.io.Streams;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
@ -42,12 +43,15 @@ import org.elasticsearch.common.path.PathTrie;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.http.HttpTransportSettings;
import org.elasticsearch.indices.breaker.CircuitBreakerService;
import org.elasticsearch.common.xcontent.XContentType;
import static org.elasticsearch.rest.RestStatus.BAD_REQUEST;
import static org.elasticsearch.rest.RestStatus.FORBIDDEN;
import static org.elasticsearch.rest.RestStatus.INTERNAL_SERVER_ERROR;
import static org.elasticsearch.rest.RestStatus.NOT_ACCEPTABLE;
import static org.elasticsearch.rest.RestStatus.OK;
public class RestController extends AbstractComponent {
@ -67,6 +71,10 @@ public class RestController extends AbstractComponent {
/** Rest headers that are copied to internal requests made during a rest request. */
private final Set<String> headersToCopy;
private final boolean isContentTypeRequired;
private final DeprecationLogger deprecationLogger;
public RestController(Settings settings, Set<String> headersToCopy, UnaryOperator<RestHandler> handlerWrapper,
NodeClient client, CircuitBreakerService circuitBreakerService) {
super(settings);
@ -77,10 +85,10 @@ public class RestController extends AbstractComponent {
this.handlerWrapper = handlerWrapper;
this.client = client;
this.circuitBreakerService = circuitBreakerService;
this.isContentTypeRequired = HttpTransportSettings.SETTING_HTTP_CONTENT_TYPE_REQUIRED.get(settings);
this.deprecationLogger = new DeprecationLogger(logger);
}
/**
* Registers a REST handler to be executed when the provided {@code method} and {@code path} match the request.
*
@ -165,15 +173,22 @@ public class RestController extends AbstractComponent {
}
RestChannel responseChannel = channel;
try {
int contentLength = request.content().length();
if (canTripCircuitBreaker(request)) {
inFlightRequestsBreaker(circuitBreakerService).addEstimateBytesAndMaybeBreak(contentLength, "<http_request>");
final int contentLength = request.hasContent() ? request.content().length() : 0;
assert contentLength >= 0 : "content length was negative, how is that possible?";
final RestHandler handler = getHandler(request);
if (contentLength > 0 && hasContentTypeOrCanAutoDetect(request, handler) == false) {
sendContentTypeErrorMessage(request, responseChannel);
} else {
inFlightRequestsBreaker(circuitBreakerService).addWithoutBreaking(contentLength);
if (canTripCircuitBreaker(request)) {
inFlightRequestsBreaker(circuitBreakerService).addEstimateBytesAndMaybeBreak(contentLength, "<http_request>");
} else {
inFlightRequestsBreaker(circuitBreakerService).addWithoutBreaking(contentLength);
}
// iff we could reserve bytes for the request we need to send the response also over this channel
responseChannel = new ResourceHandlingHttpChannel(channel, circuitBreakerService, contentLength);
dispatchRequest(request, responseChannel, client, threadContext, handler);
}
// iff we could reserve bytes for the request we need to send the response also over this channel
responseChannel = new ResourceHandlingHttpChannel(channel, circuitBreakerService, contentLength);
dispatchRequest(request, responseChannel, client, threadContext);
} catch (Exception e) {
try {
responseChannel.sendResponse(new BytesRestResponse(channel, e));
@ -185,35 +200,77 @@ public class RestController extends AbstractComponent {
}
}
void dispatchRequest(final RestRequest request, final RestChannel channel, final NodeClient client, ThreadContext threadContext) throws Exception {
if (!checkRequestParameters(request, channel)) {
return;
}
try (ThreadContext.StoredContext ignored = threadContext.stashContext()) {
for (String key : headersToCopy) {
String httpHeader = request.header(key);
if (httpHeader != null) {
threadContext.putHeader(key, httpHeader);
void dispatchRequest(final RestRequest request, final RestChannel channel, final NodeClient client, ThreadContext threadContext,
final RestHandler handler) throws Exception {
if (checkRequestParameters(request, channel) == false) {
channel.sendResponse(BytesRestResponse.createSimpleErrorResponse(BAD_REQUEST, "error traces in responses are disabled."));
} else {
try (ThreadContext.StoredContext ignored = threadContext.stashContext()) {
for (String key : headersToCopy) {
String httpHeader = request.header(key);
if (httpHeader != null) {
threadContext.putHeader(key, httpHeader);
}
}
}
final RestHandler handler = getHandler(request);
if (handler == null) {
if (request.method() == RestRequest.Method.OPTIONS) {
// when we have OPTIONS request, simply send OK by default (with the Access Control Origin header which gets automatically added)
if (handler == null) {
if (request.method() == RestRequest.Method.OPTIONS) {
// when we have OPTIONS request, simply send OK by default (with the Access Control Origin header which gets automatically added)
channel.sendResponse(new BytesRestResponse(OK, BytesRestResponse.TEXT_CONTENT_TYPE, BytesArray.EMPTY));
channel.sendResponse(new BytesRestResponse(OK, BytesRestResponse.TEXT_CONTENT_TYPE, BytesArray.EMPTY));
} else {
final String msg = "No handler found for uri [" + request.uri() + "] and method [" + request.method() + "]";
channel.sendResponse(new BytesRestResponse(BAD_REQUEST, msg));
}
} else {
final String msg = "No handler found for uri [" + request.uri() + "] and method [" + request.method() + "]";
channel.sendResponse(new BytesRestResponse(BAD_REQUEST, msg));
final RestHandler wrappedHandler = Objects.requireNonNull(handlerWrapper.apply(handler));
wrappedHandler.handleRequest(request, channel, client);
}
} else {
final RestHandler wrappedHandler = Objects.requireNonNull(handlerWrapper.apply(handler));
wrappedHandler.handleRequest(request, channel, client);
}
}
}
/**
* If a request contains content, this method will return {@code true} if the {@code Content-Type} header is present, matches an
* {@link XContentType} or the request is plain text, and content type is required. If content type is not required then this method
* returns true unless a content type could not be inferred from the body and the rest handler does not support plain text
*/
private boolean hasContentTypeOrCanAutoDetect(final RestRequest restRequest, final RestHandler restHandler) {
if (restRequest.getXContentType() == null) {
if (restHandler != null && restHandler.supportsPlainText()) {
// content type of null with a handler that supports plain text gets through for now. Once we remove plain text this can
// be removed!
deprecationLogger.deprecated("Plain text request bodies are deprecated. Use request parameters or body " +
"in a supported format.");
} else if (isContentTypeRequired) {
return false;
} else {
deprecationLogger.deprecated("Content type detection for rest requests is deprecated. Specify the content type using " +
"the [Content-Type] header.");
XContentType xContentType = XContentFactory.xContentType(restRequest.content());
if (xContentType == null) {
return false;
} else {
restRequest.setXContentType(xContentType);
}
}
}
return true;
}
private void sendContentTypeErrorMessage(RestRequest restRequest, RestChannel channel) throws IOException {
final List<String> contentTypeHeader = restRequest.getAllHeaderValues("Content-Type");
final String errorMessage;
if (contentTypeHeader == null) {
errorMessage = "Content-Type header is missing";
} else {
errorMessage = "Content-Type header [" +
Strings.collectionToCommaDelimitedString(restRequest.getAllHeaderValues("Content-Type")) + "] is not supported";
}
channel.sendResponse(BytesRestResponse.createSimpleErrorResponse(NOT_ACCEPTABLE, errorMessage));
}
/**
* Checks the request parameters against enabled settings for error trace support
* @return true if the request does not have any parameters that conflict with system settings
@ -222,15 +279,6 @@ public class RestController extends AbstractComponent {
// error_trace cannot be used when we disable detailed errors
// we consume the error_trace parameter first to ensure that it is always consumed
if (request.paramAsBoolean("error_trace", false) && channel.detailedErrorsEnabled() == false) {
try {
XContentBuilder builder = channel.newErrorBuilder();
builder.startObject().field("error", "error traces in responses are disabled.").endObject().string();
RestResponse response = new BytesRestResponse(BAD_REQUEST, builder);
response.addHeader("Content-Type", "application/json");
channel.sendResponse(response);
} catch (IOException e) {
logger.warn("Failed to send response", e);
}
return false;
}
@ -312,8 +360,8 @@ public class RestController extends AbstractComponent {
}
@Override
public XContentBuilder newBuilder(@Nullable BytesReference autoDetectSource, boolean useFiltering) throws IOException {
return delegate.newBuilder(autoDetectSource, useFiltering);
public XContentBuilder newBuilder(@Nullable XContentType xContentType, boolean useFiltering) throws IOException {
return delegate.newBuilder(xContentType, useFiltering);
}
@Override

View File

@ -28,7 +28,6 @@ public interface RestHandler {
/**
* Handles a rest request.
*
* @param request The request to handle
* @param channel The channel to write the request response to
* @param client A client to use to make internal requests on behalf of the original request
@ -38,4 +37,13 @@ public interface RestHandler {
default boolean canTripCircuitBreaker() {
return true;
}
/**
* Indicates if a RestHandler supports plain text bodies
* @deprecated use request parameters or bodies that can be parsed with XContent!
*/
@Deprecated
default boolean supportsPlainText() {
return false;
}
}

View File

@ -19,6 +19,7 @@
package org.elasticsearch.rest;
import org.apache.lucene.util.SetOnce;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.CheckedConsumer;
@ -26,20 +27,26 @@ import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.logging.Loggers;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.net.SocketAddress;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import static org.elasticsearch.common.unit.ByteSizeValue.parseBytesSizeValue;
@ -47,12 +54,25 @@ import static org.elasticsearch.common.unit.TimeValue.parseTimeValue;
public abstract class RestRequest implements ToXContent.Params {
private static final DeprecationLogger DEPRECATION_LOGGER = new DeprecationLogger(Loggers.getLogger(RestRequest.class));
// tchar pattern as defined by RFC7230 section 3.2.6
private static final Pattern TCHAR_PATTERN = Pattern.compile("[a-zA-z0-9!#$%&'*+\\-.\\^_`|~]+");
private final NamedXContentRegistry xContentRegistry;
private final Map<String, String> params;
private final Map<String, List<String>> headers;
private final String rawPath;
private final Set<String> consumedParams = new HashSet<>();
private final SetOnce<XContentType> xContentType = new SetOnce<>();
public RestRequest(NamedXContentRegistry xContentRegistry, String uri) {
/**
* Creates a new RestRequest
* @param xContentRegistry the xContentRegistry to use when parsing XContent
* @param uri the URI of the request that potentially contains request parameters
* @param headers a map of the headers. This map should implement a Case-Insensitive hashing for keys as HTTP header names are case
* insensitive
*/
public RestRequest(NamedXContentRegistry xContentRegistry, String uri, Map<String, List<String>> headers) {
this.xContentRegistry = xContentRegistry;
final Map<String, String> params = new HashMap<>();
int pathEndPos = uri.indexOf('?');
@ -63,12 +83,32 @@ public abstract class RestRequest implements ToXContent.Params {
RestUtils.decodeQueryString(uri, pathEndPos + 1, params);
}
this.params = params;
this.headers = Collections.unmodifiableMap(headers);
final List<String> contentType = getAllHeaderValues("Content-Type");
final XContentType xContentType = parseContentType(contentType);
if (xContentType != null) {
this.xContentType.set(xContentType);
}
}
public RestRequest(NamedXContentRegistry xContentRegistry, Map<String, String> params, String path) {
/**
* Creates a new RestRequest
* @param xContentRegistry the xContentRegistry to use when parsing XContent
* @param params the parameters of the request
* @param path the path of the request. This should not contain request parameters
* @param headers a map of the headers. This map should implement a Case-Insensitive hashing for keys as HTTP header names are case
* insensitive
*/
public RestRequest(NamedXContentRegistry xContentRegistry, Map<String, String> params, String path, Map<String, List<String>> headers) {
this.xContentRegistry = xContentRegistry;
this.params = params;
this.rawPath = path;
this.headers = Collections.unmodifiableMap(headers);
final List<String> contentType = getAllHeaderValues("Content-Type");
final XContentType xContentType = parseContentType(contentType);
if (xContentType != null) {
this.xContentType.set(xContentType);
}
}
public enum Method {
@ -100,9 +140,53 @@ public abstract class RestRequest implements ToXContent.Params {
public abstract BytesReference content();
public abstract String header(String name);
/**
* Get the value of the header or {@code null} if not found. This method only retrieves the first header value if multiple values are
* sent. Use of {@link #getAllHeaderValues(String)} should be preferred
*/
public final String header(String name) {
List<String> values = headers.get(name);
if (values != null && values.isEmpty() == false) {
return values.get(0);
}
return null;
}
public abstract Iterable<Map.Entry<String, String>> headers();
/**
* Get all values for the header or {@code null} if the header was not found
*/
public final List<String> getAllHeaderValues(String name) {
List<String> values = headers.get(name);
if (values != null) {
return Collections.unmodifiableList(values);
}
return null;
}
/**
* Get all of the headers and values associated with the headers. Modifications of this map are not supported.
*/
public final Map<String, List<String>> getHeaders() {
return headers;
}
/**
* The {@link XContentType} that was parsed from the {@code Content-Type} header. This value will be {@code null} in the case of
* a request without a valid {@code Content-Type} header, a request without content ({@link #hasContent()}, or a plain text request
*/
@Nullable
public final XContentType getXContentType() {
return xContentType.get();
}
/**
* Sets the {@link XContentType}
* @deprecated this is only used to allow BWC with content-type detection
*/
@Deprecated
final void setXContentType(XContentType xContentType) {
this.xContentType.set(xContentType);
}
@Nullable
public SocketAddress getRemoteAddress() {
@ -254,8 +338,10 @@ public abstract class RestRequest implements ToXContent.Params {
BytesReference content = content();
if (content.length() == 0) {
throw new ElasticsearchParseException("Body required");
} else if (xContentType.get() == null) {
throw new IllegalStateException("unknown content type");
}
return XContentFactory.xContent(content).createParser(xContentRegistry, content);
return xContentType.get().xContent().createParser(xContentRegistry, content);
}
/**
@ -283,11 +369,12 @@ public abstract class RestRequest implements ToXContent.Params {
* if you need to handle the absence request content gracefully.
*/
public final XContentParser contentOrSourceParamParser() throws IOException {
BytesReference content = contentOrSourceParam();
Tuple<XContentType, BytesReference> tuple = contentOrSourceParam();
BytesReference content = tuple.v2();
if (content.length() == 0) {
throw new ElasticsearchParseException("Body required");
}
return XContentFactory.xContent(content).createParser(xContentRegistry, content);
return tuple.v1().xContent().createParser(xContentRegistry, content);
}
/**
@ -296,9 +383,11 @@ public abstract class RestRequest implements ToXContent.Params {
* back to the user when there isn't request content.
*/
public final void withContentOrSourceParamParserOrNull(CheckedConsumer<XContentParser, IOException> withParser) throws IOException {
BytesReference content = contentOrSourceParam();
Tuple<XContentType, BytesReference> tuple = contentOrSourceParam();
BytesReference content = tuple.v2();
XContentType xContentType = tuple.v1();
if (content.length() > 0) {
try (XContentParser parser = XContentFactory.xContent(content).createParser(xContentRegistry, content)) {
try (XContentParser parser = xContentType.xContent().createParser(xContentRegistry, content)) {
withParser.accept(parser);
}
} else {
@ -310,7 +399,66 @@ public abstract class RestRequest implements ToXContent.Params {
* Get the content of the request or the contents of the {@code source} param. Prefer {@link #contentOrSourceParamParser()} or
* {@link #withContentOrSourceParamParserOrNull(CheckedConsumer)} if you need a parser.
*/
public final BytesReference contentOrSourceParam() {
public final Tuple<XContentType, BytesReference> contentOrSourceParam() {
if (hasContent()) {
if (xContentType.get() == null) {
throw new IllegalStateException("unknown content type");
}
return new Tuple<>(xContentType.get(), content());
}
String source = param("source");
String typeParam = param("source_content_type");
if (source != null) {
BytesArray bytes = new BytesArray(source);
final XContentType xContentType;
if (typeParam != null) {
xContentType = parseContentType(Collections.singletonList(typeParam));
} else {
DEPRECATION_LOGGER.deprecated("Deprecated use of the [source] parameter without the [source_content_type] parameter. Use " +
"the [source_content_type] parameter to specify the content type of the source such as [application/json]");
xContentType = XContentFactory.xContentType(bytes);
}
if (xContentType == null) {
throw new IllegalStateException("could not determine source content type");
}
return new Tuple<>(xContentType, bytes);
}
return new Tuple<>(XContentType.JSON, BytesArray.EMPTY);
}
/**
* Call a consumer with the parser for the contents of this request if it has contents, otherwise with a parser for the {@code source}
* parameter if there is one, otherwise with {@code null}. Use {@link #contentOrSourceParamParser()} if you should throw an exception
* back to the user when there isn't request content. This version allows for plain text content
*/
@Deprecated
public final void withContentOrSourceParamParserOrNullLenient(CheckedConsumer<XContentParser, IOException> withParser)
throws IOException {
if (hasContent() && xContentType.get() == null) {
withParser.accept(null);
}
Tuple<XContentType, BytesReference> tuple = contentOrSourceParam();
BytesReference content = tuple.v2();
XContentType xContentType = tuple.v1();
if (content.length() > 0) {
try (XContentParser parser = xContentType.xContent().createParser(xContentRegistry, content)) {
withParser.accept(parser);
}
} else {
withParser.accept(null);
}
}
/**
* Get the content of the request or the contents of the {@code source} param without the xcontent type. This is useful the request can
* accept non xcontent values.
* @deprecated we should only take xcontent
*/
@Deprecated
public final BytesReference getContentOrSourceParamOnly() {
if (hasContent()) {
return content();
}
@ -320,4 +468,29 @@ public abstract class RestRequest implements ToXContent.Params {
}
return BytesArray.EMPTY;
}
/**
* Parses the given content type string for the media type. This method currently ignores parameters.
*/
// TODO stop ignoring parameters such as charset...
private static XContentType parseContentType(List<String> header) {
if (header == null || header.isEmpty()) {
return null;
} else if (header.size() > 1) {
throw new IllegalArgumentException("only one Content-Type header should be provided");
}
String rawContentType = header.get(0);
final String[] elements = rawContentType.split("[ \t]*;");
if (elements.length > 0) {
final String[] splitMediaType = elements[0].split("/");
if (splitMediaType.length == 2 && TCHAR_PATTERN.matcher(splitMediaType[0]).matches()
&& TCHAR_PATTERN.matcher(splitMediaType[1].trim()).matches()) {
return XContentType.fromMediaType(elements[0]);
} else {
throw new IllegalArgumentException("invalid Content-Type header [" + rawContentType + "]");
}
}
throw new IllegalArgumentException("empty Content-Type header");
}
}

View File

@ -65,7 +65,7 @@ public class RestPutStoredScriptAction extends BaseRestHandler {
"specifying lang [" + lang + "] as part of the url path is deprecated, use request content instead");
}
PutStoredScriptRequest putRequest = new PutStoredScriptRequest(id, lang, content);
PutStoredScriptRequest putRequest = new PutStoredScriptRequest(id, lang, content, request.getXContentType());
return channel -> client.admin().cluster().putStoredScript(putRequest, new AcknowledgedRestListener<>(channel));
}
}

View File

@ -42,7 +42,7 @@ public class RestCreateIndexAction extends BaseRestHandler {
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
CreateIndexRequest createIndexRequest = new CreateIndexRequest(request.param("index"));
if (request.hasContent()) {
createIndexRequest.source(request.content());
createIndexRequest.source(request.content(), request.getXContentType());
}
createIndexRequest.updateAllTypes(request.paramAsBoolean("update_all_types", false));
createIndexRequest.timeout(request.paramAsTime("timeout", createIndexRequest.timeout()));

View File

@ -57,7 +57,7 @@ public class RestPutIndexTemplateAction extends BaseRestHandler {
putRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putRequest.masterNodeTimeout()));
putRequest.create(request.paramAsBoolean("create", false));
putRequest.cause(request.param("cause", ""));
putRequest.source(request.content());
putRequest.source(request.content(), request.getXContentType());
return channel -> client.admin().indices().putTemplate(putRequest, new AcknowledgedRestListener<>(channel));
}

View File

@ -20,7 +20,6 @@
package org.elasticsearch.rest.action.admin.indices;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
@ -65,11 +64,11 @@ public class RestPutMappingAction extends BaseRestHandler {
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
PutMappingRequest putMappingRequest = putMappingRequest(Strings.splitStringByCommaToArray(request.param("index")));
putMappingRequest.type(request.param("type"));
putMappingRequest.source(request.content().utf8ToString());
putMappingRequest.source(request.content(), request.getXContentType());
putMappingRequest.updateAllTypes(request.paramAsBoolean("update_all_types", false));
putMappingRequest.timeout(request.paramAsTime("timeout", putMappingRequest.timeout()));
putMappingRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putMappingRequest.masterNodeTimeout()));
putMappingRequest.indicesOptions(IndicesOptions.fromRequest(request, putMappingRequest.indicesOptions()));
return channel -> client.admin().indices().putMapping(putMappingRequest, new AcknowledgedRestListener<PutMappingResponse>(channel));
return channel -> client.admin().indices().putMapping(putMappingRequest, new AcknowledgedRestListener<>(channel));
}
}

View File

@ -66,7 +66,9 @@ public class RestUpdateSettingsAction extends BaseRestHandler {
Settings.Builder updateSettings = Settings.builder();
String bodySettingsStr = request.content().utf8ToString();
if (Strings.hasText(bodySettingsStr)) {
Settings buildSettings = Settings.builder().loadFromSource(bodySettingsStr).build();
Settings buildSettings = Settings.builder()
.loadFromSource(bodySettingsStr, request.getXContentType())
.build();
for (Map.Entry<String, String> entry : buildSettings.getAsMap().entrySet()) {
String key = entry.getKey();
String value = entry.getValue();

View File

@ -93,7 +93,7 @@ public class RestBulkAction extends BaseRestHandler {
bulkRequest.timeout(request.paramAsTime("timeout", BulkShardRequest.DEFAULT_TIMEOUT));
bulkRequest.setRefreshPolicy(request.param("refresh"));
bulkRequest.add(request.content(), defaultIndex, defaultType, defaultRouting, defaultFields,
defaultFetchSourceContext, defaultPipeline, null, allowExplicitIndex);
defaultFetchSourceContext, defaultPipeline, null, allowExplicitIndex, request.getXContentType());
return channel -> client.bulk(bulkRequest, new RestBuilderListener<BulkResponse>(channel) {
@Override

View File

@ -66,7 +66,7 @@ public class RestGetSourceAction extends BaseRestHandler {
client.get(getRequest, new RestResponseListener<GetResponse>(channel) {
@Override
public RestResponse buildResponse(GetResponse response) throws Exception {
XContentBuilder builder = channel.newBuilder(response.getSourceInternal(), false);
XContentBuilder builder = channel.newBuilder(request.getXContentType(), false);
if (response.isSourceEmpty()) { // check if doc source (or doc itself) is missing
return new BytesRestResponse(NOT_FOUND, builder);
} else {

View File

@ -65,7 +65,7 @@ public class RestIndexAction extends BaseRestHandler {
indexRequest.routing(request.param("routing"));
indexRequest.parent(request.param("parent")); // order is important, set it after routing, so it will set the routing
indexRequest.setPipeline(request.param("pipeline"));
indexRequest.source(request.content());
indexRequest.source(request.content(), request.getXContentType());
indexRequest.timeout(request.paramAsTime("timeout", IndexRequest.DEFAULT_TIMEOUT));
indexRequest.setRefreshPolicy(request.param("refresh"));
indexRequest.version(RestActions.parseVersion(request));

View File

@ -21,7 +21,10 @@ package org.elasticsearch.rest.action.ingest;
import org.elasticsearch.action.ingest.PutPipelineRequest;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
@ -38,7 +41,8 @@ public class RestPutPipelineAction extends BaseRestHandler {
@Override
public RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
PutPipelineRequest request = new PutPipelineRequest(restRequest.param("id"), restRequest.contentOrSourceParam());
Tuple<XContentType, BytesReference> sourceTuple = restRequest.contentOrSourceParam();
PutPipelineRequest request = new PutPipelineRequest(restRequest.param("id"), sourceTuple.v2(), sourceTuple.v1());
request.masterNodeTimeout(restRequest.paramAsTime("master_timeout", request.masterNodeTimeout()));
request.timeout(restRequest.paramAsTime("timeout", request.timeout()));
return channel -> client.admin().cluster().putPipeline(request, new AcknowledgedRestListener<>(channel));

View File

@ -21,7 +21,10 @@ package org.elasticsearch.rest.action.ingest;
import org.elasticsearch.action.ingest.SimulatePipelineRequest;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
@ -40,7 +43,8 @@ public class RestSimulatePipelineAction extends BaseRestHandler {
@Override
public RestChannelConsumer prepareRequest(RestRequest restRequest, NodeClient client) throws IOException {
SimulatePipelineRequest request = new SimulatePipelineRequest(restRequest.contentOrSourceParam());
Tuple<XContentType, BytesReference> sourceTuple = restRequest.contentOrSourceParam();
SimulatePipelineRequest request = new SimulatePipelineRequest(sourceTuple.v2(), sourceTuple.v1());
request.setId(restRequest.param("id"));
request.setVerbose(restRequest.paramAsBoolean("verbose", false));
return channel -> client.admin().cluster().simulatePipeline(request, new RestToXContentListener<>(channel));

View File

@ -20,12 +20,10 @@
package org.elasticsearch.rest.action.search;
import org.elasticsearch.action.search.ClearScrollRequest;
import org.elasticsearch.action.search.ClearScrollResponse;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
@ -50,26 +48,34 @@ public class RestClearScrollAction extends BaseRestHandler {
String scrollIds = request.param("scroll_id");
ClearScrollRequest clearRequest = new ClearScrollRequest();
clearRequest.setScrollIds(Arrays.asList(splitScrollIds(scrollIds)));
BytesReference body = request.contentOrSourceParam();
if (body.length() > 0) {
if (XContentFactory.xContentType(body) == null) {
scrollIds = body.utf8ToString();
clearRequest.setScrollIds(Arrays.asList(splitScrollIds(scrollIds)));
request.withContentOrSourceParamParserOrNullLenient((xContentParser -> {
if (xContentParser == null) {
if (request.hasContent()) {
// TODO: why do we accept this plain text value? maybe we can just use the scroll params?
BytesReference body = request.content();
String bodyScrollIds = body.utf8ToString();
clearRequest.setScrollIds(Arrays.asList(splitScrollIds(bodyScrollIds)));
}
} else {
// NOTE: if rest request with xcontent body has request parameters, these parameters does not override xcontent value
clearRequest.setScrollIds(null);
try (XContentParser parser = request.contentOrSourceParamParser()) {
buildFromContent(parser, clearRequest);
try {
buildFromContent(xContentParser, clearRequest);
} catch (IOException e) {
throw new IllegalArgumentException("Failed to parse request body", e);
}
}
}
}));
return channel -> client.clearScroll(clearRequest, new RestStatusToXContentListener<ClearScrollResponse>(channel));
return channel -> client.clearScroll(clearRequest, new RestStatusToXContentListener<>(channel));
}
public static String[] splitScrollIds(String scrollIds) {
@Override
public boolean supportsPlainText() {
return true;
}
private static String[] splitScrollIds(String scrollIds) {
if (scrollIds == null) {
return Strings.EMPTY_ARRAY;
}

View File

@ -26,10 +26,11 @@ import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContent;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
@ -93,7 +94,7 @@ public class RestMultiSearchAction extends BaseRestHandler {
}
/**
* Parses a multi-line {@link RestRequest} body, instanciating a {@link SearchRequest} for each line and applying the given consumer.
* Parses a multi-line {@link RestRequest} body, instantiating a {@link SearchRequest} for each line and applying the given consumer.
*/
public static void parseMultiLineRequest(RestRequest request, IndicesOptions indicesOptions, boolean allowExplicitIndex,
BiConsumer<SearchRequest, XContentParser> consumer) throws IOException {
@ -103,9 +104,10 @@ public class RestMultiSearchAction extends BaseRestHandler {
String searchType = request.param("search_type");
String routing = request.param("routing");
final BytesReference data = request.contentOrSourceParam();
final Tuple<XContentType, BytesReference> sourceTuple = request.contentOrSourceParam();
final XContent xContent = sourceTuple.v1().xContent();
final BytesReference data = sourceTuple.v2();
XContent xContent = XContentFactory.xContent(data);
int from = 0;
int length = data.length();
byte marker = xContent.streamSeparator();
@ -176,7 +178,7 @@ public class RestMultiSearchAction extends BaseRestHandler {
break;
}
BytesReference bytes = data.slice(from, nextMarker - from);
try (XContentParser parser = XContentFactory.xContent(bytes).createParser(request.getXContentRegistry(), bytes)) {
try (XContentParser parser = xContent.createParser(request.getXContentRegistry(), bytes)) {
consumer.accept(searchRequest, parser);
}
// move pointers

View File

@ -24,7 +24,6 @@ import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
@ -58,25 +57,33 @@ public class RestSearchScrollAction extends BaseRestHandler {
searchScrollRequest.scroll(new Scroll(parseTimeValue(scroll, null, "scroll")));
}
BytesReference body = request.contentOrSourceParam();
if (body.length() > 0) {
if (XContentFactory.xContentType(body) == null) {
if (scrollId == null) {
scrollId = body.utf8ToString();
searchScrollRequest.scrollId(scrollId);
request.withContentOrSourceParamParserOrNull(xContentParser -> {
if (xContentParser == null) {
if (request.hasContent()) {
// TODO: why do we accept this plain text value? maybe we can just use the scroll params?
BytesReference body = request.getContentOrSourceParamOnly();
if (scrollId == null) {
String bodyScrollId = body.utf8ToString();
searchScrollRequest.scrollId(bodyScrollId);
}
}
} else {
// NOTE: if rest request with xcontent body has request parameters, these parameters override xcontent values
try (XContentParser parser = request.contentOrSourceParamParser()) {
buildFromContent(parser, searchScrollRequest);
try {
buildFromContent(xContentParser, searchScrollRequest);
} catch (IOException e) {
throw new IllegalArgumentException("Failed to parse request body", e);
}
}
}
});
return channel -> client.searchScroll(searchScrollRequest, new RestStatusToXContentListener<>(channel));
}
@Override
public boolean supportsPlainText() {
return true;
}
public static void buildFromContent(XContentParser parser, SearchScrollRequest searchScrollRequest) throws IOException {
if (parser.nextToken() != XContentParser.Token.START_OBJECT) {
throw new IllegalArgumentException("Malformed content, must start with an object");

View File

@ -276,7 +276,6 @@ public final class ScriptMetaData implements MetaData.Custom, Writeable, ToXCont
} else {
source = new StoredScriptSource(id.substring(0, split), parser.text(), Collections.emptyMap());
}
scripts.put(id, source);
id = null;

View File

@ -389,7 +389,7 @@ public class ScriptService extends AbstractComponent implements Closeable, Clust
request.content().length() + "] for script [" + request.id() + "]");
}
StoredScriptSource source = StoredScriptSource.parse(request.lang(), request.content());
StoredScriptSource source = StoredScriptSource.parse(request.lang(), request.content(), request.xContentType());
if (isLangSupported(source.getLang()) == false) {
throw new IllegalArgumentException("unable to put stored script with unsupported lang [" + source.getLang() + "]");

View File

@ -40,6 +40,7 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentParser.Token;
import org.elasticsearch.common.xcontent.XContentType;
import java.io.IOException;
import java.io.UncheckedIOException;
@ -231,8 +232,8 @@ public class StoredScriptSource extends AbstractDiffable<StoredScriptSource> imp
* @param content The content from the request to be parsed as described above.
* @return The parsed {@link StoredScriptSource}.
*/
public static StoredScriptSource parse(String lang, BytesReference content) {
try (XContentParser parser = XContentHelper.createParser(NamedXContentRegistry.EMPTY, content)) {
public static StoredScriptSource parse(String lang, BytesReference content, XContentType xContentType) {
try (XContentParser parser = xContentType.xContent().createParser(NamedXContentRegistry.EMPTY, content)) {
Token token = parser.nextToken();
if (token != Token.START_OBJECT) {

View File

@ -75,6 +75,7 @@ import org.elasticsearch.action.termvectors.TermVectorsRequest;
import org.elasticsearch.action.update.UpdateAction;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.Requests;
import org.elasticsearch.cluster.metadata.IndexNameExpressionResolver;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.settings.Settings;
@ -203,7 +204,8 @@ public class IndicesRequestIT extends ESIntegTestCase {
String[] indexShardActions = new String[]{BulkAction.NAME + "[s][p]", BulkAction.NAME + "[s][r]"};
interceptTransportActions(indexShardActions);
IndexRequest indexRequest = new IndexRequest(randomIndexOrAlias(), "type", "id").source("field", "value");
IndexRequest indexRequest = new IndexRequest(randomIndexOrAlias(), "type", "id")
.source(Requests.INDEX_CONTENT_TYPE, "field", "value");
internalCluster().coordOnlyNodeClient().index(indexRequest).actionGet();
clearInterceptedActions();
@ -228,7 +230,7 @@ public class IndicesRequestIT extends ESIntegTestCase {
String indexOrAlias = randomIndexOrAlias();
client().prepareIndex(indexOrAlias, "type", "id").setSource("field", "value").get();
UpdateRequest updateRequest = new UpdateRequest(indexOrAlias, "type", "id").doc("field1", "value1");
UpdateRequest updateRequest = new UpdateRequest(indexOrAlias, "type", "id").doc(Requests.INDEX_CONTENT_TYPE, "field1", "value1");
UpdateResponse updateResponse = internalCluster().coordOnlyNodeClient().update(updateRequest).actionGet();
assertEquals(DocWriteResponse.Result.UPDATED, updateResponse.getResult());
@ -242,7 +244,8 @@ public class IndicesRequestIT extends ESIntegTestCase {
interceptTransportActions(updateShardActions);
String indexOrAlias = randomIndexOrAlias();
UpdateRequest updateRequest = new UpdateRequest(indexOrAlias, "type", "id").upsert("field", "value").doc("field1", "value1");
UpdateRequest updateRequest = new UpdateRequest(indexOrAlias, "type", "id").upsert(Requests.INDEX_CONTENT_TYPE, "field", "value")
.doc(Requests.INDEX_CONTENT_TYPE, "field1", "value1");
UpdateResponse updateResponse = internalCluster().coordOnlyNodeClient().update(updateRequest).actionGet();
assertEquals(DocWriteResponse.Result.CREATED, updateResponse.getResult());
@ -275,7 +278,7 @@ public class IndicesRequestIT extends ESIntegTestCase {
int numIndexRequests = iterations(1, 10);
for (int i = 0; i < numIndexRequests; i++) {
String indexOrAlias = randomIndexOrAlias();
bulkRequest.add(new IndexRequest(indexOrAlias, "type", "id").source("field", "value"));
bulkRequest.add(new IndexRequest(indexOrAlias, "type", "id").source(Requests.INDEX_CONTENT_TYPE, "field", "value"));
indices.add(indexOrAlias);
}
int numDeleteRequests = iterations(1, 10);
@ -287,7 +290,7 @@ public class IndicesRequestIT extends ESIntegTestCase {
int numUpdateRequests = iterations(1, 10);
for (int i = 0; i < numUpdateRequests; i++) {
String indexOrAlias = randomIndexOrAlias();
bulkRequest.add(new UpdateRequest(indexOrAlias, "type", "id").doc("field1", "value1"));
bulkRequest.add(new UpdateRequest(indexOrAlias, "type", "id").doc(Requests.INDEX_CONTENT_TYPE, "field1", "value1"));
indices.add(indexOrAlias);
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.action;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.test.ESIntegTestCase;
@ -38,7 +39,7 @@ public class ListenerActionIT extends ESIntegTestCase {
IndexRequest request = new IndexRequest("test", "type", "1");
if (randomBoolean()) {
// set the source, without it, we will have a verification failure
request.source("field1", "value1");
request.source(Requests.INDEX_CONTENT_TYPE, "field1", "value1");
}
client.index(request, new ActionListener<IndexResponse>() {

View File

@ -50,6 +50,7 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.builder.SearchSourceBuilder;
@ -300,7 +301,8 @@ public class TasksIT extends ESIntegTestCase {
registerTaskManageListeners(BulkAction.NAME + "[s][r]"); // shard task on replica
createIndex("test");
ensureGreen("test"); // Make sure all shards are allocated to catch replication tasks
client().prepareBulk().add(client().prepareIndex("test", "doc", "test_id").setSource("{\"foo\": \"bar\"}")).get();
client().prepareBulk().add(client().prepareIndex("test", "doc", "test_id")
.setSource("{\"foo\": \"bar\"}", XContentType.JSON)).get();
// the bulk operation should produce one main task
List<TaskInfo> topTask = findEvents(BulkAction.NAME, Tuple::v1);
@ -352,7 +354,7 @@ public class TasksIT extends ESIntegTestCase {
registerTaskManageListeners(SearchAction.NAME + "[*]"); // shard task
createIndex("test");
ensureGreen("test"); // Make sure all shards are allocated to catch replication tasks
client().prepareIndex("test", "doc", "test_id").setSource("{\"foo\": \"bar\"}")
client().prepareIndex("test", "doc", "test_id").setSource("{\"foo\": \"bar\"}", XContentType.JSON)
.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE).get();
assertSearchResponse(client().prepareSearch("test").setTypes("doc").setQuery(QueryBuilders.matchAllQuery()).get());

View File

@ -801,6 +801,6 @@ public class TransportTasksActionTests extends TaskManagerTestCase {
builder.endObject();
builder.flush();
logger.info(builder.string());
return XContentHelper.convertToMap(builder.bytes(), false).v2();
return XContentHelper.convertToMap(builder.bytes(), false, builder.contentType()).v2();
}
}

View File

@ -209,7 +209,7 @@ public class ClusterRerouteRequestTests extends ESTestCase {
FakeRestRequest.Builder requestBuilder = new FakeRestRequest.Builder(xContentRegistry());
requestBuilder.withParams(params);
if (hasBody) {
requestBuilder.withContent(builder.bytes());
requestBuilder.withContent(builder.bytes(), builder.contentType());
}
return requestBuilder.build();
}

View File

@ -0,0 +1,72 @@
/*
* 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.
*/
package org.elasticsearch.action.admin.cluster.storedscripts;
import org.elasticsearch.Version;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Base64;
public class PutStoredScriptRequestTests extends ESTestCase {
public void testSerialization() throws IOException {
PutStoredScriptRequest storedScriptRequest = new PutStoredScriptRequest("foo", "bar", new BytesArray("{}"), XContentType.JSON);
assertEquals(XContentType.JSON, storedScriptRequest.xContentType());
try (BytesStreamOutput output = new BytesStreamOutput()) {
storedScriptRequest.writeTo(output);
try (StreamInput in = output.bytes().streamInput()) {
PutStoredScriptRequest serialized = new PutStoredScriptRequest();
serialized.readFrom(in);
assertEquals(XContentType.JSON, serialized.xContentType());
assertEquals(storedScriptRequest.lang(), serialized.lang());
assertEquals(storedScriptRequest.id(), serialized.id());
}
}
}
public void testSerializationBwc() throws IOException {
final byte[] rawStreamBytes = Base64.getDecoder().decode("ADwDCG11c3RhY2hlAQZzY3JpcHQCe30A");
final Version version = randomFrom(Version.V_5_0_0, Version.V_5_0_1, Version.V_5_0_2,
Version.V_5_0_3_UNRELEASED, Version.V_5_1_1_UNRELEASED, Version.V_5_1_2_UNRELEASED, Version.V_5_2_0_UNRELEASED);
try (StreamInput in = StreamInput.wrap(rawStreamBytes)) {
in.setVersion(version);
PutStoredScriptRequest serialized = new PutStoredScriptRequest();
serialized.readFrom(in);
assertEquals(XContentType.JSON, serialized.xContentType());
assertEquals("mustache", serialized.lang());
assertEquals("script", serialized.id());
assertEquals(new BytesArray("{}"), serialized.content());
try (BytesStreamOutput out = new BytesStreamOutput()) {
out.setVersion(version);
serialized.writeTo(out);
out.flush();
assertArrayEquals(rawStreamBytes, out.bytes().toBytesRef().bytes);
}
}
}
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.action.admin.indices.create;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.client.NoOpClient;
import org.junit.After;
@ -57,7 +58,7 @@ public class CreateIndexRequestBuilderTests extends ESTestCase {
*/
public void testSetSource() throws IOException {
CreateIndexRequestBuilder builder = new CreateIndexRequestBuilder(this.testClient, CreateIndexAction.INSTANCE);
builder.setSource("{\""+KEY+"\" : \""+VALUE+"\"}");
builder.setSource("{\""+KEY+"\" : \""+VALUE+"\"}", XContentType.JSON);
assertEquals(VALUE, builder.request().settings().get(KEY));
XContentBuilder xContent = XContentFactory.jsonBuilder().startObject().field(KEY, VALUE).endObject();
@ -68,7 +69,7 @@ public class CreateIndexRequestBuilderTests extends ESTestCase {
ByteArrayOutputStream docOut = new ByteArrayOutputStream();
XContentBuilder doc = XContentFactory.jsonBuilder(docOut).startObject().field(KEY, VALUE).endObject();
doc.close();
builder.setSource(docOut.toByteArray());
builder.setSource(docOut.toByteArray(), XContentType.JSON);
assertEquals(VALUE, builder.request().settings().get(KEY));
Map<String, String> settingsMap = new HashMap<>();
@ -85,7 +86,7 @@ public class CreateIndexRequestBuilderTests extends ESTestCase {
builder.setSettings(KEY, VALUE);
assertEquals(VALUE, builder.request().settings().get(KEY));
builder.setSettings("{\""+KEY+"\" : \""+VALUE+"\"}");
builder.setSettings("{\""+KEY+"\" : \""+VALUE+"\"}", XContentType.JSON);
assertEquals(VALUE, builder.request().settings().get(KEY));
builder.setSettings(Settings.builder().put(KEY, VALUE));

View File

@ -0,0 +1,72 @@
/*
* 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.
*/
package org.elasticsearch.action.admin.indices.create;
import org.elasticsearch.Version;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.json.JsonXContent;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Base64;
public class CreateIndexRequestTests extends ESTestCase {
public void testSerialization() throws IOException {
CreateIndexRequest request = new CreateIndexRequest("foo");
String mapping = JsonXContent.contentBuilder().startObject().startObject("type").endObject().endObject().string();
request.mapping("my_type", mapping, XContentType.JSON);
try (BytesStreamOutput output = new BytesStreamOutput()) {
request.writeTo(output);
try (StreamInput in = output.bytes().streamInput()) {
CreateIndexRequest serialized = new CreateIndexRequest();
serialized.readFrom(in);
assertEquals(request.index(), serialized.index());
assertEquals(mapping, serialized.mappings().get("my_type"));
}
}
}
public void testSerializationBwc() throws IOException {
final byte[] data = Base64.getDecoder().decode("ADwDAANmb28APAMBB215X3R5cGULeyJ0eXBlIjp7fX0AAAD////+AA==");
final Version version = randomFrom(Version.V_5_0_0, Version.V_5_0_1, Version.V_5_0_2,
Version.V_5_0_3_UNRELEASED, Version.V_5_1_1_UNRELEASED, Version.V_5_1_2_UNRELEASED, Version.V_5_2_0_UNRELEASED);
try (StreamInput in = StreamInput.wrap(data)) {
in.setVersion(version);
CreateIndexRequest serialized = new CreateIndexRequest();
serialized.readFrom(in);
assertEquals("foo", serialized.index());
BytesReference bytesReference = JsonXContent.contentBuilder().startObject().startObject("type").endObject().endObject().bytes();
assertEquals(bytesReference.utf8ToString(), serialized.mappings().get("my_type"));
try (BytesStreamOutput out = new BytesStreamOutput()) {
out.setVersion(version);
serialized.writeTo(out);
out.flush();
assertArrayEquals(data, out.bytes().toBytesRef().bytes);
}
}
}
}

View File

@ -32,6 +32,7 @@ import org.elasticsearch.cluster.routing.UnassignedInfo;
import org.elasticsearch.common.Priority;
import org.elasticsearch.common.collect.ImmutableOpenMap;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.TermsQueryBuilder;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
@ -59,7 +60,8 @@ public class ShrinkIndexIT extends ESIntegTestCase {
internalCluster().ensureAtLeastNumDataNodes(2);
prepareCreate("source").setSettings(Settings.builder().put(indexSettings()).put("number_of_shards", shardSplits[0])).get();
for (int i = 0; i < 20; i++) {
client().prepareIndex("source", "t1", Integer.toString(i)).setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}").get();
client().prepareIndex("source", "t1", Integer.toString(i))
.setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}", XContentType.JSON).get();
}
ImmutableOpenMap<String, DiscoveryNode> dataNodes = client().admin().cluster().prepareState().get().getState().nodes()
.getDataNodes();
@ -85,7 +87,8 @@ public class ShrinkIndexIT extends ESIntegTestCase {
assertHitCount(client().prepareSearch("first_shrink").setSize(100).setQuery(new TermsQueryBuilder("foo", "bar")).get(), 20);
for (int i = 0; i < 20; i++) { // now update
client().prepareIndex("first_shrink", "t1", Integer.toString(i)).setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}").get();
client().prepareIndex("first_shrink", "t1", Integer.toString(i))
.setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}", XContentType.JSON).get();
}
flushAndRefresh();
assertHitCount(client().prepareSearch("first_shrink").setSize(100).setQuery(new TermsQueryBuilder("foo", "bar")).get(), 20);
@ -113,7 +116,8 @@ public class ShrinkIndexIT extends ESIntegTestCase {
assertHitCount(client().prepareSearch("second_shrink").setSize(100).setQuery(new TermsQueryBuilder("foo", "bar")).get(), 20);
for (int i = 0; i < 20; i++) { // now update
client().prepareIndex("second_shrink", "t1", Integer.toString(i)).setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}").get();
client().prepareIndex("second_shrink", "t1", Integer.toString(i))
.setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}", XContentType.JSON).get();
}
flushAndRefresh();
assertHitCount(client().prepareSearch("second_shrink").setSize(100).setQuery(new TermsQueryBuilder("foo", "bar")).get(), 20);
@ -129,7 +133,8 @@ public class ShrinkIndexIT extends ESIntegTestCase {
.put("index.version.created", version)
).get();
for (int i = 0; i < 20; i++) {
client().prepareIndex("source", randomFrom("t1", "t2", "t3")).setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}").get();
client().prepareIndex("source", randomFrom("t1", "t2", "t3"))
.setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}", XContentType.JSON).get();
}
ImmutableOpenMap<String, DiscoveryNode> dataNodes = client().admin().cluster().prepareState().get().getState().nodes()
.getDataNodes();
@ -164,7 +169,8 @@ public class ShrinkIndexIT extends ESIntegTestCase {
}
for (int i = 20; i < 40; i++) {
client().prepareIndex("target", randomFrom("t1", "t2", "t3")).setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}").get();
client().prepareIndex("target", randomFrom("t1", "t2", "t3"))
.setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}", XContentType.JSON).get();
}
flushAndRefresh();
assertHitCount(client().prepareSearch("target").setSize(100).setQuery(new TermsQueryBuilder("foo", "bar")).get(), 40);
@ -181,7 +187,8 @@ public class ShrinkIndexIT extends ESIntegTestCase {
.put("number_of_shards", randomIntBetween(2, 7))
.put("number_of_replicas", 0)).get();
for (int i = 0; i < 20; i++) {
client().prepareIndex("source", randomFrom("t1", "t2", "t3")).setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}").get();
client().prepareIndex("source", randomFrom("t1", "t2", "t3"))
.setSource("{\"foo\" : \"bar\", \"i\" : " + i + "}", XContentType.JSON).get();
}
ImmutableOpenMap<String, DiscoveryNode> dataNodes = client().admin().cluster().prepareState().get().getState().nodes()
.getDataNodes();

View File

@ -0,0 +1,52 @@
/*
* 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.
*/
package org.elasticsearch.action.admin.indices.mapping.get;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class GetFieldMappingsResponseTests extends ESTestCase {
public void testSerialization() throws IOException {
Map<String, Map<String, Map<String, FieldMappingMetaData>>> mappings = new HashMap<>();
FieldMappingMetaData fieldMappingMetaData = new FieldMappingMetaData("my field", new BytesArray("{}"));
mappings.put("index", Collections.singletonMap("type", Collections.singletonMap("field", fieldMappingMetaData)));
GetFieldMappingsResponse response = new GetFieldMappingsResponse(mappings);
try (BytesStreamOutput out = new BytesStreamOutput()) {
response.writeTo(out);
GetFieldMappingsResponse serialized = new GetFieldMappingsResponse();
try (StreamInput in = StreamInput.wrap(out.bytes().toBytesRef().bytes)) {
serialized.readFrom(in);
FieldMappingMetaData metaData = serialized.fieldMappings("index", "type", "field");
assertNotNull(metaData);
assertEquals(new BytesArray("{}"), metaData.getSource());
}
}
}
}

View File

@ -19,10 +19,20 @@
package org.elasticsearch.action.admin.indices.mapping.put;
import org.elasticsearch.Version;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.io.stream.BytesStreamOutput;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.common.xcontent.yaml.YamlXContent;
import org.elasticsearch.index.Index;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.Base64;
public class PutMappingRequestTests extends ESTestCase {
public void testValidation() {
@ -41,12 +51,12 @@ public class PutMappingRequestTests extends ESTestCase {
assertNotNull("source validation should fail", ex);
assertTrue(ex.getMessage().contains("source is missing"));
r.source("");
r.source("", XContentType.JSON);
ex = r.validate();
assertNotNull("source validation should fail", ex);
assertTrue(ex.getMessage().contains("source is empty"));
r.source("somevalidmapping");
r.source("somevalidmapping", XContentType.JSON);
ex = r.validate();
assertNull("validation should succeed", ex);
@ -64,4 +74,33 @@ public class PutMappingRequestTests extends ESTestCase {
() -> PutMappingRequest.buildFromSimplifiedDef("type", "only_field"));
assertEquals("mapping source must be pairs of fieldnames and properties definition.", e.getMessage());
}
public void testPutMappingRequestSerialization() throws IOException {
PutMappingRequest request = new PutMappingRequest("foo");
String mapping = YamlXContent.contentBuilder().startObject().field("foo", "bar").endObject().string();
request.source(mapping, XContentType.YAML);
assertEquals(XContentHelper.convertToJson(new BytesArray(mapping), false, XContentType.YAML), request.source());
BytesStreamOutput bytesStreamOutput = new BytesStreamOutput();
request.writeTo(bytesStreamOutput);
StreamInput in = StreamInput.wrap(bytesStreamOutput.bytes().toBytesRef().bytes);
PutMappingRequest serialized = new PutMappingRequest();
serialized.readFrom(in);
String source = serialized.source();
assertEquals(XContentHelper.convertToJson(new BytesArray(mapping), false, XContentType.YAML), source);
}
public void testSerializationBwc() throws IOException {
final byte[] data = Base64.getDecoder().decode("ADwDAQNmb28MAA8tLS0KZm9vOiAiYmFyIgoAPAMAAAA=");
final Version version = randomFrom(Version.V_5_0_0, Version.V_5_0_1, Version.V_5_0_2,
Version.V_5_0_3_UNRELEASED, Version.V_5_1_1_UNRELEASED, Version.V_5_1_2_UNRELEASED, Version.V_5_2_0_UNRELEASED);
try (StreamInput in = StreamInput.wrap(data)) {
in.setVersion(version);
PutMappingRequest request = new PutMappingRequest();
request.readFrom(in);
String mapping = YamlXContent.contentBuilder().startObject().field("foo", "bar").endObject().string();
assertEquals(XContentHelper.convertToJson(new BytesArray(mapping), false, XContentType.YAML), request.source());
}
}
}

View File

@ -19,9 +19,10 @@
package org.elasticsearch.action.admin.indices.template;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.test.ESSingleNodeTestCase;
import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
import static org.elasticsearch.test.StreamsUtils.copyToBytesFromClasspath;
/**
* Rudimentary tests that the templates used by Logstash and Beats
@ -29,14 +30,14 @@ import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
*/
public class BWCTemplateTests extends ESSingleNodeTestCase {
public void testBeatsTemplatesBWC() throws Exception {
String metricBeat = copyToStringFromClasspath("/org/elasticsearch/action/admin/indices/template/metricbeat-5.0.template.json");
String packetBeat = copyToStringFromClasspath("/org/elasticsearch/action/admin/indices/template/packetbeat-5.0.template.json");
String fileBeat = copyToStringFromClasspath("/org/elasticsearch/action/admin/indices/template/filebeat-5.0.template.json");
String winLogBeat = copyToStringFromClasspath("/org/elasticsearch/action/admin/indices/template/winlogbeat-5.0.template.json");
client().admin().indices().preparePutTemplate("metricbeat").setSource(metricBeat).get();
client().admin().indices().preparePutTemplate("packetbeat").setSource(packetBeat).get();
client().admin().indices().preparePutTemplate("filebeat").setSource(fileBeat).get();
client().admin().indices().preparePutTemplate("winlogbeat").setSource(winLogBeat).get();
byte[] metricBeat = copyToBytesFromClasspath("/org/elasticsearch/action/admin/indices/template/metricbeat-5.0.template.json");
byte[] packetBeat = copyToBytesFromClasspath("/org/elasticsearch/action/admin/indices/template/packetbeat-5.0.template.json");
byte[] fileBeat = copyToBytesFromClasspath("/org/elasticsearch/action/admin/indices/template/filebeat-5.0.template.json");
byte[] winLogBeat = copyToBytesFromClasspath("/org/elasticsearch/action/admin/indices/template/winlogbeat-5.0.template.json");
client().admin().indices().preparePutTemplate("metricbeat").setSource(metricBeat, XContentType.JSON).get();
client().admin().indices().preparePutTemplate("packetbeat").setSource(packetBeat, XContentType.JSON).get();
client().admin().indices().preparePutTemplate("filebeat").setSource(fileBeat, XContentType.JSON).get();
client().admin().indices().preparePutTemplate("winlogbeat").setSource(winLogBeat, XContentType.JSON).get();
client().prepareIndex("metricbeat-foo", "doc", "1").setSource("message", "foo").get();
client().prepareIndex("packetbeat-foo", "doc", "1").setSource("message", "foo").get();
@ -46,8 +47,8 @@ public class BWCTemplateTests extends ESSingleNodeTestCase {
}
public void testLogstashTemplatesBWC() throws Exception {
String ls5x = copyToStringFromClasspath("/org/elasticsearch/action/admin/indices/template/logstash-5.0.template.json");
client().admin().indices().preparePutTemplate("logstash-5x").setSource(ls5x).get();
byte[] ls5x = copyToBytesFromClasspath("/org/elasticsearch/action/admin/indices/template/logstash-5.0.template.json");
client().admin().indices().preparePutTemplate("logstash-5x").setSource(ls5x, XContentType.JSON).get();
client().prepareIndex("logstash-foo", "doc", "1").setSource("message", "foo").get();
assertWarnings("Deprecated field [template] used, replaced by [index_patterns]");
}

Some files were not shown because too many files have changed in this diff Show More