Skip to content

Commit 5ad3344

Browse files
committed
[RESTEASY-3283] Add option to not throw a DefaultOptionsMethodException when no OPTIONS method is found. Instead, just return the created response.
https://issues.redhat.com/browse/RESTEASY-3283 Signed-off-by: James R. Perkins <[email protected]>
1 parent 5e2e668 commit 5ad3344

File tree

5 files changed

+101
-2
lines changed

5 files changed

+101
-2
lines changed

docbook/reference/en/en-US/modules/ExceptionMappers.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ If there is an ExceptionMapper for wrapped exception, then that is used to handl
121121
<row>
122122
<entry>DefaultOptionsMethodException</entry>
123123
<entry>N/A</entry>
124-
<entry>If the user invokes HTTP OPTIONS and no JAX-RS method for it, RESTEasy provides a default behavior by throwing this exception</entry>
124+
<entry>If the user invokes HTTP OPTIONS and no JAX-RS method for it, RESTEasy provides a default behavior by throwing this exception.
125+
This can be disabled by setting the configuration property <code>dev.resteasy.throw.options.exception</code> is set to false.</entry>
125126
</row>
126127
<row>
127128
<entry>UnrecognizedPropertyExceptionHandler</entry>

docbook/reference/en/en-US/modules/Installation_Configuration.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,21 @@ String s = config.getOptionalValue("prop_name", String.class).orElse("d'oh");
10771077
for more information.
10781078
</entry>
10791079
</row>
1080+
<row>
1081+
<entry>
1082+
dev.resteasy.throw.options.exception
1083+
</entry>
1084+
<entry>
1085+
false
1086+
</entry>
1087+
<entry>
1088+
Setting this value to true will throw a <classname>org.jboss.resteasy.spi.DefaultOptionsMethodException</classname>
1089+
if the HTTP method "OPTIONS" is sent and the matching method is not annotated with
1090+
<classname>@OPTIONS</classname>. This is the original behavior of RESTEasy. However, this
1091+
has been changed to return the response so that it&apos;s processed with an
1092+
<classname>ExceptionMapper</classname>.
1093+
</entry>
1094+
</row>
10801095
</tbody>
10811096
</tgroup>
10821097
</table>
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* JBoss, Home of Professional Open Source.
3+
*
4+
* Copyright 2023 Red Hat, Inc., and individual contributors
5+
* as indicated by the @author tags.
6+
*
7+
* Licensed under the Apache License, Version 2.0 (the "License");
8+
* you may not use this file except in compliance with the License.
9+
* You may obtain a copy of the License at
10+
*
11+
* http://www.apache.org/licenses/LICENSE-2.0
12+
*
13+
* Unless required by applicable law or agreed to in writing, software
14+
* distributed under the License is distributed on an "AS IS" BASIS,
15+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
* See the License for the specific language governing permissions and
17+
* limitations under the License.
18+
*/
19+
20+
package org.jboss.resteasy.core.registry;
21+
22+
import java.lang.reflect.Method;
23+
24+
import org.jboss.resteasy.core.ResourceInvoker;
25+
import org.jboss.resteasy.specimpl.BuiltResponse;
26+
import org.jboss.resteasy.spi.HttpRequest;
27+
import org.jboss.resteasy.spi.HttpResponse;
28+
import org.jboss.resteasy.spi.statistics.MethodStatisticsLogger;
29+
30+
/**
31+
* A resource invoker which simply returns the given response.
32+
*
33+
* @author <a href="mailto:[email protected]">James R. Perkins</a>
34+
*/
35+
class ConstantResourceInvoker implements ResourceInvoker {
36+
private final BuiltResponse response;
37+
private volatile MethodStatisticsLogger logger;
38+
39+
ConstantResourceInvoker(final BuiltResponse response) {
40+
this.response = response;
41+
}
42+
43+
@Override
44+
public BuiltResponse invoke(final HttpRequest request, final HttpResponse response) {
45+
return this.response;
46+
}
47+
48+
@Override
49+
public BuiltResponse invoke(final HttpRequest request, final HttpResponse response, final Object target) {
50+
return this.response;
51+
}
52+
53+
@Override
54+
public Method getMethod() {
55+
return null;
56+
}
57+
58+
@Override
59+
public void setMethodStatisticsLogger(final MethodStatisticsLogger msLogger) {
60+
this.logger = msLogger;
61+
}
62+
63+
@Override
64+
public MethodStatisticsLogger getMethodStatisticsLogger() {
65+
return logger;
66+
}
67+
}

resteasy-jaxrs/src/main/java/org/jboss/resteasy/core/registry/SegmentNode.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
import org.jboss.resteasy.core.ResourceMethodInvoker;
66
import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages;
77
import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages;
8+
import org.jboss.resteasy.specimpl.BuiltResponse;
9+
import org.jboss.resteasy.specimpl.ResponseBuilderImpl;
810
import org.jboss.resteasy.spi.DefaultOptionsMethodException;
911
import org.jboss.resteasy.spi.HttpRequest;
12+
import org.jboss.resteasy.spi.ResteasyConfiguration;
1013
import org.jboss.resteasy.spi.ResteasyDeployment;
1114
import org.jboss.resteasy.spi.ResteasyProviderFactory;
1215
import org.jboss.resteasy.spi.ResteasyUriInfo;
@@ -456,7 +459,13 @@ public Match match(List<Match> matches, String httpMethod, HttpRequest request)
456459
if (httpMethod.equals("OPTIONS"))
457460
{
458461

459-
ResponseBuilder resBuilder = Response.ok(allowHeaderValue.toString(), MediaType.TEXT_PLAIN_TYPE).header(HttpHeaderNames.ALLOW, allowHeaderValue.toString());
462+
// Normally we would not create the ResponseBuilder like this. However, we need to ensure we end up with
463+
// a BuiltResponse, so we'll do it like this.
464+
ResponseBuilder resBuilder = new ResponseBuilderImpl()
465+
.entity(allowHeaderValue)
466+
.type(MediaType.TEXT_PLAIN_TYPE)
467+
.status(Response.Status.OK.getStatusCode(), Response.Status.OK.getReasonPhrase())
468+
.header(HttpHeaderNames.ALLOW, allowHeaderValue);
460469

461470
if (allowed.contains("PATCH"))
462471
{
@@ -481,6 +490,12 @@ public Match match(List<Match> matches, String httpMethod, HttpRequest request)
481490
}
482491
resBuilder.header(HttpHeaderNames.ACCEPT_PATCH, acceptPatch.toString());
483492
}
493+
// Default to the old behavior of throwing an exception.
494+
final ResteasyConfiguration context = ResteasyProviderFactory.getContextData(ResteasyConfiguration.class);
495+
if (context != null && !Boolean.parseBoolean(context.getParameter("dev.resteasy.throw.options.exception"))) {
496+
final MethodExpression expression = new MethodExpression(this, "", new ConstantResourceInvoker((BuiltResponse) resBuilder.build()));
497+
return new Match(expression, null);
498+
}
484499
throw new DefaultOptionsMethodException(Messages.MESSAGES.noResourceMethodFoundForOptions(), resBuilder.build());
485500
}
486501
else

resteasy-jaxrs/src/main/java/org/jboss/resteasy/spi/DefaultOptionsMethodException.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* does not have a Java method that supports OPTIONS. RESTEasy provides a default behavior for OPTIONS.
88
* If you want to override this behavior, write an exception mapper for this exception.
99
*/
10+
@Deprecated
1011
public class DefaultOptionsMethodException extends Failure
1112
{
1213
public DefaultOptionsMethodException(final String s, final Response response)

0 commit comments

Comments
 (0)