Skip to content

Commit

Permalink
Properly return HTTP 406 on invalid Accept header
Browse files Browse the repository at this point in the history
This is very similar to what we do with the
Content-Type header

Fixes: quarkusio#34858
  • Loading branch information
geoand committed Jul 20, 2023
1 parent e23f434 commit 338fe53
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,14 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti
if (!accepts.isEmpty()) {
boolean hasAtLeastOneMatch = false;
for (int i = 0; i < accepts.size(); i++) {
boolean matches = acceptHeaderMatches(target, accepts.get(i));
if (matches) {
hasAtLeastOneMatch = true;
break;
try {
boolean matches = acceptHeaderMatches(target, accepts.get(i));
if (matches) {
hasAtLeastOneMatch = true;
break;
}
} catch (IllegalArgumentException ignored) {
// the provided header was not valid
}
}
if (!hasAtLeastOneMatch) {
Expand All @@ -150,16 +154,19 @@ public void handle(ResteasyReactiveRequestContext requestContext) throws Excepti
}
}

/**
* @return {@code true} if the provided string matches one of the {@code @Produces} values of the resource method
* @throws IllegalArgumentException if the provided string cannot be parsed into a {@link MediaType}
*/
private boolean acceptHeaderMatches(RequestMapper.RequestMatch<RuntimeResource> target, String accepts) {
if ((accepts != null) && !accepts.equals(MediaType.WILDCARD)) {
int commaIndex = accepts.indexOf(',');
boolean multipleAcceptsValues = commaIndex >= 0;
MediaType[] producesMediaTypes = target.value.getProduces().getSortedOriginalMediaTypes();
if (!multipleAcceptsValues && (producesMediaTypes.length == 1)) {
// the point of this branch is to eliminate any list creation or string indexing as none is needed
MediaType acceptsMediaType = MediaType.valueOf(accepts.trim());
MediaType providedMediaType = producesMediaTypes[0];
return providedMediaType.isCompatible(acceptsMediaType);
return providedMediaType.isCompatible(toMediaType(accepts.trim()));
} else if (multipleAcceptsValues && (producesMediaTypes.length == 1)) {
// this is fairly common case, so we want it to be as fast as possible
// we do that by manually splitting the accepts header and immediately checking
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.jboss.resteasy.reactive.server.vertx.test.mediatype;

import static io.restassured.RestAssured.config;
import static io.restassured.RestAssured.given;
import static io.restassured.config.EncoderConfig.encoderConfig;

import java.util.function.Supplier;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;

import org.jboss.resteasy.reactive.server.vertx.test.framework.ResteasyReactiveUnitTest;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.JavaArchive;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.restassured.http.ContentType;

public class InvalidAcceptTest {

@RegisterExtension
static ResteasyReactiveUnitTest test = new ResteasyReactiveUnitTest()
.setArchiveProducer(new Supplier<>() {
@Override
public JavaArchive get() {
return ShrinkWrap.create(JavaArchive.class)
.addClasses(HelloResource.class);
}
});

@Test
public void test() {
given().config(config().encoderConfig(encoderConfig().encodeContentTypeAs("invalid", ContentType.TEXT))).body("dummy")
.accept("invalid").get("/hello")
.then()
.statusCode(406);
}

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

@Produces("text/plain")
@GET
public String hello() {
return "hello";
}
}
}

0 comments on commit 338fe53

Please sign in to comment.