Skip to content

Commit

Permalink
Merge pull request #2776 from andymc12/2880-make-in-memory-thresholds…
Browse files Browse the repository at this point in the history
…-configurable

[RESTEASY-2880] Config options for in-memory limit
  • Loading branch information
jamezp committed Jul 21, 2021
2 parents 0eb49bf + f20d9f5 commit 1498585
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 18 deletions.
5 changes: 5 additions & 0 deletions providers/multipart/pom.xml
Expand Up @@ -70,6 +70,11 @@
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<profiles>
Expand Down
Expand Up @@ -11,8 +11,8 @@
* @version $Revision: 1 $
*/
public class HeaderFlushedOutputStream extends OutputStream {
private MultivaluedMap<String, Object> headers;
private OutputStream stream;
private final MultivaluedMap<String, Object> headers;
private final OutputStream stream;
private boolean headersFlushed = false;

public HeaderFlushedOutputStream(final MultivaluedMap<String, Object> headers,
Expand Down
Expand Up @@ -33,13 +33,18 @@
import org.apache.james.mime4j.storage.ThresholdStorageProvider;
import org.apache.james.mime4j.stream.BodyDescriptorBuilder;
import org.apache.james.mime4j.stream.MimeConfig;
import org.jboss.resteasy.plugins.providers.multipart.i18n.LogMessages;
import org.jboss.resteasy.spi.config.Configuration;
import org.jboss.resteasy.spi.config.ConfigurationFactory;

/**
* Copy code from org.apache.james.mime4j.message.DefaultMessageBuilder.parseMessage().
* Alter said code to use Mime4JWorkaroundBinaryEntityBuilder instead of EntityBuilder.
*/
public class Mime4JWorkaround {
static final String MEM_THRESHOLD_PROPERTY = "org.jboss.resteasy.plugins.providers.multipart.memoryThreshold";
static final int DEFAULT_MEM_THRESHOLD = 1024;

/**
* This is a rough copy of DefaultMessageBuilder.parseMessage() modified to use a Mime4JWorkaround as the contentHandler instead
* of an EntityBuilder.
Expand All @@ -64,7 +69,7 @@ public static Message parseMessage(InputStream is) throws IOException, MimeIOExc
storageProvider = DefaultStorageProvider.getInstance();
} else {
StorageProvider backend = new CustomTempFileStorageProvider();
storageProvider = new ThresholdStorageProvider(backend, 1024);
storageProvider = new ThresholdStorageProvider(backend, getMemThreshold());
}
BodyFactory bf = new StorageBodyFactory(storageProvider, mon);

Expand All @@ -82,6 +87,25 @@ public static Message parseMessage(InputStream is) throws IOException, MimeIOExc
}
}

static int getMemThreshold()
{
try
{
Configuration cfg = ConfigurationFactory.getInstance().getConfiguration();
int threshold = Integer.parseInt(cfg.getOptionalValue(MEM_THRESHOLD_PROPERTY, String.class).orElse(
Integer.toString(DEFAULT_MEM_THRESHOLD)));
if (threshold > -1)
{
return threshold;
}
LogMessages.LOGGER.debugf("Negative threshold, %s, specified. Using default value", threshold);
}
catch (Exception e)
{
LogMessages.LOGGER.debug("Exception caught parsing memory threshold. Using default value.", e);
}
return DEFAULT_MEM_THRESHOLD;
}

/**
* A custom TempFileStorageProvider that do no set deleteOnExit on temp files,
Expand Down
@@ -0,0 +1,79 @@
package org.jboss.resteasy.plugins.providers.multipart;

import static org.junit.Assert.assertEquals;

import java.util.HashMap;
import java.util.Map;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class Mime4JWorkaroundTest {

private static final Map<String, String> preTestProperties = new HashMap<>();

@BeforeClass
public static void saveCurrentStateOfMemThresholdProperty()
{
if (System.getProperties().containsKey(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY))
{
String value = System.getProperty(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY);
preTestProperties.put(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY, value);
}
}

@AfterClass
public static void resetPropertiesToPreTestValues()
{
if (!preTestProperties.containsKey(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY))
{
System.clearProperty(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY);
}
else
{
preTestProperties.forEach(System::setProperty);
}
}

@Before
public void unsetMemThresholdProperty()
{
System.clearProperty(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY);
}

@Test
public void testMemThresholdDefault()
{
assertEquals(Mime4JWorkaround.DEFAULT_MEM_THRESHOLD, Mime4JWorkaround.getMemThreshold());
}

@Test
public void testMemThresholdConfigProperty()
{
System.setProperty(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY, "2048");
assertEquals(2048, Mime4JWorkaround.getMemThreshold());
}

@Test
public void testInvalidMemThresholdConfigPropertyReturnsDefault_NegativeNumber()
{
System.setProperty(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY, "-2048");
assertEquals(Mime4JWorkaround.DEFAULT_MEM_THRESHOLD, Mime4JWorkaround.getMemThreshold());
}

@Test
public void testInvalidMemThresholdConfigPropertyReturnsDefault_DecimalNumber()
{
System.setProperty(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY, "2048.2");
assertEquals(Mime4JWorkaround.DEFAULT_MEM_THRESHOLD, Mime4JWorkaround.getMemThreshold());
}

@Test
public void testInvalidMemThresholdConfigPropertyReturnsDefault_NotANumber()
{
System.setProperty(Mime4JWorkaround.MEM_THRESHOLD_PROPERTY, "Infinity");
assertEquals(Mime4JWorkaround.DEFAULT_MEM_THRESHOLD, Mime4JWorkaround.getMemThreshold());
}
}
Expand Up @@ -54,6 +54,9 @@
public class ManualClosingApacheHttpClient43Engine implements ApacheHttpClientEngine
{

static final String FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY =
"org.jboss.resteasy.client.jaxrs.engines.fileUploadInMemoryThreshold";

/**
* Used to build temp file prefix.
*/
Expand Down Expand Up @@ -123,39 +126,58 @@ public String run() throws Exception

public ManualClosingApacheHttpClient43Engine()
{
this.httpClient = createDefaultHttpClient();
this.allowClosingHttpClient = true;
this(null, null, true, null);
}

public ManualClosingApacheHttpClient43Engine(final HttpHost defaultProxy)
{
this.defaultProxy = defaultProxy;
this.httpClient = createDefaultHttpClient();
this.allowClosingHttpClient = true;
this(null, null, true, defaultProxy);
}

public ManualClosingApacheHttpClient43Engine(final HttpClient httpClient)
{
this.httpClient = httpClient;
this.allowClosingHttpClient = true;
this(httpClient, null, true, null);
}

public ManualClosingApacheHttpClient43Engine(final HttpClient httpClient, final boolean closeHttpClient)
{
if (closeHttpClient && !(httpClient instanceof CloseableHttpClient))
this(httpClient, null, closeHttpClient, null);
}

public ManualClosingApacheHttpClient43Engine(final HttpClient httpClient,
final HttpContextProvider httpContextProvider)
{
this(httpClient, httpContextProvider, true, null);
}

private ManualClosingApacheHttpClient43Engine(final HttpClient httpClient,
final HttpContextProvider httpContextProvider, final boolean closeHttpClient, final HttpHost defaultProxy)
{
this.httpClient = httpClient != null ? httpClient : createDefaultHttpClient();
if (closeHttpClient && !(this.httpClient instanceof CloseableHttpClient))
{
throw new IllegalArgumentException(
"httpClient must be a CloseableHttpClient instance in order for allowing engine to close it!");
}
this.httpClient = httpClient;
this.httpContextProvider = httpContextProvider;
this.allowClosingHttpClient = closeHttpClient;
}
this.defaultProxy = defaultProxy;

public ManualClosingApacheHttpClient43Engine(final HttpClient httpClient, final HttpContextProvider httpContextProvider)
{
this.httpClient = httpClient;
this.httpContextProvider = httpContextProvider;
this.allowClosingHttpClient = true;
try
{
int threshold = Integer.parseInt(ConfigurationFactory.getInstance().getConfiguration()
.getOptionalValue(FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY, String.class)
.orElse("1"));
if (threshold > -1)
{
this.fileUploadInMemoryThresholdLimit = threshold;
}
LogMessages.LOGGER.debugf("Negative threshold, %s, specified. Using default value", threshold);
}
catch (Exception e)
{
LogMessages.LOGGER.debug("Exception caught parsing memory threshold. Using default value.", e);
}
}

/**
Expand Down
@@ -0,0 +1,79 @@
package org.jboss.resteasy.client.jaxrs.engines;

import static org.junit.Assert.assertEquals;
import static org.jboss.resteasy.client.jaxrs.engines.ManualClosingApacheHttpClient43Engine.FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY;

import java.util.HashMap;
import java.util.Map;

import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

public class ManualClosingApacheHttpClient43EngineTest {

private static final Map<String, String> preTestProperties = new HashMap<>();

@BeforeClass
public static void saveCurrentStateOfMemThresholdProperty()
{
if (System.getProperties().containsKey(FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY))
{
String value = System.getProperty(FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY);
preTestProperties.put(FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY, value);
}
}

@AfterClass
public static void resetPropertiesToPreTestValues()
{
if (!preTestProperties.containsKey(FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY))
{
System.clearProperty(FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY);
}
else
{
preTestProperties.forEach(System::setProperty);
}
}

@Before
public void unsetMemThresholdProperty()
{
System.clearProperty(ManualClosingApacheHttpClient43Engine.FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY);
}
@Test
public void testMemThresholdDefault()
{
assertEquals(1, new ManualClosingApacheHttpClient43Engine().getFileUploadInMemoryThresholdLimit());
}

@Test
public void testMemThresholdConfigProperty()
{
System.setProperty(ManualClosingApacheHttpClient43Engine.FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY, "8");
assertEquals(8, new ManualClosingApacheHttpClient43Engine().getFileUploadInMemoryThresholdLimit());
}

@Test
public void testInvalidMemThresholdConfigPropertyReturnsDefault_NegativeNumber()
{
System.setProperty(ManualClosingApacheHttpClient43Engine.FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY, "-8");
assertEquals(1, new ManualClosingApacheHttpClient43Engine().getFileUploadInMemoryThresholdLimit());
}

@Test
public void testInvalidMemThresholdConfigPropertyReturnsDefault_DecimalNumber()
{
System.setProperty(ManualClosingApacheHttpClient43Engine.FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY, "2048.2");
assertEquals(1, new ManualClosingApacheHttpClient43Engine().getFileUploadInMemoryThresholdLimit());
}

@Test
public void testInvalidMemThresholdConfigPropertyReturnsDefault_NotANumber()
{
System.setProperty(ManualClosingApacheHttpClient43Engine.FILE_UPLOAD_IN_MEMORY_THRESHOLD_PROPERTY, "Infinity");
assertEquals(1, new ManualClosingApacheHttpClient43Engine().getFileUploadInMemoryThresholdLimit());
}
}

0 comments on commit 1498585

Please sign in to comment.