summaryrefslogtreecommitdiff
path: root/core/src/main/java/org/elasticsearch
diff options
context:
space:
mode:
authorJay Modi <jaymode@users.noreply.github.com>2017-02-02 14:07:13 -0500
committerGitHub <noreply@github.com>2017-02-02 14:07:13 -0500
commit7520a107bee67099338813728147d2aee25ed240 (patch)
tree22828e74c5aa601c185c36c7463665fbfeaa4c51 /core/src/main/java/org/elasticsearch
parentb41d5747f0bd67dad05c8168312ba456bcdaebda (diff)
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
Diffstat (limited to 'core/src/main/java/org/elasticsearch')
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequest.java18
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequestBuilder.java17
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java24
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestBuilder.java21
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java20
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequestBuilder.java17
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java32
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java33
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java42
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestBuilder.java23
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/analyze/AnalyzeRequest.java2
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java119
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestBuilder.java67
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java10
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsIndexAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java38
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestBuilder.java11
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequest.java16
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequestBuilder.java15
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java102
-rw-r--r--core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequestBuilder.java61
-rw-r--r--core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java59
-rw-r--r--core/src/main/java/org/elasticsearch/action/bulk/BulkRequestBuilder.java22
-rw-r--r--core/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java12
-rw-r--r--core/src/main/java/org/elasticsearch/action/bulk/byscroll/ClientScrollableHitSource.java6
-rw-r--r--core/src/main/java/org/elasticsearch/action/bulk/byscroll/ScrollableHitSource.java16
-rw-r--r--core/src/main/java/org/elasticsearch/action/index/IndexRequest.java115
-rw-r--r--core/src/main/java/org/elasticsearch/action/index/IndexRequestBuilder.java62
-rw-r--r--core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequest.java40
-rw-r--r--core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequestBuilder.java6
-rw-r--r--core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequest.java35
-rw-r--r--core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequestBuilder.java24
-rw-r--r--core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineTransportAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/action/termvectors/TermVectorsRequest.java32
-rw-r--r--core/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java3
-rw-r--r--core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java80
-rw-r--r--core/src/main/java/org/elasticsearch/action/update/UpdateRequestBuilder.java74
-rw-r--r--core/src/main/java/org/elasticsearch/client/ClusterAdminClient.java14
-rw-r--r--core/src/main/java/org/elasticsearch/client/support/AbstractClient.java11
-rw-r--r--core/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java1
-rw-r--r--core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java6
-rw-r--r--core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java1
-rw-r--r--core/src/main/java/org/elasticsearch/common/settings/Settings.java22
-rw-r--r--core/src/main/java/org/elasticsearch/common/settings/loader/SettingsLoaderFactory.java26
-rw-r--r--core/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java39
-rw-r--r--core/src/main/java/org/elasticsearch/common/xcontent/XContentGenerator.java30
-rw-r--r--core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java79
-rw-r--r--core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java36
-rw-r--r--core/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContentGenerator.java15
-rw-r--r--core/src/main/java/org/elasticsearch/http/HttpTransportSettings.java2
-rw-r--r--core/src/main/java/org/elasticsearch/index/IndexingSlowLog.java2
-rw-r--r--core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java4
-rw-r--r--core/src/main/java/org/elasticsearch/index/mapper/DocumentMapperParser.java6
-rw-r--r--core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java1
-rwxr-xr-xcore/src/main/java/org/elasticsearch/index/mapper/MapperService.java10
-rw-r--r--core/src/main/java/org/elasticsearch/index/mapper/ParsedDocument.java12
-rw-r--r--core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java3
-rw-r--r--core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java22
-rw-r--r--core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java26
-rw-r--r--core/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java4
-rw-r--r--core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java12
-rw-r--r--core/src/main/java/org/elasticsearch/ingest/PipelineConfiguration.java44
-rw-r--r--core/src/main/java/org/elasticsearch/ingest/PipelineStore.java4
-rw-r--r--core/src/main/java/org/elasticsearch/rest/AbstractRestChannel.java37
-rw-r--r--core/src/main/java/org/elasticsearch/rest/BytesRestResponse.java8
-rw-r--r--core/src/main/java/org/elasticsearch/rest/RestChannel.java5
-rw-r--r--core/src/main/java/org/elasticsearch/rest/RestController.java132
-rw-r--r--core/src/main/java/org/elasticsearch/rest/RestHandler.java10
-rw-r--r--core/src/main/java/org/elasticsearch/rest/RestRequest.java193
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestPutStoredScriptAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java5
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestUpdateSettingsAction.java4
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/document/RestGetSourceAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/document/RestIndexAction.java2
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/ingest/RestPutPipelineAction.java6
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/ingest/RestSimulatePipelineAction.java6
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/search/RestClearScrollAction.java30
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java12
-rw-r--r--core/src/main/java/org/elasticsearch/rest/action/search/RestSearchScrollAction.java27
-rw-r--r--core/src/main/java/org/elasticsearch/script/ScriptMetaData.java1
-rw-r--r--core/src/main/java/org/elasticsearch/script/ScriptService.java2
-rw-r--r--core/src/main/java/org/elasticsearch/script/StoredScriptSource.java5
85 files changed, 1890 insertions, 315 deletions
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequest.java
index a06175a598..f0f8d50b4c 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequest.java
@@ -142,9 +142,11 @@ 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;
@@ -153,6 +155,18 @@ public class PutRepositoryRequest extends AcknowledgedRequest<PutRepositoryReque
/**
* 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.
+ *
* @param source repository settings
* @return this request
*/
@@ -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);
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequestBuilder.java
index 39cfa6af7f..aed09daff2 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/repositories/put/PutRepositoryRequestBuilder.java
@@ -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,17 +90,31 @@ 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
*
* @param source repository settings
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java
index e5f5bdb7fb..bd0110e644 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequest.java
@@ -83,13 +83,23 @@ 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
*/
@SuppressWarnings("unchecked")
@@ -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,13 +132,23 @@ 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
*/
@SuppressWarnings("unchecked")
@@ -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);
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestBuilder.java
index f0492edfeb..906b1867b1 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestBuilder.java
@@ -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,13 +53,23 @@ 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
*/
public ClusterUpdateSettingsRequestBuilder setTransientSettings(Map settings) {
@@ -84,13 +95,23 @@ 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
*/
public ClusterUpdateSettingsRequestBuilder setPersistentSettings(Map settings) {
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java
index ae715050e8..3267b6d9c9 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequest.java
@@ -288,19 +288,35 @@ 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>
* See repository documentation for more information.
@@ -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);
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequestBuilder.java
index ebdd206b5c..d3b5e12351 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/create/CreateSnapshotRequestBuilder.java
@@ -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,13 +148,29 @@ 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>
* See repository documentation for more information.
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java
index a7bbd02ee5..9d8ed49aaa 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequest.java
@@ -313,19 +313,35 @@ 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>
* See repository documentation for more information.
@@ -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,7 +452,9 @@ 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;
@@ -445,11 +463,19 @@ public class RestoreSnapshotRequest extends MasterNodeRequest<RestoreSnapshotReq
/**
* 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
+ */
public RestoreSnapshotRequest indexSettings(Map<String, Object> source) {
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);
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java
index 661a1a1d01..807e238724 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/snapshots/restore/RestoreSnapshotRequestBuilder.java
@@ -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,19 +154,35 @@ 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>
* See repository documentation for more information.
@@ -251,7 +268,9 @@ 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;
@@ -261,6 +280,18 @@ public class RestoreSnapshotRequestBuilder extends MasterNodeOperationRequestBui
* 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
+ *
+ * @param source index settings
* @return this builder
*/
public RestoreSnapshotRequestBuilder setIndexSettings(Map<String, Object> source) {
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java
index 0dcfe22514..28c70dc45b 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequest.java
@@ -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 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) {
- this.content = 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
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestBuilder.java
index b701745e47..f8223d6919 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/cluster/storedscripts/PutStoredScriptRequestBuilder.java
@@ -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;
}
- public PutStoredScriptRequestBuilder setLang(String lang) {
- request.lang(lang);
-
+ /**
+ * 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;
}
- public PutStoredScriptRequestBuilder setContent(BytesReference content) {
- request.content(content);
+ /**
+ * 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;
}
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/analyze/AnalyzeRequest.java b/core/src/main/java/org/elasticsearch/action/admin/indices/analyze/AnalyzeRequest.java
index 6d0824eeb3..08f220e019 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/analyze/AnalyzeRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/analyze/AnalyzeRequest.java
@@ -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);
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java b/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java
index 203483d89b..798c08bd18 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequest.java
@@ -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++) {
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestBuilder.java
index eaae4d53b7..237c88244b 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/create/CreateIndexRequestBuilder.java
@@ -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,14 +77,24 @@ 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.
*/
public CreateIndexRequestBuilder setSettings(Object... settings) {
@@ -104,13 +115,27 @@ 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.
*/
public CreateIndexRequestBuilder setCause(String cause) {
@@ -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,6 +263,16 @@ 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;
@@ -224,6 +281,14 @@ public class CreateIndexRequestBuilder extends AcknowledgedRequestBuilder<Create
/**
* 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.
+ */
public CreateIndexRequestBuilder setSource(Map<String, ?> source) {
request.source(source);
return this;
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java
index e0cedcf841..3f4ddaf08d 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/GetFieldMappingsResponse.java
@@ -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;
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsIndexAction.java b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsIndexAction.java
index 864c6703c4..ec84ce4e34 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsIndexAction.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/get/TransportGetFieldMappingsIndexAction.java
@@ -220,4 +220,4 @@ public class TransportGetFieldMappingsIndexAction extends TransportSingleShardAc
}
}
-} \ No newline at end of file
+}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java
index 152bc51654..400701f91c 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequest.java
@@ -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);
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestBuilder.java
index c21c40cf04..012a593ebc 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/mapping/put/PutMappingRequestBuilder.java
@@ -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,13 +83,23 @@ 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").
*/
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequest.java b/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequest.java
index e912c6ec73..80f3fb1a07 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequest.java
@@ -121,14 +121,24 @@ 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);
}
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequestBuilder.java
index 36dfbf3b2d..a9cecbfc5a 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/settings/put/UpdateSettingsRequestBuilder.java
@@ -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);
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java b/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java
index a7d6241d31..b0c13540df 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequest.java
@@ -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++) {
diff --git a/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequestBuilder.java
index c1db96ae7c..e7ca25e511 100644
--- a/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/admin/indices/template/put/PutIndexTemplateRequestBuilder.java
@@ -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,13 +131,27 @@ 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;
+ }
}
diff --git a/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java b/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java
index 20d5e64f49..371659586f 100644
--- a/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/bulk/BulkRequest.java
@@ -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)
diff --git a/core/src/main/java/org/elasticsearch/action/bulk/BulkRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/bulk/BulkRequestBuilder.java
index c48a8f507b..8f634fa28a 100644
--- a/core/src/main/java/org/elasticsearch/action/bulk/BulkRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/bulk/BulkRequestBuilder.java
@@ -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,12 +109,31 @@ 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.
*/
diff --git a/core/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java b/core/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java
index 12981664c2..f5faa18403 100644
--- a/core/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java
+++ b/core/src/main/java/org/elasticsearch/action/bulk/TransportShardBulkAction.java
@@ -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());
}
diff --git a/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ClientScrollableHitSource.java b/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ClientScrollableHitSource.java
index 8831b2f636..4f2aefc101 100644
--- a/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ClientScrollableHitSource.java
+++ b/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ClientScrollableHitSource.java
@@ -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;
@@ -233,6 +235,10 @@ public class ClientScrollableHitSource extends ScrollableHitSource {
}
@Override
+ public XContentType getXContentType() {
+ return XContentFactory.xContentType(source);
+ }
+ @Override
public long getVersion() {
return delegate.getVersion();
}
diff --git a/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ScrollableHitSource.java b/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ScrollableHitSource.java
index 8b8a350ffd..73aa653698 100644
--- a/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ScrollableHitSource.java
+++ b/core/src/main/java/org/elasticsearch/action/bulk/byscroll/ScrollableHitSource.java
@@ -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();
@@ -190,6 +191,10 @@ public abstract class ScrollableHitSource implements Closeable {
*/
@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.
*/
@Nullable String getParent();
@@ -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;
}
diff --git a/core/src/main/java/org/elasticsearch/action/index/IndexRequest.java b/core/src/main/java/org/elasticsearch/action/index/IndexRequest.java
index d1a9927c67..7e3f14368d 100644
--- a/core/src/main/java/org/elasticsearch/action/index/IndexRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/index/IndexRequest.java
@@ -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,21 +182,14 @@ 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.
*/
@Override
@@ -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,30 +376,63 @@ 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 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) {
- this.source = new BytesArray(source, offset, length);
- return this;
+ 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).
+ *
+ * @param source The source to index
+ * @param offset The offset in the byte array
+ * @param length The length of the data
+ */
+ 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
diff --git a/core/src/main/java/org/elasticsearch/action/index/IndexRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/index/IndexRequestBuilder.java
index f7df8bffce..7af43ec35e 100644
--- a/core/src/main/java/org/elasticsearch/action/index/IndexRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/index/IndexRequestBuilder.java
@@ -82,13 +82,23 @@ 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.
*
* @param source The map to index
@@ -112,14 +122,27 @@ 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.
*/
public IndexRequestBuilder setSource(XContentBuilder sourceBuilder) {
@@ -129,26 +152,52 @@ 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).
*
* @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>
* <b>Note: the number of objects passed to this method must be an even
@@ -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;
}
diff --git a/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequest.java b/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequest.java
index 10416146ba..a28950b24c 100644
--- a/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequest.java
@@ -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);
+ }
}
}
diff --git a/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequestBuilder.java
index bd927115fb..c03b3b84f8 100644
--- a/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/ingest/PutPipelineRequestBuilder.java
@@ -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));
+ }
}
diff --git a/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequest.java b/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequest.java
index ef7b5e3d5b..362d2e7ab9 100644
--- a/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequest.java
@@ -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 {
diff --git a/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequestBuilder.java
index 4a13fa111e..bb5d0e4e40 100644
--- a/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineRequestBuilder.java
@@ -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;
diff --git a/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineTransportAction.java b/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineTransportAction.java
index 61fd400a1d..3f67007df6 100644
--- a/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineTransportAction.java
+++ b/core/src/main/java/org/elasticsearch/action/ingest/SimulatePipelineTransportAction.java
@@ -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 {
diff --git a/core/src/main/java/org/elasticsearch/action/termvectors/TermVectorsRequest.java b/core/src/main/java/org/elasticsearch/action/termvectors/TermVectorsRequest.java
index b83713e3a6..544b14523b 100644
--- a/core/src/main/java/org/elasticsearch/action/termvectors/TermVectorsRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/termvectors/TermVectorsRequest.java
@@ -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;
}
+ 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);
+ 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);
diff --git a/core/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java b/core/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java
index 45e4aa8afd..4e2a7b466b 100644
--- a/core/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java
+++ b/core/src/main/java/org/elasticsearch/action/update/TransportUpdateAction.java
@@ -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);
diff --git a/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java b/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java
index 0d2801e44a..504a297627 100644
--- a/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java
+++ b/core/src/main/java/org/elasticsearch/action/update/UpdateRequest.java
@@ -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,12 +584,30 @@ 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,12 +700,30 @@ 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;
}
diff --git a/core/src/main/java/org/elasticsearch/action/update/UpdateRequestBuilder.java b/core/src/main/java/org/elasticsearch/action/update/UpdateRequestBuilder.java
index 50d84a2412..1a4d4077b1 100644
--- a/core/src/main/java/org/elasticsearch/action/update/UpdateRequestBuilder.java
+++ b/core/src/main/java/org/elasticsearch/action/update/UpdateRequestBuilder.java
@@ -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;
}
@@ -263,6 +285,15 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
}
/**
+ * 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,12 +357,30 @@ 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.
*/
@@ -329,6 +390,15 @@ public class UpdateRequestBuilder extends InstanceShardOperationRequestBuilder<U
}
/**
+ * 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.
*/
public UpdateRequestBuilder setDocAsUpsert(boolean shouldUpsertDoc) {
diff --git a/core/src/main/java/org/elasticsearch/client/ClusterAdminClient.java b/core/src/main/java/org/elasticsearch/client/ClusterAdminClient.java
index 14abc77513..3f705a215e 100644
--- a/core/src/main/java/org/elasticsearch/client/ClusterAdminClient.java
+++ b/core/src/main/java/org/elasticsearch/client/ClusterAdminClient.java
@@ -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,10 +546,17 @@ 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
*/
void deletePipeline(DeletePipelineRequest request, ActionListener<WritePipelineResponse> listener);
@@ -596,9 +604,15 @@ 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
*/
void allocationExplain(ClusterAllocationExplainRequest request, ActionListener<ClusterAllocationExplainResponse> listener);
diff --git a/core/src/main/java/org/elasticsearch/client/support/AbstractClient.java b/core/src/main/java/org/elasticsearch/client/support/AbstractClient.java
index b93c00ca9f..5a789af3ee 100644
--- a/core/src/main/java/org/elasticsearch/client/support/AbstractClient.java
+++ b/core/src/main/java/org/elasticsearch/client/support/AbstractClient.java
@@ -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;
@@ -1082,6 +1083,11 @@ public abstract class AbstractClient extends AbstractComponent implements Client
}
@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);
}
@@ -1132,6 +1138,11 @@ public abstract class AbstractClient extends AbstractComponent implements Client
}
@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);
}
diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java
index 4ba244e107..5bba34904d 100644
--- a/core/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java
+++ b/core/src/main/java/org/elasticsearch/cluster/metadata/IndexTemplateMetaData.java
@@ -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;
diff --git a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java
index 0efb640c5a..0bde4a23b0 100644
--- a/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java
+++ b/core/src/main/java/org/elasticsearch/cluster/metadata/MetaDataCreateIndexService.java
@@ -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
diff --git a/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java b/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java
index 279be58e01..69adc5878f 100644
--- a/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java
+++ b/core/src/main/java/org/elasticsearch/common/settings/ClusterSettings.java
@@ -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,
diff --git a/core/src/main/java/org/elasticsearch/common/settings/Settings.java b/core/src/main/java/org/elasticsearch/common/settings/Settings.java
index 883f1e7c82..579be7ce31 100644
--- a/core/src/main/java/org/elasticsearch/common/settings/Settings.java
+++ b/core/src/main/java/org/elasticsearch/common/settings/Settings.java
@@ -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 {
@@ -973,8 +976,23 @@ public final class Settings implements ToXContent {
}
/**
+ * 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);
diff --git a/core/src/main/java/org/elasticsearch/common/settings/loader/SettingsLoaderFactory.java b/core/src/main/java/org/elasticsearch/common/settings/loader/SettingsLoaderFactory.java
index 5f2da22c5f..5d8cb4918b 100644
--- a/core/src/main/java/org/elasticsearch/common/settings/loader/SettingsLoaderFactory.java
+++ b/core/src/main/java/org/elasticsearch/common/settings/loader/SettingsLoaderFactory.java
@@ -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 + "]");
+ }
+ }
}
diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java
index df34ec726f..189e9d3c8d 100644
--- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java
+++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentBuilder.java
@@ -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;
diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentGenerator.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentGenerator.java
index 478f3a8a08..60a188ca6c 100644
--- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentGenerator.java
+++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentGenerator.java
@@ -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;
/**
diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java
index 6cf8d12c21..dd7508280d 100644
--- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java
+++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentHelper.java
@@ -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) {
@@ -377,6 +428,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.
*/
diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java b/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java
index ddd736e0d0..8e3c298270 100644
--- a/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java
+++ b/core/src/main/java/org/elasticsearch/common/xcontent/XContentType.java
@@ -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();
diff --git a/core/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContentGenerator.java b/core/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContentGenerator.java
index 07ae16b96c..1e09f8334f 100644
--- a/core/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContentGenerator.java
+++ b/core/src/main/java/org/elasticsearch/common/xcontent/json/JsonXContentGenerator.java
@@ -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 {
diff --git a/core/src/main/java/org/elasticsearch/http/HttpTransportSettings.java b/core/src/main/java/org/elasticsearch/http/HttpTransportSettings.java
index 60bc3449d0..b5e254aa4c 100644
--- a/core/src/main/java/org/elasticsearch/http/HttpTransportSettings.java
+++ b/core/src/main/java/org/elasticsearch/http/HttpTransportSettings.java
@@ -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 =
diff --git a/core/src/main/java/org/elasticsearch/index/IndexingSlowLog.java b/core/src/main/java/org/elasticsearch/index/IndexingSlowLog.java
index 8672bbc835..b1d8ac1886 100644
--- a/core/src/main/java/org/elasticsearch/index/IndexingSlowLog.java
+++ b/core/src/main/java/org/elasticsearch/index/IndexingSlowLog.java
@@ -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_]");
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java
index fdc45530b9..a8c74101bf 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapper.java
@@ -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 {
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapperParser.java b/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapperParser.java
index 031f139075..be25775c13 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapperParser.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/DocumentMapperParser.java
@@ -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);
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java b/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java
index 014ff45200..97891b28aa 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/DocumentParser.java
@@ -154,6 +154,7 @@ final class DocumentParser {
source.routing(),
context.docs(),
context.sourceToParse().source(),
+ context.sourceToParse().getXContentType(),
update
).parent(source.parent());
}
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java b/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java
index ee4b5fea15..41b29f3c67 100755
--- a/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/MapperService.java
@@ -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());
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/ParsedDocument.java b/core/src/main/java/org/elasticsearch/index/mapper/ParsedDocument.java
index db8bdf9df7..f7d5804be0 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/ParsedDocument.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/ParsedDocument.java
@@ -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) {
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java b/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java
index e06ec80a47..2eb2fdeaa0 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/SourceFieldMapper.java
@@ -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();
diff --git a/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java b/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java
index 0cafc50bbe..a8a983ecde 100644
--- a/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java
+++ b/core/src/main/java/org/elasticsearch/index/mapper/SourceToParse.java
@@ -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;
diff --git a/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java
index bfb579e0c3..ee0eff2a45 100644
--- a/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java
+++ b/core/src/main/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilder.java
@@ -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);
diff --git a/core/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java b/core/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java
index 6f4ae66a12..ad00e39097 100644
--- a/core/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java
+++ b/core/src/main/java/org/elasticsearch/index/shard/TranslogRecoveryPerformer.java
@@ -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);
diff --git a/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java b/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
index 520cb13390..7981c89124 100644
--- a/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
+++ b/core/src/main/java/org/elasticsearch/index/termvectors/TermVectorsService.java
@@ -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());
}
diff --git a/core/src/main/java/org/elasticsearch/ingest/PipelineConfiguration.java b/core/src/main/java/org/elasticsearch/ingest/PipelineConfiguration.java
index 5cb9f6111f..3e874a0fd1 100644
--- a/core/src/main/java/org/elasticsearch/ingest/PipelineConfiguration.java
+++ b/core/src/main/java/org/elasticsearch/ingest/PipelineConfiguration.java
@@ -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
diff --git a/core/src/main/java/org/elasticsearch/ingest/PipelineStore.java b/core/src/main/java/org/elasticsearch/ingest/PipelineStore.java
index 1171865a00..d476d7c2bd 100644
--- a/core/src/main/java/org/elasticsearch/ingest/PipelineStore.java
+++ b/core/src/main/java/org/elasticsearch/ingest/PipelineStore.java
@@ -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))
diff --git a/core/src/main/java/org/elasticsearch/rest/AbstractRestChannel.java b/core/src/main/java/org/elasticsearch/rest/AbstractRestChannel.java
index 4b3505e97e..bdc78c82dd 100644
--- a/core/src/main/java/org/elasticsearch/rest/AbstractRestChannel.java
+++ b/core/src/main/java/org/elasticsearch/rest/AbstractRestChannel.java
@@ -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;
}
-
}
diff --git a/core/src/main/java/org/elasticsearch/rest/BytesRestResponse.java b/core/src/main/java/org/elasticsearch/rest/BytesRestResponse.java
index 2d45bc1765..a7b709625c 100644
--- a/core/src/main/java/org/elasticsearch/rest/BytesRestResponse.java
+++ b/core/src/main/java/org/elasticsearch/rest/BytesRestResponse.java
@@ -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);
diff --git a/core/src/main/java/org/elasticsearch/rest/RestChannel.java b/core/src/main/java/org/elasticsearch/rest/RestChannel.java
index 2a56313fd8..8c8346f0ef 100644
--- a/core/src/main/java/org/elasticsearch/rest/RestChannel.java
+++ b/core/src/main/java/org/elasticsearch/rest/RestChannel.java
@@ -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);
-
}
diff --git a/core/src/main/java/org/elasticsearch/rest/RestController.java b/core/src/main/java/org/elasticsearch/rest/RestController.java
index 5ac82b7e45..fd3587df2a 100644
--- a/core/src/main/java/org/elasticsearch/rest/RestController.java
+++ b/core/src/main/java/org/elasticsearch/rest/RestController.java
@@ -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,33 +200,75 @@ 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);
}
+ }
+ }
+ }
+
+ /**
+ * 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 {
- final RestHandler wrappedHandler = Objects.requireNonNull(handlerWrapper.apply(handler));
- wrappedHandler.handleRequest(request, channel, client);
+ 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));
}
/**
@@ -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
diff --git a/core/src/main/java/org/elasticsearch/rest/RestHandler.java b/core/src/main/java/org/elasticsearch/rest/RestHandler.java
index 393e425baf..740b98ae73 100644
--- a/core/src/main/java/org/elasticsearch/rest/RestHandler.java
+++ b/core/src/main/java/org/elasticsearch/rest/RestHandler.java
@@ -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;
+ }
}
diff --git a/core/src/main/java/org/elasticsearch/rest/RestRequest.java b/core/src/main/java/org/elasticsearch/rest/RestRequest.java
index b4b0614f8a..7d41faf12e 100644
--- a/core/src/main/java/org/elasticsearch/rest/RestRequest.java
+++ b/core/src/main/java/org/elasticsearch/rest/RestRequest.java
@@ -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;
+ }
+
+ /**
+ * 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;
+ }
- public abstract Iterable<Map.Entry<String, String>> 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");
+ }
}
diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestPutStoredScriptAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestPutStoredScriptAction.java
index cee46eba04..358c3656ce 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestPutStoredScriptAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/admin/cluster/RestPutStoredScriptAction.java
@@ -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));
}
}
diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java
index ea0cf7bf0c..8c314efee6 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestCreateIndexAction.java
@@ -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()));
diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java
index c48ed3716d..b376f3dab3 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutIndexTemplateAction.java
@@ -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));
}
diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java
index 60c434c6b0..06fe679264 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestPutMappingAction.java
@@ -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));
}
}
diff --git a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestUpdateSettingsAction.java b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestUpdateSettingsAction.java
index 9e38fb5e07..47037460e2 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestUpdateSettingsAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/admin/indices/RestUpdateSettingsAction.java
@@ -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();
diff --git a/core/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java b/core/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java
index af0faac553..8fdf2792a4 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java
@@ -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
diff --git a/core/src/main/java/org/elasticsearch/rest/action/document/RestGetSourceAction.java b/core/src/main/java/org/elasticsearch/rest/action/document/RestGetSourceAction.java
index 728e1ff599..83d424ed74 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/document/RestGetSourceAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/document/RestGetSourceAction.java
@@ -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 {
diff --git a/core/src/main/java/org/elasticsearch/rest/action/document/RestIndexAction.java b/core/src/main/java/org/elasticsearch/rest/action/document/RestIndexAction.java
index 042b0d57b5..ddaf226875 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/document/RestIndexAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/document/RestIndexAction.java
@@ -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));
diff --git a/core/src/main/java/org/elasticsearch/rest/action/ingest/RestPutPipelineAction.java b/core/src/main/java/org/elasticsearch/rest/action/ingest/RestPutPipelineAction.java
index b7a8e6366b..2496c9b4a2 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/ingest/RestPutPipelineAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/ingest/RestPutPipelineAction.java
@@ -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));
diff --git a/core/src/main/java/org/elasticsearch/rest/action/ingest/RestSimulatePipelineAction.java b/core/src/main/java/org/elasticsearch/rest/action/ingest/RestSimulatePipelineAction.java
index 5885dc9df6..9dbe1808a8 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/ingest/RestSimulatePipelineAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/ingest/RestSimulatePipelineAction.java
@@ -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));
diff --git a/core/src/main/java/org/elasticsearch/rest/action/search/RestClearScrollAction.java b/core/src/main/java/org/elasticsearch/rest/action/search/RestClearScrollAction.java
index e7ee7c7397..47252f5a10 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/search/RestClearScrollAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/search/RestClearScrollAction.java
@@ -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));
+ }
+
+ @Override
+ public boolean supportsPlainText() {
+ return true;
}
- public static String[] splitScrollIds(String scrollIds) {
+ private static String[] splitScrollIds(String scrollIds) {
if (scrollIds == null) {
return Strings.EMPTY_ARRAY;
}
diff --git a/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java b/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java
index 567823a6e2..a803958618 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/search/RestMultiSearchAction.java
@@ -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
diff --git a/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchScrollAction.java b/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchScrollAction.java
index 87a6f464cc..2a60fc6317 100644
--- a/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchScrollAction.java
+++ b/core/src/main/java/org/elasticsearch/rest/action/search/RestSearchScrollAction.java
@@ -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");
diff --git a/core/src/main/java/org/elasticsearch/script/ScriptMetaData.java b/core/src/main/java/org/elasticsearch/script/ScriptMetaData.java
index e9fb6e126f..87afc21a8c 100644
--- a/core/src/main/java/org/elasticsearch/script/ScriptMetaData.java
+++ b/core/src/main/java/org/elasticsearch/script/ScriptMetaData.java
@@ -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;
diff --git a/core/src/main/java/org/elasticsearch/script/ScriptService.java b/core/src/main/java/org/elasticsearch/script/ScriptService.java
index f9bcc77ab4..692e081a7b 100644
--- a/core/src/main/java/org/elasticsearch/script/ScriptService.java
+++ b/core/src/main/java/org/elasticsearch/script/ScriptService.java
@@ -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() + "]");
diff --git a/core/src/main/java/org/elasticsearch/script/StoredScriptSource.java b/core/src/main/java/org/elasticsearch/script/StoredScriptSource.java
index 69fc1ed34c..e6c5b09362 100644
--- a/core/src/main/java/org/elasticsearch/script/StoredScriptSource.java
+++ b/core/src/main/java/org/elasticsearch/script/StoredScriptSource.java
@@ -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) {