You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ja...@apache.org on 2023/12/19 07:54:51 UTC

(lucene-solr) branch branch_8_11 updated: SOLR-16949: Fix inputstream leaks

This is an automated email from the ASF dual-hosted git repository.

janhoy pushed a commit to branch branch_8_11
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git


The following commit(s) were added to refs/heads/branch_8_11 by this push:
     new 6c8f24eb9e3 SOLR-16949: Fix inputstream leaks
6c8f24eb9e3 is described below

commit 6c8f24eb9e3fe1cb19058173f2e221de3febfeda
Author: Jan Høydahl <ja...@apache.org>
AuthorDate: Mon Dec 18 09:32:33 2023 +0100

    SOLR-16949: Fix inputstream leaks
---
 .../org/apache/solr/util/FileTypeMagicUtil.java    | 72 +++++++++++++++-------
 .../apache/solr/util/FileTypeMagicUtilTest.java    | 58 ++++++++---------
 2 files changed, 81 insertions(+), 49 deletions(-)

diff --git a/solr/core/src/java/org/apache/solr/util/FileTypeMagicUtil.java b/solr/core/src/java/org/apache/solr/util/FileTypeMagicUtil.java
index cfc2e965537..cc66fced2b8 100644
--- a/solr/core/src/java/org/apache/solr/util/FileTypeMagicUtil.java
+++ b/solr/core/src/java/org/apache/solr/util/FileTypeMagicUtil.java
@@ -20,7 +20,6 @@ package org.apache.solr.util;
 import com.j256.simplemagic.ContentInfo;
 import com.j256.simplemagic.ContentInfoUtil;
 import com.j256.simplemagic.ContentType;
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.nio.file.FileVisitResult;
@@ -58,22 +57,18 @@ public class FileTypeMagicUtil implements ContentInfoUtil.ErrorCallBack {
   public static void assertConfigSetFolderLegal(Path confPath) throws IOException {
     Files.walkFileTree(confPath, new SimpleFileVisitor<Path>() {
       @Override
-      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+      public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
         // Read first 100 bytes of the file to determine the mime type
-        try(InputStream fileStream = Files.newInputStream(file)) {
-          byte[] bytes = new byte[100];
-          fileStream.read(bytes);
-          if (FileTypeMagicUtil.isFileForbiddenInConfigset(bytes)) {
-            throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
-                String.format(Locale.ROOT, "Not uploading file %s to configset, as it matched the MAGIC signature of a forbidden mime type %s",
-                    file, FileTypeMagicUtil.INSTANCE.guessMimeType(bytes)));
-          }
-          return FileVisitResult.CONTINUE;
+        if (FileTypeMagicUtil.isFileForbiddenInConfigset(file)) {
+          throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
+              String.format(Locale.ROOT, "Not uploading file %s to configset, as it matched the MAGIC signature of a forbidden mime type %s",
+                  file, FileTypeMagicUtil.INSTANCE.guessMimeType(file)));
         }
+        return FileVisitResult.CONTINUE;
       }
 
       @Override
-      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
+      public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
         if (SKIP_FOLDERS.contains(dir.getFileName().toString())) return FileVisitResult.SKIP_SUBTREE;
 
         return FileVisitResult.CONTINUE;
@@ -81,19 +76,29 @@ public class FileTypeMagicUtil implements ContentInfoUtil.ErrorCallBack {
     });
   }
 
+  /**
+   * Guess the mime type of file based on its magic number.
+   *
+   * @param file file to check
+   * @return string with content-type or "application/octet-stream" if unknown
+   */
+  public String guessMimeType(Path file) {
+    try {
+      return guessTypeFallbackToOctetStream(util.findMatch(file.toFile()));
+    } catch (IOException e) {
+      throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
+    }
+  }
+
   /**
    * Guess the mime type of file based on its magic number.
    *
    * @param stream input stream of the file
    * @return string with content-type or "application/octet-stream" if unknown
    */
-  public String guessMimeType(InputStream stream) {
+  String guessMimeType(InputStream stream) {
     try {
-      ContentInfo info = util.findMatch(stream);
-      if (info == null) {
-        return ContentType.OTHER.getMimeType();
-      }
-      return info.getContentType().getMimeType();
+      return guessTypeFallbackToOctetStream(util.findMatch(stream));
     } catch (IOException e) {
       throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, e);
     }
@@ -106,7 +111,7 @@ public class FileTypeMagicUtil implements ContentInfoUtil.ErrorCallBack {
    * @return string with content-type or "application/octet-stream" if unknown
    */
   public String guessMimeType(byte[] bytes) {
-    return guessMimeType(new ByteArrayInputStream(bytes));
+    return guessTypeFallbackToOctetStream(util.findMatch(bytes));
   }
 
   @Override
@@ -117,6 +122,24 @@ public class FileTypeMagicUtil implements ContentInfoUtil.ErrorCallBack {
         e);
   }
 
+  /**
+   * Determine forbidden file type based on magic bytes matching of the file itself. Forbidden types
+   * are:
+   *
+   * <ul>
+   *   <li><code>application/x-java-applet</code>: java class file
+   *   <li><code>application/zip</code>: jar or zip archives
+   *   <li><code>application/x-tar</code>: tar archives
+   *   <li><code>text/x-shellscript</code>: shell or bash script
+   * </ul>
+   *
+   * @param file file to check
+   * @return true if file is among the forbidden mime-types
+   */
+  public static boolean isFileForbiddenInConfigset(Path file) {
+    return forbiddenTypes.contains(FileTypeMagicUtil.INSTANCE.guessMimeType(file));
+  }
+
   /**
    * Determine forbidden file type based on magic bytes matching of the file itself. Forbidden types
    * are:
@@ -131,7 +154,7 @@ public class FileTypeMagicUtil implements ContentInfoUtil.ErrorCallBack {
    * @param fileStream stream from the file content
    * @return true if file is among the forbidden mime-types
    */
-  public static boolean isFileForbiddenInConfigset(InputStream fileStream) {
+  static boolean isFileForbiddenInConfigset(InputStream fileStream) {
     return forbiddenTypes.contains(FileTypeMagicUtil.INSTANCE.guessMimeType(fileStream));
   }
 
@@ -144,7 +167,7 @@ public class FileTypeMagicUtil implements ContentInfoUtil.ErrorCallBack {
   public static boolean isFileForbiddenInConfigset(byte[] bytes) {
     if (bytes == null || bytes.length == 0)
       return false; // A ZK znode may be a folder with no content
-    return isFileForbiddenInConfigset(new ByteArrayInputStream(bytes));
+    return forbiddenTypes.contains(FileTypeMagicUtil.INSTANCE.guessMimeType(bytes));
   }
 
   private static final Set<String> forbiddenTypes =
@@ -155,4 +178,11 @@ public class FileTypeMagicUtil implements ContentInfoUtil.ErrorCallBack {
                       "application/x-java-applet,application/zip,application/x-tar,text/x-shellscript")
                   .split(",")));
 
+  private String guessTypeFallbackToOctetStream(ContentInfo contentInfo) {
+    if (contentInfo == null) {
+      return ContentType.OTHER.getMimeType();
+    } else {
+      return contentInfo.getContentType().getMimeType();
+    }
+  }
 }
diff --git a/solr/core/src/test/org/apache/solr/util/FileTypeMagicUtilTest.java b/solr/core/src/test/org/apache/solr/util/FileTypeMagicUtilTest.java
index b8e9a35a3d9..5c02528a7f4 100644
--- a/solr/core/src/test/org/apache/solr/util/FileTypeMagicUtilTest.java
+++ b/solr/core/src/test/org/apache/solr/util/FileTypeMagicUtilTest.java
@@ -17,38 +17,40 @@
 
 package org.apache.solr.util;
 
+import java.io.IOException;
+import java.io.InputStream;
 import org.apache.solr.SolrTestCaseJ4;
 
 public class FileTypeMagicUtilTest extends SolrTestCaseJ4 {
-  public void testGuessMimeType() {
-    assertEquals(
-        "application/x-java-applet",
-        FileTypeMagicUtil.INSTANCE.guessMimeType(
-            FileTypeMagicUtil.class.getResourceAsStream("/magic/HelloWorldJavaClass.class.bin")));
-    assertEquals(
-        "application/zip",
-        FileTypeMagicUtil.INSTANCE.guessMimeType(
-            FileTypeMagicUtil.class.getResourceAsStream(
-                "/runtimecode/containerplugin.v.1.jar.bin")));
-    assertEquals(
-        "application/x-tar",
-        FileTypeMagicUtil.INSTANCE.guessMimeType(
-            FileTypeMagicUtil.class.getResourceAsStream("/magic/hello.tar.bin")));
-    assertEquals(
-        "text/x-shellscript",
-        FileTypeMagicUtil.INSTANCE.guessMimeType(
-            FileTypeMagicUtil.class.getResourceAsStream("/magic/shell.sh.txt")));
+  public void testGuessMimeType() throws IOException {
+    assertResourceMimeType("application/x-java-applet", "/magic/HelloWorldJavaClass.class.bin");
+    assertResourceMimeType("application/zip", "/runtimecode/containerplugin.v.1.jar.bin");
+    assertResourceMimeType("application/x-tar", "/magic/hello.tar.bin");
+    assertResourceMimeType("text/x-shellscript", "/magic/shell.sh.txt");
   }
 
-  public void testIsFileForbiddenInConfigset() {
-    assertTrue(
-        FileTypeMagicUtil.isFileForbiddenInConfigset(
-            FileTypeMagicUtil.class.getResourceAsStream("/magic/HelloWorldJavaClass.class.bin")));
-    assertTrue(
-        FileTypeMagicUtil.isFileForbiddenInConfigset(
-            FileTypeMagicUtil.class.getResourceAsStream("/magic/shell.sh.txt")));
-    assertFalse(
-        FileTypeMagicUtil.isFileForbiddenInConfigset(
-            FileTypeMagicUtil.class.getResourceAsStream("/magic/plain.txt")));
+  public void testIsFileForbiddenInConfigset() throws IOException {
+    assertResourceForbiddenInConfigset("/magic/HelloWorldJavaClass.class.bin");
+    assertResourceForbiddenInConfigset("/magic/shell.sh.txt");
+    assertResourceAllowedInConfigset("/magic/plain.txt");
+  }
+
+  private void assertResourceMimeType(String mimeType, String resourcePath) throws IOException {
+    try (InputStream stream =
+        FileTypeMagicUtil.class.getResourceAsStream("/magic/HelloWorldJavaClass.class.bin")) {
+      assertEquals("application/x-java-applet", FileTypeMagicUtil.INSTANCE.guessMimeType(stream));
+    }
+  }
+
+  private void assertResourceForbiddenInConfigset(String resourcePath) throws IOException {
+    try (InputStream stream = FileTypeMagicUtil.class.getResourceAsStream(resourcePath)) {
+      assertTrue(FileTypeMagicUtil.isFileForbiddenInConfigset(stream));
+    }
+  }
+
+  private void assertResourceAllowedInConfigset(String resourcePath) throws IOException {
+    try (InputStream stream = FileTypeMagicUtil.class.getResourceAsStream(resourcePath)) {
+      assertFalse(FileTypeMagicUtil.isFileForbiddenInConfigset(stream));
+    }
   }
 }