Skip to content

Commit

Permalink
[RESTEASY-754] Ported code from 2014 PR into current master. Add modu…
Browse files Browse the repository at this point in the history
…le to jboss-modules for mime4j
  • Loading branch information
rsearls authored and asoldano committed Mar 6, 2019
1 parent 28d62da commit e76ad11
Show file tree
Hide file tree
Showing 12 changed files with 601 additions and 305 deletions.
7 changes: 7 additions & 0 deletions jboss-modules/build.xml
Expand Up @@ -101,6 +101,13 @@
<module-def name="org.glassfish.javax.json">
<maven-resource group="org.glassfish" artifact="javax.json"/>
</module-def>
<!-- todo this is temporary and should be removed when wildfly makes the needed update
-->
<module-def name="org.apache.james.mime4j">
<maven-resource group="org.apache.james" artifact="apache-mime4j-core"/>
<maven-resource group="org.apache.james" artifact="apache-mime4j-dom"/>
<maven-resource group="org.apache.james" artifact="apache-mime4j-storage"/>
</module-def>

<!-- already present in wildfly -->
<module-def name="javax.ws.rs.api">
Expand Down
13 changes: 13 additions & 0 deletions jboss-modules/pom.xml
Expand Up @@ -244,6 +244,19 @@
<artifactId>yasson</artifactId>
</dependency>

<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-dom</artifactId>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-storage</artifactId>
</dependency>

</dependencies>

<build>
Expand Down
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2011, Red Hat, Inc., and individual contributors
~ as indicated by the @author tags. See the copyright.txt file in the
~ distribution for a full listing of individual contributors.
~
~ This is free software; you can redistribute it and/or modify it
~ under the terms of the GNU Lesser General Public License as
~ published by the Free Software Foundation; either version 2.1 of
~ the License, or (at your option) any later version.
~
~ This software is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
~ Lesser General Public License for more details.
~
~ You should have received a copy of the GNU Lesser General Public
~ License along with this software; if not, write to the Free
~ Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
~ 02110-1301 USA, or see the FSF site: http://www.fsf.org.
-->
<module xmlns="urn:jboss:module:1.5" name="org.apache.james.mime4j" >
<properties>
<property name="jboss.api" value="private"/>
</properties>

<resources>
<!-- Insert resources here -->
</resources>

<dependencies>
<module name="javax.api"/>
<module name="org.apache.commons.logging"/>
</dependencies>
</module>
6 changes: 5 additions & 1 deletion providers/multipart/pom.xml
Expand Up @@ -39,7 +39,11 @@
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j</artifactId>
<artifactId>apache-mime4j-dom</artifactId>
</dependency>
<dependency>
<groupId>org.apache.james</groupId>
<artifactId>apache-mime4j-storage</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.spec.javax.servlet</groupId>
Expand Down
@@ -0,0 +1,228 @@
/****************************************************************
* 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.jboss.resteasy.plugins.providers.multipart;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.MimeIOException;
import org.apache.james.mime4j.codec.DecodeMonitor;
import org.apache.james.mime4j.dom.Message;
import org.apache.james.mime4j.field.DefaultFieldParser;
import org.apache.james.mime4j.field.LenientFieldParser;
import org.apache.james.mime4j.message.BodyFactory;
import org.apache.james.mime4j.message.DefaultBodyDescriptorBuilder;
import org.apache.james.mime4j.message.MessageImpl;
import org.apache.james.mime4j.parser.MimeStreamParser;
import org.apache.james.mime4j.storage.AbstractStorageProvider;
import org.apache.james.mime4j.storage.DefaultStorageProvider;
import org.apache.james.mime4j.storage.Storage;
import org.apache.james.mime4j.storage.StorageBodyFactory;
import org.apache.james.mime4j.storage.StorageOutputStream;
import org.apache.james.mime4j.storage.StorageProvider;
import org.apache.james.mime4j.storage.ThresholdStorageProvider;
import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
import org.apache.james.mime4j.stream.MimeConfig;

/**
* Copy code from org.apache.james.mime4j.message.DefaultMessageBuilder.parseMessage().
* Alter said code to use Mime4JWorkaroundBinaryEntityBuilder instead of EntityBuilder.
*/
public class Mime4JWorkaround {
/**
* This is a rough copy of DefaultMessageBuilder.parseMessage() modified to use a Mime4JWorkaround as the contentHandler instead
* of an EntityBuilder.
* <p>
*
* @param is
* @return
* @throws IOException
* @throws MimeIOException
* @see org.apache.james.mime4j.message.DefaultMessageBuilder#parseMessage(java.io.InputStream)
*/
public static Message parseMessage(InputStream is) throws IOException, MimeIOException {
try {
MessageImpl message = new MessageImpl();
MimeConfig cfg = new MimeConfig();
boolean strict = cfg.isStrictParsing();
DecodeMonitor mon = strict ? DecodeMonitor.STRICT : DecodeMonitor.SILENT;
BodyDescriptorBuilder bdb = new DefaultBodyDescriptorBuilder(null, strict ? DefaultFieldParser.getParser() : LenientFieldParser.getParser(), mon);

StorageProvider storageProvider;
if (System.getProperty(DefaultStorageProvider.DEFAULT_STORAGE_PROVIDER_PROPERTY) != null) {
storageProvider = DefaultStorageProvider.getInstance();
} else {
StorageProvider backend = new CustomTempFileStorageProvider();
storageProvider = new ThresholdStorageProvider(backend, 1024);
}
BodyFactory bf = new StorageBodyFactory(storageProvider, mon);

MimeStreamParser parser = new MimeStreamParser(cfg, mon, bdb);
// EntityBuilder expect the parser will send ParserFields for the well known fields
// It will throw exceptions, otherwise.
parser.setContentHandler(new Mime4jWorkaroundBinaryEntityBuilder(message, bf));
parser.setContentDecoding(false);
parser.setRecurse();

parser.parse(is);
return message;
} catch (MimeException e) {
throw new MimeIOException(e);
}
}


/**
* A custom TempFileStorageProvider that do no set deleteOnExit on temp files,
* to avoid memory leaks (see https://issues.apache.org/jira/browse/MIME4J-251)
*
*/
private static class CustomTempFileStorageProvider extends AbstractStorageProvider
{

private static final String DEFAULT_PREFIX = "m4j";

private final String prefix;

private final String suffix;

private final File directory;

CustomTempFileStorageProvider()
{
this(DEFAULT_PREFIX, null, null);
}

CustomTempFileStorageProvider(final String prefix, final String suffix, final File directory)
{
if (prefix == null || prefix.length() < 3)
throw new IllegalArgumentException("invalid prefix");

if (directory != null && !directory.isDirectory() && !directory.mkdirs())
throw new IllegalArgumentException("invalid directory");

this.prefix = prefix;
this.suffix = suffix;
this.directory = directory;
}

public StorageOutputStream createStorageOutputStream() throws IOException
{
File file = File.createTempFile(prefix, suffix, directory);

return new TempFileStorageOutputStream(file);
}

private static final class TempFileStorageOutputStream extends StorageOutputStream
{
private File file;

private OutputStream out;

TempFileStorageOutputStream(final File file) throws IOException
{
this.file = file;
this.out = new FileOutputStream(file);
}

@Override
public void close() throws IOException
{
super.close();
out.close();
}

@Override
protected void write0(byte[] buffer, int offset, int length) throws IOException
{
out.write(buffer, offset, length);
}

@Override
protected Storage toStorage0() throws IOException
{
// out has already been closed because toStorage calls close
return new TempFileStorage(file);
}
}

private static final class TempFileStorage implements Storage
{

private File file;

private static final Set<File> filesToDelete = new HashSet<File>();

TempFileStorage(final File file)
{
this.file = file;
}

public void delete()
{
// deleting a file might not immediately succeed if there are still
// streams left open (especially under Windows). so we keep track of
// the files that have to be deleted and try to delete all these
// files each time this method gets invoked.

// a better but more complicated solution would be to start a
// separate thread that tries to delete the files periodically.

synchronized (filesToDelete)
{
if (file != null)
{
filesToDelete.add(file);
file = null;
}

for (Iterator<File> iterator = filesToDelete.iterator(); iterator.hasNext();)
{
File f = iterator.next();
if (f.delete())
{
iterator.remove();
}
}
}
}

public InputStream getInputStream() throws IOException
{
if (file == null)
throw new IllegalStateException("storage has been deleted");

return new BufferedInputStream(new FileInputStream(file));
}

}
}

}


0 comments on commit e76ad11

Please sign in to comment.