Skip to content

Commit

Permalink
Merge pull request #40 from breakponchito/FISH-9690-filtering-incorre…
Browse files Browse the repository at this point in the history
…ct-characters-from-header-rfc-9110-payara5

Fish 9690 filtering incorrect characters from header rfc 9110
  • Loading branch information
breakponchito authored Dec 12, 2024
2 parents a789abe + 8ec8902 commit de7177e
Show file tree
Hide file tree
Showing 7 changed files with 541 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ public void testClientCloseConnection() throws Exception {
s.setSoLinger(false, 0);
s.setSoTimeout(500);
OutputStream os = s.getOutputStream();
String a = "GET " + alias + " HTTP/1.1\n" + "Host: localhost:" + PORT + "\n\n";
String a = "GET " + alias + " HTTP/1.1\r\n" + "Host: localhost:" + PORT + "\r\n\r\n";
System.out.println(" " + a);
os.write(a.getBytes());
os.flush();
Expand Down Expand Up @@ -162,11 +162,11 @@ public void service(Request request, Response response) throws Exception {
Socket s = new Socket("localhost", PORT);
s.setSoTimeout(10 * 1000);
OutputStream os = s.getOutputStream();
String cometRequest = "GET " + alias + " HTTP/1.1\nHost: localhost:" + PORT + "\n\n";
String staticRequest = "GET /static HTTP/1.1\nHost: localhost:" + PORT + "\n\n";
String cometRequest = "GET " + alias + " HTTP/1.1\r\nHost: localhost:" + PORT + "\r\n\r\n";
String staticRequest = "GET /static HTTP/1.1\r\nHost: localhost:" + PORT + "\r\n\r\n";


String lastCometRequest = "GET " + alias + " HTTP/1.1\n"+"Host: localhost:" + PORT + "\nConnection: close\n\n";
String lastCometRequest = "GET " + alias + " HTTP/1.1\r\n"+"Host: localhost:" + PORT + "\r\nConnection: close\r\n\r\n";


String pipelinedRequest1 = cometRequest + staticRequest + cometRequest;
Expand Down Expand Up @@ -254,8 +254,8 @@ public void service(Request request, Response response) throws Exception {
Socket s = new Socket("localhost", PORT);
s.setSoTimeout(10 * 1000);
OutputStream os = s.getOutputStream();
String cometRequest = "GET " + alias + " HTTP/1.1\nHost: localhost:" + PORT + "\n\n";
String staticRequest = "GET /static HTTP/1.1\nHost: localhost:" + PORT + "\n\n";
String cometRequest = "GET " + alias + " HTTP/1.1\r\nHost: localhost:" + PORT + "\r\n\r\n";
String staticRequest = "GET /static HTTP/1.1\r\nHost: localhost:" + PORT + "\r\n\r\n";


try {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2010, 2017 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2010, 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -31,6 +31,7 @@
import org.glassfish.grizzly.http.util.ByteChunk;
import org.glassfish.grizzly.http.util.CacheableDataChunk;
import org.glassfish.grizzly.http.util.Constants;
import org.glassfish.grizzly.http.util.CookieHeaderParser;
import org.glassfish.grizzly.http.util.DataChunk;
import org.glassfish.grizzly.http.util.Header;
import org.glassfish.grizzly.http.util.MimeHeaders;
Expand Down Expand Up @@ -129,6 +130,14 @@ public abstract class HttpCodecFilter extends HttpBaseFilter
* @see #setRemoveHandledContentEncodingHeaders
*/
private boolean removeHandledContentEncodingHeaders = false;

public static final String STRICT_HEADER_NAME_VALIDATION_RFC_9110 = "org.glassfish.grizzly.http.STRICT_HEADER_NAME_VALIDATION_RFC_9110";

public static final String STRICT_HEADER_VALUE_VALIDATION_RFC_9110 = "org.glassfish.grizzly.http.STRICT_HEADER_VALUE_VALIDATION_RFC_9110";

private static final boolean isStrictHeaderNameValidationSet = Boolean.parseBoolean((System.getProperty(STRICT_HEADER_NAME_VALIDATION_RFC_9110) == null) ? "true" : System.getProperty(STRICT_HEADER_NAME_VALIDATION_RFC_9110));

private static final boolean isStrictHeaderValueValidationSet = Boolean.parseBoolean((System.getProperty(STRICT_HEADER_VALUE_VALIDATION_RFC_9110) == null) ? "true": System.getProperty(STRICT_HEADER_VALUE_VALIDATION_RFC_9110));

/**
* File cache probes
Expand Down Expand Up @@ -809,6 +818,10 @@ protected boolean parseHeaderFromBytes(final HttpHeader httpHeader,
return false;
}

if (parsingState.subState == 0 && parsingState.start == -1) { // EOL. ignore field-lines
return true;
}

parsingState.subState++;
parsingState.start = -1;
}
Expand Down Expand Up @@ -880,6 +893,23 @@ protected boolean parseHeaderName(final HttpHeader httpHeader,
b -= Constants.LC_OFFSET;
}
input[offset] = b;
} else if (isStrictHeaderNameValidationSet && b == Constants.CR) {
parsingState.offset = offset - arrayOffs;
final int eol = checkEOL(parsingState, input, end);
if (eol == 0) { // EOL
// the offset is already increased in the check
parsingState.subState = 0;
parsingState.start = -1;
return true;
} else if (eol == -2) { // not enough data
// by keeping the offset unchanged, we will recheck the EOL at the next opportunity.
break;
}
}

if (isStrictHeaderNameValidationSet && !CookieHeaderParser.isToken(b)) {
throw new IllegalStateException(
"An invalid character 0x" + Integer.toHexString(b) + " was found in the header name");
}

offset++;
Expand All @@ -903,6 +933,20 @@ protected static int parseHeaderValue(final HttpHeader httpHeader,
while (offset < limit) {
final byte b = input[offset];
if (b == Constants.CR) {
if (isStrictHeaderValueValidationSet) {
if (offset + 1 < limit) {
final byte b2 = input[offset + 1];
if (b2 == Constants.LF) {
// Continue for next parsing without the validation
offset++;
continue;
}
} else {
// not enough data
parsingState.offset = offset - arrayOffs;
return -1;
}
}
} else if (b == Constants.LF) {
// Check if it's not multi line header
if (offset + 1 < limit) {
Expand All @@ -912,6 +956,11 @@ protected static int parseHeaderValue(final HttpHeader httpHeader,
parsingState.offset = offset + 2 - arrayOffs;
return -2;
} else {
final byte b3 = input[offset - 1];
if (!(b3 == Constants.CR) && isStrictHeaderValueValidationSet) {
throw new IllegalStateException(
"An invalid character 0x" + Integer.toHexString(b) + " was found in the header value");
}
parsingState.offset = offset + 1 - arrayOffs;
finalizeKnownHeaderValues(httpHeader, parsingState, input,
arrayOffs + parsingState.start,
Expand Down Expand Up @@ -940,6 +989,10 @@ protected static int parseHeaderValue(final HttpHeader httpHeader,
parsingState.checkpoint2 = parsingState.checkpoint;
}

if (isStrictHeaderValueValidationSet && !CookieHeaderParser.isText(b)) {
throw new IllegalStateException(
"An invalid character 0x" + Integer.toHexString(b) + " was found in the header value");
}
offset++;
}
parsingState.offset = offset - arrayOffs;
Expand Down Expand Up @@ -1093,6 +1146,10 @@ protected boolean parseHeaderFromBuffer(final HttpHeader httpHeader,
return false;
}

if (parsingState.subState == 0 && parsingState.start == -1) { // EOL. ignore field-lines
return true;
}

parsingState.subState++;
parsingState.start = -1;
}
Expand Down Expand Up @@ -1159,6 +1216,23 @@ protected boolean parseHeaderName(final HttpHeader httpHeader,
b -= Constants.LC_OFFSET;
}
input.put(offset, b);
} else if (isStrictHeaderNameValidationSet && b == Constants.CR) {
parsingState.offset = offset;
final int eol = checkEOL(parsingState, input);
if (eol == 0) { // EOL
// the offset is already increased in the check
parsingState.subState = 0;
parsingState.start = -1;
return true;
} else if (eol == -2) { // not enough data
// by keeping the offset unchanged, we will recheck the EOL at the next opportunity.
break;
}
}

if (isStrictHeaderNameValidationSet && !CookieHeaderParser.isToken(b)) {
throw new IllegalStateException(
"An invalid character 0x" + Integer.toHexString(b) + " was found in the header name");
}

offset++;
Expand All @@ -1180,6 +1254,20 @@ protected static int parseHeaderValue(final HttpHeader httpHeader,
while(offset < limit) {
final byte b = input.get(offset);
if (b == Constants.CR) {
if (isStrictHeaderValueValidationSet) {
if (offset + 1 < limit) {
final byte b2 = input.get(offset + 1);
if (b2 == Constants.LF) {
// Continue for next parsing without the validation
offset++;
continue;
}
} else {
// not enough data
parsingState.offset = offset;
return -1;
}
}
} else if (b == Constants.LF) {
// Check if it's not multi line header
if (offset + 1 < limit) {
Expand All @@ -1189,6 +1277,11 @@ protected static int parseHeaderValue(final HttpHeader httpHeader,
parsingState.offset = offset + 2;
return -2;
} else {
final byte b3 = input.get(offset - 1);
if (!(b3 == Constants.CR) && isStrictHeaderValueValidationSet) {
throw new IllegalStateException(
"An invalid character 0x" + Integer.toHexString(b) + " was found in the header value");
}
parsingState.offset = offset + 1;
finalizeKnownHeaderValues(httpHeader, parsingState, input,
parsingState.start, parsingState.checkpoint2);
Expand All @@ -1215,6 +1308,10 @@ protected static int parseHeaderValue(final HttpHeader httpHeader,
parsingState.checkpoint2 = parsingState.checkpoint;
}

if (isStrictHeaderValueValidationSet && !CookieHeaderParser.isText(b)) {
throw new IllegalStateException(
"An invalid character 0x" + Integer.toHexString(b) + " was found in the header value");
}
offset++;
}
parsingState.offset = offset;
Expand Down
Loading

0 comments on commit de7177e

Please sign in to comment.