diff --git a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartRequestContent.java b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartRequestContent.java
index 0068a5692e7..eb5ddaede32 100644
--- a/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartRequestContent.java
+++ b/jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/util/MultiPartRequestContent.java
@@ -70,7 +70,7 @@ public class MultiPartRequestContent extends MultiPartFormData.ContentSource imp
if (headers.contains(HttpHeader.CONTENT_TYPE))
return headers;
- Content.Source partContent = part.getNewContent();
+ Content.Source partContent = part.newContentSource();
if (partContent instanceof Request.Content requestContent)
{
String contentType = requestContent.getContentType();
diff --git a/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartRequestContentTest.java b/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartRequestContentTest.java
index 8e20301db14..6ca29407eb9 100644
--- a/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartRequestContentTest.java
+++ b/jetty-core/jetty-client/src/test/java/org/eclipse/jetty/client/util/MultiPartRequestContentTest.java
@@ -129,7 +129,7 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
int equal = contentType.lastIndexOf('=');
Charset charset = Charset.forName(contentType.substring(equal + 1));
assertEquals(encoding, charset);
- assertEquals(value, Content.Source.asString(part.getNewContent(), charset));
+ assertEquals(value, Content.Source.asString(part.newContentSource(), charset));
}
});
@@ -163,7 +163,7 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
MultiPart.Part part = parts.iterator().next();
assertEquals(name, part.getName());
assertEquals("text/plain", part.getHeaders().get(HttpHeader.CONTENT_TYPE));
- assertArrayEquals(data, Content.Source.asByteBuffer(part.getNewContent()).array());
+ assertArrayEquals(data, Content.Source.asByteBuffer(part.newContentSource()).array());
}
});
@@ -215,8 +215,8 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
assertEquals(name, part.getName());
assertEquals(contentType, part.getHeaders().get(HttpHeader.CONTENT_TYPE));
assertEquals(fileName, part.getFileName());
- assertEquals(data.length, part.getNewContent().getLength());
- assertArrayEquals(data, Content.Source.asByteBuffer(part.getNewContent()).array());
+ assertEquals(data.length, part.newContentSource().getLength());
+ assertArrayEquals(data, Content.Source.asByteBuffer(part.newContentSource()).array());
}
});
@@ -271,8 +271,8 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
assertEquals(name, part.getName());
assertEquals(contentType, part.getHeaders().get(HttpHeader.CONTENT_TYPE));
assertEquals(tmpPath.getFileName().toString(), part.getFileName());
- assertEquals(Files.size(tmpPath), part.getNewContent().getLength());
- assertEquals(data, Content.Source.asString(part.getNewContent(), encoding));
+ assertEquals(Files.size(tmpPath), part.newContentSource().getLength());
+ assertEquals(data, Content.Source.asString(part.newContentSource(), encoding));
}
});
@@ -323,14 +323,14 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
assertEquals(field, fieldPart.getName());
assertEquals(contentType, fieldPart.getHeaders().get(HttpHeader.CONTENT_TYPE));
- assertEquals(value, Content.Source.asString(fieldPart.getNewContent(), encoding));
+ assertEquals(value, Content.Source.asString(fieldPart.newContentSource(), encoding));
assertEquals(headerValue, fieldPart.getHeaders().get(headerName));
assertEquals(fileField, filePart.getName());
assertEquals("application/octet-stream", filePart.getHeaders().get(HttpHeader.CONTENT_TYPE));
assertEquals(tmpPath.getFileName().toString(), filePart.getFileName());
- assertEquals(Files.size(tmpPath), filePart.getNewContent().getLength());
- assertArrayEquals(data, Content.Source.asByteBuffer(filePart.getNewContent()).array());
+ assertEquals(Files.size(tmpPath), filePart.newContentSource().getLength());
+ assertArrayEquals(data, Content.Source.asByteBuffer(filePart.newContentSource()).array());
}
});
@@ -367,11 +367,11 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
MultiPart.Part fieldPart = parts.get(0);
MultiPart.Part filePart = parts.get(1);
- assertEquals(value, Content.Source.asString(fieldPart.getNewContent(), encoding));
+ assertEquals(value, Content.Source.asString(fieldPart.newContentSource(), encoding));
assertEquals("file", filePart.getName());
assertEquals("application/octet-stream", filePart.getHeaders().get(HttpHeader.CONTENT_TYPE));
assertEquals("fileName", filePart.getFileName());
- assertArrayEquals(fileData, Content.Source.asByteBuffer(filePart.getNewContent()).array());
+ assertArrayEquals(fileData, Content.Source.asByteBuffer(filePart.newContentSource()).array());
}
});
diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java
index b39d3475312..4455af9e140 100644
--- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java
+++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPart.java
@@ -176,7 +176,7 @@ public class MultiPart
public Content.Source getContentSource()
{
if (content == null)
- content = getNewContent();
+ content = newContentSource();
return content;
}
@@ -192,11 +192,11 @@ public class MultiPart
*
* @return the content of this part as a new {@link Content.Source}
*/
- public abstract Content.Source getNewContent();
+ public abstract Content.Source newContentSource();
public long getLength()
{
- return getNewContent().getLength();
+ return newContentSource().getLength();
}
/**
@@ -221,7 +221,7 @@ public class MultiPart
Charset charset = defaultCharset != null ? defaultCharset : UTF_8;
if (charsetName != null)
charset = Charset.forName(charsetName);
- return Content.Source.asString(getNewContent(), charset);
+ return Content.Source.asString(newContentSource(), charset);
}
catch (IOException x)
{
@@ -237,11 +237,6 @@ public class MultiPart
return fields;
}
- public Path getPath()
- {
- return path;
- }
-
/**
*
Writes the content of this part to the given path.
*
@@ -254,7 +249,7 @@ public class MultiPart
{
try (OutputStream out = Files.newOutputStream(path))
{
- IO.copy(Content.Source.asInputStream(getNewContent()), out);
+ IO.copy(Content.Source.asInputStream(newContentSource()), out);
}
this.path = path;
}
@@ -306,7 +301,7 @@ public class MultiPart
}
@Override
- public Content.Source getNewContent()
+ public Content.Source newContentSource()
{
return new ByteBufferContentSource(content);
}
@@ -346,7 +341,7 @@ public class MultiPart
}
@Override
- public Content.Source getNewContent()
+ public Content.Source newContentSource()
{
return new ChunksContentSource(content.stream().map(Content.Chunk::slice).toList());
}
@@ -395,8 +390,13 @@ public class MultiPart
}
}
+ public Path getPath()
+ {
+ return path;
+ }
+
@Override
- public Content.Source getNewContent()
+ public Content.Source newContentSource()
{
return new PathContentSource(path);
}
@@ -409,7 +409,7 @@ public class MultiPart
hashCode(),
getName(),
getFileName(),
- getPath()
+ path
);
}
}
@@ -428,7 +428,7 @@ public class MultiPart
}
@Override
- public Content.Source getNewContent()
+ public Content.Source newContentSource()
{
Content.Source c = content;
content = null;
@@ -630,7 +630,7 @@ public class MultiPart
else
{
part = parts.poll();
- partContent = part.getNewContent();
+ partContent = part.newContentSource();
state = State.HEADERS;
yield Content.Chunk.from(firstBoundary.slice(), false);
}
@@ -657,7 +657,7 @@ public class MultiPart
else
{
part = parts.poll();
- partContent = part.getNewContent();
+ partContent = part.newContentSource();
state = State.HEADERS;
yield Content.Chunk.from(middleBoundary.slice(), false);
}
@@ -743,7 +743,7 @@ public class MultiPart
if (state == State.CONTENT)
{
- partContent.demand(() ->
+ part.getContentSource().demand(() ->
{
try (AutoLock ignoredAgain = lock.lock())
{
@@ -850,6 +850,8 @@ public class MultiPart
private int trailingWhiteSpaces;
private String fieldName;
private String fieldValue;
+ private long maxParts;
+ private int numParts = 0;
public Parser(String boundary, Listener listener)
{
@@ -881,6 +883,22 @@ public class MultiPart
this.partHeadersMaxLength = partHeadersMaxLength;
}
+ /**
+ * @return the maximum number of parts that can be parsed from the multipart content.
+ */
+ public long getMaxParts()
+ {
+ return maxParts;
+ }
+
+ /**
+ * @param maxParts the maximum number of parts that can be parsed from the multipart content.
+ */
+ public void setMaxParts(long maxParts)
+ {
+ this.maxParts = maxParts;
+ }
+
/**
* Resets this parser to make it ready to parse again a multipart/form-data content.
*/
@@ -939,6 +957,10 @@ public class MultiPart
}
else if (type == HttpTokens.Type.LF)
{
+ numParts++;
+ if (numParts >= maxParts)
+ throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", numParts, maxParts));
+
notifyPartBegin();
state = State.HEADER_START;
trailingWhiteSpaces = 0;
@@ -1343,37 +1365,93 @@ public class MultiPart
private void notifyPartBegin()
{
- listener.onPartBegin();
+ try
+ {
+ listener.onPartBegin();
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("failure while notifying listener {}", listener, x);
+ }
}
private void notifyPartHeader(String name, String value)
{
- listener.onPartHeader(name, value);
+ try
+ {
+ listener.onPartHeader(name, value);
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("failure while notifying listener {}", listener, x);
+ }
}
private void notifyPartHeaders()
{
- listener.onPartHeaders();
+ try
+ {
+ listener.onPartHeaders();
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("failure while notifying listener {}", listener, x);
+ }
}
private void notifyPartContent(Content.Chunk chunk)
{
- listener.onPartContent(chunk);
+ try
+ {
+ listener.onPartContent(chunk);
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("failure while notifying listener {}", listener, x);
+ }
}
private void notifyPartEnd()
{
- listener.onPartEnd();
+ try
+ {
+ listener.onPartEnd();
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("failure while notifying listener {}", listener, x);
+ }
}
private void notifyComplete()
{
- listener.onComplete();
+ try
+ {
+ listener.onComplete();
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("failure while notifying listener {}", listener, x);
+ }
}
private void notifyFailure(Throwable failure)
{
- listener.onFailure(failure);
+ try
+ {
+ listener.onFailure(failure);
+ }
+ catch (Throwable x)
+ {
+ if (LOG.isDebugEnabled())
+ LOG.debug("failure while notifying listener {}", listener, x);
+ }
}
/**
diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartByteRanges.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartByteRanges.java
index 80117431dc5..4f4feebd1d4 100644
--- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartByteRanges.java
+++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MultiPartByteRanges.java
@@ -265,7 +265,7 @@ public class MultiPartByteRanges extends CompletableFuture implements Closeable
+public class MultiPartFormData extends CompletableFuture
{
private static final Logger LOG = LoggerFactory.getLogger(MultiPartFormData.class);
@@ -80,8 +80,6 @@ public class MultiPartFormData extends CompletableFutureAn ordered list of {@link MultiPart.Part}s that can
* be accessed by index or by name, or iterated over.
*/
- public static class Parts implements Iterable
+ public class Parts implements Iterable
{
- private final String boundary;
private final List parts;
- private Parts(String boundary, List parts)
+ private Parts(List parts)
{
- this.boundary = boundary;
this.parts = parts;
}
- /**
- * @return the boundary string
- */
- public String getBoundary()
+ public MultiPartFormData getMultiPartFormData()
{
- return boundary;
+ return MultiPartFormData.this;
}
/**
@@ -383,6 +376,21 @@ public class MultiPartFormData extends CompletableFuture= maxParts)
- throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", numParts, maxParts));
- }
-
@Override
public void onPart(String name, String fileName, HttpFields headers)
{
@@ -536,7 +535,7 @@ public class MultiPartFormData extends CompletableFuture getParts()
@@ -629,25 +628,4 @@ public class MultiPartFormData extends CompletableFuture charSetParts = allParts.get("_charset_");
if (charSetParts != null)
{
- defaultCharset = Promise.Completable.with(p -> Content.Source.asString(charSetParts.get(0).getNewContent(), StandardCharsets.US_ASCII, p))
+ defaultCharset = Promise.Completable.with(p -> Content.Source.asString(charSetParts.get(0).newContentSource(), StandardCharsets.US_ASCII, p))
.get();
}
@@ -255,8 +255,8 @@ public class MultiPartCaptureTest
assertThat("Part[" + expected.name + "]", parts, is(notNullValue()));
MultiPart.Part part = parts.get(0);
String charset = getCharsetFromContentType(part.getHeaders().get(HttpHeader.CONTENT_TYPE), defaultCharset);
- assertTrue(part.getNewContent().rewind());
- String partContent = Content.Source.asString(part.getNewContent(), Charset.forName(charset));
+ assertTrue(part.newContentSource().rewind());
+ String partContent = Content.Source.asString(part.newContentSource(), Charset.forName(charset));
assertThat("Part[" + expected.name + "].contents", partContent, containsString(expected.value));
}
@@ -276,8 +276,8 @@ public class MultiPartCaptureTest
assertThat("Part[" + expected.name + "]", parts, is(notNullValue()));
MultiPart.Part part = parts.get(0);
MessageDigest digest = MessageDigest.getInstance("SHA1");
- assertTrue(part.getNewContent().rewind());
- try (InputStream partInputStream = Content.Source.asInputStream(part.getNewContent());
+ assertTrue(part.newContentSource().rewind());
+ try (InputStream partInputStream = Content.Source.asInputStream(part.newContentSource());
DigestOutputStream digester = new DigestOutputStream(OutputStream.nullOutputStream(), digest))
{
IO.copy(partInputStream, digester);
diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormDataTest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormDataTest.java
index 80c2ef614b7..6eeff622a34 100644
--- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormDataTest.java
+++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartFormDataTest.java
@@ -189,25 +189,25 @@ public class MultiPartFormDataTest
MultiPart.Part fileName = parts.getFirst("fileName");
assertThat(fileName, notNullValue());
- Content.Source partContent = fileName.getNewContent();
+ Content.Source partContent = fileName.newContentSource();
assertThat(partContent.getLength(), is(3L));
assertThat(Content.Source.asString(partContent), is("abc"));
MultiPart.Part desc = parts.getFirst("desc");
assertThat(desc, notNullValue());
- partContent = desc.getNewContent();
+ partContent = desc.newContentSource();
assertThat(partContent.getLength(), is(3L));
assertThat(Content.Source.asString(partContent), is("123"));
MultiPart.Part title = parts.getFirst("title");
assertThat(title, notNullValue());
- partContent = title.getNewContent();
+ partContent = title.newContentSource();
assertThat(partContent.getLength(), is(3L));
assertThat(Content.Source.asString(partContent), is("ttt"));
MultiPart.Part datafile = parts.getFirst("datafile5239138112980980385.txt");
assertThat(datafile, notNullValue());
- partContent = datafile.getNewContent();
+ partContent = datafile.newContentSource();
assertThat(partContent.getLength(), is(3L));
assertThat(Content.Source.asString(partContent), is("000"));
}
@@ -275,11 +275,11 @@ public class MultiPartFormDataTest
assertThat(parts.size(), is(2));
MultiPart.Part part1 = parts.getFirst("field1");
assertThat(part1, notNullValue());
- Content.Source partContent = part1.getNewContent();
+ Content.Source partContent = part1.newContentSource();
assertThat(Content.Source.asString(partContent), is("Joe Blow"));
MultiPart.Part part2 = parts.getFirst("stuff");
assertThat(part2, notNullValue());
- partContent = part2.getNewContent();
+ partContent = part2.newContentSource();
assertThat(Content.Source.asString(partContent), is("aaaabbbbb"));
}
@@ -312,7 +312,7 @@ public class MultiPartFormDataTest
assertThat(parts.size(), is(1));
MultiPart.Part part2 = parts.getFirst("stuff");
assertThat(part2, notNullValue());
- Content.Source partContent = part2.getNewContent();
+ Content.Source partContent = part2.newContentSource();
assertThat(Content.Source.asString(partContent), is("aaaabbbbb"));
}
@@ -340,7 +340,7 @@ public class MultiPartFormDataTest
assertThat(part, instanceOf(MultiPart.PathPart.class));
MultiPart.PathPart pathPart = (MultiPart.PathPart)part;
assertTrue(Files.exists(pathPart.getPath()));
- assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Content.Source.asString(part.getNewContent()));
+ assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Content.Source.asString(part.newContentSource()));
}
@Test
@@ -422,13 +422,13 @@ public class MultiPartFormDataTest
MultiPart.Part part1 = parts.get(0);
assertThat(part1, instanceOf(MultiPart.ChunksPart.class));
- assertEquals(chunk, Content.Source.asString(part1.getNewContent()));
+ assertEquals(chunk, Content.Source.asString(part1.newContentSource()));
MultiPart.Part part2 = parts.get(1);
assertThat(part2, instanceOf(MultiPart.PathPart.class));
MultiPart.PathPart pathPart2 = (MultiPart.PathPart)part2;
assertTrue(Files.exists(pathPart2.getPath()));
- assertEquals(chunk.repeat(4), Content.Source.asString(part2.getNewContent()));
+ assertEquals(chunk.repeat(4), Content.Source.asString(part2.newContentSource()));
}
@Test
diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartTest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartTest.java
index 18b1fd45ad1..5560a495e8c 100644
--- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartTest.java
+++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MultiPartTest.java
@@ -361,11 +361,11 @@ public class MultiPartTest
MultiPart.Part part1 = listener.parts.get(0);
assertEquals("value", part1.getHeaders().get("name"));
- assertEquals("Hello", Content.Source.asString(part1.getNewContent()));
+ assertEquals("Hello", Content.Source.asString(part1.newContentSource()));
MultiPart.Part part2 = listener.parts.get(1);
assertEquals("9001", part2.getHeaders().get("powerLevel"));
- assertEquals("secondary\r\ncontent", Content.Source.asString(part2.getNewContent()));
+ assertEquals("secondary\r\ncontent", Content.Source.asString(part2.newContentSource()));
assertEquals(0, data.remaining());
}
@@ -397,11 +397,11 @@ public class MultiPartTest
MultiPart.Part part1 = listener.parts.get(0);
assertEquals("value", part1.getHeaders().get("name"));
- assertEquals("Hello", Content.Source.asString(part1.getNewContent()));
+ assertEquals("Hello", Content.Source.asString(part1.newContentSource()));
MultiPart.Part part2 = listener.parts.get(1);
assertEquals("9001", part2.getHeaders().get("powerLevel"));
- assertEquals("secondary\ncontent", Content.Source.asString(part2.getNewContent()));
+ assertEquals("secondary\ncontent", Content.Source.asString(part2.newContentSource()));
assertEquals(0, data.remaining());
}
@@ -457,7 +457,7 @@ public class MultiPartTest
assertEquals(1, listener.parts.size());
MultiPart.Part part = listener.parts.get(0);
assertEquals("value", part.getHeaders().get("name"));
- assertEquals("", Content.Source.asString(part.getNewContent()));
+ assertEquals("", Content.Source.asString(part.newContentSource()));
}
@Test
@@ -477,7 +477,7 @@ public class MultiPartTest
assertEquals(1, listener.parts.size());
MultiPart.Part part = listener.parts.get(0);
assertEquals("value", part.getHeaders().get("name"));
- assertEquals("", Content.Source.asString(part.getNewContent()));
+ assertEquals("", Content.Source.asString(part.newContentSource()));
}
@Test
@@ -508,7 +508,7 @@ public class MultiPartTest
assertEquals(1, listener.parts.size());
MultiPart.Part part = listener.parts.get(0);
assertEquals("value", part.getHeaders().get("name"));
- assertThat(Content.Source.asString(part.getNewContent()), is("""
+ assertThat(Content.Source.asString(part.newContentSource()), is("""
Hello\r
this is not a --BOUNDARY\r
that's a boundary"""));
@@ -532,7 +532,7 @@ public class MultiPartTest
assertThat(epilogueBuffer.remaining(), is(0));
assertEquals(1, listener.parts.size());
MultiPart.Part part = listener.parts.get(0);
- assertThat(Content.Source.asByteBuffer(part.getNewContent()), is(ByteBuffer.wrap(random)));
+ assertThat(Content.Source.asByteBuffer(part.newContentSource()), is(ByteBuffer.wrap(random)));
}
@Test
@@ -556,7 +556,7 @@ public class MultiPartTest
assertEquals(1, listener.parts.size());
MultiPart.Part part = listener.parts.get(0);
assertEquals("value", part.getHeaders().get("name"));
- assertEquals("Hello", Content.Source.asString(part.getNewContent()));
+ assertEquals("Hello", Content.Source.asString(part.newContentSource()));
}
@Test
diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
index e862905048a..5680b82e4a7 100644
--- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
+++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/DelayedHandler.java
@@ -269,13 +269,13 @@ public class DelayedHandler extends Handler.Wrapper
super(handler, wrapped, response, callback);
String boundary = MultiPart.extractBoundary(contentType);
_formData = boundary == null ? null : new MultiPartFormData(boundary);
- getRequest().setAttribute(MultiPartFormData.class.getName(), _formData);
}
private void process(MultiPartFormData.Parts parts, Throwable x)
{
if (x == null)
{
+ getRequest().setAttribute(MultiPartFormData.Parts.class.getName(), parts);
super.process();
}
else
diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpChannelState.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpChannelState.java
index ca5a944153d..17384c26355 100644
--- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpChannelState.java
+++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpChannelState.java
@@ -34,7 +34,7 @@ import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
-import org.eclipse.jetty.http.MultiPartFormData;
+import org.eclipse.jetty.http.MultiPartFormData.Parts;
import org.eclipse.jetty.http.PreEncodedHttpField;
import org.eclipse.jetty.http.Trailers;
import org.eclipse.jetty.http.UriCompliance;
@@ -649,9 +649,9 @@ public class HttpChannelState implements HttpChannel, Components
}
// Clean up any multipart tmp files and release any associated resources.
- MultiPartFormData multiParts = (MultiPartFormData)_request.getAttribute(MultiPartFormData.class.getName());
- if (multiParts != null)
- multiParts.close();
+ Parts parts = (Parts)_request.getAttribute(Parts.class.getName());
+ if (parts != null)
+ parts.close();
}
finally
{
diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/MultiPartByteRangesTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/MultiPartByteRangesTest.java
index f955f5ea909..204c552381b 100644
--- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/MultiPartByteRangesTest.java
+++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/MultiPartByteRangesTest.java
@@ -119,11 +119,11 @@ public class MultiPartByteRangesTest
assertEquals(3, parts.size());
MultiPart.Part part1 = parts.get(0);
- assertEquals("12", Content.Source.asString(part1.getNewContent()));
+ assertEquals("12", Content.Source.asString(part1.newContentSource()));
MultiPart.Part part2 = parts.get(1);
- assertEquals("456", Content.Source.asString(part2.getNewContent()));
+ assertEquals("456", Content.Source.asString(part2.newContentSource()));
MultiPart.Part part3 = parts.get(2);
- assertEquals("CDEF", Content.Source.asString(part3.getNewContent()));
+ assertEquals("CDEF", Content.Source.asString(part3.newContentSource()));
}
}
}
diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/MultiPartFormDataHandlerTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/MultiPartFormDataHandlerTest.java
index a365abed169..cf8cba7064b 100644
--- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/MultiPartFormDataHandlerTest.java
+++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/MultiPartFormDataHandlerTest.java
@@ -80,7 +80,7 @@ public class MultiPartFormDataHandlerTest
.whenComplete((parts, failure) ->
{
if (parts != null)
- Content.copy(parts.get(0).getNewContent(), response, callback);
+ Content.copy(parts.get(0).newContentSource(), response, callback);
else
Response.writeError(request, response, callback, failure);
});
@@ -126,10 +126,10 @@ public class MultiPartFormDataHandlerTest
public boolean process(Request request, Response response, Callback callback) throws Exception
{
processLatch.countDown();
- MultiPartFormData formData = (MultiPartFormData)request.getAttribute(MultiPartFormData.class.getName());
- assertNotNull(formData);
- MultiPart.Part part = formData.get().get(0);
- Content.copy(part.getNewContent(), response, callback);
+ MultiPartFormData.Parts parts = (MultiPartFormData.Parts)request.getAttribute(MultiPartFormData.Parts.class.getName());
+ assertNotNull(parts);
+ MultiPart.Part part = parts.get(0);
+ Content.copy(part.newContentSource(), response, callback);
return true;
}
});
@@ -195,8 +195,8 @@ public class MultiPartFormDataHandlerTest
{
if (parts != null)
{
- response.getHeaders().put(HttpHeader.CONTENT_TYPE, "multipart/form-data; boundary=\"%s\"".formatted(parts.getBoundary()));
- MultiPartFormData.ContentSource source = new MultiPartFormData.ContentSource(parts.getBoundary());
+ response.getHeaders().put(HttpHeader.CONTENT_TYPE, "multipart/form-data; boundary=\"%s\"".formatted(parts.getMultiPartFormData().getBoundary()));
+ MultiPartFormData.ContentSource source = new MultiPartFormData.ContentSource(parts.getMultiPartFormData().getBoundary());
source.setPartHeadersMaxLength(1024);
parts.forEach(source::addPart);
source.close();
@@ -321,7 +321,7 @@ public class MultiPartFormDataHandlerTest
HttpFields headers2 = part2.getHeaders();
assertEquals(2, headers2.size());
assertEquals("application/octet-stream", headers2.get(HttpHeader.CONTENT_TYPE));
- assertEquals(32, part2.getNewContent().getLength());
+ assertEquals(32, part2.newContentSource().getLength());
}
}
}
diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerByteRangesTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerByteRangesTest.java
index 8247eff178a..0495089f89f 100644
--- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerByteRangesTest.java
+++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ResourceHandlerByteRangesTest.java
@@ -181,10 +181,10 @@ public class ResourceHandlerByteRangesTest
assertEquals(2, parts.size());
MultiPart.Part part1 = parts.get(0);
assertEquals("text/plain", part1.getHeaders().get(HttpHeader.CONTENT_TYPE));
- assertEquals("234", Content.Source.asString(part1.getNewContent()));
+ assertEquals("234", Content.Source.asString(part1.newContentSource()));
MultiPart.Part part2 = parts.get(1);
assertEquals("text/plain", part2.getHeaders().get(HttpHeader.CONTENT_TYPE));
- assertEquals("xyz", Content.Source.asString(part2.getNewContent()));
+ assertEquals("xyz", Content.Source.asString(part2.newContentSource()));
}
}
}
diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletMultiPartFormData.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletMultiPartFormData.java
index 28ad413be6f..22680abb252 100644
--- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletMultiPartFormData.java
+++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/ServletMultiPartFormData.java
@@ -77,9 +77,9 @@ public class ServletMultiPartFormData
try
{
// Look for a previously read and parsed MultiPartFormData from the DelayedHandler.
- MultiPartFormData formData = (MultiPartFormData)request.getAttribute(MultiPartFormData.class.getName());
- if (formData != null)
- return new Parts(formData);
+ MultiPartFormData.Parts parts = (MultiPartFormData.Parts)request.getAttribute(MultiPartFormData.Parts.class.getName());
+ if (parts != null)
+ return new Parts(parts);
// TODO set the files directory
return new ServletMultiPartFormData().parse(request, maxParts);
@@ -102,7 +102,6 @@ public class ServletMultiPartFormData
// Store MultiPartFormData as attribute on request so it is released by the HttpChannel.
MultiPartFormData formData = new MultiPartFormData(boundary);
- request.setAttribute(MultiPartFormData.class.getName(), formData);
formData.setMaxParts(maxParts);
File tmpDirFile = (File)request.getServletContext().getAttribute(ServletContext.TEMPDIR);
@@ -123,7 +122,7 @@ public class ServletMultiPartFormData
Connection connection = connectionMetaData.getConnection();
int bufferSize = connection instanceof AbstractConnection c ? c.getInputBufferSize() : 2048;
InputStream input = request.getInputStream();
- while (true)
+ while (!formData.isDone())
{
ByteBuffer buffer = byteBufferPool.newByteBuffer(bufferSize, false);
boolean readEof = false;
@@ -145,7 +144,9 @@ public class ServletMultiPartFormData
}
}
- return new Parts(formData);
+ Parts parts = new Parts(formData.join());
+ request.setAttribute(Parts.class.getName(), parts);
+ return parts;
}
/**
@@ -155,9 +156,9 @@ public class ServletMultiPartFormData
{
private final List parts = new ArrayList<>();
- public Parts(MultiPartFormData formData)
+ public Parts(MultiPartFormData.Parts parts)
{
- formData.join().forEach(part -> parts.add(new ServletPart(formData, part)));
+ parts.forEach(part -> this.parts.add(new ServletPart(parts.getMultiPartFormData(), part)));
}
public Part getPart(String name)
@@ -190,7 +191,7 @@ public class ServletMultiPartFormData
@Override
public InputStream getInputStream() throws IOException
{
- return Content.Source.asInputStream(_part.getNewContent());
+ return Content.Source.asInputStream(_part.newContentSource());
}
@Override
diff --git a/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/MultiPartServletTest.java b/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/MultiPartServletTest.java
index 69230d1827a..1850e9dfd75 100644
--- a/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/MultiPartServletTest.java
+++ b/jetty-ee10/jetty-ee10-servlet/src/test/java/org/eclipse/jetty/ee10/servlet/MultiPartServletTest.java
@@ -129,10 +129,6 @@ public class MultiPartServletTest
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
req.getParameterMap();
- req.getParts();
- resp.setStatus(200);
- resp.getWriter().print("success");
- resp.getWriter().close();
}
}, new MultipartConfigElement(tmpDirString));
@@ -174,10 +170,6 @@ public class MultiPartServletTest
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
req.getParameterMap();
- req.getParts();
- resp.setStatus(200);
- resp.getWriter().print("success");
- resp.getWriter().close();
}
}, new MultipartConfigElement(tmpDirString));
@@ -216,10 +208,6 @@ public class MultiPartServletTest
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
req.getParameterMap();
- req.getParts();
- resp.setStatus(200);
- resp.getWriter().print("success");
- resp.getWriter().close();
}
}, new MultipartConfigElement(tmpDirString, -1, 1024, 1024 * 1024 * 8));