Skip to content

Commit

Permalink
RESTEasy Reactive: Handle separator for bean params
Browse files Browse the repository at this point in the history
Fixes #31050
  • Loading branch information
TwoFX committed Mar 17, 2023
1 parent 629b2f0 commit 4e0dd65
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package io.quarkus.resteasy.reactive.server.test.simple;

import static io.restassured.RestAssured.*;
import static io.restassured.RestAssured.get;

import java.util.List;

Expand Down Expand Up @@ -69,6 +69,15 @@ public void multipleQueryParams() {
.header("x-size", "6");
}

@Test
public void multipleQueryParamsBean() {
get("/hello/bean?name=foo,bar&name=one,two,three&name=yolo")
.then()
.statusCode(200)
.body(Matchers.equalTo("hello foo bar one two three yolo"))
.header("x-size", "6");
}

@Path("hello")
public static class HelloResource {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ public Optional<ResourceClass> createEndpoints(ClassInfo classInfo, boolean cons
clazz.setPath(sanitizePath(path));
}
if (factoryCreator != null) {
clazz.setFactory((BeanFactory<Object>) factoryCreator.apply(classInfo.name().toString()));
clazz.setFactory(factoryCreator.apply(classInfo.name().toString()));
}
Map<String, String> classLevelExceptionMappers = this.classLevelExceptionMappers.get(classInfo.name());
if (classLevelExceptionMappers != null) {
Expand Down Expand Up @@ -1211,10 +1211,12 @@ public PARAM extractParameterInfo(ClassInfo currentClassInfo, ClassInfo actualEn
} else if (queryParam != null) {
builder.setName(queryParam.value().asString());
builder.setType(ParameterType.QUERY);
builder.setSeparator(getSeparator(anns));
convertible = true;
} else if (restQueryParam != null) {
builder.setName(valueOrDefault(restQueryParam.value(), sourceName));
builder.setType(ParameterType.QUERY);
builder.setSeparator(getSeparator(anns));
convertible = true;
} else if (cookieParam != null) {
builder.setName(cookieParam.value().asString());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class IndexedParameter<T extends IndexedParameter<T>> {
protected String elementType;
protected boolean single;
protected boolean optional;
protected String separator;

public boolean isObtainedAsCollection() {
return !single
Expand Down Expand Up @@ -208,4 +209,13 @@ public T setOptional(boolean optional) {
this.optional = optional;
return (T) this;
}

public String getSeparator() {
return separator;
}

public T setSeparator(String separator) {
this.separator = separator;
return (T) this;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -275,26 +275,27 @@ public void visitEnd() {
break;
case FORM:
injectParameterWithConverter(injectMethod, "getFormParameter", fieldInfo, extractor, true, true,
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED));
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED), false);
break;
case HEADER:
injectParameterWithConverter(injectMethod, "getHeader", fieldInfo, extractor, true, false, false);
injectParameterWithConverter(injectMethod, "getHeader", fieldInfo, extractor, true, false, false,
false);
break;
case MATRIX:
injectParameterWithConverter(injectMethod, "getMatrixParameter", fieldInfo, extractor, true, true,
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED));
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED), false);
break;
case COOKIE:
injectParameterWithConverter(injectMethod, "getCookieParameter", fieldInfo, extractor, false, false,
false);
false, false);
break;
case PATH:
injectParameterWithConverter(injectMethod, "getPathParameter", fieldInfo, extractor, false, true,
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED));
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED), false);
break;
case QUERY:
injectParameterWithConverter(injectMethod, "getQueryParameter", fieldInfo, extractor, true, true,
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED));
fieldInfo.hasAnnotation(ResteasyReactiveDotNames.ENCODED), true);
break;
default:
break;
Expand Down Expand Up @@ -518,7 +519,8 @@ private ParameterConverterSupplier removeRuntimeResolvedConverterDelegate(Parame
}

private void injectParameterWithConverter(MethodVisitor injectMethod, String methodName, FieldInfo fieldInfo,
ServerIndexedParameter extractor, boolean extraSingleParameter, boolean extraEncodedParam, boolean encoded) {
ServerIndexedParameter extractor, boolean extraSingleParameter, boolean extraEncodedParam, boolean encoded,
boolean extraSeparatorParam) {

// spec says:
/*
Expand Down Expand Up @@ -552,7 +554,8 @@ private void injectParameterWithConverter(MethodVisitor injectMethod, String met
// push the parameter value
MultipartFormParamExtractor.Type multipartType = getMultipartFormType(extractor);
if (multipartType == null) {
loadParameter(injectMethod, methodName, extractor, extraSingleParameter, extraEncodedParam, encoded);
loadParameter(injectMethod, methodName, extractor, extraSingleParameter, extraEncodedParam, encoded,
extraSeparatorParam);
} else {
loadMultipartParameter(injectMethod, fieldInfo, extractor, multipartType);
}
Expand Down Expand Up @@ -886,13 +889,22 @@ private void convertParameter(MethodVisitor injectMethod, ServerIndexedParameter
}

private void loadParameter(MethodVisitor injectMethod, String methodName, IndexedParameter extractor,
boolean extraSingleParameter, boolean extraEncodedParam, boolean encoded) {
boolean extraSingleParameter, boolean extraEncodedParam, boolean encoded, boolean extraSeparatorParam) {
// ctx param
injectMethod.visitIntInsn(Opcodes.ALOAD, 1);
// name param
injectMethod.visitLdcInsn(extractor.getName());
String methodSignature;
if (extraEncodedParam && extraSingleParameter) {
if (extraEncodedParam && extraSingleParameter && extraSeparatorParam) {
injectMethod.visitLdcInsn(extractor.isSingle());
injectMethod.visitLdcInsn(encoded);
if (extractor.getSeparator() != null) {
injectMethod.visitLdcInsn(extractor.getSeparator());
} else {
injectMethod.visitInsn(Opcodes.ACONST_NULL);
}
methodSignature = "(Ljava/lang/String;ZZLjava/lang/String;)Ljava/lang/Object;";
} else if (extraEncodedParam && extraSingleParameter) {
injectMethod.visitLdcInsn(extractor.isSingle());
injectMethod.visitLdcInsn(encoded);
methodSignature = "(Ljava/lang/String;ZZ)Ljava/lang/Object;";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ public ResteasyReactiveRequestContext(Deployment deployment,

public abstract ServerHttpRequest serverRequest();

@Override
public abstract ServerHttpResponse serverResponse();

public Deployment getDeployment() {
Expand Down Expand Up @@ -286,6 +287,7 @@ public Object getResult() {
return result;
}

@Override
public Throwable getThrowable() {
return throwable;
}
Expand Down Expand Up @@ -618,6 +620,7 @@ public ResteasyReactiveRequestContext setWriterInterceptors(WriterInterceptor[]
return this;
}

@Override
protected void handleUnrecoverableError(Throwable throwable) {
log.error("Request failed", throwable);
if (serverResponse().headWritten()) {
Expand All @@ -628,6 +631,7 @@ protected void handleUnrecoverableError(Throwable throwable) {
close();
}

@Override
protected void handleRequestScopeActivation() {
CurrentRequestManager.set(this);
}
Expand Down Expand Up @@ -703,6 +707,7 @@ public boolean hasInputStream() {
return inputStream != null;
}

@Override
public InputStream getInputStream() {
if (inputStream == null) {
inputStream = serverRequest().createInputStream();
Expand Down Expand Up @@ -805,25 +810,46 @@ public Object getHeader(String name, boolean single) {
}
}

@Override
public Object getQueryParameter(String name, boolean single, boolean encoded) {
return getQueryParameter(name, single, encoded, null);
}

@Override
public Object getQueryParameter(String name, boolean single, boolean encoded, String separator) {
if (single) {
String val = serverRequest().getQueryParam(name);
if (encoded && val != null) {
val = Encode.encodeQueryParam(val);
}
return val;

if (separator != null) {
String[] parts = val.split(separator);
return new ArrayList<>(Arrays.asList(parts));
} else {
return val;
}
}

// empty collections must not be turned to null
List<String> strings = serverRequest().getAllQueryParams(name);
if (encoded) {
List<String> newStrings = new ArrayList<>();
for (String i : strings) {
newStrings.add(Encode.encodeQueryParam(i));
}
return newStrings;
strings = newStrings;
}

if (separator != null) {
List<String> result = new ArrayList<>(strings.size());
for (int i = 0; i < strings.size(); i++) {
String[] parts = strings.get(i).split(separator);
result.addAll(Arrays.asList(parts));
}
return result;
} else {
return strings;
}
return strings;
}

@Override
Expand Down Expand Up @@ -916,6 +942,7 @@ public String getPathParameter(String name, boolean encoded) {
return value;
}

@Override
public <T> T unwrap(Class<T> type) {
return serverRequest().unwrap(type);
}
Expand Down Expand Up @@ -953,6 +980,7 @@ public OutputStream getOutputStream() {
return outputStream;
}

@Override
public OutputStream getOrCreateOutputStream() {
if (outputStream == null) {
return outputStream = underlyingOutputStream = serverResponse().createResponseOutputStream();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
package org.jboss.resteasy.reactive.server.core.parameters;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.jboss.resteasy.reactive.server.core.ResteasyReactiveRequestContext;

@SuppressWarnings("ForLoopReplaceableByForEach")
Expand All @@ -22,27 +18,7 @@ public QueryParamExtractor(String name, boolean single, boolean encoded, String
}

@Override
@SuppressWarnings("unchecked")
public Object extractParameter(ResteasyReactiveRequestContext context) {
Object queryParameter = context.getQueryParameter(name, single, encoded);
if (separator != null) {
if (queryParameter instanceof List) { // it's List<String>
List<String> list = (List<String>) queryParameter;
List<String> result = new ArrayList<>(list.size());
for (int i = 0; i < list.size(); i++) {
String[] parts = list.get(i).split(separator);
result.addAll(Arrays.asList(parts));
}
queryParameter = result;
} else if (queryParameter instanceof String) {
List<String> result = new ArrayList<>(1);
String[] parts = ((String) queryParameter).split(separator);
result.addAll(Arrays.asList(parts));
queryParameter = result;
} else {
// can't really happen
}
}
return queryParameter;
return context.getQueryParameter(name, single, encoded, separator);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
public interface ResteasyReactiveInjectionContext {
Object getHeader(String name, boolean single);

Object getQueryParameter(String name, boolean single, boolean encoded);
Object getQueryParameter(String name, boolean single, boolean encoded, String separator);

String getPathParameter(String name, boolean encoded);

Expand Down

0 comments on commit 4e0dd65

Please sign in to comment.