Skip to content

Commit

Permalink
Merge pull request #29716 from geoand/#20938
Browse files Browse the repository at this point in the history
Ensure that file is written on disk for multipart when endpoint expects it
  • Loading branch information
geoand authored Dec 8, 2022
2 parents 1dc1a77 + ec2a4a4 commit 25b8a47
Show file tree
Hide file tree
Showing 18 changed files with 125 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ private void doTest(String path) {
.post("/multipart/" + path + "/2")
.then()
.statusCode(200)
.body(equalTo("Alice - true - 50 - WORKING - text/html - true - true"));
.body(equalTo("Alice - true - 50 - WORKING - true - true - true"));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ public void testSimple() {
.post("/multipart/simple/2")
.then()
.statusCode(200)
.body(equalTo("Alice - true - 50 - WORKING - text/html - true - true"));
.body(equalTo("Alice - true - 50 - WORKING - true - true - true"));

// ensure that the 3 uploaded files where created on disk
Assertions.assertEquals(3, uploadDir.toFile().listFiles().length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ public JavaArchive get() {
private final File HTML_FILE2 = new File("./src/test/resources/test2.html");
private final File XML_FILE = new File("./src/test/resources/test.html");
private final File TXT_FILE = new File("./src/test/resources/lorem.txt");
private final String TXT = "lorem ipsum";
private final String XML = "<note></note>";
private final String HTML = "<!DOCTYPE html><html></html>";

@BeforeEach
public void assertEmptyUploads() {
Expand All @@ -68,15 +71,15 @@ public void testSimple() {
.multiPart("active", "true")
.multiPart("num", "25")
.multiPart("status", "WORKING")
.multiPart("htmlFile", HTML_FILE, "text/html")
.multiPart("xmlFile", XML_FILE, "text/xml")
.multiPart("txtFile", TXT_FILE, "text/plain")
.multiPart("htmlFile", HTML, "text/html")
.multiPart("xmlFile", XML, "text/xml")
.multiPart("txtFile", TXT, "text/plain")
.accept("text/plain")
.when()
.post("/multipart/simple/2")
.then()
.statusCode(200)
.body(equalTo("Alice - true - 50 - WORKING - text/html - true - true"));
.body(equalTo("Alice - true - 50 - WORKING - true - true - true"));

// ensure that the 3 uploaded files where created on disk
Assertions.assertEquals(3, uploadDir.toFile().listFiles().length);
Expand Down Expand Up @@ -110,15 +113,15 @@ public void testSimpleParam() {
.multiPart("active", "true")
.multiPart("num", "25")
.multiPart("status", "WORKING")
.multiPart("htmlFile", HTML_FILE, "text/html")
.multiPart("xmlFile", XML_FILE, "text/xml")
.multiPart("txtFile", TXT_FILE, "text/plain")
.multiPart("htmlFile", HTML, "text/html")
.multiPart("xmlFile", XML, "text/xml")
.multiPart("txtFile", TXT, "text/plain")
.accept("text/plain")
.when()
.post("/multipart/param/simple/2")
.then()
.statusCode(200)
.body(equalTo("Alice - true - 50 - WORKING - text/html - true - true"));
.body(equalTo("Alice - true - 50 - WORKING - true - true - true"));

// ensure that the 3 uploaded files where created on disk
Assertions.assertEquals(3, uploadDir.toFile().listFiles().length);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public String simple(@BeanParam FormData formData, Integer times) {
}
return formData.getName() + " - " + formData.active + " - " + times * formData.getNum() + " - " + formData.getStatus()
+ " - "
+ formData.getHtmlPart().contentType() + " - " + Files.exists(formData.xmlPart) + " - "
+ Files.exists(formData.getHtmlPart().filePath()) + " - " + Files.exists(formData.xmlPart) + " - "
+ formData.txtFile.exists();
}

Expand Down Expand Up @@ -74,7 +74,7 @@ public String simple(
}
return name + " - " + active + " - " + times * num + " - " + status
+ " - "
+ htmlPart.contentType() + " - " + Files.exists(xmlPart) + " - "
+ Files.exists(htmlPart.filePath()) + " - " + Files.exists(xmlPart) + " - "
+ txtFile.exists();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.MediaType;

Expand Down Expand Up @@ -115,7 +116,8 @@ protected ResourceMethod createResourceMethod(MethodInfo info, ClassInfo actualE
}

@Override
protected boolean handleBeanParam(ClassInfo actualEndpointInfo, Type paramType, MethodParameter[] methodParameters, int i) {
protected boolean handleBeanParam(ClassInfo actualEndpointInfo, Type paramType, MethodParameter[] methodParameters, int i,
Set<String> fileFormNames) {
ClassInfo beanParamClassInfo = index.getClassByName(paramType.name());
methodParameters[i] = parseClientBeanParam(beanParamClassInfo, index);

Expand All @@ -127,15 +129,18 @@ private MethodParameter parseClientBeanParam(ClassInfo beanParamClassInfo, Index
return new ClientBeanParamInfo(items, beanParamClassInfo.name().toString());
}

@Override
protected InjectableBean scanInjectableBean(ClassInfo currentClassInfo, ClassInfo actualEndpointInfo,
Map<String, String> existingConverters, AdditionalReaders additionalReaders,
Map<String, InjectableBean> injectableBeans, boolean hasRuntimeConverters) {
throw new RuntimeException("Injectable beans not supported in client");
}

@Override
protected MethodParameter createMethodParameter(ClassInfo currentClassInfo, ClassInfo actualEndpointInfo, boolean encoded,
Type paramType, ClientIndexedParam parameterResult, String name, String defaultValue, ParameterType type,
String elementType, boolean single, String signature) {
String elementType, boolean single, String signature,
Set<String> fileFormNames) {
DeclaredTypes declaredTypes = getDeclaredTypes(paramType, currentClassInfo, actualEndpointInfo);
String mimePart = getPartMime(parameterResult.getAnns());
String partFileName = getPartFileName(parameterResult.getAnns());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,7 @@ private ResourceMethod createResourceMethod(ClassInfo currentClassInfo, ClassInf
boolean suspended = false;
boolean sse = false;
boolean formParamRequired = false;
Set<String> fileFormNames = new HashSet<>();
Type bodyParamType = null;
TypeArgMapper typeArgMapper = new TypeArgMapper(currentMethodInfo.declaringClass(), index);
for (int i = 0; i < methodParameters.length; ++i) {
Expand Down Expand Up @@ -604,12 +605,12 @@ private ResourceMethod createResourceMethod(ClassInfo currentClassInfo, ClassInf
}
methodParameters[i] = createMethodParameter(currentClassInfo, actualEndpointInfo, encoded, paramType,
parameterResult, name, defaultValue, type, elementType, single,
AsmUtil.getSignature(paramType, typeArgMapper));
AsmUtil.getSignature(paramType, typeArgMapper), fileFormNames);

if (type == ParameterType.BEAN
|| type == ParameterType.MULTI_PART_FORM) {
// transform the bean param
formParamRequired |= handleBeanParam(actualEndpointInfo, paramType, methodParameters, i);
formParamRequired |= handleBeanParam(actualEndpointInfo, paramType, methodParameters, i, fileFormNames);
} else if (type == ParameterType.FORM) {
formParamRequired = true;
}
Expand Down Expand Up @@ -731,6 +732,7 @@ private ResourceMethod createResourceMethod(ClassInfo currentClassInfo, ClassInf
.setSse(sse)
.setStreamElementType(streamElementType)
.setFormParamRequired(formParamRequired)
.setFileFormNames(fileFormNames)
.setParameters(methodParameters)
.setSimpleReturnType(
toClassName(currentMethodInfo.returnType(), currentClassInfo, actualEndpointInfo, index))
Expand Down Expand Up @@ -885,7 +887,7 @@ private String determineReturnType(Type returnType, TypeArgMapper typeArgMapper,
}

protected abstract boolean handleBeanParam(ClassInfo actualEndpointInfo, Type paramType, MethodParameter[] methodParameters,
int i);
int i, Set<String> fileFormNames);

protected void handleAdditionalMethodProcessing(METHOD method, ClassInfo currentClassInfo, MethodInfo info,
AnnotationStore annotationStore) {
Expand All @@ -901,7 +903,8 @@ protected abstract InjectableBean scanInjectableBean(ClassInfo currentClassInfo,

protected abstract MethodParameter createMethodParameter(ClassInfo currentClassInfo, ClassInfo actualEndpointInfo,
boolean encoded, Type paramType, PARAM parameterResult, String name, String defaultValue,
ParameterType type, String elementType, boolean single, String signature);
ParameterType type, String elementType, boolean single, String signature,
Set<String> fileFormNames);

private String[] applyDefaultProduces(String[] produces, Type nonAsyncReturnType,
DotName httpMethod) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.jboss.resteasy.reactive.common.model;

import java.util.HashSet;
import java.util.Set;

public class BeanParamInfo implements InjectableBean {
private boolean isFormParamRequired;
private boolean isInjectionRequired;
private int fieldExtractorsCount;
private Set<String> fileFormNames = new HashSet<>();

@Override
public boolean isFormParamRequired() {
Expand Down Expand Up @@ -36,4 +40,14 @@ public int getFieldExtractorsCount() {
public void setFieldExtractorsCount(int fieldExtractorsCount) {
this.fieldExtractorsCount = fieldExtractorsCount;
}

@Override
public Set<String> getFileFormNames() {
return fileFormNames;
}

@Override
public void setFileFormNames(Set<String> fileFormNames) {
this.fileFormNames = fileFormNames;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package org.jboss.resteasy.reactive.common.model;

import java.util.Set;

/**
* Class that represents information about injectable beans as we scan them, such as
* resource endpoint beans, or BeanParam classes.
Expand All @@ -25,4 +27,8 @@ public interface InjectableBean {
int getFieldExtractorsCount();

void setFieldExtractorsCount(int fieldExtractorsCount);

Set<String> getFileFormNames();

void setFileFormNames(Set<String> fileFormNames);
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ public class ResourceMethod {

private boolean isFormParamRequired;

private Set<String> fileFormNames;

private List<ResourceMethod> subResourceMethods;

public ResourceMethod() {
Expand Down Expand Up @@ -224,6 +226,15 @@ public ResourceMethod setFormParamRequired(boolean isFormParamRequired) {
return this;
}

public Set<String> getFileFormNames() {
return fileFormNames;
}

public ResourceMethod setFileFormNames(Set<String> fileFormNames) {
this.fileFormNames = fileFormNames;
return this;
}

public ResourceMethod setStreamElementType(String streamElementType) {
this.streamElementType = streamElementType;
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,13 @@

public class ServerEndpointIndexer
extends EndpointIndexer<ServerEndpointIndexer, ServerIndexedParameter, ServerResourceMethod> {

private static final DotName FILE_DOT_NAME = DotName.createSimple(File.class.getName());
private static final DotName PATH_DOT_NAME = DotName.createSimple(Path.class.getName());
private static final DotName FILEUPLOAD_DOT_NAME = DotName.createSimple(FileUpload.class.getName());

private static final Set<DotName> SUPPORTED_MULTIPART_FILE_TYPES = Set.of(FILE_DOT_NAME, PATH_DOT_NAME,
FILEUPLOAD_DOT_NAME);
protected final EndpointInvokerFactory endpointInvokerFactory;
protected final List<MethodScanner> methodScanners;
protected final FieldInjectionIndexerExtension fieldInjectionHandler;
Expand Down Expand Up @@ -176,7 +183,8 @@ protected ServerResourceMethod createResourceMethod(MethodInfo methodInfo, Class
}

@Override
protected boolean handleBeanParam(ClassInfo actualEndpointInfo, Type paramType, MethodParameter[] methodParameters, int i) {
protected boolean handleBeanParam(ClassInfo actualEndpointInfo, Type paramType, MethodParameter[] methodParameters, int i,
Set<String> fileFormNames) {
ClassInfo beanParamClassInfo = index.getClassByName(paramType.name());
InjectableBean injectableBean = scanInjectableBean(beanParamClassInfo,
actualEndpointInfo,
Expand All @@ -186,7 +194,7 @@ protected boolean handleBeanParam(ClassInfo actualEndpointInfo, Type paramType,
+ "Annotations like `@QueryParam` should be used in fields, not in methods.",
beanParamClassInfo.name()));
}

fileFormNames.addAll(injectableBean.getFileFormNames());
return injectableBean.isFormParamRequired();
}

Expand Down Expand Up @@ -233,6 +241,7 @@ private void validateMethodPath(ServerResourceMethod method, ClassInfo currentCl
}
}

@Override
protected InjectableBean scanInjectableBean(ClassInfo currentClassInfo, ClassInfo actualEndpointInfo,
Map<String, String> existingConverters, AdditionalReaders additionalReaders,
Map<String, InjectableBean> injectableBeans, boolean hasRuntimeConverters) {
Expand Down Expand Up @@ -280,6 +289,24 @@ protected InjectableBean scanInjectableBean(ClassInfo currentClassInfo, ClassInf
} else if (result.getType() == ParameterType.FORM) {
// direct form param requirement
currentInjectableBean.setFormParamRequired(true);

if (SUPPORTED_MULTIPART_FILE_TYPES.contains(field.type().name())) {
String name = field.name();
AnnotationInstance restForm = field.annotation(ResteasyReactiveDotNames.REST_FORM_PARAM);
AnnotationInstance formParam = field.annotation(ResteasyReactiveDotNames.FORM_PARAM);
if (restForm != null) {
AnnotationValue value = restForm.value();
if (value != null) {
name = value.asString();
}
} else if (formParam != null) {
AnnotationValue value = formParam.value();
if (value != null) {
name = value.asString();
}
}
currentInjectableBean.getFileFormNames().add(name);
}
}
}
// the TCK expects that fields annotated with @BeanParam are handled last
Expand Down Expand Up @@ -309,15 +336,22 @@ protected InjectableBean scanInjectableBean(ClassInfo currentClassInfo, ClassInf
return currentInjectableBean;
}

@Override
protected MethodParameter createMethodParameter(ClassInfo currentClassInfo, ClassInfo actualEndpointInfo, boolean encoded,
Type paramType, ServerIndexedParameter parameterResult, String name, String defaultValue, ParameterType type,
String elementType, boolean single, String signature) {
String elementType, boolean single, String signature,
Set<String> fileFormNames) {
ParameterConverterSupplier converter = parameterResult.getConverter();
DeclaredTypes declaredTypes = getDeclaredTypes(paramType, currentClassInfo, actualEndpointInfo);
String mimeType = getPartMime(parameterResult.getAnns());
String separator = getSeparator(parameterResult.getAnns());
String declaredType = declaredTypes.getDeclaredType();

if (SUPPORTED_MULTIPART_FILE_TYPES.contains(DotName.createSimple(declaredType))) {
fileFormNames.add(name);
}
return new ServerMethodParameter(name,
elementType, declaredTypes.getDeclaredType(), declaredTypes.getDeclaredUnresolvedType(),
elementType, declaredType, declaredTypes.getDeclaredUnresolvedType(),
type, single, signature,
converter, defaultValue, parameterResult.isObtainedAsCollection(), parameterResult.isOptional(), encoded,
parameterResult.getCustomParameterExtractor(), mimeType, separator);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Set;

import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.HttpHeaders;
Expand Down Expand Up @@ -37,7 +38,7 @@ public FormEncodedDataDefinition() {
}

@Override
public FormDataParser create(final ResteasyReactiveRequestContext exchange) {
public FormDataParser create(final ResteasyReactiveRequestContext exchange, Set<String> fileFormNames) {
String mimeType = exchange.serverRequest().getRequestHeader(HttpHeaders.CONTENT_TYPE);
if (forceCreation || (mimeType != null && mimeType.startsWith(APPLICATION_X_WWW_FORM_URLENCODED))) {

Expand Down
Loading

0 comments on commit 25b8a47

Please sign in to comment.