Repository navigation
Handle an unknown HTTP method instead of raising IllegalArgumentException #2043
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,8 @@ | |
| */ | ||
| package org.apache.struts2.interceptor.httpmethod; | ||
|
|
||
| import java.util.Locale; | ||
|
|
||
| /** | ||
| * Enum represents possible http request types | ||
| * | ||
|
|
@@ -36,8 +38,28 @@ public enum HttpMethod { | |
| CONNECT, | ||
| PATCH; | ||
|
|
||
| /** | ||
| * Returns the {@link HttpMethod} for the given request method, or {@code null} if it is not | ||
| * one of the methods this enum knows about. | ||
| * | ||
| * <p>Use this for the method of an incoming request. The client chooses that token freely, | ||
| * so an unrecognised value is ordinary input rather than a programming error, and must not | ||
| * raise.</p> | ||
| */ | ||
| public static HttpMethod parseOrNull(String httpRequestMethod) { | ||
| if (httpRequestMethod == null) { | ||
| return null; | ||
| } | ||
|
|
||
| try { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: catching return Arrays.stream(values())
.filter(method -> method.name().equalsIgnoreCase(httpRequestMethod))
.findFirst()
.orElse(null); |
||
| return valueOf(httpRequestMethod.toUpperCase(Locale.ROOT)); | ||
| } catch (IllegalArgumentException e) { | ||
| return null; | ||
| } | ||
| } | ||
|
|
||
| public static HttpMethod parse(String httpRequestMethod) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. After this change Simplest fix: have |
||
| return valueOf(httpRequestMethod.toUpperCase()); | ||
| return valueOf(httpRequestMethod.toUpperCase(Locale.ROOT)); | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -95,7 +95,10 @@ public String intercept(ActionInvocation invocation) throws Exception { | |
| if (action instanceof HttpMethodAware) { | ||
| LOG.debug("Action: {} implements: {}, setting request method: {}", | ||
| action, HttpMethodAware.class.getSimpleName(), request.getMethod()); | ||
| ((HttpMethodAware) (action)).setMethod(HttpMethod.parse(request.getMethod())); | ||
| HttpMethod requestedHttpMethod = HttpMethod.parseOrNull(request.getMethod()); | ||
| if (requestedHttpMethod != null) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Skipping the call changes the The debug line just above also still says "setting request method: PROPFIND" when nothing is set; worth adjusting once the null is passed through. |
||
| ((HttpMethodAware) (action)).setMethod(requestedHttpMethod); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The four new tests exercise the enum directly, so none of them reach this line. I reverted this hunk locally and Please add a test to public void testHttpMethodAwareActionWithUnknownRequestMethod() throws Exception {
HttpMethodsTestAction action = new HttpMethodsTestAction();
prepareActionInvocation(action, actionConfig());
MockHttpServletResponse response = prepareRequest("PROPFIND");
String resultName = interceptor.intercept(invocation);
assertEquals(Action.NONE, resultName);
assertEquals(HttpServletResponse.SC_METHOD_NOT_ALLOWED, response.getStatus());
assertEquals("POST", response.getHeader("Allow"));
assertNull(action.getHttpMethod());
} |
||
| } | ||
| } | ||
|
|
||
| if (invocation.getProxy().isMethodSpecified()) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |
|
|
||
| import static org.junit.Assert.assertEquals; | ||
| import static org.junit.Assert.assertNotNull; | ||
| import static org.junit.Assert.assertNull; | ||
|
|
||
| public class HttpMethodTest { | ||
|
|
||
|
|
@@ -55,4 +56,58 @@ public void shouldValueOfThrowsException() { | |
| assertEquals(expected.getClass(), IllegalArgumentException.class); | ||
| } | ||
|
|
||
|
|
||
| @Test | ||
| public void shouldParseUnknownRequestMethod_asNull_notRaise() { | ||
| // given : a request method this enum does not know about, e.g. a WebDAV verb | ||
| String httpRequestMethod = "PROPFIND"; | ||
|
|
||
| // when | ||
| HttpMethod httpMethod = HttpMethod.parseOrNull(httpRequestMethod); | ||
|
|
||
| // then | ||
| assertNull(httpMethod); | ||
| } | ||
|
|
||
| @Test | ||
| public void shouldParseKnownRequestMethod_regardlessOfCase() { | ||
| // given | ||
| String httpRequestMethod = "get"; | ||
|
|
||
| // when | ||
| HttpMethod httpMethod = HttpMethod.parseOrNull(httpRequestMethod); | ||
|
|
||
| // then | ||
| assertEquals(HttpMethod.GET, httpMethod); | ||
| } | ||
|
|
||
| @Test | ||
| public void shouldParseNullRequestMethod_asNull() { | ||
| // given | ||
| String httpRequestMethod = null; | ||
|
|
||
| // when | ||
| HttpMethod httpMethod = HttpMethod.parseOrNull(httpRequestMethod); | ||
|
|
||
| // then | ||
| assertNull(httpMethod); | ||
| } | ||
|
|
||
| @Test | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Minor: JUnit 4.13 has assertThrows(IllegalArgumentException.class, () -> HttpMethod.parse("PROPFIND")); |
||
| public void shouldStillRejectUnknownMethodInConfiguration() { | ||
| // given : configuration is trusted input, an unknown name there is a real error | ||
| String configuredMethod = "PROPFIND"; | ||
|
|
||
| // when | ||
| Throwable expected = null; | ||
| try { | ||
| HttpMethod.parse(configuredMethod); | ||
| } catch (IllegalArgumentException e) { | ||
| expected = e; | ||
| } | ||
|
|
||
| // then | ||
| assertNotNull(expected); | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor: the second paragraph is the rationale from the PR description, which is where it is best kept. A one-liner is enough here:
@return the matching method, or null when the request method is not one of the constants.