Merge remote-tracking branch 'origin/jetty-11.0.x' into jetty-12.0.x
# Conflicts: # jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ForwardedRequestCustomizerTest.java # jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/Request.java # jetty-ee9/jetty-ee9-nested/src/test/java/org/eclipse/jetty/ee9/nested/RequestTest.java
This commit is contained in:
commit
4aa6bca630
|
@ -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 <a href="https://www.rfc-editor.org/rfc/rfc7230#section-5.4">RFC 7230: Section 5.4</a>, 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 <a href="https://tools.ietf.org/html/rfc2616">RFC 7230</a>
|
||||
* 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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 <a href="https://www.rfc-editor.org/rfc/rfc2616#section-5.2">RFC 2616 - Section 5.2 - The Resource Identified by a Request</a>
|
||||
*/
|
||||
@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;
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -22,6 +22,12 @@
|
|||
<Set name="sendDateHeader">false</Set>
|
||||
<Set name="headerCacheSize">1024</Set>
|
||||
|
||||
<Set name="httpCompliance">
|
||||
<Call class="org.eclipse.jetty.http.HttpCompliance" name="from">
|
||||
<Arg>RFC2616</Arg>
|
||||
</Call>
|
||||
</Set>
|
||||
|
||||
<!-- Uncomment to enable handling of X-Forwarded- style headers
|
||||
<Call name="addCustomizer">
|
||||
<Arg><New class="org.eclipse.jetty.server.ForwardedRequestCustomizer"/></Arg>
|
||||
|
|
|
@ -322,7 +322,7 @@ public class Request implements HttpServletRequest
|
|||
cookieValue = cookieFields.get("value");
|
||||
cookieMaxAge = cookieFields.get("max-age") != null ? Long.parseLong(cookieFields.get("max-age")) : -1;
|
||||
}
|
||||
|
||||
|
||||
if (cookieMaxAge > 0)
|
||||
cookies.put(cookieName, cookieValue);
|
||||
else
|
||||
|
|
|
@ -901,6 +901,19 @@ public class RequestTest
|
|||
i = 0;
|
||||
assertThat(response, containsString("400 Bad"));
|
||||
|
||||
results.clear();
|
||||
response = _connector.getResponse(
|
||||
"GET http://myhost:8888/ HTTP/1.1\n" +
|
||||
"Host: myhost:8888\n" +
|
||||
"Connection: close\n" +
|
||||
"\n");
|
||||
i = 0;
|
||||
assertThat(response, containsString("200 OK"));
|
||||
assertEquals("http://myhost:8888/", results.get(i++));
|
||||
assertEquals("0.0.0.0", results.get(i++));
|
||||
assertEquals("myhost", results.get(i++));
|
||||
assertEquals("8888", results.get(i));
|
||||
|
||||
results.clear();
|
||||
response = _connector.getResponse(
|
||||
"GET / HTTP/1.1\n" +
|
||||
|
|
Loading…
Reference in New Issue