diff --git a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/cbor/CborXContentImpl.java b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/cbor/CborXContentImpl.java index 063db426d87c0..bd78062a861fe 100644 --- a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/cbor/CborXContentImpl.java +++ b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/cbor/CborXContentImpl.java @@ -63,6 +63,11 @@ public XContentType type() { return XContentType.CBOR; } + @Override + public boolean hasBulkSeparator() { + return false; + } + @Override public byte bulkSeparator() { throw new XContentParseException("cbor does not support bulk parsing..."); diff --git a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java index d109fd28dd839..d0bcae054f1f5 100644 --- a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java +++ b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/json/JsonXContentImpl.java @@ -68,6 +68,11 @@ public XContentType type() { return XContentType.JSON; } + @Override + public boolean hasBulkSeparator() { + return true; + } + @Override public byte bulkSeparator() { return '\n'; diff --git a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/smile/SmileXContentImpl.java b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/smile/SmileXContentImpl.java index a2139b519d0a0..a54ee8cff55b1 100644 --- a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/smile/SmileXContentImpl.java +++ b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/smile/SmileXContentImpl.java @@ -70,6 +70,11 @@ public byte bulkSeparator() { return (byte) 0xFF; } + @Override + public boolean hasBulkSeparator() { + return true; + } + @Override public boolean detectContent(byte[] bytes, int offset, int length) { return length > 2 diff --git a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/yaml/YamlXContentImpl.java b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/yaml/YamlXContentImpl.java index 69d9acc50cae9..ec2a7535d2df6 100644 --- a/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/yaml/YamlXContentImpl.java +++ b/libs/x-content/impl/src/main/java/org/elasticsearch/xcontent/provider/yaml/YamlXContentImpl.java @@ -61,6 +61,11 @@ public XContentType type() { return XContentType.YAML; } + @Override + public boolean hasBulkSeparator() { + return false; + } + @Override public byte bulkSeparator() { throw new UnsupportedOperationException("yaml does not support bulk parsing..."); diff --git a/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContent.java b/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContent.java index 3325287fd6abf..8d45cf9e7f01c 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContent.java +++ b/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContent.java @@ -25,6 +25,20 @@ public interface XContent { */ XContentType type(); + /** + * @return {@code true} if this {@link XContent} can be sent in bulk, delimited by the byte returned by {@link #bulkSeparator()}, or + * {@code false} if this {@link XContent} does not support a delimited bulk format (in which case {@link #bulkSeparator()} throws an + * exception. + *
+ * In practice, this is {@code true} for content with canonical type {@link XContentType#JSON} or {@link XContentType#SMILE} and + * {@code false} for content with canonical type {@link XContentType#CBOR} or {@link XContentType#YAML}. + */ + boolean hasBulkSeparator(); + + /** + * @return a {@link byte} that separates items in a bulk request that uses this {@link XContent}. + * @throws RuntimeException if this {@link XContent} does not support a delimited bulk format. See {@link #hasBulkSeparator()}. + */ byte bulkSeparator(); @Deprecated diff --git a/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContentType.java b/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContentType.java index 4a6547b307a61..f31b963b8b127 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContentType.java +++ b/libs/x-content/src/main/java/org/elasticsearch/xcontent/XContentType.java @@ -9,6 +9,7 @@ package org.elasticsearch.xcontent; +import org.elasticsearch.core.Nullable; import org.elasticsearch.xcontent.cbor.CborXContent; import org.elasticsearch.xcontent.json.JsonXContent; import org.elasticsearch.xcontent.smile.SmileXContent; @@ -287,4 +288,15 @@ public XContentType canonical() { public static XContentType ofOrdinal(int ordinal) { return values[ordinal]; } + + /** + * Indicates if the {@link XContentType} (from the {@code Content-Type} header of a REST request) is compatible with delimited bulk + * content. A bulk request contains multiple objects each terminated with {@link XContent#bulkSeparator()}. + *
+ * In practice, this returns {@code true} if the argument has canonical type {@link XContentType#JSON} or {@link XContentType#SMILE}
+ * and {@code false} if the argument is {@code null} or has canonical type {@link XContentType#CBOR} or {@link XContentType#YAML}.
+ */
+ public static boolean supportsDelimitedBulkRequests(@Nullable XContentType xContentType) {
+ return xContentType != null && xContentType.xContent.hasBulkSeparator();
+ }
}
diff --git a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java
index 0b497d1122914..5a5b1df64907d 100644
--- a/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java
+++ b/modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/RestMultiSearchTemplateAction.java
@@ -18,6 +18,7 @@
import org.elasticsearch.rest.action.RestToXContentListener;
import org.elasticsearch.rest.action.search.RestMultiSearchAction;
import org.elasticsearch.rest.action.search.RestSearchAction;
+import org.elasticsearch.xcontent.XContentType;
import java.io.IOException;
import java.util.List;
@@ -95,8 +96,8 @@ public MultiSearchTemplateRequest parseRequest(RestRequest restRequest, boolean
}
@Override
- public boolean supportsBulkContent() {
- return true;
+ public boolean mediaTypesValid(RestRequest request) {
+ return super.mediaTypesValid(request) && XContentType.supportsDelimitedBulkRequests(request.getXContentType());
}
@Override
diff --git a/server/src/main/java/org/elasticsearch/rest/FilterRestHandler.java b/server/src/main/java/org/elasticsearch/rest/FilterRestHandler.java
index 21a44ac9af5c8..130b0b1dafe82 100644
--- a/server/src/main/java/org/elasticsearch/rest/FilterRestHandler.java
+++ b/server/src/main/java/org/elasticsearch/rest/FilterRestHandler.java
@@ -43,11 +43,6 @@ public boolean canTripCircuitBreaker() {
return delegate.canTripCircuitBreaker();
}
- @Override
- public boolean supportsBulkContent() {
- return delegate.supportsBulkContent();
- }
-
@Override
public boolean mediaTypesValid(RestRequest request) {
return delegate.mediaTypesValid(request);
diff --git a/server/src/main/java/org/elasticsearch/rest/RestController.java b/server/src/main/java/org/elasticsearch/rest/RestController.java
index 66532026fc1ca..6fca7c2d60c6d 100644
--- a/server/src/main/java/org/elasticsearch/rest/RestController.java
+++ b/server/src/main/java/org/elasticsearch/rest/RestController.java
@@ -421,20 +421,6 @@ private void dispatchRequest(
sendContentTypeErrorMessage(request.getAllHeaderValues("Content-Type"), channel);
return;
}
- final XContentType xContentType = request.getXContentType();
- // TODO consider refactoring to handler.supportsContentStream(xContentType). It is only used with JSON and SMILE
- if (handler.supportsBulkContent()
- && XContentType.JSON != xContentType.canonical()
- && XContentType.SMILE != xContentType.canonical()) {
- channel.sendResponse(
- RestResponse.createSimpleErrorResponse(
- channel,
- RestStatus.NOT_ACCEPTABLE,
- "Content-Type [" + xContentType + "] does not support stream parsing. Use JSON or SMILE instead"
- )
- );
- return;
- }
}
RestChannel responseChannel = channel;
if (apiProtections.isEnabled()) {
diff --git a/server/src/main/java/org/elasticsearch/rest/RestHandler.java b/server/src/main/java/org/elasticsearch/rest/RestHandler.java
index 5e08d4900dc75..ed8263e7e83e2 100644
--- a/server/src/main/java/org/elasticsearch/rest/RestHandler.java
+++ b/server/src/main/java/org/elasticsearch/rest/RestHandler.java
@@ -15,7 +15,6 @@
import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.RestApiVersion;
import org.elasticsearch.rest.RestRequest.Method;
-import org.elasticsearch.xcontent.XContent;
import java.util.Collections;
import java.util.List;
@@ -44,15 +43,6 @@ default boolean supportsContentStream() {
return false;
}
- /**
- * Indicates if the RestHandler supports bulk content. A bulk request contains multiple objects
- * delineated by {@link XContent#bulkSeparator()}. If a handler returns true this will affect
- * the types of content that can be sent to this endpoint.
- */
- default boolean supportsBulkContent() {
- return false;
- }
-
/**
* Returns the concrete RestHandler for this RestHandler. That is, if this is a delegating RestHandler it returns the delegate.
* Otherwise it returns itself.
diff --git a/server/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java b/server/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java
index 20a9fb7ed23aa..e381b1c207072 100644
--- a/server/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java
+++ b/server/src/main/java/org/elasticsearch/rest/action/document/RestBulkAction.java
@@ -36,6 +36,7 @@
import org.elasticsearch.rest.action.RestToXContentListener;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.transport.Transports;
+import org.elasticsearch.xcontent.XContentType;
import java.io.IOException;
import java.util.ArrayDeque;
@@ -303,12 +304,12 @@ private ArrayList