Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package org.apache.axis2.builder;

import java.io.File;
import java.io.InputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
Expand All @@ -28,6 +29,7 @@

import jakarta.activation.DataHandler;
import jakarta.activation.DataSource;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;

import org.apache.axiom.om.OMAbstractFactory;
Expand Down Expand Up @@ -94,7 +96,7 @@ private MultipleEntryHashMap getParameterMap(HttpServletRequest request,

MultipleEntryHashMap parameterMap = new MultipleEntryHashMap();

List items = parseRequest(new JakartaServletRequestContext(request), messageContext);
List items = parseRequest(request, messageContext);
Iterator iter = items.iterator();
while (iter.hasNext()) {
DiskFileItem diskFileItem = (DiskFileItem)iter.next();
Expand Down Expand Up @@ -144,16 +146,27 @@ private static void deleteQuietly(DiskFileItem diskFileItem) {
}
}

private static List parseRequest(JakartaServletRequestContext requestContext,
private static List parseRequest(HttpServletRequest request,
MessageContext messageContext)
throws FileUploadException {
// Create a factory for disk-based file items. Parts above the factory's
// threshold spill to a temp file; register them so the file goes away
// once the item that owns it is unreachable.
DiskFileItemFactory fileItemFactory = DiskFileItemFactory.builder()
DiskFileItemFactory.Builder factoryBuilder = DiskFileItemFactory.builder()
.setCharset(StandardCharsets.UTF_8)
.setFileCleaningTracker(MultipartTempFileTracker.getTracker())
.get();
.setFileCleaningTracker(MultipartTempFileTracker.getTracker());
// commons-fileupload2 otherwise spills into java.io.tmpdir, creating the
// file with the process umask, so an uploaded part is readable by other
// local accounts. Use the servlet context's private temp directory, as
// the container's own multipart handling does.
ServletContext servletContext = request.getServletContext();
Object tempDir = servletContext == null ? null
: servletContext.getAttribute(ServletContext.TEMPDIR);
if (tempDir instanceof File) {
factoryBuilder.setPath(((File) tempDir).toPath());
}
DiskFileItemFactory fileItemFactory = factoryBuilder.get();
JakartaServletRequestContext requestContext = new JakartaServletRequestContext(request);
JakartaServletFileUpload upload = new JakartaServletFileUpload<>(fileItemFactory);
// There must be a limit.
// This is for contentType="multipart/form-data"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.apache.axis2.builder;

import jakarta.servlet.ReadListener;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import junit.framework.TestCase;
Expand All @@ -35,6 +36,7 @@
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
Expand Down Expand Up @@ -165,6 +167,42 @@ public void testFilePartTempFileIsDeletedOnceUnreachable() throws Exception {
awaitTempFileCount(before));
}

/**
* A file part is spilled into the servlet context's private temp directory,
* not the shared {@code java.io.tmpdir}, where the umask-mode file would be
* readable by other local accounts.
*/
public void testFilePartIsSpilledIntoServletContextTempDir() throws Exception {
File contextTempDir = Files.createTempDirectory("axis2-context-tmp").toFile();
try {
int sharedBefore = countUploadTempFiles();

MessageContext messageContext = newMessageContext(buildBody("bigFile", "big.bin"));
HttpServletRequest request = (HttpServletRequest) messageContext.getProperty(
HTTPConstants.MC_HTTP_SERVLETREQUEST);
ServletContext servletContext = mock(ServletContext.class);
when(servletContext.getAttribute(ServletContext.TEMPDIR)).thenReturn(contextTempDir);
when(request.getServletContext()).thenReturn(servletContext);

OMElement result = new MultipartFormDataBuilder().processDocument(null,
multipartContentType(), messageContext);
assertNotNull(result);

assertEquals("The file part must not be written to the shared temp directory",
sharedBefore, countUploadTempFiles());
assertEquals("The file part should be in the servlet context temp directory",
1, countUploadTempFiles(contextTempDir));
} finally {
File[] files = contextTempDir.listFiles();
if (files != null) {
for (File file : files) {
file.delete();
}
}
contextTempDir.delete();
}
}

/**
* Poll for the temp-file count to fall back to the expected value, nudging
* the collector each time, since the reaper only acts once the owning item
Expand All @@ -182,7 +220,11 @@ private boolean awaitTempFileCount(int expected) throws InterruptedException {
}

private int countUploadTempFiles() {
String[] names = tempDirectory.list();
return countUploadTempFiles(tempDirectory);
}

private static int countUploadTempFiles(File directory) {
String[] names = directory.list();
if (names == null) {
return 0;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import javax.xml.namespace.QName;
Expand Down Expand Up @@ -152,7 +153,15 @@ public Redirect doUpload(HttpServletRequest req) throws ServletException {
boolean isMultipart = JakartaServletFileUpload.isMultipartContent(reqContext);
if (isMultipart) {
try {
JakartaServletFileUpload upload = new JakartaServletFileUpload<>(DiskFileItemFactory.builder().get());
// Spill into the servlet context's private temp directory rather
// than java.io.tmpdir, where the archive would be readable by
// other local accounts while it is being uploaded.
DiskFileItemFactory.Builder factoryBuilder = DiskFileItemFactory.builder();
Object tempDir = req.getServletContext().getAttribute(ServletContext.TEMPDIR);
if (tempDir instanceof File) {
factoryBuilder.setPath(((File) tempDir).toPath());
}
JakartaServletFileUpload upload = new JakartaServletFileUpload<>(factoryBuilder.get());
// There must be a limit. This is for an aar file upload,
// presumably only one. See:
// https://axis.apache.org/axis2/java/core/docs/webadminguide.html#upservice
Expand Down