diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java
index 8e0a47d6924..1b9a20b9846 100644
--- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java
+++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java
@@ -117,7 +117,14 @@ public final class HttpCompliance implements ComplianceViolation.Mode
* should reject a request if the Host headers contains an invalid / unsafe authority.
* A deployment may include this violation to allow unsafe host headesr on a received request.
*/
- UNSAFE_HOST_HEADER("https://www.rfc-editor.org/rfc/rfc7230#section-2.7.1", "Invalid Authority");
+ UNSAFE_HOST_HEADER("https://www.rfc-editor.org/rfc/rfc7230#section-2.7.1", "Invalid Authority"),
+
+ /**
+ * Since RFC 7230: Section 5.4, the HTTP protocol
+ * must reject a request if the target URI has an authority that is different than a provided Host header.
+ * A deployment may include this violation to allow different values on the target URI and the Host header on a received request.
+ */
+ MISMATCHED_AUTHORITY("https://www.rfc-editor.org/rfc/rfc7230#section-5.4", "Mismatched Authority");
private final String url;
private final String description;
@@ -162,7 +169,11 @@ public final class HttpCompliance implements ComplianceViolation.Mode
* The HttpCompliance mode that supports RFC 7230
* with only the violations that differ from {@link #RFC7230}.
*/
- public static final HttpCompliance RFC2616 = new HttpCompliance("RFC2616", of(Violation.HTTP_0_9, Violation.MULTILINE_FIELD_VALUE));
+ public static final HttpCompliance RFC2616 = new HttpCompliance("RFC2616", of(
+ Violation.HTTP_0_9,
+ Violation.MULTILINE_FIELD_VALUE,
+ Violation.MISMATCHED_AUTHORITY
+ ));
/**
* A legacy HttpCompliance mode that allows all violations except case-insensitive methods.
diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
index c97d5cbb798..ad48badb429 100644
--- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
+++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java
@@ -42,7 +42,6 @@ import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java
index f1a86e1e774..41c1ed65c02 100644
--- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java
+++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java
@@ -75,6 +75,7 @@ import org.eclipse.jetty.util.thread.Invocable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.eclipse.jetty.http.HttpCompliance.Violation.MISMATCHED_AUTHORITY;
import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500;
/**
@@ -359,6 +360,30 @@ public class HttpConnection extends AbstractConnection implements Runnable, Writ
_useOutputDirectByteBuffers = useOutputDirectByteBuffers;
}
+ protected void onComplianceViolation(ComplianceViolation.Mode mode, ComplianceViolation violation, String details)
+ {
+ //TODO configure this somewhere else
+ //TODO what about cookie compliance
+ //TODO what about http2 & 3
+ //TODO test this in core
+ if (isRecordHttpComplianceViolations())
+ {
+ HttpStreamOverHTTP1 stream = _stream.get();
+ if (stream != null)
+ {
+ if (stream._complianceViolations == null)
+ {
+ stream._complianceViolations = new ArrayList<>();
+ }
+ String record = String.format("%s (see %s) in mode %s for %s in %s",
+ violation.getDescription(), violation.getURL(), mode, details, HttpConnection.this);
+ stream._complianceViolations.add(record);
+ if (LOG.isDebugEnabled())
+ LOG.debug(record);
+ }
+ }
+ }
+
@Override
public ByteBuffer onUpgradeFrom()
{
@@ -1086,26 +1111,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Writ
@Override
public void onComplianceViolation(ComplianceViolation.Mode mode, ComplianceViolation violation, String details)
{
- //TODO configure this somewhere else
- //TODO what about cookie compliance
- //TODO what about http2 & 3
- //TODO test this in core
- if (isRecordHttpComplianceViolations())
- {
- HttpStreamOverHTTP1 stream = _stream.get();
- if (stream != null)
- {
- if (stream._complianceViolations == null)
- {
- stream._complianceViolations = new ArrayList<>();
- }
- String record = String.format("%s (see %s) in mode %s for %s in %s",
- violation.getDescription(), violation.getURL(), mode, details, HttpConnection.this);
- stream._complianceViolations.add(record);
- if (LOG.isDebugEnabled())
- LOG.debug(record);
- }
- }
+ HttpConnection.this.onComplianceViolation(mode, violation, details);
}
}
@@ -1222,7 +1228,13 @@ public class HttpConnection extends AbstractConnection implements Runnable, Writ
if (_uri.isAbsolute())
{
if (!_hostField.getValue().equals(_uri.getAuthority()))
- throw new BadMessageException("Authority!=Host");
+ {
+ HttpCompliance httpCompliance = getHttpConfiguration().getHttpCompliance();
+ if (httpCompliance.allows(MISMATCHED_AUTHORITY))
+ onComplianceViolation(httpCompliance, MISMATCHED_AUTHORITY, _uri.asString());
+ else
+ throw new BadMessageException("Authority!=Host");
+ }
}
else
{
diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
index 7a5b24606a4..d8ddbd24a6d 100644
--- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
+++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java
@@ -20,6 +20,7 @@ import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Stream;
+import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.util.Callback;
import org.junit.jupiter.api.AfterEach;
@@ -64,7 +65,10 @@ public class ForwardedRequestCustomizerTest
// Default behavior Connector
HttpConnectionFactory http = new HttpConnectionFactory();
+ HttpCompliance mismatchedAuthorityHttpCompliance = HttpCompliance.RFC7230.with("Mismatched_Authority", HttpCompliance.Violation.MISMATCHED_AUTHORITY);
+ http.getHttpConfiguration().setHttpCompliance(mismatchedAuthorityHttpCompliance);
http.getHttpConfiguration().setSecurePort(443);
+
customizer = new ForwardedRequestCustomizer();
http.getHttpConfiguration().addCustomizer(customizer);
connector = new LocalConnector(server, http);
@@ -73,6 +77,7 @@ public class ForwardedRequestCustomizerTest
// Alternate behavior Connector
HttpConnectionFactory httpAlt = new HttpConnectionFactory();
httpAlt.getHttpConfiguration().setSecurePort(8443);
+ httpAlt.getHttpConfiguration().setHttpCompliance(mismatchedAuthorityHttpCompliance);
customizerAlt = new ForwardedRequestCustomizer();
httpAlt.getHttpConfiguration().addCustomizer(customizerAlt);
connectorAlt = new LocalConnector(server, httpAlt);
@@ -93,6 +98,7 @@ public class ForwardedRequestCustomizerTest
http.getHttpConfiguration().addCustomizer(customizerConfigured);
connectorConfigured = new LocalConnector(server, http);
+ connectorConfigured.getConnectionFactory(HttpConnectionFactory.class).getHttpConfiguration().setHttpCompliance(mismatchedAuthorityHttpCompliance);
server.addConnector(connectorConfigured);
RequestHandler handler = new RequestHandler();
diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
index 5e1cb473a16..a296dd716e6 100644
--- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
+++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/PartialRFC2616Test.java
@@ -17,6 +17,7 @@ import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
+import org.eclipse.jetty.http.HttpCompliance;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpParser;
@@ -48,6 +49,7 @@ public class PartialRFC2616Test
{
server = new Server();
connector = new LocalConnector(server);
+ connector.getConnectionFactory(HttpConfiguration.ConnectionFactory.class).getHttpConfiguration().setHttpCompliance(HttpCompliance.RFC2616);
connector.setIdleTimeout(10000);
server.addConnector(connector);
@@ -403,13 +405,20 @@ public class PartialRFC2616Test
}
+ /**
+ * @throws Exception
+ * @see RFC 2616 - Section 5.2 - The Resource Identified by a Request
+ */
@Test
@Disabled // TODO
public void test521() throws Exception
{
// Default Host
int offset = 0;
- String response = connector.getResponse("GET http://VirtualHost:8888/path/R1 HTTP/1.1\n" + "Host: wronghost\n" + "Connection: close\n" + "\n");
+ String response = connector.getResponse(
+ "GET http://VirtualHost:8888/path/R1 HTTP/1.1\n" +
+ "Host: wronghost\n" +
+ "Connection: close\n" + "\n");
offset = checkContains(response, offset, "HTTP/1.1 200", "Virtual host") + 1;
offset = checkContains(response, offset, "Virtual Dump", "Virtual host") + 1;
offset = checkContains(response, offset, "pathInContext=/path/R1", "Virtual host") + 1;
diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java
index c98b162aff6..c15f165703c 100644
--- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java
+++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/NcsaRequestLogTest.java
@@ -163,7 +163,7 @@ public class NcsaRequestLogTest
_connector.getResponse(
"GET http://hostname:8888/foo?name=value HTTP/1.1\n" +
- "Host: servername\n" +
+ "Host: hostname:8888\n" +
"\n");
String log = _entries.poll(5, TimeUnit.SECONDS);
assertThat(log, containsString("GET http://hostname:8888/foo?name=value"));
diff --git a/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-integration/src/test/resources/RFC2616Base.xml b/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-integration/src/test/resources/RFC2616Base.xml
index 9f6af74dd8e..b80ae305b73 100644
--- a/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-integration/src/test/resources/RFC2616Base.xml
+++ b/jetty-ee10/jetty-ee10-tests/jetty-ee10-test-integration/src/test/resources/RFC2616Base.xml
@@ -22,6 +22,12 @@
false
1024
+
+
+ RFC2616
+
+
+