Skip to content

Commit 061c51b

Browse files
committed
SONARJAVA-5909 FN on S3752 when @RequestMapping in class
1 parent c5519e7 commit 061c51b

4 files changed

Lines changed: 63 additions & 9 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"ruleKey": "S3752",
33
"hasTruePositives": true,
4-
"falseNegatives": 26,
4+
"falseNegatives": 38,
55
"falsePositives": 0
66
}
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"ruleKey": "S4488",
33
"hasTruePositives": false,
4-
"falseNegatives": 14,
4+
"falseNegatives": 20,
55
"falsePositives": 0
6-
}
6+
}

java-checks-test-sources/default/src/main/java/checks/spring/SpringRequestMappingMethodCheckSample.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,39 @@ String get() {
6464
return "Hello from get";
6565
}
6666

67+
@RequestMapping(value = "/post", method = RequestMethod.POST) // Noncompliant
68+
String post() {
69+
return "Hello from post";
70+
}
71+
72+
@RequestMapping(value = "/put", method = RequestMethod.PUT) // Noncompliant
73+
String put() {
74+
return "Hello from put";
75+
}
76+
77+
@RequestMapping(value = "/delete", method = RequestMethod.DELETE) // Noncompliant
78+
String delete() {
79+
return "Hello from delete";
80+
}
81+
}
82+
83+
@RestController
84+
@RequestMapping(path = "/update", method = RequestMethod.POST)
85+
public static class UpdateController {
86+
@RequestMapping(value = "/", method = RequestMethod.GET) // Noncompliant
87+
String get() {
88+
return "Hello from get";
89+
}
90+
91+
@RequestMapping(value = "/head", method = RequestMethod.HEAD) // Noncompliant
92+
String head() {
93+
return "Hello from head";
94+
}
95+
96+
@RequestMapping(value = "/delete", method = RequestMethod.DELETE)
97+
String delete() {
98+
return "Hello from delete";
99+
}
67100
}
68101

69102
public static class DerivedController extends OtherController {

java-checks/src/main/java/org/sonar/java/checks/spring/SpringRequestMappingMethodCheck.java

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,13 @@ public class SpringRequestMappingMethodCheck extends IssuableSubscriptionVisitor
4545
private static final String REQUEST_METHOD = "method";
4646
public static final String MESSAGE = "Make sure allowing safe and unsafe HTTP methods is safe here.";
4747

48+
private boolean classHasSafeMethods = false;
49+
private boolean classHasUnsafeMethods = false;
50+
private boolean methodHasSafeMethods = false;
51+
private boolean methodHasUnsafeMethods = false;
52+
53+
private boolean isClassVisited = false;
54+
4855
@Override
4956
public List<Tree.Kind> nodesToVisit() {
5057
return Collections.singletonList(Tree.Kind.CLASS);
@@ -53,11 +60,12 @@ public List<Tree.Kind> nodesToVisit() {
5360
@Override
5461
public void visitNode(Tree tree) {
5562
ClassTree classTree = (ClassTree) tree;
63+
isClassVisited = true;
5664
findRequestMappingAnnotation(classTree.modifiers())
5765
.flatMap(SpringRequestMappingMethodCheck::findRequestMethods)
58-
.filter(SpringRequestMappingMethodCheck::mixSafeAndUnsafeMethods)
66+
.filter(this::mixSafeAndUnsafeMethods)
5967
.ifPresent(methods -> reportIssue(methods, MESSAGE));
60-
68+
isClassVisited = false;
6169
classTree.members().stream()
6270
.filter(member -> member.is(Tree.Kind.METHOD))
6371
.forEach(member -> checkMethod((MethodTree) member, classTree.symbol()));
@@ -69,9 +77,15 @@ private void checkMethod(MethodTree method, Symbol.TypeSymbol classSymbol) {
6977
.flatMap(SpringRequestMappingMethodCheck::findRequestMethods);
7078

7179
if (requestMethods.isPresent()) {
72-
requestMethods
73-
.filter(SpringRequestMappingMethodCheck::mixSafeAndUnsafeMethods)
74-
.ifPresent(methods -> reportIssue(methods, MESSAGE));
80+
Optional<ExpressionTree> expressionTree = requestMethods
81+
.filter(this::mixSafeAndUnsafeMethods);
82+
if (expressionTree.isPresent()) {
83+
reportIssue(expressionTree.get(), MESSAGE);
84+
} else {
85+
if ((classHasSafeMethods && methodHasUnsafeMethods) || (classHasUnsafeMethods && methodHasSafeMethods)) {
86+
reportIssue(requestMethods.get(), MESSAGE);
87+
}
88+
}
7589
} else if (requestMappingAnnotation.isPresent() && !inheritRequestMethod(classSymbol)) {
7690
reportIssue(requestMappingAnnotation.get().annotationType(), MESSAGE);
7791
}
@@ -109,9 +123,16 @@ private static boolean inheritRequestMethod(Symbol.TypeSymbol symbol) {
109123
return false;
110124
}
111125

112-
private static boolean mixSafeAndUnsafeMethods(ExpressionTree requestMethodsAssignment) {
126+
private boolean mixSafeAndUnsafeMethods(ExpressionTree requestMethodsAssignment) {
113127
HttpMethodVisitor visitor = new HttpMethodVisitor();
114128
requestMethodsAssignment.accept(visitor);
129+
if (isClassVisited) {
130+
classHasSafeMethods = visitor.hasSafeMethods;
131+
classHasUnsafeMethods = visitor.hasUnsafeMethods;
132+
} else {
133+
methodHasSafeMethods = visitor.hasSafeMethods;
134+
methodHasUnsafeMethods = visitor.hasUnsafeMethods;
135+
}
115136
return visitor.hasSafeMethods && visitor.hasUnsafeMethods;
116137
}
117138

0 commit comments

Comments
 (0)