فهرست منبع

ESQL: Fail `profile` on text response formats (#128627)

Fails requests with `profile` when the request has a text response
format. This information is just not included in that response.
Nik Everett 2 ماه پیش
والد
کامیت
1f174d1122

+ 5 - 0
docs/changelog/128627.yaml

@@ -0,0 +1,5 @@
+pr: 128627
+summary: Fail `profile` on text response formats
+area: ES|QL
+type: feature
+issues: []

+ 19 - 10
x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlMediaTypeParser.java

@@ -45,6 +45,7 @@ public class EsqlMediaTypeParser {
         var mediaType = getResponseMediaType(request, (MediaType) null);
         validateColumnarRequest(esqlRequest.columnar(), mediaType);
         validateIncludeCCSMetadata(esqlRequest.includeCCSMetadata(), mediaType);
+        validateProfile(esqlRequest.profile(), mediaType);
         return checkNonNullMediaType(mediaType, request);
     }
 
@@ -67,24 +68,32 @@ public class EsqlMediaTypeParser {
 
     private static void validateColumnarRequest(boolean requestIsColumnar, MediaType fromMediaType) {
         if (requestIsColumnar && fromMediaType instanceof TextFormat) {
-            throw new IllegalArgumentException(
-                "Invalid use of [columnar] argument: cannot be used in combination with "
-                    + Arrays.stream(TextFormat.values()).map(MediaType::queryParameter).toList()
-                    + " formats"
-            );
+            throw invalid("columnar");
         }
     }
 
     private static void validateIncludeCCSMetadata(boolean includeCCSMetadata, MediaType fromMediaType) {
         if (includeCCSMetadata && fromMediaType instanceof TextFormat) {
-            throw new IllegalArgumentException(
-                "Invalid use of [include_ccs_metadata] argument: cannot be used in combination with "
-                    + Arrays.stream(TextFormat.values()).map(MediaType::queryParameter).toList()
-                    + " formats"
-            );
+            throw invalid("include_ccs_metadata");
         }
     }
 
+    private static void validateProfile(boolean profile, MediaType fromMediaType) {
+        if (profile && fromMediaType instanceof TextFormat) {
+            throw invalid("profile");
+        }
+    }
+
+    private static IllegalArgumentException invalid(String argument) {
+        return new IllegalArgumentException(
+            "Invalid use of ["
+                + argument
+                + "] argument: cannot be used in combination with "
+                + Arrays.stream(TextFormat.values()).map(MediaType::queryParameter).toList()
+                + " formats"
+        );
+    }
+
     private static MediaType checkNonNullMediaType(MediaType mediaType, RestRequest request) {
         if (mediaType == null) {
             String msg = String.format(

+ 22 - 4
x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/plugin/EsqlMediaTypeParserTests.java

@@ -85,7 +85,7 @@ public class EsqlMediaTypeParserTests extends ESTestCase {
         var accept = randomFrom("text/plain", "text/csv", "text/tab-separated-values");
         IllegalArgumentException e = expectThrows(
             IllegalArgumentException.class,
-            () -> getResponseMediaType(reqWithAccept(accept), createTestInstance(false, true))
+            () -> getResponseMediaType(reqWithAccept(accept), createTestInstance(false, true, false))
         );
         assertEquals(
             "Invalid use of [include_ccs_metadata] argument: cannot be used in combination with [txt, csv, tsv] formats",
@@ -106,7 +106,7 @@ public class EsqlMediaTypeParserTests extends ESTestCase {
             RestRequest restRequest = reqWithParams(Map.of("format", randomFrom("txt", "csv", "tsv")));
             IllegalArgumentException e = expectThrows(
                 IllegalArgumentException.class,
-                () -> getResponseMediaType(restRequest, createTestInstance(false, true))
+                () -> getResponseMediaType(restRequest, createTestInstance(false, true, false))
             );
             assertEquals(
                 "Invalid use of [include_ccs_metadata] argument: cannot be used in combination with [txt, csv, tsv] formats",
@@ -116,7 +116,24 @@ public class EsqlMediaTypeParserTests extends ESTestCase {
         {
             // check that no exception is thrown for the XContent types
             RestRequest restRequest = reqWithParams(Map.of("format", randomFrom("SMILE", "YAML", "CBOR", "JSON")));
-            MediaType responseMediaType = getResponseMediaType(restRequest, createTestInstance(true, true));
+            MediaType responseMediaType = getResponseMediaType(restRequest, createTestInstance(true, true, false));
+            assertNotNull(responseMediaType);
+        }
+    }
+
+    public void testProfileWithNonJSONMediaTypesInParams() {
+        {
+            RestRequest restRequest = reqWithParams(Map.of("format", randomFrom("txt", "csv", "tsv")));
+            IllegalArgumentException e = expectThrows(
+                IllegalArgumentException.class,
+                () -> getResponseMediaType(restRequest, createTestInstance(false, false, true))
+            );
+            assertEquals("Invalid use of [profile] argument: cannot be used in combination with [txt, csv, tsv] formats", e.getMessage());
+        }
+        {
+            // check that no exception is thrown for the XContent types
+            RestRequest restRequest = reqWithParams(Map.of("format", randomFrom("SMILE", "YAML", "CBOR", "JSON")));
+            MediaType responseMediaType = getResponseMediaType(restRequest, createTestInstance(true, false, true));
             assertNotNull(responseMediaType);
         }
     }
@@ -157,9 +174,10 @@ public class EsqlMediaTypeParserTests extends ESTestCase {
         return request;
     }
 
-    protected EsqlQueryRequest createTestInstance(boolean columnar, boolean includeCCSMetadata) {
+    protected EsqlQueryRequest createTestInstance(boolean columnar, boolean includeCCSMetadata, boolean profile) {
         var request = createTestInstance(columnar);
         request.includeCCSMetadata(includeCCSMetadata);
+        request.profile(profile);
         return request;
     }
 }