Skip to content

Commit 4cef69c

Browse files
authored
Enhance HTTP Compliance CRLF modes (#12564)
Added modes to allow strict requirement for CRLF termination of headers and/or chunks
1 parent 7be7d0e commit 4cef69c

File tree

10 files changed

+1588
-936
lines changed

10 files changed

+1588
-936
lines changed

documentation/jetty/modules/code/examples/src/main/java/org/eclipse/jetty/docs/programming/server/ServerDocs.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ public void httpCompliance()
271271
{
272272
// tag::httpCompliance[]
273273
HttpConfiguration httpConfiguration = new HttpConfiguration();
274-
httpConfiguration.setHttpCompliance(HttpCompliance.RFC7230);
274+
httpConfiguration.setHttpCompliance(HttpCompliance.RFC9110);
275275
// end::httpCompliance[]
276276
}
277277

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

283-
// RFC7230 compliance, but allow Violation.MULTIPLE_CONTENT_LENGTHS.
284-
HttpCompliance customHttpCompliance = HttpCompliance.from("RFC7230,MULTIPLE_CONTENT_LENGTHS");
283+
// RFC9110 compliance, but allow Violation.MULTIPLE_CONTENT_LENGTHS.
284+
HttpCompliance customHttpCompliance = HttpCompliance.from("RFC9110,MULTIPLE_CONTENT_LENGTHS");
285285

286286
httpConfiguration.setHttpCompliance(customHttpCompliance);
287287
// end::httpComplianceCustom[]

documentation/jetty/modules/operations-guide/pages/modules/standard.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ Among the configurable properties, the most relevant are:
558558
Configures the compliance to HTTP specifications.
559559
The value could be:
560560

561-
* One of the predefined link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] constants, such as `RFC7230` or `RFC2616`.
561+
* One of the predefined link:{javadoc-url}/org/eclipse/jetty/http/HttpCompliance.html[`HttpCompliance`] constants, such as `RFC9110`, RFC7230` or `RFC2616`.
562562
For example: `jetty.httpConfig.compliance=RFC2616`.
563563
* 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.
564564
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`).

documentation/jetty/modules/programming-guide/pages/server/compliance.adoc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ There are compliance modes provided for:
2525

2626
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>>).
2727

28-
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.
28+
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.
2929

3030
[[http]]
3131
== HTTP Compliance Modes
@@ -37,11 +37,12 @@ In 1995, when Jetty was first implemented, there were no RFC specification of HT
3737
* https://datatracker.ietf.org/doc/html/rfc2616[RFC 2616] for HTTP/1.1 bis in 1999
3838
* 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
3939
* https://datatracker.ietf.org/doc/html/rfc7540[RFC 7540] for HTTP/2.0 in 2015
40+
* 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
4041

4142
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).
4243
Therefore, upgrading to a newer Jetty version may cause runtime behavior differences that may break your applications.
4344

44-
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`]).
45+
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`]).
4546

4647
For example:
4748

jetty-core/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ public class HttpClient extends ContainerLifeCycle implements AutoCloseable
131131
private boolean strictEventOrdering = false;
132132
private long destinationIdleTimeout;
133133
private String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode());
134-
private HttpCompliance httpCompliance = HttpCompliance.RFC7230;
134+
private HttpCompliance httpCompliance = HttpCompliance.RFC9110;
135135
private String defaultRequestContentType = "application/octet-stream";
136136
private boolean useInputDirectByteBuffers = true;
137137
private boolean useOutputDirectByteBuffers = true;
@@ -917,7 +917,7 @@ public void setMaxRedirects(int maxRedirects)
917917

918918
/**
919919
* Gets the http compliance mode for parsing http responses.
920-
* The default http compliance level is {@link HttpCompliance#RFC7230} which is the latest HTTP/1.1 specification
920+
* The default http compliance level is {@link HttpCompliance#RFC9110} which is the latest HTTP specification
921921
*
922922
* @return the HttpCompliance instance
923923
*/

jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -54,28 +54,28 @@ public enum Violation implements ComplianceViolation
5454
* match and handle fields names insensitively and this violation only affects how the names are reported to the application.
5555
* There is a small performance and garbage impact of using this mode.
5656
*/
57-
CASE_SENSITIVE_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2", "Field name is case-insensitive"),
57+
CASE_SENSITIVE_FIELD_NAME("https://datatracker.ietf.org/doc/html/rfc9110#name-field-names", "Field name is case-insensitive"),
5858

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

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

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

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

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

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

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

116116
/**
117117
* Since <a href="https://www.rfc-editor.org/rfc/rfc7230#section-2.7.1">RFC 7230</a>, the HTTP protocol
118118
* should reject a request if the Host headers contains an invalid / unsafe authority.
119-
* A deployment may include this violation to allow unsafe host headesr on a received request.
119+
* A deployment may include this violation to allow unsafe host headers on a received request.
120120
*/
121-
UNSAFE_HOST_HEADER("https://www.rfc-editor.org/rfc/rfc7230#section-2.7.1", "Invalid Authority"),
121+
UNSAFE_HOST_HEADER("https://datatracker.ietf.org/doc/html/rfc9112#name-request-target", "Invalid Authority"),
122122

123123
/**
124124
* Since <a href="https://www.rfc-editor.org/rfc/rfc7230#section-5.4">RFC 7230: Section 5.4</a>, the HTTP protocol
125125
* must reject a request if the target URI has an authority that is different than a provided Host header.
126126
* A deployment may include this violation to allow different values on the target URI and the Host header on a received request.
127127
*/
128-
MISMATCHED_AUTHORITY("https://www.rfc-editor.org/rfc/rfc7230#section-5.4", "Mismatched Authority");
128+
MISMATCHED_AUTHORITY("https://datatracker.ietf.org/doc/html/rfc9112#name-request-target", "Mismatched Authority"),
129+
130+
/**
131+
* Allow LF termination of start line and header fields.
132+
*/
133+
LF_HEADER_TERMINATION("https://www.rfc-editor.org/rfc/rfc9112.html#section-2.2", "LF line terminator in header"),
134+
135+
/**
136+
* Allow LF termination of chunk headers and chunks
137+
*/
138+
LF_CHUNK_TERMINATION("https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1", "LF line terminator in chunk");
129139

130140
private final String url;
131141
private final String description;
@@ -167,10 +177,19 @@ public String getDescription()
167177
public static final String VIOLATIONS_ATTR = ComplianceViolation.CapturingListener.VIOLATIONS_ATTR_KEY;
168178

169179
/**
170-
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc7230">RFC 7230</a>
171-
* with no known violations.
180+
* The HttpCompliance mode that supports no known violations.
181+
*/
182+
public static final HttpCompliance STRICT = new HttpCompliance("STRICT", noneOf(Violation.class));
183+
184+
/**
185+
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc9110">RFC 9110</a>.
186+
*/
187+
public static final HttpCompliance RFC9110 = new HttpCompliance("RFC9110", of(Violation.LF_HEADER_TERMINATION));
188+
189+
/**
190+
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc7230">RFC 7230</a>.
172191
*/
173-
public static final HttpCompliance RFC7230 = new HttpCompliance("RFC7230", noneOf(Violation.class));
192+
public static final HttpCompliance RFC7230 = new HttpCompliance("RFC7230", of(Violation.LF_CHUNK_TERMINATION, Violation.LF_HEADER_TERMINATION));
174193

175194
/**
176195
* The HttpCompliance mode that supports <a href="https://tools.ietf.org/html/rfc2616">RFC 7230</a>
@@ -179,7 +198,9 @@ public String getDescription()
179198
public static final HttpCompliance RFC2616 = new HttpCompliance("RFC2616", of(
180199
Violation.HTTP_0_9,
181200
Violation.MULTILINE_FIELD_VALUE,
182-
Violation.MISMATCHED_AUTHORITY
201+
Violation.MISMATCHED_AUTHORITY,
202+
Violation.LF_CHUNK_TERMINATION,
203+
Violation.LF_HEADER_TERMINATION
183204
));
184205

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

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

208229
/**

0 commit comments

Comments
 (0)