Return-Path: X-Original-To: apmail-cxf-commits-archive@www.apache.org Delivered-To: apmail-cxf-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 4D5DD79EC for ; Wed, 26 Oct 2011 15:41:51 +0000 (UTC) Received: (qmail 42050 invoked by uid 500); 26 Oct 2011 15:41:51 -0000 Delivered-To: apmail-cxf-commits-archive@cxf.apache.org Received: (qmail 41942 invoked by uid 500); 26 Oct 2011 15:41:51 -0000 Mailing-List: contact commits-help@cxf.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cxf.apache.org Delivered-To: mailing list commits@cxf.apache.org Received: (qmail 41935 invoked by uid 99); 26 Oct 2011 15:41:51 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 26 Oct 2011 15:41:51 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 26 Oct 2011 15:41:49 +0000 Received: from eris.apache.org (localhost [127.0.0.1]) by eris.apache.org (Postfix) with ESMTP id 0FC342388978 for ; Wed, 26 Oct 2011 15:41:29 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1189272 - in /cxf/trunk: api/src/main/java/org/apache/cxf/io/ rt/core/src/main/java/org/apache/cxf/attachment/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/ rt/fron... Date: Wed, 26 Oct 2011 15:41:28 -0000 To: commits@cxf.apache.org From: dkulp@apache.org X-Mailer: svnmailer-1.0.8-patched Message-Id: <20111026154129.0FC342388978@eris.apache.org> Author: dkulp Date: Wed Oct 26 15:41:28 2011 New Revision: 1189272 URL: http://svn.apache.org/viewvc?rev=1189272&view=rev Log: [CXF-3879] Allow controlling the maximum size of incoming attachments. Patch from Sam Meder applied. Modified: cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java cxf/trunk/rt/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/MultipartProvider.java cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/multipart/AttachmentUtils.java cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java Modified: cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java (original) +++ cxf/trunk/api/src/main/java/org/apache/cxf/io/CachedOutputStream.java Wed Oct 26 15:41:28 2011 @@ -43,6 +43,7 @@ import org.apache.cxf.helpers.LoadingByt public class CachedOutputStream extends OutputStream { private static final File DEFAULT_TEMP_DIR; private static final int DEFAULT_THRESHOLD; + private static final long DEFAULT_MAX_SIZE; static { String s = SystemPropertyAction.getProperty("org.apache.cxf.io.CachedOutputStream.Threshold", "-1"); @@ -63,12 +64,17 @@ public class CachedOutputStream extends } else { DEFAULT_TEMP_DIR = null; } + + s = System.getProperty("org.apache.cxf.io.CachedOutputStream.MaxSize", + "-1"); + DEFAULT_MAX_SIZE = Long.parseLong(s); } protected boolean outputLocked; protected OutputStream currentStream; private long threshold = DEFAULT_THRESHOLD; + private long maxSize = DEFAULT_MAX_SIZE; private int totalLength; @@ -383,13 +389,20 @@ public class CachedOutputStream extends } + private void enforceLimits() throws IOException { + if (maxSize > 0 && totalLength > maxSize) { + throw new CacheSizeExceededException(); + } + if (inmem && totalLength > threshold && currentStream instanceof ByteArrayOutputStream) { + createFileOutputStream(); + } + } + public void write(byte[] b, int off, int len) throws IOException { if (!outputLocked) { onWrite(); this.totalLength += len; - if (inmem && totalLength > threshold && currentStream instanceof ByteArrayOutputStream) { - createFileOutputStream(); - } + enforceLimits(); currentStream.write(b, off, len); } } @@ -398,9 +411,7 @@ public class CachedOutputStream extends if (!outputLocked) { onWrite(); this.totalLength += b.length; - if (inmem && totalLength > threshold && currentStream instanceof ByteArrayOutputStream) { - createFileOutputStream(); - } + enforceLimits(); currentStream.write(b); } } @@ -409,9 +420,7 @@ public class CachedOutputStream extends if (!outputLocked) { onWrite(); this.totalLength++; - if (inmem && totalLength > threshold && currentStream instanceof ByteArrayOutputStream) { - createFileOutputStream(); - } + enforceLimits(); currentStream.write(b); } } @@ -498,4 +507,8 @@ public class CachedOutputStream extends public void setThreshold(long threshold) { this.threshold = threshold; } + + public void setMaxSize(long maxSize) { + this.maxSize = maxSize; + } } Modified: cxf/trunk/rt/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/rt/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java (original) +++ cxf/trunk/rt/core/src/main/java/org/apache/cxf/attachment/AttachmentDeserializer.java Wed Oct 26 15:41:28 2011 @@ -48,6 +48,8 @@ public class AttachmentDeserializer { public static final String ATTACHMENT_MEMORY_THRESHOLD = "attachment-memory-threshold"; + public static final String ATTACHMENT_MAX_SIZE = "attachment-max-size"; + public static final int THRESHOLD = 1024 * 100; //100K (byte unit) private static final Pattern CONTENT_TYPE_BOUNDARY_PATTERN = Pattern.compile("boundary=\"?([^\";]*)"); @@ -186,6 +188,15 @@ public class AttachmentDeserializer { } else { bos.setThreshold(THRESHOLD); } + + Object maxSize = message.getContextualProperty(ATTACHMENT_MAX_SIZE); + if (maxSize != null) { + if (maxSize instanceof Long) { + bos.setMaxSize((Long) maxSize); + } else { + bos.setMaxSize(Long.valueOf((String)maxSize)); + } + } } public AttachmentImpl readNext() throws IOException { Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java (original) +++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/ext/MessageContextImpl.java Wed Oct 26 15:41:28 2011 @@ -46,6 +46,7 @@ import org.apache.cxf.attachment.Attachm import org.apache.cxf.attachment.AttachmentUtil; import org.apache.cxf.endpoint.Endpoint; import org.apache.cxf.interceptor.AttachmentOutInterceptor; +import org.apache.cxf.io.CacheSizeExceededException; import org.apache.cxf.jaxrs.ext.multipart.Attachment; import org.apache.cxf.jaxrs.ext.multipart.MultipartBody; import org.apache.cxf.jaxrs.impl.ProvidersImpl; @@ -67,7 +68,11 @@ public class MessageContextImpl implemen String keyValue = key.toString(); if (MultipartBody.INBOUND_MESSAGE_ATTACHMENTS.equals(keyValue) || (MultipartBody.INBOUND_MESSAGE_ATTACHMENTS + ".embedded").equals(keyValue)) { - return createAttachments(key.toString()); + try { + return createAttachments(key.toString()); + } catch (CacheSizeExceededException e) { + throw new WebApplicationException(413); + } } if (keyValue.equals("WRITE-" + Message.ATTACHMENTS)) { return m.getExchange().getOutMessage().get(Message.ATTACHMENTS); @@ -216,6 +221,8 @@ public class MessageContextImpl implemen m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_DIRECTORY)); inMessage.put(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD, m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD)); + inMessage.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE, + m.getExchange().getInMessage().get(AttachmentDeserializer.ATTACHMENT_MAX_SIZE)); inMessage.setContent(InputStream.class, m.getExchange().getInMessage().get("org.apache.cxf.multipart.embedded.input")); inMessage.put(Message.CONTENT_TYPE, Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java (original) +++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/FormEncodingProvider.java Wed Oct 26 15:41:28 2011 @@ -61,6 +61,7 @@ public class FormEncodingProvider implem @Context private MessageContext mc; private String attachmentDir; private String attachmentThreshold; + private String attachmentMaxSize; private boolean expectEncoded; @@ -76,6 +77,10 @@ public class FormEncodingProvider implem attachmentThreshold = threshold; } + public void setAttachmentMaxSize(String maxSize) { + attachmentMaxSize = maxSize; + } + public void setValidator(FormValidator formValidator) { validator = formValidator; } @@ -151,7 +156,7 @@ public class FormEncodingProvider implem InputStream is, MediaType mt, boolean decode) { if (mt.isCompatible(MediaType.MULTIPART_FORM_DATA_TYPE)) { MultipartBody body = - AttachmentUtils.getMultipartBody(mc, attachmentDir, attachmentThreshold); + AttachmentUtils.getMultipartBody(mc, attachmentDir, attachmentThreshold, attachmentMaxSize); FormUtils.populateMapFromMultipart(params, body, decode); } else { String enc = HttpUtils.getEncoding(mt, "UTF-8"); Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/MultipartProvider.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/MultipartProvider.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/MultipartProvider.java (original) +++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/MultipartProvider.java Wed Oct 26 15:41:28 2011 @@ -82,6 +82,7 @@ public class MultipartProvider extends A private MessageContext mc; private String attachmentDir; private String attachmentThreshold; + private String attachmentMaxSize; public void setMessageContext(MessageContext context) { this.mc = context; @@ -95,6 +96,10 @@ public class MultipartProvider extends A attachmentThreshold = threshold; } + public void setAttachmentMaxSize(String maxSize) { + attachmentMaxSize = maxSize; + } + public boolean isReadable(Class type, Type genericType, Annotation[] annotations, MediaType mt) { return isSupported(type, genericType, annotations, mt); @@ -131,8 +136,8 @@ public class MultipartProvider extends A MultivaluedMap headers, InputStream is) throws IOException, WebApplicationException { checkContentLength(); - List infos = - AttachmentUtils.getAttachments(mc, attachmentDir, attachmentThreshold); + List infos = AttachmentUtils.getAttachments( + mc, attachmentDir, attachmentThreshold, attachmentMaxSize); if (Collection.class.isAssignableFrom(c) && AnnotationUtils.getAnnotation(anns, Multipart.class) == null) { Modified: cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/multipart/AttachmentUtils.java URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/multipart/AttachmentUtils.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/multipart/AttachmentUtils.java (original) +++ cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/utils/multipart/AttachmentUtils.java Wed Oct 26 15:41:28 2011 @@ -72,13 +72,16 @@ public final class AttachmentUtils { } public static MultipartBody getMultipartBody(MessageContext mc, - String attachmentDir, String attachmentThreshold) { + String attachmentDir, String attachmentThreshold, String attachmentMaxSize) { if (attachmentDir != null) { mc.put(AttachmentDeserializer.ATTACHMENT_DIRECTORY, attachmentDir); } if (attachmentThreshold != null) { mc.put(AttachmentDeserializer.ATTACHMENT_MEMORY_THRESHOLD, attachmentThreshold); } + if (attachmentMaxSize != null) { + mc.put(AttachmentDeserializer.ATTACHMENT_MAX_SIZE, attachmentMaxSize); + } boolean embeddedAttachment = mc.get("org.apache.cxf.multipart.embedded") != null; String propertyName = embeddedAttachment ? MultipartBody.INBOUND_MESSAGE_ATTACHMENTS + ".embedded" @@ -88,8 +91,11 @@ public final class AttachmentUtils { } public static List getAttachments(MessageContext mc, - String attachmentDir, String attachmentThreshold) { - return getMultipartBody(mc, attachmentDir, attachmentThreshold).getAllAttachments(); + String attachmentDir, String attachmentThreshold, String attachmentMaxSize) { + return getMultipartBody(mc, + attachmentDir, + attachmentThreshold, + attachmentMaxSize).getAllAttachments(); } public static Attachment getMultipart(Class c, Annotation[] anns, Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java (original) +++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/JAXRSMultipartTest.java Wed Oct 26 15:41:28 2011 @@ -43,6 +43,10 @@ import org.apache.commons.httpclient.Htt import org.apache.commons.httpclient.methods.InputStreamRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; +import org.apache.commons.httpclient.methods.multipart.ByteArrayPartSource; +import org.apache.commons.httpclient.methods.multipart.FilePart; +import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; +import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.cxf.helpers.IOUtils; import org.apache.cxf.io.CachedOutputStream; import org.apache.cxf.jaxrs.client.JAXRSClientFactory; @@ -526,6 +530,28 @@ public class JAXRSMultipartTest extends } } + @Test + public void testMultipartRequestTooLarge() throws Exception { + PostMethod post = new PostMethod("http://localhost:" + PORT + "/bookstore/books/image"); + String ct = "multipart/mixed"; + post.setRequestHeader("Content-Type", ct); + Part[] parts = new Part[1]; + parts[0] = new FilePart("image", + new ByteArrayPartSource("testfile.png", new byte[1024 * 1024 * 15]), + "image/png", null); + post.setRequestEntity(new MultipartRequestEntity(parts, post.getParams())); + + HttpClient httpclient = new HttpClient(); + + try { + int result = httpclient.executeMethod(post); + assertEquals(413, result); + } finally { + // Release current connection to the connection pool once you are done + post.releaseConnection(); + } + } + private void doAddBook(String address, String resourceName, int status) throws Exception { doAddBook("multipart/related", address, resourceName, status); } Modified: cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java?rev=1189272&r1=1189271&r2=1189272&view=diff ============================================================================== --- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java (original) +++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/MultipartServer.java Wed Oct 26 15:41:28 2011 @@ -19,15 +19,22 @@ package org.apache.cxf.systest.jaxrs; +import java.util.Collections; + +import org.apache.cxf.attachment.AttachmentDeserializer; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider; import org.apache.cxf.testutil.common.AbstractBusTestServerBase; + public class MultipartServer extends AbstractBusTestServerBase { public static final String PORT = allocatePort(MultipartServer.class); protected void run() { JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean(); sf.setResourceClasses(MultipartStore.class); + sf.setProperties(Collections.singletonMap( + AttachmentDeserializer.ATTACHMENT_MAX_SIZE, + String.valueOf(1024 * 1024 * 10))); //default lifecycle is per-request, change it to singleton sf.setResourceProvider(MultipartStore.class, new SingletonResourceProvider(new MultipartStore()));