Browse Source

Ignore media ranges when parsing (#64721)

Browsers are sending media ranges with quality factors on Accept header.
We should ignore the value and respond with applicaiton/json

closes #64689
relates #51816
Przemyslaw Gomulka 5 years ago
parent
commit
dd5bcd4093

+ 11 - 10
libs/x-content/src/main/java/org/elasticsearch/common/xcontent/ParsedMediaType.java

@@ -33,11 +33,6 @@ import java.util.regex.Pattern;
  * @see MediaTypeRegistry
  */
 public class ParsedMediaType {
-    // TODO this should be removed once strict parsing is implemented https://github.com/elastic/elasticsearch/issues/63080
-    // sun.net.www.protocol.http.HttpURLConnection sets a default Accept header if it was not provided on a request.
-    // For this value Parsing returns null.
-    public static final String DEFAULT_ACCEPT_STRING = "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
-
     private final String type;
     private final String subType;
     private final Map<String, String> parameters;
@@ -63,18 +58,19 @@ public class ParsedMediaType {
 
     /**
      * Parses a header value into it's parts.
-     * follows https://tools.ietf.org/html/rfc7231#section-3.1.1.1 but allows only single media type and do not support quality factors
+     * follows https://tools.ietf.org/html/rfc7231#section-3.1.1.1
+     * but allows only single media type. Media ranges will be ignored (treated as not provided)
      * Note: parsing can return null, but it will throw exceptions once https://github.com/elastic/elasticsearch/issues/63080 is done
-     * Do not rely on nulls
+     * TODO Do not rely on nulls
      *
      * @return a {@link ParsedMediaType} if the header could be parsed.
      * @throws IllegalArgumentException if the header is malformed
      */
     public static ParsedMediaType parseMediaType(String headerValue) {
-        if (DEFAULT_ACCEPT_STRING.equals(headerValue) || "*/*".equals(headerValue)) {
-            return null;
-        }
         if (headerValue != null) {
+            if (isMediaRange(headerValue) || "*/*".equals(headerValue)) {
+                return null;
+            }
             final String[] elements = headerValue.toLowerCase(Locale.ROOT).split("[\\s\\t]*;");
 
             final String[] splitMediaType = elements[0].split("/");
@@ -107,6 +103,11 @@ public class ParsedMediaType {
         return null;
     }
 
+    // simplistic check for media ranges. do not validate if this is a correct header
+    private static boolean isMediaRange(String headerValue) {
+        return headerValue.contains(",");
+    }
+
     private static boolean hasTrailingSpace(String s) {
         return s.length() == 0 || Character.isWhitespace(s.charAt(s.length()-1));
     }

+ 10 - 3
libs/x-content/src/test/java/org/elasticsearch/common/xcontent/ParsedMediaTypeTests.java

@@ -111,14 +111,21 @@ public class ParsedMediaTypeTests extends ESTestCase {
         expectThrows(IllegalArgumentException.class, () -> ParsedMediaType.parseMediaType(mediaType + ";k="));
     }
 
-    public void testDefaultAcceptHeader() {
+    public void testIgnoredMediaTypes() {
+        // When using curl */* is used a default Accept header when not specified by a user
+        assertThat(ParsedMediaType.parseMediaType("*/*"), is(nullValue()));
+
+
         // This media type is defined in sun.net.www.protocol.http.HttpURLConnection as a default Accept header
         // and used when a header was not set on a request
         // It should be treated as if a user did not specify a header value
         String mediaType = "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2";
         assertThat(ParsedMediaType.parseMediaType(mediaType), is(nullValue()));
 
-        // When using curl */* is used a default Accept header when not specified by a user
-        assertThat(ParsedMediaType.parseMediaType("*/*"), is(nullValue()));
+        //example accept header used by a browser
+        mediaType = "text/html,application/xhtml+xml,application/xml;q=0.9," +
+            "image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9";
+        ParsedMediaType parsedMediaType = ParsedMediaType.parseMediaType(mediaType);
+        assertThat(parsedMediaType, equalTo(null));
     }
 }