Skip to content

Commit

Permalink
Enhance HTTP Compliance CRLF modes (#12564)
Browse files Browse the repository at this point in the history
Added modes to allow strict requirement for CRLF termination of headers and/or chunks
  • Loading branch information
gregw authored Nov 28, 2024
1 parent 7be7d0e commit 4cef69c
Show file tree
Hide file tree
Showing 10 changed files with 1,588 additions and 936 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ public void httpCompliance()
{
// tag::httpCompliance[]
HttpConfiguration httpConfiguration = new HttpConfiguration();
httpConfiguration.setHttpCompliance(HttpCompliance.RFC7230);
httpConfiguration.setHttpCompliance(HttpCompliance.RFC9110);
// end::httpCompliance[]
}

Expand All @@ -280,8 +280,8 @@ public void httpComplianceCustom()
// tag::httpComplianceCustom[]
HttpConfiguration httpConfiguration = new HttpConfiguration();

// RFC7230 compliance, but allow Violation.MULTIPLE_CONTENT_LENGTHS.
HttpCompliance customHttpCompliance = HttpCompliance.from("RFC7230,MULTIPLE_CONTENT_LENGTHS");
// RFC9110 compliance, but allow Violation.MULTIPLE_CONTENT_LENGTHS.
HttpCompliance customHttpCompliance = HttpCompliance.from("RFC9110,MULTIPLE_CONTENT_LENGTHS");

httpConfiguration.setHttpCompliance(customHttpCompliance);
// end::httpComplianceCustom[]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,7 @@ Among the configurable properties, the most relevant are:
Configures the compliance to HTTP specifications.
The value could be:

* One of the predefined link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] constants, such as `RFC7230` or `RFC2616`.
* One of the predefined link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] constants, such as `RFC9110`, RFC7230` or `RFC2616`.
For example: `jetty.httpConfig.compliance=RFC2616`.
* A comma-separated list of violations to allow or forbid, as specified by the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html#from(java.lang.String)[`HttpCompliance.from(String)`] method.
For example, `jetty.httpConfig.compliance=RFC7230,MULTIPLE_CONTENT_LENGTHS` means that the HTTP compliance is that defined by `RFC7230`, but also allows the `HttpCompliance.Violation.MULTIPLE_CONTENT_LENGTHS`, so that requests that have multiple `Content-Length` headers are accepted (they would be rejected when using just `HttpCompliance.RFC7230`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ There are compliance modes provided for:

Compliance modes can be configured to allow violations from the RFC requirements, or in some cases to allow additional behaviors that Jetty has implemented in excess of the RFC (for example, to allow <<uri,ambiguous URIs>>).

For example, the HTTP RFCs require that request HTTP methods are https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1[case sensitive], however Jetty can allow case-insensitive HTTP methods by including the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.Violation.html#CASE_INSENSITIVE_METHOD[`HttpCompliance.Violation.CASE_INSENSITIVE_METHOD`] in the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] set of allowed violations.
For example, the HTTP RFCs require that request HTTP methods are https://datatracker.ietf.org/doc/html/rfc9110#section-9.1[case sensitive], however Jetty can allow case-insensitive HTTP methods by including the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.Violation.html#CASE_INSENSITIVE_METHOD[`HttpCompliance.Violation.CASE_INSENSITIVE_METHOD`] in the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] set of allowed violations.

[[http]]
== HTTP Compliance Modes
Expand All @@ -37,11 +37,12 @@ In 1995, when Jetty was first implemented, there were no RFC specification of HT
* https://datatracker.ietf.org/doc/html/rfc2616[RFC 2616] for HTTP/1.1 bis in 1999
* https://datatracker.ietf.org/doc/html/rfc7230[RFC 7230], https://datatracker.ietf.org/doc/html/rfc7231[RFC 7231], https://datatracker.ietf.org/doc/html/rfc7232[RFC 7232], https://datatracker.ietf.org/doc/html/rfc7233[RFC 7233], https://datatracker.ietf.org/doc/html/rfc7234[RFC 7234], https://datatracker.ietf.org/doc/html/rfc7235[RFC 7235] again for HTTP/1.1 in 2014
* https://datatracker.ietf.org/doc/html/rfc7540[RFC 7540] for HTTP/2.0 in 2015
* https://datatracker.ietf.org/doc/html/rfc9110[RFC 9110] for common HTTP semantics and https://datatracker.ietf.org/doc/html/rfc9112[RFC 9112] for HTTP/1.1

In addition to these evolving requirements, some earlier version of Jetty did not completely or strictly implement the RFC at the time (for example, case-insensitive HTTP methods).
Therefore, upgrading to a newer Jetty version may cause runtime behavior differences that may break your applications.

The link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.Violation.html[`HttpCompliance.Violation`] enumeration defines the RFC requirements that may be optionally enforced by Jetty, to support legacy deployments. These possible violations are grouped into modes by the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] class, which also defines several named modes that support common deployed sets of violations (with the default being link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html#RFC7230[`HttpCompliance.RFC7230`]).
The link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.Violation.html[`HttpCompliance.Violation`] enumeration defines the RFC requirements that may be optionally enforced by Jetty, to support legacy deployments. These possible violations are grouped into modes by the link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] class, which also defines several named modes that support common deployed sets of violations (with the default being link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html#RFC9110[`HttpCompliance.RFC9110`]).

For example:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public class HttpClient extends ContainerLifeCycle implements AutoCloseable
private boolean strictEventOrdering = false;
private long destinationIdleTimeout;
private String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
private HttpCompliance httpCompliance = HttpCompliance.RFC7230;
private HttpCompliance httpCompliance = HttpCompliance.RFC9110;
private String defaultRequestContentType = "application/octet-stream";
private boolean useInputDirectByteBuffers = true;
private boolean useOutputDirectByteBuffers = true;
Expand Down Expand Up @@ -917,7 +917,7 @@ public void setMaxRedirects(int maxRedirects)

/**
* Gets the http compliance mode for parsing http responses.
* The default http compliance level is {@link HttpCompliance#RFC7230} which is the latest HTTP/1.1 specification
* The default http compliance level is {@link HttpCompliance#RFC9110} which is the latest HTTP specification
*
* @return the HttpCompliance instance
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,28 +54,28 @@ public enum Violation implements ComplianceViolation
* match and handle fields names insensitively and this violation only affects how the names are reported to the application.
* There is a small performance and garbage impact of using this mode.
*/
CASE_SENSITIVE_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2", "Field name is case-insensitive"),
CASE_SENSITIVE_FIELD_NAME("https://datatracker.ietf.org/doc/html/rfc9110#name-field-names", "Field name is case-insensitive"),

/**
* The HTTP RFC(s) require that method names are case-sensitive, so that "{@code Get}" and "{@code GET}" are considered
* different methods. Jetty releases prior to 9.4 used a case-insensitive cache to match method names, thus this requirement
* was violated. Deployments which wish to retain this legacy violation can include this violation in the
* {@link HttpCompliance} mode.
*/
CASE_INSENSITIVE_METHOD("https://tools.ietf.org/html/rfc7230#section-3.1.1", "Method is case-sensitive"),
CASE_INSENSITIVE_METHOD("https://datatracker.ietf.org/doc/html/rfc9110#name-methods", "Method is case-sensitive"),

/**
* Since RFC 7230, the expectation that HTTP/0.9 is supported has been removed from the specification. If a deployment
* wished to accept HTTP/0.9 requests, then it can include this violation in it's {@link HttpCompliance} mode.
*/
HTTP_0_9("https://tools.ietf.org/html/rfc7230#appendix-A.2", "HTTP/0.9 not supported"),
HTTP_0_9("https://datatracker.ietf.org/doc/html/rfc9112#appendix-C.1", "HTTP/0.9 not supported"),

/**
* Since <a href="https://tools.ietf.org/html/rfc7230#section-3.2.4">RFC 7230</a>, the HTTP protocol no longer supports
* line folding, which allows a field value to be provided over several lines. Deployments that wish to receive folder
* field values may include this violation in their {@link HttpCompliance} mode.
*/
MULTILINE_FIELD_VALUE("https://tools.ietf.org/html/rfc7230#section-3.2.4", "Line Folding not supported"),
MULTILINE_FIELD_VALUE("https://datatracker.ietf.org/doc/html/rfc9112#name-obsolete-line-folding", "Line Folding not supported"),

/**
* Since <a href="https://tools.ietf.org/html/rfc7230#section-3.3.2">RFC 7230</a>, the HTTP protocol has required that
Expand All @@ -90,42 +90,52 @@ public enum Violation implements ComplianceViolation
* a request is invalid if it contains both a {@code Transfer-Encoding} field and {@code Content-Length} field.
* A deployment may include this violation to allow both fields to be in a received request.
*/
TRANSFER_ENCODING_WITH_CONTENT_LENGTH("https://tools.ietf.org/html/rfc7230#section-3.3.1", "Transfer-Encoding and Content-Length"),
TRANSFER_ENCODING_WITH_CONTENT_LENGTH("https://datatracker.ietf.org/doc/html/rfc9112#name-content-length", "Transfer-Encoding and Content-Length"),

/**
* Since <a href="https://tools.ietf.org/html/rfc7230#section-3.2.4">RFC 7230</a>, the HTTP protocol has required that
* a request header field has no white space after the field name and before the ':'.
* A deployment may include this violation to allow such fields to be in a received request.
*/
WHITESPACE_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4", "Whitespace not allowed after field name"),
WHITESPACE_AFTER_FIELD_NAME("https://datatracker.ietf.org/doc/html/rfc9112#name-field-syntax", "Whitespace not allowed after field name"),

/**
* Prior to <a href="https://tools.ietf.org/html/rfc7230#section-3.2">RFC 7230</a>, the HTTP protocol allowed a header
* line of a single token with neither a colon nor value following, to be interpreted as a field name with no value.
* A deployment may include this violation to allow such fields to be in a received request.
*/
NO_COLON_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2", "Fields must have a Colon"),
NO_COLON_AFTER_FIELD_NAME("https://datatracker.ietf.org/doc/html/rfc9112#name-field-syntax", "Fields must have a Colon"),

/**
* Since <a href="https://www.rfc-editor.org/rfc/rfc7230#section-5.4">RFC 7230: Section 5.4</a>, the HTTP protocol
* says that a Server must reject a request duplicate host headers.
* A deployment may include this violation to allow duplicate host headers on a received request.
*/
DUPLICATE_HOST_HEADERS("https://www.rfc-editor.org/rfc/rfc7230#section-5.4", "Duplicate Host Header"),
DUPLICATE_HOST_HEADERS("https://datatracker.ietf.org/doc/html/rfc9112#name-request-target", "Duplicate Host Header"),

/**
* Since <a href="https://www.rfc-editor.org/rfc/rfc7230#section-2.7.1">RFC 7230</a>, the HTTP protocol
* 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.
* A deployment may include this violation to allow unsafe host headers on a received request.
*/
UNSAFE_HOST_HEADER("https://www.rfc-editor.org/rfc/rfc7230#section-2.7.1", "Invalid Authority"),
UNSAFE_HOST_HEADER("https://datatracker.ietf.org/doc/html/rfc9112#name-request-target", "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");
MISMATCHED_AUTHORITY("https://datatracker.ietf.org/doc/html/rfc9112#name-request-target", "Mismatched Authority"),

/**
* Allow LF termination of start line and header fields.
*/
LF_HEADER_TERMINATION("https://www.rfc-editor.org/rfc/rfc9112.html#section-2.2", "LF line terminator in header"),

/**
* Allow LF termination of chunk headers and chunks
*/
LF_CHUNK_TERMINATION("https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1", "LF line terminator in chunk");

private final String url;
private final String description;
Expand Down Expand Up @@ -167,10 +177,19 @@ public String getDescription()
public static final String VIOLATIONS_ATTR = ComplianceViolation.CapturingListener.VIOLATIONS_ATTR_KEY;

/**
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc7230">RFC 7230</a>
* with no known violations.
* The HttpCompliance mode that supports no known violations.
*/
public static final HttpCompliance STRICT = new HttpCompliance("STRICT", noneOf(Violation.class));

/**
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc9110">RFC 9110</a>.
*/
public static final HttpCompliance RFC9110 = new HttpCompliance("RFC9110", of(Violation.LF_HEADER_TERMINATION));

/**
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc7230">RFC 7230</a>.
*/
public static final HttpCompliance RFC7230 = new HttpCompliance("RFC7230", noneOf(Violation.class));
public static final HttpCompliance RFC7230 = new HttpCompliance("RFC7230", of(Violation.LF_CHUNK_TERMINATION, Violation.LF_HEADER_TERMINATION));

/**
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc2616">RFC 7230</a>
Expand All @@ -179,7 +198,9 @@ public String getDescription()
public static final HttpCompliance RFC2616 = new HttpCompliance("RFC2616", of(
Violation.HTTP_0_9,
Violation.MULTILINE_FIELD_VALUE,
Violation.MISMATCHED_AUTHORITY
Violation.MISMATCHED_AUTHORITY,
Violation.LF_CHUNK_TERMINATION,
Violation.LF_HEADER_TERMINATION
));

/**
Expand All @@ -202,7 +223,7 @@ public String getDescription()
*/
public static final HttpCompliance RFC7230_LEGACY = RFC7230.with("RFC7230_LEGACY", Violation.CASE_INSENSITIVE_METHOD);

private static final List<HttpCompliance> KNOWN_MODES = Arrays.asList(RFC7230, RFC2616, LEGACY, RFC2616_LEGACY, RFC7230_LEGACY);
private static final List<HttpCompliance> KNOWN_MODES = Arrays.asList(STRICT, RFC9110, RFC7230, RFC2616, LEGACY, RFC2616_LEGACY, RFC7230_LEGACY);
private static final AtomicInteger __custom = new AtomicInteger();

/**
Expand Down
Loading

0 comments on commit 4cef69c

Please sign in to comment.