2323import java .util .Collections ;
2424import java .util .Set ;
2525
26+ import org .apache .commons .compress .MemoryLimitException ;
2627import org .apache .commons .compress .PasswordRequiredException ;
2728import org .apache .commons .compress .archivers .sevenz .SevenZArchiveEntry ;
2829import org .apache .commons .compress .archivers .sevenz .SevenZFile ;
2930import org .xml .sax .ContentHandler ;
3031import org .xml .sax .SAXException ;
3132
33+ import org .apache .tika .config .ConfigDeserializer ;
34+ import org .apache .tika .config .JsonConfig ;
3235import org .apache .tika .config .TikaComponent ;
3336import org .apache .tika .exception .EncryptedDocumentException ;
3437import org .apache .tika .exception .TikaException ;
38+ import org .apache .tika .exception .TikaMemoryLimitException ;
3539import org .apache .tika .extractor .EmbeddedDocumentExtractor ;
3640import org .apache .tika .extractor .EmbeddedDocumentUtil ;
3741import org .apache .tika .io .TemporaryResources ;
@@ -60,6 +64,37 @@ public class SevenZParser extends AbstractArchiveParser {
6064
6165 private static final Set <MediaType > SUPPORTED_TYPES = Collections .singleton (SEVENZ );
6266
67+ /**
68+ * Configuration class for JSON deserialization.
69+ */
70+ public static class Config {
71+ // Cap the LZMA/LZMA2 dictionary allocation. A tiny 7z can declare a huge dictionary
72+ // (a single header byte), forcing an eager multi-GiB allocation and OOMing the parser.
73+ // Mirrors CompressorParser's default.
74+ private int memoryLimitInKb = 100000 ;
75+
76+ public int getMemoryLimitInKb () {
77+ return memoryLimitInKb ;
78+ }
79+
80+ public void setMemoryLimitInKb (int memoryLimitInKb ) {
81+ this .memoryLimitInKb = memoryLimitInKb ;
82+ }
83+ }
84+
85+ private Config defaultConfig = new Config ();
86+
87+ public SevenZParser () {
88+ }
89+
90+ public SevenZParser (Config config ) {
91+ this .defaultConfig = config ;
92+ }
93+
94+ public SevenZParser (JsonConfig jsonConfig ) {
95+ this (ConfigDeserializer .buildConfig (jsonConfig , Config .class ));
96+ }
97+
6398 @ Override
6499 public Set <MediaType > getSupportedTypes (ParseContext context ) {
65100 return SUPPORTED_TYPES ;
@@ -78,14 +113,21 @@ public void parse(TikaInputStream tis, ContentHandler handler, Metadata metadata
78113
79114 SevenZFile sevenZFile ;
80115 try {
81- SevenZFile .Builder builder = new SevenZFile .Builder ().setFile (tis .getFile ());
116+ // Use setMaxMemoryLimitKiB (direct KiB); setMaxMemoryLimitKb divides the arg by 1024.
117+ SevenZFile .Builder builder = new SevenZFile .Builder ()
118+ .setFile (tis .getFile ())
119+ .setMaxMemoryLimitKiB (defaultConfig .getMemoryLimitInKb ());
82120 if (password == null ) {
83121 sevenZFile = builder .get ();
84122 } else {
85123 sevenZFile = builder .setPassword (password .toCharArray ()).get ();
86124 }
87125 } catch (PasswordRequiredException e ) {
88126 throw new EncryptedDocumentException (e );
127+ } catch (MemoryLimitException e ) {
128+ // The limit can be exceeded at open time (assertValidity) as well as lazily on the
129+ // first getNextEntry() when the LZMA/LZMA2 dictionary is allocated.
130+ throw new TikaMemoryLimitException (e .getMessage ());
89131 }
90132
91133 metadata .set (Metadata .CONTENT_TYPE , SEVENZ .toString ());
@@ -106,6 +148,8 @@ public void parse(TikaInputStream tis, ContentHandler handler, Metadata metadata
106148 }
107149 } catch (PasswordRequiredException e ) {
108150 throw new EncryptedDocumentException (e );
151+ } catch (MemoryLimitException e ) {
152+ throw new TikaMemoryLimitException (e .getMessage ());
109153 } finally {
110154 sevenZFile .close ();
111155 xhtml .endDocument ();
0 commit comments