Skip to content

Commit

Permalink
Expand the precondition tests to include PUT
Browse files Browse the repository at this point in the history
  • Loading branch information
markt-asf committed Dec 12, 2024
1 parent e523cd7 commit f5d3579
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 23 deletions.
13 changes: 7 additions & 6 deletions java/org/apache/catalina/servlets/DefaultServlet.java
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,10 @@ protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws Se
return;
}

if (!checkIfHeaders(req, resp, resource)) {
return;
}

InputStream resourceInputStream = null;

try {
Expand Down Expand Up @@ -2079,11 +2083,6 @@ protected boolean checkIfMatch(HttpServletRequest request, HttpServletResponse r
return true;
}
String resourceETag = generateETag(resource);
if (resourceETag == null) {
// if a current representation for the target resource is not present
response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED);
return false;
}

boolean hasAsteriskValue = false;// check existence of special header value '*'
int headerCount = 0;
Expand All @@ -2092,7 +2091,9 @@ protected boolean checkIfMatch(HttpServletRequest request, HttpServletResponse r
String headerValue = headerValues.nextElement();
if ("*".equals(headerValue)) {
hasAsteriskValue = true;
conditionSatisfied = true;
if (resourceETag != null) {
conditionSatisfied = true;
}
} else {
// RFC 7232 requires strong comparison for If-Match headers
Boolean matched = EntityTag.compareEntityTag(new StringReader(headerValue), false, resourceETag);
Expand Down
11 changes: 7 additions & 4 deletions java/org/apache/tomcat/util/http/parser/EntityTag.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,20 @@ public class EntityTag {
*/
public static Boolean compareEntityTag(StringReader input, boolean compareWeak, String resourceETag)
throws IOException {

Boolean result = Boolean.FALSE;

// The resourceETag may be weak so to do weak comparison remove /W
// before comparison
String comparisonETag;
if (compareWeak && resourceETag.startsWith("W/")) {
if (resourceETag == null) {
comparisonETag = null;
} else if (compareWeak && resourceETag.startsWith("W/")) {
comparisonETag = resourceETag.substring(2);
} else {
comparisonETag = resourceETag;
}

Boolean result = Boolean.FALSE;

while (true) {
boolean strong = false;
HttpParser.skipLws(input);
Expand All @@ -71,7 +74,7 @@ public static Boolean compareEntityTag(StringReader input, boolean compareWeak,
}

if (strong || compareWeak) {
if (comparisonETag.equals(value)) {
if (value.equals(comparisonETag)) {
result = Boolean.TRUE;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import java.util.Map;
import java.util.Map.Entry;

import jakarta.servlet.http.HttpServletResponse;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
Expand Down Expand Up @@ -117,12 +119,15 @@ public static Collection<Object[]> parameters() {

// RFC 9110, Section 13.2.2, Step 3, HEAD: If-None-Match with and without If-Modified-Since
for (DatePrecondition dateCondition : DatePrecondition.values()) {
parameterSets.add(new Object[] { useStrongEtag, task, null, null, EtagPrecondition.ALL,
dateCondition, null, null, Boolean.FALSE, task.equals(Task.POST_INDEX_HTML) ? SC_412 : SC_304 });
parameterSets.add(new Object[] { useStrongEtag, task, null, null, EtagPrecondition.EXACTLY,
dateCondition, null, null, Boolean.FALSE, task.equals(Task.POST_INDEX_HTML) ? SC_412 : SC_304 });
parameterSets.add(new Object[] { useStrongEtag, task, null, null, EtagPrecondition.IN,
dateCondition, null, null, Boolean.FALSE, task.equals(Task.POST_INDEX_HTML) ? SC_412 : SC_304 });
parameterSets
.add(new Object[] { useStrongEtag, task, null, null, EtagPrecondition.ALL, dateCondition,
null, null, Boolean.FALSE, task.equals(Task.POST_INDEX_HTML) ? SC_412 : SC_304 });
parameterSets.add(
new Object[] { useStrongEtag, task, null, null, EtagPrecondition.EXACTLY, dateCondition,
null, null, Boolean.FALSE, task.equals(Task.POST_INDEX_HTML) ? SC_412 : SC_304 });
parameterSets
.add(new Object[] { useStrongEtag, task, null, null, EtagPrecondition.IN, dateCondition,
null, null, Boolean.FALSE, task.equals(Task.POST_INDEX_HTML) ? SC_412 : SC_304 });
parameterSets.add(new Object[] { useStrongEtag, task, null, null, EtagPrecondition.NOT_IN,
dateCondition, null, null, Boolean.FALSE, SC_200 });
parameterSets.add(new Object[] { useStrongEtag, task, null, null, EtagPrecondition.INVALID,
Expand Down Expand Up @@ -224,17 +229,48 @@ public static Collection<Object[]> parameters() {
DatePrecondition.MULTI_IN_REV, Boolean.FALSE, SC_200 });
parameterSets.add(new Object[] { useStrongEtag, Task.GET_INDEX_HTML, null, null, null, null, null,
DatePrecondition.INVALID, Boolean.FALSE, SC_200 });

// PUT tests
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_EXIST_TXT, null, null, null, null, null, null,
Boolean.FALSE, SC_204 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_EXIST_TXT, EtagPrecondition.ALL, null, null, null,
null, null, Boolean.FALSE, SC_204 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_EXIST_TXT, EtagPrecondition.EXACTLY, null, null,
null, null, null, Boolean.FALSE, useStrongEtag.booleanValue() ? SC_204 : SC_412 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_EXIST_TXT, EtagPrecondition.IN, null, null, null,
null, null, Boolean.FALSE, useStrongEtag.booleanValue() ? SC_204 : SC_412 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_EXIST_TXT, EtagPrecondition.NOT_IN, null, null,
null, null, null, Boolean.FALSE, SC_412 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_EXIST_TXT, EtagPrecondition.INVALID, null, null,
null, null, null, Boolean.FALSE, SC_400 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_EXIST_TXT, EtagPrecondition.INVALID_ALL_PLUS_OTHER,
null, null, null, null, null, Boolean.FALSE, SC_400 });

parameterSets.add(new Object[] { useStrongEtag, Task.PUT_NEW_TXT, null, null, null, null, null, null,
Boolean.FALSE, SC_201 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_NEW_TXT, EtagPrecondition.ALL, null, null, null,
null, null, Boolean.FALSE, SC_412 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_NEW_TXT, EtagPrecondition.IN, null, null, null,
null, null, Boolean.FALSE, SC_412 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_NEW_TXT, EtagPrecondition.NOT_IN, null, null, null,
null, null, Boolean.FALSE, SC_412 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_NEW_TXT, EtagPrecondition.INVALID, null, null,
null, null, null, Boolean.FALSE, SC_400 });
parameterSets.add(new Object[] { useStrongEtag, Task.PUT_NEW_TXT, EtagPrecondition.INVALID_ALL_PLUS_OTHER,
null, null, null, null, null, Boolean.FALSE, SC_400 });
}

return parameterSets;
}


private static Integer SC_200 = Integer.valueOf(200);
private static Integer SC_206 = Integer.valueOf(206);
private static Integer SC_304 = Integer.valueOf(304);
private static Integer SC_400 = Integer.valueOf(400);
private static Integer SC_412 = Integer.valueOf(412);
private static Integer SC_200 = Integer.valueOf(HttpServletResponse.SC_OK);
private static Integer SC_201 = Integer.valueOf(HttpServletResponse.SC_CREATED);
private static Integer SC_204 = Integer.valueOf(HttpServletResponse.SC_NO_CONTENT);
private static Integer SC_206 = Integer.valueOf(HttpServletResponse.SC_PARTIAL_CONTENT);
private static Integer SC_304 = Integer.valueOf(HttpServletResponse.SC_NOT_MODIFIED);
private static Integer SC_400 = Integer.valueOf(HttpServletResponse.SC_BAD_REQUEST);
private static Integer SC_412 = Integer.valueOf(HttpServletResponse.SC_PRECONDITION_FAILED);


private enum HTTP_METHOD {
Expand Down Expand Up @@ -337,7 +373,8 @@ protected void genETagPrecondition(String strongETag, String weakETag, EtagPreco
break;
case IN:
headerValues.add("\"1a2b3c4d\"");
headerValues.add(weakETag + "," + strongETag + ",W/\"*\"");
headerValues.add((weakETag != null ? weakETag + "," : "") +
(strongETag != null ? strongETag + "," : "") + "W/\"*\"");
headerValues.add("\"abcdefg\"");
break;
case NOT_IN:
Expand Down Expand Up @@ -467,7 +504,7 @@ public void testPreconditions() throws Exception {

Wrapper w = Tomcat.addServlet(ctxt, "default", DefaultServlet.class.getName());
w.addInitParameter("readonly", "false");
w.addInitParameter("allowPartialPut", Boolean.toString(true));
w.addInitParameter("allowPartialPut", "true");
w.addInitParameter("useStrongETags", Boolean.toString(useStrongETags));
ctxt.addServletMappingDecoded("/", "default");

Expand Down

0 comments on commit f5d3579

Please sign in to comment.