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

rcordier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/james-project.git

commit 9785c573fb4b5be24f51019d9e5aa7c11a6de5f7
Author: Benoit TELLIER <[email protected]>
AuthorDate: Tue Mar 5 09:24:04 2024 +0100

    [ENHANCEMENT] Computing preview: avoid decoding base64
---
 .../org/apache/james/jmap/api/model/Preview.java   |   4 +-
 .../mime4j/AvoidBinaryBodyReadingBodyFactory.java  | 270 +++++++++++++++++++++
 2 files changed, 272 insertions(+), 2 deletions(-)

diff --git 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/model/Preview.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/model/Preview.java
index 2ef3ecc876..9f10faa79b 100644
--- 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/model/Preview.java
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/api/model/Preview.java
@@ -29,7 +29,7 @@ import java.util.Objects;
 import javax.inject.Inject;
 
 import org.apache.commons.lang3.StringUtils;
-import org.apache.james.jmap.mime4j.AvoidBinaryBodyBufferingBodyFactory;
+import org.apache.james.jmap.mime4j.AvoidBinaryBodyReadingBodyFactory;
 import org.apache.james.mailbox.exception.MailboxException;
 import org.apache.james.mailbox.model.MessageResult;
 import org.apache.james.mime4j.dom.Message;
@@ -82,7 +82,7 @@ public class Preview {
         private Message parse(InputStream inputStream) throws IOException {
             DefaultMessageBuilder defaultMessageBuilder = new 
DefaultMessageBuilder();
             defaultMessageBuilder.setMimeEntityConfig(MimeConfig.PERMISSIVE);
-            defaultMessageBuilder.setBodyFactory(new 
AvoidBinaryBodyBufferingBodyFactory());
+            defaultMessageBuilder.setBodyFactory(new 
AvoidBinaryBodyReadingBodyFactory());
             return defaultMessageBuilder.parseMessage(inputStream);
         }
     }
diff --git 
a/server/data/data-jmap/src/main/java/org/apache/james/jmap/mime4j/AvoidBinaryBodyReadingBodyFactory.java
 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/mime4j/AvoidBinaryBodyReadingBodyFactory.java
new file mode 100644
index 0000000000..7d78eb0833
--- /dev/null
+++ 
b/server/data/data-jmap/src/main/java/org/apache/james/jmap/mime4j/AvoidBinaryBodyReadingBodyFactory.java
@@ -0,0 +1,270 @@
+/****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one   *
+ * or more contributor license agreements.  See the NOTICE file *
+ * distributed with this work for additional information        *
+ * regarding copyright ownership.  The ASF licenses this file   *
+ * to you under the Apache License, Version 2.0 (the            *
+ * "License"); you may not use this file except in compliance   *
+ * with the License.  You may obtain a copy of the License at   *
+ *                                                              *
+ *   http://www.apache.org/licenses/LICENSE-2.0                 *
+ *                                                              *
+ * Unless required by applicable law or agreed to in writing,   *
+ * software distributed under the License is distributed on an  *
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
+ * KIND, either express or implied.  See the License for the    *
+ * specific language governing permissions and limitations      *
+ * under the License.                                           *
+ ****************************************************************/
+
+package org.apache.james.jmap.mime4j;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.nio.charset.IllegalCharsetNameException;
+import java.nio.charset.UnsupportedCharsetException;
+
+import org.apache.james.mime4j.Charsets;
+import org.apache.james.mime4j.dom.BinaryBody;
+import org.apache.james.mime4j.dom.SingleBody;
+import org.apache.james.mime4j.dom.TextBody;
+import org.apache.james.mime4j.io.InputStreams;
+import org.apache.james.mime4j.message.BasicBodyFactory;
+import org.apache.james.mime4j.message.BodyFactory;
+import org.apache.james.mime4j.util.ByteArrayOutputStreamRecycler;
+import org.apache.james.mime4j.util.ContentUtil;
+
+/**
+ * Factory for creating message bodies.
+ */
+public class AvoidBinaryBodyReadingBodyFactory implements BodyFactory {
+
+    public static final BasicBodyFactory INSTANCE = new BasicBodyFactory();
+
+    private final Charset defaultCharset;
+
+    public AvoidBinaryBodyReadingBodyFactory() {
+        this(true);
+    }
+
+    public AvoidBinaryBodyReadingBodyFactory(final Charset defaultCharset) {
+        this.defaultCharset = defaultCharset;
+    }
+
+    public AvoidBinaryBodyReadingBodyFactory(final boolean lenient) {
+        this(lenient ? Charset.defaultCharset() : null);
+    }
+
+    /**
+     * <p>
+     * Select the Charset for the given <code>mimeCharset</code> string.
+     * </p>
+     * <p>
+     * If you need support for non standard or invalid 
<code>mimeCharset</code> specifications you might want to
+     * create your own derived {@link BodyFactory} extending {@link 
BasicBodyFactory} and overriding this method as
+     * suggested by <a 
href="https://issues.apache.org/jira/browse/MIME4J-218";>MIME4J-218</a>
+     * </p>
+     * <p>
+     * The default behavior is lenient, invalid <code>mimeCharset</code> 
specifications will return the
+     * <code>defaultCharset</code>.
+     * </p>
+     *
+     * @param mimeCharset - the string specification for a Charset e.g. "UTF-8"
+     * @throws UnsupportedEncodingException if the mimeCharset is invalid
+     */
+    protected Charset resolveCharset(final String mimeCharset) throws 
UnsupportedEncodingException {
+        if (mimeCharset != null) {
+            try {
+                return Charset.forName(mimeCharset);
+            } catch (UnsupportedCharsetException | IllegalCharsetNameException 
ex) {
+                if (defaultCharset == null) {
+                    throw new UnsupportedEncodingException(mimeCharset);
+                }
+            }
+        }
+        return defaultCharset;
+    }
+
+    public TextBody textBody(final String text, final String mimeCharset) 
throws UnsupportedEncodingException {
+        if (text == null) {
+            throw new IllegalArgumentException("Text may not be null");
+        }
+        return new StringBody1(text, resolveCharset(mimeCharset));
+    }
+
+    public TextBody textBody(final byte[] content, final Charset charset) {
+        if (content == null) {
+            throw new IllegalArgumentException("Content may not be null");
+        }
+        return new StringBody2(content, charset);
+    }
+
+    public TextBody textBody(final InputStream content, final String 
mimeCharset) throws IOException {
+        if (content == null) {
+            throw new IllegalArgumentException("Input stream may not be null");
+        }
+        return new StringBody3(ContentUtil.bufferEfficient(content), 
resolveCharset(mimeCharset));
+    }
+
+    public TextBody textBody(final String text, final Charset charset) {
+        if (text == null) {
+            throw new IllegalArgumentException("Text may not be null");
+        }
+        return new StringBody1(text, charset);
+    }
+
+    public TextBody textBody(final String text) {
+        return textBody(text, Charsets.DEFAULT_CHARSET);
+    }
+
+
+    public BinaryBody binaryBody(final InputStream is) {
+        return new FakeBinaryBody(-1);
+    }
+
+    static class StringBody1 extends TextBody {
+
+        private final String content;
+        private final Charset charset;
+
+        StringBody1(final String content, final Charset charset) {
+            super();
+            this.content = content;
+            this.charset = charset;
+        }
+
+        @Override
+        public String getMimeCharset() {
+            return this.charset != null ? this.charset.name() : null;
+        }
+
+        @Override
+        public Charset getCharset() {
+            return charset;
+        }
+
+        @Override
+        public Reader getReader() throws IOException {
+            return new StringReader(this.content);
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return InputStreams.create(this.content,
+                    this.charset != null ? this.charset : 
Charsets.DEFAULT_CHARSET);
+        }
+
+        @Override
+        public SingleBody copy() {
+            return new StringBody1(this.content, this.charset);
+        }
+
+    }
+
+    static class StringBody2 extends TextBody {
+
+        private final byte[] content;
+        private final Charset charset;
+
+        StringBody2(final byte[] content, final Charset charset) {
+            super();
+            this.content = content;
+            this.charset = charset;
+        }
+
+        @Override
+        public String getMimeCharset() {
+            return this.charset != null ? this.charset.name() : null;
+        }
+
+        @Override
+        public Charset getCharset() {
+            return charset;
+        }
+
+        @Override
+        public Reader getReader() throws IOException {
+            return new InputStreamReader(InputStreams.create(this.content), 
this.charset);
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return InputStreams.create(this.content);
+        }
+
+        @Override
+        public void writeTo(OutputStream out) throws IOException {
+            out.write(content);
+        }
+
+        @Override
+        public long size() {
+            return content.length;
+        }
+
+        @Override
+        public SingleBody copy() {
+            return new StringBody2(this.content, this.charset);
+        }
+
+    }
+
+    static class StringBody3 extends TextBody {
+
+        private final ByteArrayOutputStreamRecycler.Wrapper content;
+        private final Charset charset;
+
+        StringBody3(final ByteArrayOutputStreamRecycler.Wrapper content, final 
Charset charset) {
+            super();
+            this.content = content;
+            this.charset = charset;
+        }
+
+        @Override
+        public String getMimeCharset() {
+            return this.charset != null ? this.charset.name() : null;
+        }
+
+        @Override
+        public Charset getCharset() {
+            return charset;
+        }
+
+        @Override
+        public Reader getReader() throws IOException {
+            return new 
InputStreamReader(this.content.getValue().toInputStream(), this.charset);
+        }
+
+        @Override
+        public InputStream getInputStream() throws IOException {
+            return this.content.getValue().toInputStream();
+        }
+
+        @Override
+        public long size() {
+            return content.getValue().size();
+        }
+
+        @Override
+        public void writeTo(OutputStream out) throws IOException {
+            content.getValue().writeTo(out);
+        }
+
+        @Override
+        public void dispose() {
+            this.content.release();
+        }
+
+        @Override
+        public SingleBody copy() {
+            return new StringBody3(this.content, this.charset);
+        }
+
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to