improvements to multipart
Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
1e20abc902
commit
5bcfeaac09
|
@ -70,7 +70,7 @@ public class MultiPartRequestContent extends MultiPartFormData.ContentSource imp
|
||||||
if (headers.contains(HttpHeader.CONTENT_TYPE))
|
if (headers.contains(HttpHeader.CONTENT_TYPE))
|
||||||
return headers;
|
return headers;
|
||||||
|
|
||||||
Content.Source partContent = part.getNewContent();
|
Content.Source partContent = part.newContentSource();
|
||||||
if (partContent instanceof Request.Content requestContent)
|
if (partContent instanceof Request.Content requestContent)
|
||||||
{
|
{
|
||||||
String contentType = requestContent.getContentType();
|
String contentType = requestContent.getContentType();
|
||||||
|
|
|
@ -129,7 +129,7 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
|
||||||
int equal = contentType.lastIndexOf('=');
|
int equal = contentType.lastIndexOf('=');
|
||||||
Charset charset = Charset.forName(contentType.substring(equal + 1));
|
Charset charset = Charset.forName(contentType.substring(equal + 1));
|
||||||
assertEquals(encoding, charset);
|
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();
|
MultiPart.Part part = parts.iterator().next();
|
||||||
assertEquals(name, part.getName());
|
assertEquals(name, part.getName());
|
||||||
assertEquals("text/plain", part.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
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(name, part.getName());
|
||||||
assertEquals(contentType, part.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
assertEquals(contentType, part.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
||||||
assertEquals(fileName, part.getFileName());
|
assertEquals(fileName, part.getFileName());
|
||||||
assertEquals(data.length, part.getNewContent().getLength());
|
assertEquals(data.length, part.newContentSource().getLength());
|
||||||
assertArrayEquals(data, Content.Source.asByteBuffer(part.getNewContent()).array());
|
assertArrayEquals(data, Content.Source.asByteBuffer(part.newContentSource()).array());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -271,8 +271,8 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
|
||||||
assertEquals(name, part.getName());
|
assertEquals(name, part.getName());
|
||||||
assertEquals(contentType, part.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
assertEquals(contentType, part.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
||||||
assertEquals(tmpPath.getFileName().toString(), part.getFileName());
|
assertEquals(tmpPath.getFileName().toString(), part.getFileName());
|
||||||
assertEquals(Files.size(tmpPath), part.getNewContent().getLength());
|
assertEquals(Files.size(tmpPath), part.newContentSource().getLength());
|
||||||
assertEquals(data, Content.Source.asString(part.getNewContent(), encoding));
|
assertEquals(data, Content.Source.asString(part.newContentSource(), encoding));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -323,14 +323,14 @@ public class MultiPartRequestContentTest extends AbstractHttpClientServerTest
|
||||||
|
|
||||||
assertEquals(field, fieldPart.getName());
|
assertEquals(field, fieldPart.getName());
|
||||||
assertEquals(contentType, fieldPart.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
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(headerValue, fieldPart.getHeaders().get(headerName));
|
||||||
|
|
||||||
assertEquals(fileField, filePart.getName());
|
assertEquals(fileField, filePart.getName());
|
||||||
assertEquals("application/octet-stream", filePart.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
assertEquals("application/octet-stream", filePart.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
||||||
assertEquals(tmpPath.getFileName().toString(), filePart.getFileName());
|
assertEquals(tmpPath.getFileName().toString(), filePart.getFileName());
|
||||||
assertEquals(Files.size(tmpPath), filePart.getNewContent().getLength());
|
assertEquals(Files.size(tmpPath), filePart.newContentSource().getLength());
|
||||||
assertArrayEquals(data, Content.Source.asByteBuffer(filePart.getNewContent()).array());
|
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 fieldPart = parts.get(0);
|
||||||
MultiPart.Part filePart = parts.get(1);
|
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("file", filePart.getName());
|
||||||
assertEquals("application/octet-stream", filePart.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
assertEquals("application/octet-stream", filePart.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
||||||
assertEquals("fileName", filePart.getFileName());
|
assertEquals("fileName", filePart.getFileName());
|
||||||
assertArrayEquals(fileData, Content.Source.asByteBuffer(filePart.getNewContent()).array());
|
assertArrayEquals(fileData, Content.Source.asByteBuffer(filePart.newContentSource()).array());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ public class MultiPart
|
||||||
public Content.Source getContentSource()
|
public Content.Source getContentSource()
|
||||||
{
|
{
|
||||||
if (content == null)
|
if (content == null)
|
||||||
content = getNewContent();
|
content = newContentSource();
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,11 +192,11 @@ public class MultiPart
|
||||||
*
|
*
|
||||||
* @return the content of this part as a new {@link Content.Source}
|
* @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()
|
public long getLength()
|
||||||
{
|
{
|
||||||
return getNewContent().getLength();
|
return newContentSource().getLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,7 +221,7 @@ public class MultiPart
|
||||||
Charset charset = defaultCharset != null ? defaultCharset : UTF_8;
|
Charset charset = defaultCharset != null ? defaultCharset : UTF_8;
|
||||||
if (charsetName != null)
|
if (charsetName != null)
|
||||||
charset = Charset.forName(charsetName);
|
charset = Charset.forName(charsetName);
|
||||||
return Content.Source.asString(getNewContent(), charset);
|
return Content.Source.asString(newContentSource(), charset);
|
||||||
}
|
}
|
||||||
catch (IOException x)
|
catch (IOException x)
|
||||||
{
|
{
|
||||||
|
@ -237,11 +237,6 @@ public class MultiPart
|
||||||
return fields;
|
return fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Path getPath()
|
|
||||||
{
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Writes the content of this part to the given path.</p>
|
* <p>Writes the content of this part to the given path.</p>
|
||||||
*
|
*
|
||||||
|
@ -254,7 +249,7 @@ public class MultiPart
|
||||||
{
|
{
|
||||||
try (OutputStream out = Files.newOutputStream(path))
|
try (OutputStream out = Files.newOutputStream(path))
|
||||||
{
|
{
|
||||||
IO.copy(Content.Source.asInputStream(getNewContent()), out);
|
IO.copy(Content.Source.asInputStream(newContentSource()), out);
|
||||||
}
|
}
|
||||||
this.path = path;
|
this.path = path;
|
||||||
}
|
}
|
||||||
|
@ -306,7 +301,7 @@ public class MultiPart
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content.Source getNewContent()
|
public Content.Source newContentSource()
|
||||||
{
|
{
|
||||||
return new ByteBufferContentSource(content);
|
return new ByteBufferContentSource(content);
|
||||||
}
|
}
|
||||||
|
@ -346,7 +341,7 @@ public class MultiPart
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content.Source getNewContent()
|
public Content.Source newContentSource()
|
||||||
{
|
{
|
||||||
return new ChunksContentSource(content.stream().map(Content.Chunk::slice).toList());
|
return new ChunksContentSource(content.stream().map(Content.Chunk::slice).toList());
|
||||||
}
|
}
|
||||||
|
@ -395,8 +390,13 @@ public class MultiPart
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Path getPath()
|
||||||
|
{
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content.Source getNewContent()
|
public Content.Source newContentSource()
|
||||||
{
|
{
|
||||||
return new PathContentSource(path);
|
return new PathContentSource(path);
|
||||||
}
|
}
|
||||||
|
@ -409,7 +409,7 @@ public class MultiPart
|
||||||
hashCode(),
|
hashCode(),
|
||||||
getName(),
|
getName(),
|
||||||
getFileName(),
|
getFileName(),
|
||||||
getPath()
|
path
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,7 +428,7 @@ public class MultiPart
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content.Source getNewContent()
|
public Content.Source newContentSource()
|
||||||
{
|
{
|
||||||
Content.Source c = content;
|
Content.Source c = content;
|
||||||
content = null;
|
content = null;
|
||||||
|
@ -630,7 +630,7 @@ public class MultiPart
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
part = parts.poll();
|
part = parts.poll();
|
||||||
partContent = part.getNewContent();
|
partContent = part.newContentSource();
|
||||||
state = State.HEADERS;
|
state = State.HEADERS;
|
||||||
yield Content.Chunk.from(firstBoundary.slice(), false);
|
yield Content.Chunk.from(firstBoundary.slice(), false);
|
||||||
}
|
}
|
||||||
|
@ -657,7 +657,7 @@ public class MultiPart
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
part = parts.poll();
|
part = parts.poll();
|
||||||
partContent = part.getNewContent();
|
partContent = part.newContentSource();
|
||||||
state = State.HEADERS;
|
state = State.HEADERS;
|
||||||
yield Content.Chunk.from(middleBoundary.slice(), false);
|
yield Content.Chunk.from(middleBoundary.slice(), false);
|
||||||
}
|
}
|
||||||
|
@ -743,7 +743,7 @@ public class MultiPart
|
||||||
|
|
||||||
if (state == State.CONTENT)
|
if (state == State.CONTENT)
|
||||||
{
|
{
|
||||||
partContent.demand(() ->
|
part.getContentSource().demand(() ->
|
||||||
{
|
{
|
||||||
try (AutoLock ignoredAgain = lock.lock())
|
try (AutoLock ignoredAgain = lock.lock())
|
||||||
{
|
{
|
||||||
|
@ -850,6 +850,8 @@ public class MultiPart
|
||||||
private int trailingWhiteSpaces;
|
private int trailingWhiteSpaces;
|
||||||
private String fieldName;
|
private String fieldName;
|
||||||
private String fieldValue;
|
private String fieldValue;
|
||||||
|
private long maxParts;
|
||||||
|
private int numParts = 0;
|
||||||
|
|
||||||
public Parser(String boundary, Listener listener)
|
public Parser(String boundary, Listener listener)
|
||||||
{
|
{
|
||||||
|
@ -881,6 +883,22 @@ public class MultiPart
|
||||||
this.partHeadersMaxLength = partHeadersMaxLength;
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Resets this parser to make it ready to parse again a multipart/form-data content.</p>
|
* <p>Resets this parser to make it ready to parse again a multipart/form-data content.</p>
|
||||||
*/
|
*/
|
||||||
|
@ -939,6 +957,10 @@ public class MultiPart
|
||||||
}
|
}
|
||||||
else if (type == HttpTokens.Type.LF)
|
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();
|
notifyPartBegin();
|
||||||
state = State.HEADER_START;
|
state = State.HEADER_START;
|
||||||
trailingWhiteSpaces = 0;
|
trailingWhiteSpaces = 0;
|
||||||
|
@ -1343,37 +1365,93 @@ public class MultiPart
|
||||||
|
|
||||||
private void notifyPartBegin()
|
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)
|
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()
|
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)
|
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()
|
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()
|
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)
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -265,7 +265,7 @@ public class MultiPartByteRanges extends CompletableFuture<MultiPartByteRanges.P
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Content.Source getNewContent()
|
public Content.Source newContentSource()
|
||||||
{
|
{
|
||||||
return new PathContentSource(path, byteRange);
|
return new PathContentSource(path, byteRange);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,7 +68,7 @@ import static java.nio.charset.StandardCharsets.US_ASCII;
|
||||||
*
|
*
|
||||||
* @see Parts
|
* @see Parts
|
||||||
*/
|
*/
|
||||||
public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts> implements Closeable
|
public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts>
|
||||||
{
|
{
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(MultiPartFormData.class);
|
private static final Logger LOG = LoggerFactory.getLogger(MultiPartFormData.class);
|
||||||
|
|
||||||
|
@ -80,8 +80,6 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
private long maxMemoryFileSize;
|
private long maxMemoryFileSize;
|
||||||
private long maxLength = -1;
|
private long maxLength = -1;
|
||||||
private long length;
|
private long length;
|
||||||
private int numParts = 0;
|
|
||||||
private long maxParts = 1000;
|
|
||||||
|
|
||||||
public MultiPartFormData(String boundary)
|
public MultiPartFormData(String boundary)
|
||||||
{
|
{
|
||||||
|
@ -281,7 +279,7 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
*/
|
*/
|
||||||
public long getMaxParts()
|
public long getMaxParts()
|
||||||
{
|
{
|
||||||
return maxLength;
|
return parser.getMaxParts();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -289,7 +287,7 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
*/
|
*/
|
||||||
public void setMaxParts(long maxParts)
|
public void setMaxParts(long maxParts)
|
||||||
{
|
{
|
||||||
this.maxParts = maxParts;
|
parser.setMaxParts(maxParts);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -309,23 +307,18 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
* <p>An ordered list of {@link MultiPart.Part}s that can
|
* <p>An ordered list of {@link MultiPart.Part}s that can
|
||||||
* be accessed by index or by name, or iterated over.</p>
|
* be accessed by index or by name, or iterated over.</p>
|
||||||
*/
|
*/
|
||||||
public static class Parts implements Iterable<MultiPart.Part>
|
public class Parts implements Iterable<MultiPart.Part>
|
||||||
{
|
{
|
||||||
private final String boundary;
|
|
||||||
private final List<MultiPart.Part> parts;
|
private final List<MultiPart.Part> parts;
|
||||||
|
|
||||||
private Parts(String boundary, List<MultiPart.Part> parts)
|
private Parts(List<MultiPart.Part> parts)
|
||||||
{
|
{
|
||||||
this.boundary = boundary;
|
|
||||||
this.parts = parts;
|
this.parts = parts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
public MultiPartFormData getMultiPartFormData()
|
||||||
* @return the boundary string
|
|
||||||
*/
|
|
||||||
public String getBoundary()
|
|
||||||
{
|
{
|
||||||
return boundary;
|
return MultiPartFormData.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -383,6 +376,21 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
{
|
{
|
||||||
return parts.iterator();
|
return parts.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
for (MultiPart.Part p : parts)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
p.close();
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
LOG.warn("Errors deleting multipart tmp files", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -502,15 +510,6 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPartBegin()
|
|
||||||
{
|
|
||||||
// TODO: Move to parser.
|
|
||||||
numParts++;
|
|
||||||
if (numParts >= maxParts)
|
|
||||||
throw new IllegalStateException(String.format("Form with too many keys [%d > %d]", numParts, maxParts));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPart(String name, String fileName, HttpFields headers)
|
public void onPart(String name, String fileName, HttpFields headers)
|
||||||
{
|
{
|
||||||
|
@ -536,7 +535,7 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
public void onComplete()
|
public void onComplete()
|
||||||
{
|
{
|
||||||
super.onComplete();
|
super.onComplete();
|
||||||
complete(new Parts(getBoundary(), getParts()));
|
complete(new Parts(getParts()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MultiPart.Part> getParts()
|
private List<MultiPart.Part> getParts()
|
||||||
|
@ -629,25 +628,4 @@ public class MultiPartFormData extends CompletableFuture<MultiPartFormData.Parts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close()
|
|
||||||
{
|
|
||||||
// TODO: Can we do this async?
|
|
||||||
MultiPartFormData.Parts parts = getNow(null);
|
|
||||||
if (parts != null)
|
|
||||||
{
|
|
||||||
for (MultiPart.Part p : parts)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
p.close();
|
|
||||||
}
|
|
||||||
catch (Throwable e)
|
|
||||||
{
|
|
||||||
LOG.warn("Errors deleting multipart tmp files", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,7 @@ public class MultiPartCaptureTest
|
||||||
List<MultiPart.Part> charSetParts = allParts.get("_charset_");
|
List<MultiPart.Part> charSetParts = allParts.get("_charset_");
|
||||||
if (charSetParts != null)
|
if (charSetParts != null)
|
||||||
{
|
{
|
||||||
defaultCharset = Promise.Completable.<String>with(p -> Content.Source.asString(charSetParts.get(0).getNewContent(), StandardCharsets.US_ASCII, p))
|
defaultCharset = Promise.Completable.<String>with(p -> Content.Source.asString(charSetParts.get(0).newContentSource(), StandardCharsets.US_ASCII, p))
|
||||||
.get();
|
.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,8 +255,8 @@ public class MultiPartCaptureTest
|
||||||
assertThat("Part[" + expected.name + "]", parts, is(notNullValue()));
|
assertThat("Part[" + expected.name + "]", parts, is(notNullValue()));
|
||||||
MultiPart.Part part = parts.get(0);
|
MultiPart.Part part = parts.get(0);
|
||||||
String charset = getCharsetFromContentType(part.getHeaders().get(HttpHeader.CONTENT_TYPE), defaultCharset);
|
String charset = getCharsetFromContentType(part.getHeaders().get(HttpHeader.CONTENT_TYPE), defaultCharset);
|
||||||
assertTrue(part.getNewContent().rewind());
|
assertTrue(part.newContentSource().rewind());
|
||||||
String partContent = Content.Source.asString(part.getNewContent(), Charset.forName(charset));
|
String partContent = Content.Source.asString(part.newContentSource(), Charset.forName(charset));
|
||||||
assertThat("Part[" + expected.name + "].contents", partContent, containsString(expected.value));
|
assertThat("Part[" + expected.name + "].contents", partContent, containsString(expected.value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -276,8 +276,8 @@ public class MultiPartCaptureTest
|
||||||
assertThat("Part[" + expected.name + "]", parts, is(notNullValue()));
|
assertThat("Part[" + expected.name + "]", parts, is(notNullValue()));
|
||||||
MultiPart.Part part = parts.get(0);
|
MultiPart.Part part = parts.get(0);
|
||||||
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
MessageDigest digest = MessageDigest.getInstance("SHA1");
|
||||||
assertTrue(part.getNewContent().rewind());
|
assertTrue(part.newContentSource().rewind());
|
||||||
try (InputStream partInputStream = Content.Source.asInputStream(part.getNewContent());
|
try (InputStream partInputStream = Content.Source.asInputStream(part.newContentSource());
|
||||||
DigestOutputStream digester = new DigestOutputStream(OutputStream.nullOutputStream(), digest))
|
DigestOutputStream digester = new DigestOutputStream(OutputStream.nullOutputStream(), digest))
|
||||||
{
|
{
|
||||||
IO.copy(partInputStream, digester);
|
IO.copy(partInputStream, digester);
|
||||||
|
|
|
@ -189,25 +189,25 @@ public class MultiPartFormDataTest
|
||||||
|
|
||||||
MultiPart.Part fileName = parts.getFirst("fileName");
|
MultiPart.Part fileName = parts.getFirst("fileName");
|
||||||
assertThat(fileName, notNullValue());
|
assertThat(fileName, notNullValue());
|
||||||
Content.Source partContent = fileName.getNewContent();
|
Content.Source partContent = fileName.newContentSource();
|
||||||
assertThat(partContent.getLength(), is(3L));
|
assertThat(partContent.getLength(), is(3L));
|
||||||
assertThat(Content.Source.asString(partContent), is("abc"));
|
assertThat(Content.Source.asString(partContent), is("abc"));
|
||||||
|
|
||||||
MultiPart.Part desc = parts.getFirst("desc");
|
MultiPart.Part desc = parts.getFirst("desc");
|
||||||
assertThat(desc, notNullValue());
|
assertThat(desc, notNullValue());
|
||||||
partContent = desc.getNewContent();
|
partContent = desc.newContentSource();
|
||||||
assertThat(partContent.getLength(), is(3L));
|
assertThat(partContent.getLength(), is(3L));
|
||||||
assertThat(Content.Source.asString(partContent), is("123"));
|
assertThat(Content.Source.asString(partContent), is("123"));
|
||||||
|
|
||||||
MultiPart.Part title = parts.getFirst("title");
|
MultiPart.Part title = parts.getFirst("title");
|
||||||
assertThat(title, notNullValue());
|
assertThat(title, notNullValue());
|
||||||
partContent = title.getNewContent();
|
partContent = title.newContentSource();
|
||||||
assertThat(partContent.getLength(), is(3L));
|
assertThat(partContent.getLength(), is(3L));
|
||||||
assertThat(Content.Source.asString(partContent), is("ttt"));
|
assertThat(Content.Source.asString(partContent), is("ttt"));
|
||||||
|
|
||||||
MultiPart.Part datafile = parts.getFirst("datafile5239138112980980385.txt");
|
MultiPart.Part datafile = parts.getFirst("datafile5239138112980980385.txt");
|
||||||
assertThat(datafile, notNullValue());
|
assertThat(datafile, notNullValue());
|
||||||
partContent = datafile.getNewContent();
|
partContent = datafile.newContentSource();
|
||||||
assertThat(partContent.getLength(), is(3L));
|
assertThat(partContent.getLength(), is(3L));
|
||||||
assertThat(Content.Source.asString(partContent), is("000"));
|
assertThat(Content.Source.asString(partContent), is("000"));
|
||||||
}
|
}
|
||||||
|
@ -275,11 +275,11 @@ public class MultiPartFormDataTest
|
||||||
assertThat(parts.size(), is(2));
|
assertThat(parts.size(), is(2));
|
||||||
MultiPart.Part part1 = parts.getFirst("field1");
|
MultiPart.Part part1 = parts.getFirst("field1");
|
||||||
assertThat(part1, notNullValue());
|
assertThat(part1, notNullValue());
|
||||||
Content.Source partContent = part1.getNewContent();
|
Content.Source partContent = part1.newContentSource();
|
||||||
assertThat(Content.Source.asString(partContent), is("Joe Blow"));
|
assertThat(Content.Source.asString(partContent), is("Joe Blow"));
|
||||||
MultiPart.Part part2 = parts.getFirst("stuff");
|
MultiPart.Part part2 = parts.getFirst("stuff");
|
||||||
assertThat(part2, notNullValue());
|
assertThat(part2, notNullValue());
|
||||||
partContent = part2.getNewContent();
|
partContent = part2.newContentSource();
|
||||||
assertThat(Content.Source.asString(partContent), is("aaaabbbbb"));
|
assertThat(Content.Source.asString(partContent), is("aaaabbbbb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ public class MultiPartFormDataTest
|
||||||
assertThat(parts.size(), is(1));
|
assertThat(parts.size(), is(1));
|
||||||
MultiPart.Part part2 = parts.getFirst("stuff");
|
MultiPart.Part part2 = parts.getFirst("stuff");
|
||||||
assertThat(part2, notNullValue());
|
assertThat(part2, notNullValue());
|
||||||
Content.Source partContent = part2.getNewContent();
|
Content.Source partContent = part2.newContentSource();
|
||||||
assertThat(Content.Source.asString(partContent), is("aaaabbbbb"));
|
assertThat(Content.Source.asString(partContent), is("aaaabbbbb"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +340,7 @@ public class MultiPartFormDataTest
|
||||||
assertThat(part, instanceOf(MultiPart.PathPart.class));
|
assertThat(part, instanceOf(MultiPart.PathPart.class));
|
||||||
MultiPart.PathPart pathPart = (MultiPart.PathPart)part;
|
MultiPart.PathPart pathPart = (MultiPart.PathPart)part;
|
||||||
assertTrue(Files.exists(pathPart.getPath()));
|
assertTrue(Files.exists(pathPart.getPath()));
|
||||||
assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Content.Source.asString(part.getNewContent()));
|
assertEquals("ABCDEFGHIJKLMNOPQRSTUVWXYZ", Content.Source.asString(part.newContentSource()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -422,13 +422,13 @@ public class MultiPartFormDataTest
|
||||||
|
|
||||||
MultiPart.Part part1 = parts.get(0);
|
MultiPart.Part part1 = parts.get(0);
|
||||||
assertThat(part1, instanceOf(MultiPart.ChunksPart.class));
|
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);
|
MultiPart.Part part2 = parts.get(1);
|
||||||
assertThat(part2, instanceOf(MultiPart.PathPart.class));
|
assertThat(part2, instanceOf(MultiPart.PathPart.class));
|
||||||
MultiPart.PathPart pathPart2 = (MultiPart.PathPart)part2;
|
MultiPart.PathPart pathPart2 = (MultiPart.PathPart)part2;
|
||||||
assertTrue(Files.exists(pathPart2.getPath()));
|
assertTrue(Files.exists(pathPart2.getPath()));
|
||||||
assertEquals(chunk.repeat(4), Content.Source.asString(part2.getNewContent()));
|
assertEquals(chunk.repeat(4), Content.Source.asString(part2.newContentSource()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -361,11 +361,11 @@ public class MultiPartTest
|
||||||
|
|
||||||
MultiPart.Part part1 = listener.parts.get(0);
|
MultiPart.Part part1 = listener.parts.get(0);
|
||||||
assertEquals("value", part1.getHeaders().get("name"));
|
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);
|
MultiPart.Part part2 = listener.parts.get(1);
|
||||||
assertEquals("9001", part2.getHeaders().get("powerLevel"));
|
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());
|
assertEquals(0, data.remaining());
|
||||||
}
|
}
|
||||||
|
@ -397,11 +397,11 @@ public class MultiPartTest
|
||||||
|
|
||||||
MultiPart.Part part1 = listener.parts.get(0);
|
MultiPart.Part part1 = listener.parts.get(0);
|
||||||
assertEquals("value", part1.getHeaders().get("name"));
|
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);
|
MultiPart.Part part2 = listener.parts.get(1);
|
||||||
assertEquals("9001", part2.getHeaders().get("powerLevel"));
|
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());
|
assertEquals(0, data.remaining());
|
||||||
}
|
}
|
||||||
|
@ -457,7 +457,7 @@ public class MultiPartTest
|
||||||
assertEquals(1, listener.parts.size());
|
assertEquals(1, listener.parts.size());
|
||||||
MultiPart.Part part = listener.parts.get(0);
|
MultiPart.Part part = listener.parts.get(0);
|
||||||
assertEquals("value", part.getHeaders().get("name"));
|
assertEquals("value", part.getHeaders().get("name"));
|
||||||
assertEquals("", Content.Source.asString(part.getNewContent()));
|
assertEquals("", Content.Source.asString(part.newContentSource()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -477,7 +477,7 @@ public class MultiPartTest
|
||||||
assertEquals(1, listener.parts.size());
|
assertEquals(1, listener.parts.size());
|
||||||
MultiPart.Part part = listener.parts.get(0);
|
MultiPart.Part part = listener.parts.get(0);
|
||||||
assertEquals("value", part.getHeaders().get("name"));
|
assertEquals("value", part.getHeaders().get("name"));
|
||||||
assertEquals("", Content.Source.asString(part.getNewContent()));
|
assertEquals("", Content.Source.asString(part.newContentSource()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -508,7 +508,7 @@ public class MultiPartTest
|
||||||
assertEquals(1, listener.parts.size());
|
assertEquals(1, listener.parts.size());
|
||||||
MultiPart.Part part = listener.parts.get(0);
|
MultiPart.Part part = listener.parts.get(0);
|
||||||
assertEquals("value", part.getHeaders().get("name"));
|
assertEquals("value", part.getHeaders().get("name"));
|
||||||
assertThat(Content.Source.asString(part.getNewContent()), is("""
|
assertThat(Content.Source.asString(part.newContentSource()), is("""
|
||||||
Hello\r
|
Hello\r
|
||||||
this is not a --BOUNDARY\r
|
this is not a --BOUNDARY\r
|
||||||
that's a boundary"""));
|
that's a boundary"""));
|
||||||
|
@ -532,7 +532,7 @@ public class MultiPartTest
|
||||||
assertThat(epilogueBuffer.remaining(), is(0));
|
assertThat(epilogueBuffer.remaining(), is(0));
|
||||||
assertEquals(1, listener.parts.size());
|
assertEquals(1, listener.parts.size());
|
||||||
MultiPart.Part part = listener.parts.get(0);
|
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
|
@Test
|
||||||
|
@ -556,7 +556,7 @@ public class MultiPartTest
|
||||||
assertEquals(1, listener.parts.size());
|
assertEquals(1, listener.parts.size());
|
||||||
MultiPart.Part part = listener.parts.get(0);
|
MultiPart.Part part = listener.parts.get(0);
|
||||||
assertEquals("value", part.getHeaders().get("name"));
|
assertEquals("value", part.getHeaders().get("name"));
|
||||||
assertEquals("Hello", Content.Source.asString(part.getNewContent()));
|
assertEquals("Hello", Content.Source.asString(part.newContentSource()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -269,13 +269,13 @@ public class DelayedHandler extends Handler.Wrapper
|
||||||
super(handler, wrapped, response, callback);
|
super(handler, wrapped, response, callback);
|
||||||
String boundary = MultiPart.extractBoundary(contentType);
|
String boundary = MultiPart.extractBoundary(contentType);
|
||||||
_formData = boundary == null ? null : new MultiPartFormData(boundary);
|
_formData = boundary == null ? null : new MultiPartFormData(boundary);
|
||||||
getRequest().setAttribute(MultiPartFormData.class.getName(), _formData);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void process(MultiPartFormData.Parts parts, Throwable x)
|
private void process(MultiPartFormData.Parts parts, Throwable x)
|
||||||
{
|
{
|
||||||
if (x == null)
|
if (x == null)
|
||||||
{
|
{
|
||||||
|
getRequest().setAttribute(MultiPartFormData.Parts.class.getName(), parts);
|
||||||
super.process();
|
super.process();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -34,7 +34,7 @@ import org.eclipse.jetty.http.HttpStatus;
|
||||||
import org.eclipse.jetty.http.HttpURI;
|
import org.eclipse.jetty.http.HttpURI;
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
import org.eclipse.jetty.http.MetaData;
|
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.PreEncodedHttpField;
|
||||||
import org.eclipse.jetty.http.Trailers;
|
import org.eclipse.jetty.http.Trailers;
|
||||||
import org.eclipse.jetty.http.UriCompliance;
|
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.
|
// Clean up any multipart tmp files and release any associated resources.
|
||||||
MultiPartFormData multiParts = (MultiPartFormData)_request.getAttribute(MultiPartFormData.class.getName());
|
Parts parts = (Parts)_request.getAttribute(Parts.class.getName());
|
||||||
if (multiParts != null)
|
if (parts != null)
|
||||||
multiParts.close();
|
parts.close();
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,11 +119,11 @@ public class MultiPartByteRangesTest
|
||||||
|
|
||||||
assertEquals(3, parts.size());
|
assertEquals(3, parts.size());
|
||||||
MultiPart.Part part1 = parts.get(0);
|
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);
|
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);
|
MultiPart.Part part3 = parts.get(2);
|
||||||
assertEquals("CDEF", Content.Source.asString(part3.getNewContent()));
|
assertEquals("CDEF", Content.Source.asString(part3.newContentSource()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -80,7 +80,7 @@ public class MultiPartFormDataHandlerTest
|
||||||
.whenComplete((parts, failure) ->
|
.whenComplete((parts, failure) ->
|
||||||
{
|
{
|
||||||
if (parts != null)
|
if (parts != null)
|
||||||
Content.copy(parts.get(0).getNewContent(), response, callback);
|
Content.copy(parts.get(0).newContentSource(), response, callback);
|
||||||
else
|
else
|
||||||
Response.writeError(request, response, callback, failure);
|
Response.writeError(request, response, callback, failure);
|
||||||
});
|
});
|
||||||
|
@ -126,10 +126,10 @@ public class MultiPartFormDataHandlerTest
|
||||||
public boolean process(Request request, Response response, Callback callback) throws Exception
|
public boolean process(Request request, Response response, Callback callback) throws Exception
|
||||||
{
|
{
|
||||||
processLatch.countDown();
|
processLatch.countDown();
|
||||||
MultiPartFormData formData = (MultiPartFormData)request.getAttribute(MultiPartFormData.class.getName());
|
MultiPartFormData.Parts parts = (MultiPartFormData.Parts)request.getAttribute(MultiPartFormData.Parts.class.getName());
|
||||||
assertNotNull(formData);
|
assertNotNull(parts);
|
||||||
MultiPart.Part part = formData.get().get(0);
|
MultiPart.Part part = parts.get(0);
|
||||||
Content.copy(part.getNewContent(), response, callback);
|
Content.copy(part.newContentSource(), response, callback);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -195,8 +195,8 @@ public class MultiPartFormDataHandlerTest
|
||||||
{
|
{
|
||||||
if (parts != null)
|
if (parts != null)
|
||||||
{
|
{
|
||||||
response.getHeaders().put(HttpHeader.CONTENT_TYPE, "multipart/form-data; boundary=\"%s\"".formatted(parts.getBoundary()));
|
response.getHeaders().put(HttpHeader.CONTENT_TYPE, "multipart/form-data; boundary=\"%s\"".formatted(parts.getMultiPartFormData().getBoundary()));
|
||||||
MultiPartFormData.ContentSource source = new MultiPartFormData.ContentSource(parts.getBoundary());
|
MultiPartFormData.ContentSource source = new MultiPartFormData.ContentSource(parts.getMultiPartFormData().getBoundary());
|
||||||
source.setPartHeadersMaxLength(1024);
|
source.setPartHeadersMaxLength(1024);
|
||||||
parts.forEach(source::addPart);
|
parts.forEach(source::addPart);
|
||||||
source.close();
|
source.close();
|
||||||
|
@ -321,7 +321,7 @@ public class MultiPartFormDataHandlerTest
|
||||||
HttpFields headers2 = part2.getHeaders();
|
HttpFields headers2 = part2.getHeaders();
|
||||||
assertEquals(2, headers2.size());
|
assertEquals(2, headers2.size());
|
||||||
assertEquals("application/octet-stream", headers2.get(HttpHeader.CONTENT_TYPE));
|
assertEquals("application/octet-stream", headers2.get(HttpHeader.CONTENT_TYPE));
|
||||||
assertEquals(32, part2.getNewContent().getLength());
|
assertEquals(32, part2.newContentSource().getLength());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -181,10 +181,10 @@ public class ResourceHandlerByteRangesTest
|
||||||
assertEquals(2, parts.size());
|
assertEquals(2, parts.size());
|
||||||
MultiPart.Part part1 = parts.get(0);
|
MultiPart.Part part1 = parts.get(0);
|
||||||
assertEquals("text/plain", part1.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
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);
|
MultiPart.Part part2 = parts.get(1);
|
||||||
assertEquals("text/plain", part2.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
assertEquals("text/plain", part2.getHeaders().get(HttpHeader.CONTENT_TYPE));
|
||||||
assertEquals("xyz", Content.Source.asString(part2.getNewContent()));
|
assertEquals("xyz", Content.Source.asString(part2.newContentSource()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,9 +77,9 @@ public class ServletMultiPartFormData
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Look for a previously read and parsed MultiPartFormData from the DelayedHandler.
|
// Look for a previously read and parsed MultiPartFormData from the DelayedHandler.
|
||||||
MultiPartFormData formData = (MultiPartFormData)request.getAttribute(MultiPartFormData.class.getName());
|
MultiPartFormData.Parts parts = (MultiPartFormData.Parts)request.getAttribute(MultiPartFormData.Parts.class.getName());
|
||||||
if (formData != null)
|
if (parts != null)
|
||||||
return new Parts(formData);
|
return new Parts(parts);
|
||||||
|
|
||||||
// TODO set the files directory
|
// TODO set the files directory
|
||||||
return new ServletMultiPartFormData().parse(request, maxParts);
|
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.
|
// Store MultiPartFormData as attribute on request so it is released by the HttpChannel.
|
||||||
MultiPartFormData formData = new MultiPartFormData(boundary);
|
MultiPartFormData formData = new MultiPartFormData(boundary);
|
||||||
request.setAttribute(MultiPartFormData.class.getName(), formData);
|
|
||||||
formData.setMaxParts(maxParts);
|
formData.setMaxParts(maxParts);
|
||||||
|
|
||||||
File tmpDirFile = (File)request.getServletContext().getAttribute(ServletContext.TEMPDIR);
|
File tmpDirFile = (File)request.getServletContext().getAttribute(ServletContext.TEMPDIR);
|
||||||
|
@ -123,7 +122,7 @@ public class ServletMultiPartFormData
|
||||||
Connection connection = connectionMetaData.getConnection();
|
Connection connection = connectionMetaData.getConnection();
|
||||||
int bufferSize = connection instanceof AbstractConnection c ? c.getInputBufferSize() : 2048;
|
int bufferSize = connection instanceof AbstractConnection c ? c.getInputBufferSize() : 2048;
|
||||||
InputStream input = request.getInputStream();
|
InputStream input = request.getInputStream();
|
||||||
while (true)
|
while (!formData.isDone())
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = byteBufferPool.newByteBuffer(bufferSize, false);
|
ByteBuffer buffer = byteBufferPool.newByteBuffer(bufferSize, false);
|
||||||
boolean readEof = 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<Part> parts = new ArrayList<>();
|
private final List<Part> 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)
|
public Part getPart(String name)
|
||||||
|
@ -190,7 +191,7 @@ public class ServletMultiPartFormData
|
||||||
@Override
|
@Override
|
||||||
public InputStream getInputStream() throws IOException
|
public InputStream getInputStream() throws IOException
|
||||||
{
|
{
|
||||||
return Content.Source.asInputStream(_part.getNewContent());
|
return Content.Source.asInputStream(_part.newContentSource());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -129,10 +129,6 @@ public class MultiPartServletTest
|
||||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
req.getParameterMap();
|
req.getParameterMap();
|
||||||
req.getParts();
|
|
||||||
resp.setStatus(200);
|
|
||||||
resp.getWriter().print("success");
|
|
||||||
resp.getWriter().close();
|
|
||||||
}
|
}
|
||||||
}, new MultipartConfigElement(tmpDirString));
|
}, new MultipartConfigElement(tmpDirString));
|
||||||
|
|
||||||
|
@ -174,10 +170,6 @@ public class MultiPartServletTest
|
||||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
req.getParameterMap();
|
req.getParameterMap();
|
||||||
req.getParts();
|
|
||||||
resp.setStatus(200);
|
|
||||||
resp.getWriter().print("success");
|
|
||||||
resp.getWriter().close();
|
|
||||||
}
|
}
|
||||||
}, new MultipartConfigElement(tmpDirString));
|
}, new MultipartConfigElement(tmpDirString));
|
||||||
|
|
||||||
|
@ -216,10 +208,6 @@ public class MultiPartServletTest
|
||||||
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
|
||||||
{
|
{
|
||||||
req.getParameterMap();
|
req.getParameterMap();
|
||||||
req.getParts();
|
|
||||||
resp.setStatus(200);
|
|
||||||
resp.getWriter().print("success");
|
|
||||||
resp.getWriter().close();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}, new MultipartConfigElement(tmpDirString, -1, 1024, 1024 * 1024 * 8));
|
}, new MultipartConfigElement(tmpDirString, -1, 1024, 1024 * 1024 * 8));
|
||||||
|
|
Loading…
Reference in New Issue