diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java index 35d33ddafb7..9cae7f7997a 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java @@ -52,9 +52,11 @@ import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.http.HttpClientTransportOverHTTP; import org.eclipse.jetty.client.util.FormContentProvider; +import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpMethod; +import org.eclipse.jetty.http.HttpParser; import org.eclipse.jetty.http.HttpScheme; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ClientConnectionFactory; @@ -147,6 +149,7 @@ public class HttpClient extends ContainerLifeCycle private boolean removeIdleDestinations = false; private boolean connectBlocking = false; private String name = getClass().getSimpleName() + "@" + Integer.toHexString(hashCode()); + private HttpCompliance httpCompliance = HttpCompliance.RFC7230; /** * Creates a {@link HttpClient} instance that can perform requests to non-TLS destinations only @@ -972,6 +975,25 @@ public class HttpClient extends ContainerLifeCycle { } + /** + * 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 + */ + public HttpCompliance getHttpCompliance() + { + return httpCompliance; + } + + /** + * Sets the http compliance mode for parsing http responses. + * This affect how weak the {@link HttpParser} parses http responses and which http protocol level is supported + * @param httpCompliance The compliance level which is used to actually parse http responses + */ + public void setHttpCompliance(HttpCompliance httpCompliance) + { + this.httpCompliance = httpCompliance; + } + /** * @return whether request events must be strictly ordered * @see #setStrictEventOrdering(boolean) diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java index 387d6f2b925..4dbd7acec00 100644 --- a/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java +++ b/jetty-client/src/main/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTP.java @@ -26,6 +26,7 @@ import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.client.HttpReceiver; import org.eclipse.jetty.client.HttpResponse; import org.eclipse.jetty.client.HttpResponseException; +import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpParser; @@ -38,13 +39,14 @@ import org.eclipse.jetty.util.CompletableCallback; public class HttpReceiverOverHTTP extends HttpReceiver implements HttpParser.ResponseHandler { - private final HttpParser parser = new HttpParser(this); + private final HttpParser parser; private ByteBuffer buffer; private boolean shutdown; public HttpReceiverOverHTTP(HttpChannelOverHTTP channel) { super(channel); + parser = new HttpParser(this, -1, channel.getHttpDestination().getHttpClient().getHttpCompliance()); } @Override diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java index f81010bca59..d131c02f6b1 100644 --- a/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java +++ b/jetty-client/src/test/java/org/eclipse/jetty/client/http/HttpReceiverOverHTTPTest.java @@ -20,6 +20,8 @@ package org.eclipse.jetty.client.http; import java.io.EOFException; import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; @@ -30,9 +32,9 @@ import org.eclipse.jetty.client.HttpExchange; import org.eclipse.jetty.client.HttpRequest; import org.eclipse.jetty.client.HttpResponseException; import org.eclipse.jetty.client.Origin; -import org.eclipse.jetty.client.api.Connection; import org.eclipse.jetty.client.api.Response; import org.eclipse.jetty.client.util.FutureResponseListener; +import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpHeader; import org.eclipse.jetty.http.HttpVersion; @@ -44,21 +46,38 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +@RunWith(Parameterized.class) public class HttpReceiverOverHTTPTest -{ +{ @Rule public final TestTracker tracker = new TestTracker(); + @Parameterized.Parameter(0) + public HttpCompliance compliance; + private HttpClient client; private HttpDestinationOverHTTP destination; private ByteArrayEndPoint endPoint; private HttpConnectionOverHTTP connection; - + + @Parameterized.Parameters + public static Collection parameters() throws Exception + { + return Arrays.asList( + new Object[] { HttpCompliance.LEGACY }, + new Object[] { HttpCompliance.RFC2616_LEGACY }, + new Object[] { HttpCompliance.RFC7230_LEGACY } + ); + } + @Before public void init() throws Exception { client = new HttpClient(); + client.setHttpCompliance(compliance); client.start(); destination = new HttpDestinationOverHTTP(client, new Origin("http", "localhost", 8080)); destination.start(); diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java index 7d7912d5e65..96c9d72fecb 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpCompliance.java @@ -18,15 +18,175 @@ package org.eclipse.jetty.http; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; /** - * HTTP compliance modes: - *
- *
RFC7230
(default) Compliance with RFC7230
- *
RFC2616
Wrapped/Continued headers and HTTP/0.9 supported
- *
LEGACY
(aka STRICT) Adherence to Servlet Specification requirement for - * exact case of header names, bypassing the header caches, which are case insensitive, - * otherwise equivalent to RFC2616
+ * HTTP compliance modes for Jetty HTTP parsing and handling. + * A Compliance mode consists of a set of {@link HttpComplianceSection}s which are applied + * when the mode is enabled. + *

+ * Currently the set of modes is an enum and cannot be dynamically extended, but future major releases may convert this + * to a class. To modify modes there are four custom modes that can be modified by setting the property + * org.eclipse.jetty.http.HttpCompliance.CUSTOMn (where 'n' is '0', '1', '2' or '3'), to a comma separated + * list of sections. The list should start with one of the following strings:

+ *
0
No {@link HttpComplianceSection}s
+ *
*
All {@link HttpComplianceSection}s
+ *
RFC2616
The set of {@link HttpComplianceSection}s application to https://tools.ietf.org/html/rfc2616, + * but not https://tools.ietf.org/html/rfc7230
+ *
RFC7230
The set of {@link HttpComplianceSection}s application to https://tools.ietf.org/html/rfc7230
*
+ * The remainder of the list can contain then names of {@link HttpComplianceSection}s to include them in the mode, or prefixed + * with a '-' to exclude thm from the mode. Note that Jetty's modes may have some historic minor differences from the strict + * RFC compliance, for example the RFC2616_LEGACY HttpCompliance is defined as + * RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE. + *

+ * Note also that the {@link EnumSet} return by {@link HttpCompliance#sections()} is mutable, so that modes may + * be altered in code and will affect all usages of the mode. */ -public enum HttpCompliance { LEGACY, RFC2616, RFC7230 } \ No newline at end of file +public enum HttpCompliance // TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically +{ + /** A Legacy compliance mode to match jetty's behavior prior to RFC2616 and RFC7230. It only + * contains {@link HttpComplianceSection#METHOD_CASE_SENSITIVE} + */ + LEGACY(sectionsBySpec("0,METHOD_CASE_SENSITIVE")), + + /** The legacy RFC2616 support, which incorrectly excludes + * {@link HttpComplianceSection#METHOD_CASE_SENSITIVE}, {@link HttpComplianceSection#FIELD_COLON} + */ + RFC2616_LEGACY(sectionsBySpec("RFC2616,-FIELD_COLON,-METHOD_CASE_SENSITIVE")), + + /** The strict RFC2616 support mode */ + RFC2616(sectionsBySpec("RFC2616")), + + /** Jetty's current RFC7230 support, which incorrectly excludes {@link HttpComplianceSection#METHOD_CASE_SENSITIVE} */ + RFC7230_LEGACY(sectionsBySpec("RFC7230,-METHOD_CASE_SENSITIVE")), + + /** The RFC7230 support mode */ + RFC7230(sectionsBySpec("RFC7230")), + + /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM0 */ + @Deprecated + CUSTOM0(sectionsByProperty("CUSTOM0")), + /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM1 */ + @Deprecated + CUSTOM1(sectionsByProperty("CUSTOM1")), + /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM2 */ + @Deprecated + CUSTOM2(sectionsByProperty("CUSTOM2")), + /** Custom compliance mode that can be defined with System property org.eclipse.jetty.http.HttpCompliance.CUSTOM3 */ + @Deprecated + CUSTOM3(sectionsByProperty("CUSTOM3")); + + private static final Logger LOG = Log.getLogger(HttpParser.class); + private static EnumSet sectionsByProperty(String property) + { + String s = System.getProperty(HttpCompliance.class.getName()+property); + return sectionsBySpec(s==null?"*":s); + } + + static EnumSet sectionsBySpec(String spec) + { + EnumSet sections; + String[] elements = spec.split("\\s*,\\s*"); + int i=0; + + switch(elements[i]) + { + case "0": + sections = EnumSet.noneOf(HttpComplianceSection.class); + i++; + break; + + case "*": + i++; + sections = EnumSet.allOf(HttpComplianceSection.class); + break; + + case "RFC2616": + sections = EnumSet.complementOf(EnumSet.of( + HttpComplianceSection.NO_FIELD_FOLDING, + HttpComplianceSection.NO_HTTP_9)); + i++; + break; + + case "RFC7230": + i++; + sections = EnumSet.allOf(HttpComplianceSection.class); + break; + + default: + sections = EnumSet.noneOf(HttpComplianceSection.class); + break; + } + + while(i __required = new HashMap<>(); + static + { + for (HttpComplianceSection section : HttpComplianceSection.values()) + { + for (HttpCompliance compliance : HttpCompliance.values()) + { + if (compliance.sections().contains(section)) + { + __required.put(section,compliance); + break; + } + } + } + } + + /** + * @param section The section to query + * @return The minimum compliance required to enable the section. + */ + public static HttpCompliance requiredCompliance(HttpComplianceSection section) + { + return __required.get(section); + } + + private final EnumSet _sections; + + private HttpCompliance(EnumSet sections) + { + _sections = sections; + } + + /** + * Get the set of {@link HttpComplianceSection}s supported by this compliance mode. This set + * is mutable, so it can be modified. Any modification will affect all usages of the mode + * within the same {@link ClassLoader}. + * @return The set of {@link HttpComplianceSection}s supported by this compliance mode. + */ + public EnumSet sections() + { + return _sections; + } + +} \ No newline at end of file diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java new file mode 100644 index 00000000000..ef52f741342 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpComplianceSection.java @@ -0,0 +1,53 @@ +// +// ======================================================================== +// Copyright (c) 1995-2018 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.http; + +/** + */ +public enum HttpComplianceSection +{ + CASE_INSENSITIVE_FIELD_VALUE_CACHE("","Use case insensitive field value cache"), + METHOD_CASE_SENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.1.1","Method is case-sensitive"), + FIELD_COLON("https://tools.ietf.org/html/rfc7230#section-3.2","Fields must have a Colon"), + FIELD_NAME_CASE_INSENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.2","Field name is case-insensitive"), + NO_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4","Whitespace not allowed after field name"), + NO_FIELD_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4","No line Folding"), + NO_HTTP_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9"), + ; + + final String url; + final String description; + + HttpComplianceSection(String url,String description) + { + this.url = url; + this.description = description; + } + + public String getURL() + { + return url; + } + + public String getDescription() + { + return description; + } + +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java index f327eae44de..f99f66e8a79 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpMethod.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.http; import java.nio.ByteBuffer; +import org.eclipse.jetty.util.ArrayTernaryTrie; import org.eclipse.jetty.util.ArrayTrie; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.Trie; @@ -132,7 +133,15 @@ public enum HttpMethod } /* ------------------------------------------------------------ */ - public final static Trie CACHE= new ArrayTrie<>(); + public final static Trie INSENSITIVE_CACHE= new ArrayTrie<>(); + static + { + for (HttpMethod method : HttpMethod.values()) + INSENSITIVE_CACHE.put(method.toString(),method); + } + + /* ------------------------------------------------------------ */ + public final static Trie CACHE= new ArrayTernaryTrie<>(false); static { for (HttpMethod method : HttpMethod.values()) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java index 127924e5eec..684829dbaaf 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpParser.java @@ -35,9 +35,6 @@ import org.eclipse.jetty.util.Utf8StringBuilder; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; -import static org.eclipse.jetty.http.HttpCompliance.LEGACY; -import static org.eclipse.jetty.http.HttpCompliance.RFC2616; -import static org.eclipse.jetty.http.HttpCompliance.RFC7230; import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN; import static org.eclipse.jetty.http.HttpTokens.LINE_FEED; import static org.eclipse.jetty.http.HttpTokens.SPACE; @@ -82,6 +79,7 @@ import static org.eclipse.jetty.http.HttpTokens.TAB; *

*
RFC7230
(default) Compliance with RFC7230
*
RFC2616
Wrapped headers and HTTP/0.9 supported
+ *
WEAK
Wrapped headers, HTTP/0.9 supported and a weaker parsing behaviour
*
LEGACY
(aka STRICT) Adherence to Servlet Specification requirement for * exact case of header names, bypassing the header caches, which are case insensitive, * otherwise equivalent to RFC2616
@@ -116,6 +114,7 @@ public class HttpParser IN_NAME, VALUE, IN_VALUE, + WS_AFTER_NAME, } // States @@ -154,6 +153,7 @@ public class HttpParser private final ComplianceHandler _complianceHandler; private final int _maxHeaderBytes; private final HttpCompliance _compliance; + private final EnumSet _compliances; private HttpField _field; private HttpHeader _header; private String _headerString; @@ -191,16 +191,21 @@ public class HttpParser CACHE.put(new HttpField(HttpHeader.CONNECTION,HttpHeaderValue.UPGRADE)); CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip")); CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip, deflate, br")); CACHE.put(new HttpField(HttpHeader.ACCEPT_ENCODING,"gzip,deflate,sdch")); CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-US,en;q=0.5")); CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-GB,en-US;q=0.8,en;q=0.6")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_LANGUAGE,"en-AU,en;q=0.9,it-IT;q=0.8,it;q=0.7,en-GB;q=0.6,en-US;q=0.5")); CACHE.put(new HttpField(HttpHeader.ACCEPT_CHARSET,"ISO-8859-1,utf-8;q=0.7,*;q=0.3")); CACHE.put(new HttpField(HttpHeader.ACCEPT,"*/*")); CACHE.put(new HttpField(HttpHeader.ACCEPT,"image/png,image/*;q=0.8,*/*;q=0.5")); CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8")); + CACHE.put(new HttpField(HttpHeader.ACCEPT,"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8")); + CACHE.put(new HttpField(HttpHeader.ACCEPT_RANGES,HttpHeaderValue.BYTES)); CACHE.put(new HttpField(HttpHeader.PRAGMA,"no-cache")); CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"private, no-cache, no-cache=Set-Cookie, proxy-revalidate")); CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"no-cache")); + CACHE.put(new HttpField(HttpHeader.CACHE_CONTROL,"max-age=0")); CACHE.put(new HttpField(HttpHeader.CONTENT_LENGTH,"0")); CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"gzip")); CACHE.put(new HttpField(HttpHeader.CONTENT_ENCODING,"deflate")); @@ -237,7 +242,12 @@ public class HttpParser private static HttpCompliance compliance() { Boolean strict = Boolean.getBoolean(__STRICT); - return strict?HttpCompliance.LEGACY:HttpCompliance.RFC7230; + if (strict) + { + LOG.warn("Deprecated property used: "+__STRICT); + return HttpCompliance.LEGACY; + } + return HttpCompliance.RFC7230; } /* ------------------------------------------------------------------------------- */ @@ -287,23 +297,25 @@ public class HttpParser /* ------------------------------------------------------------------------------- */ public HttpParser(RequestHandler handler,int maxHeaderBytes,HttpCompliance compliance) { - _handler=handler; - _requestHandler=handler; - _responseHandler=null; - _maxHeaderBytes=maxHeaderBytes; - _compliance=compliance==null?compliance():compliance; - _complianceHandler=(ComplianceHandler)(handler instanceof ComplianceHandler?handler:null); + this(handler,null,maxHeaderBytes,compliance==null?compliance():compliance); } /* ------------------------------------------------------------------------------- */ public HttpParser(ResponseHandler handler,int maxHeaderBytes,HttpCompliance compliance) { - _handler=handler; - _requestHandler=null; - _responseHandler=handler; + this(null,handler,maxHeaderBytes,compliance==null?compliance():compliance); + } + + /* ------------------------------------------------------------------------------- */ + private HttpParser(RequestHandler requestHandler,ResponseHandler responseHandler,int maxHeaderBytes,HttpCompliance compliance) + { + _handler=requestHandler!=null?requestHandler:responseHandler; + _requestHandler=requestHandler; + _responseHandler=responseHandler; _maxHeaderBytes=maxHeaderBytes; - _compliance=compliance==null?compliance():compliance; - _complianceHandler=(ComplianceHandler)(handler instanceof ComplianceHandler?handler:null); + _compliance=compliance; + _compliances=compliance.sections(); + _complianceHandler=(ComplianceHandler)(_handler instanceof ComplianceHandler?_handler:null); } /* ------------------------------------------------------------------------------- */ @@ -314,27 +326,36 @@ public class HttpParser /* ------------------------------------------------------------------------------- */ /** Check RFC compliance violation - * @param compliance The compliance level violated + * @param violation The compliance section violation * @param reason The reason for the violation * @return True if the current compliance level is set so as to Not allow this violation */ - protected boolean complianceViolation(HttpCompliance compliance,String reason) + protected boolean complianceViolation(HttpComplianceSection violation, String reason) { - if (_complianceHandler==null) - return _compliance.ordinal()>=compliance.ordinal(); - if (_compliance.ordinal()=0) { // HTTP/0.9 - if (complianceViolation(RFC7230,"https://tools.ietf.org/html/rfc7230#appendix-A.2 HTTP/0.9")) + if (complianceViolation(HttpComplianceSection.NO_HTTP_9,"No request version")) throw new BadMessageException("HTTP/0.9 not supported"); handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9); setState(State.END); @@ -835,7 +854,7 @@ public class HttpParser else { // HTTP/0.9 - if (complianceViolation(RFC7230,"https://tools.ietf.org/html/rfc7230#appendix-A.2 HTTP/0.9")) + if (complianceViolation(HttpComplianceSection.NO_HTTP_9,"No request version")) throw new BadMessageException("HTTP/0.9 not supported"); handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9); @@ -953,7 +972,9 @@ public class HttpParser _host=true; if (!(_field instanceof HostPortHttpField) && _valueString!=null && !_valueString.isEmpty()) { - _field=new HostPortHttpField(_header,caseInsensitiveHeader(_headerString,_header.asString()),_valueString); + _field=new HostPortHttpField(_header, + _compliances.contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE)?_header.asString():_headerString, + _valueString); add_to_connection_trie=_fieldCache!=null; } break; @@ -1050,7 +1071,7 @@ public class HttpParser case HttpTokens.SPACE: case HttpTokens.TAB: { - if (complianceViolation(RFC7230,"https://tools.ietf.org/html/rfc7230#section-3.2.4 folding")) + if (complianceViolation(HttpComplianceSection.NO_FIELD_FOLDING,_headerString)) throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding"); // header value without name - continuation? @@ -1160,36 +1181,39 @@ public class HttpParser if (buffer.hasRemaining()) { // Try a look ahead for the known header name and value. - HttpField field=_fieldCache==null?null:_fieldCache.getBest(buffer,-1,buffer.remaining()); - if (field==null) - field=CACHE.getBest(buffer,-1,buffer.remaining()); + HttpField cached_field=_fieldCache==null?null:_fieldCache.getBest(buffer,-1,buffer.remaining()); + if (cached_field==null) + cached_field=CACHE.getBest(buffer,-1,buffer.remaining()); - if (field!=null) + if (cached_field!=null) { - final String n; - final String v; + String n = cached_field.getName(); + String v = cached_field.getValue(); - if (_compliance==LEGACY) + if (!_compliances.contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE)) { // Have to get the fields exactly from the buffer to match case - String fn=field.getName(); - n=caseInsensitiveHeader(BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StandardCharsets.US_ASCII),fn); - String fv=field.getValue(); - if (fv==null) - v=null; - else + String en = BufferUtil.toString(buffer,buffer.position()-1,n.length(),StandardCharsets.US_ASCII); + if (!n.equals(en)) { - v=caseInsensitiveHeader(BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1),fv); - field=new HttpField(field.getHeader(),n,v); + handleViolation(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE,en); + n = en; + cached_field = new HttpField(cached_field.getHeader(),n,v); } } - else + + if (v!=null && !_compliances.contains(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE)) { - n=field.getName(); - v=field.getValue(); + String ev = BufferUtil.toString(buffer,buffer.position()+n.length()+1,v.length(),StandardCharsets.ISO_8859_1); + if (!v.equals(ev)) + { + handleViolation(HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE,ev+"!="+v); + v = ev; + cached_field = new HttpField(cached_field.getHeader(),n,v); + } } - - _header=field.getHeader(); + + _header=cached_field.getHeader(); _headerString=n; if (v==null) @@ -1209,7 +1233,7 @@ public class HttpParser if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED) { - _field=field; + _field=cached_field; _valueString=v; setState(FieldState.IN_VALUE); @@ -1238,12 +1262,28 @@ public class HttpParser _string.setLength(0); _string.append((char)b); _length=1; - } } break; case IN_NAME: + if (b>HttpTokens.SPACE && b!=HttpTokens.COLON) + { + if (_header!=null) + { + setString(_header.asString()); + _header=null; + _headerString=null; + } + + _string.append((char)b); + _length=_string.length(); + break; + } + + // Fallthrough + + case WS_AFTER_NAME: if (b==HttpTokens.COLON) { if (_headerString==null) @@ -1256,23 +1296,8 @@ public class HttpParser setState(FieldState.VALUE); break; } - - if (b>HttpTokens.SPACE) - { - if (_header!=null) - { - setString(_header.asString()); - _header=null; - _headerString=null; - } - - _string.append((char)b); - if (b>HttpTokens.SPACE) - _length=_string.length(); - break; - } - if (b==HttpTokens.LINE_FEED && !complianceViolation(RFC7230,"https://tools.ietf.org/html/rfc7230#section-3.2 No colon")) + if (b==HttpTokens.LINE_FEED) { if (_headerString==null) { @@ -1283,7 +1308,17 @@ public class HttpParser _valueString=""; _length=-1; - setState(FieldState.FIELD); + if (!complianceViolation(HttpComplianceSection.FIELD_COLON,_headerString)) + { + setState(FieldState.FIELD); + break; + } + } + + //Ignore trailing whitespaces + if (b==HttpTokens.SPACE && !complianceViolation(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME,null)) + { + setState(FieldState.WS_AFTER_NAME); break; } @@ -1817,7 +1852,13 @@ public class HttpParser /* ------------------------------------------------------------------------------- */ public interface ComplianceHandler extends HttpHandler { - public void onComplianceViolation(HttpCompliance compliance,HttpCompliance required,String reason); + @Deprecated + public default void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason) {} + + public default void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String details) + { + onComplianceViolation(compliance,HttpCompliance.requiredCompliance(violation), details); + } } /* ------------------------------------------------------------------------------- */ diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java index fce4cce23da..b955024476f 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpParserTest.java @@ -18,9 +18,12 @@ package org.eclipse.jetty.http; +import static org.hamcrest.Matchers.contains; + import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.eclipse.jetty.http.HttpParser.State; @@ -33,6 +36,11 @@ import org.junit.Test; public class HttpParserTest { + static + { + HttpCompliance.CUSTOM0.sections().remove(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME); + } + /** * Parse until {@link State#END} state. * If the parser is already in the END state, then it is {@link HttpParser#reset()} and re-parsed. @@ -112,7 +120,7 @@ public class HttpParserTest ByteBuffer buffer = BufferUtil.toBuffer("GET /999\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616); + HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY); parseAll(parser, buffer); Assert.assertNull(_bad); @@ -120,7 +128,7 @@ public class HttpParserTest Assert.assertEquals("/999", _uriOrStatus); Assert.assertEquals("HTTP/0.9", _versionOrReason); Assert.assertEquals(-1, _headers); - Assert.assertThat(_complianceViolation, Matchers.containsString("0.9")); + Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.NO_HTTP_9)); } @Test @@ -132,7 +140,7 @@ public class HttpParserTest HttpParser parser = new HttpParser(handler); parseAll(parser, buffer); Assert.assertEquals("HTTP/0.9 not supported", _bad); - Assert.assertNull(_complianceViolation); + Assert.assertThat(_complianceViolation,Matchers.empty()); } @Test @@ -141,7 +149,7 @@ public class HttpParserTest ByteBuffer buffer = BufferUtil.toBuffer("POST /222 \r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616); + HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY); parseAll(parser, buffer); Assert.assertNull(_bad); @@ -149,7 +157,7 @@ public class HttpParserTest Assert.assertEquals("/222", _uriOrStatus); Assert.assertEquals("HTTP/0.9", _versionOrReason); Assert.assertEquals(-1, _headers); - Assert.assertThat(_complianceViolation, Matchers.containsString("0.9")); + Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.NO_HTTP_9)); } @Test @@ -162,7 +170,7 @@ public class HttpParserTest HttpParser parser = new HttpParser(handler); parseAll(parser, buffer); Assert.assertEquals("HTTP/0.9 not supported", _bad); - Assert.assertNull(_complianceViolation); + Assert.assertThat(_complianceViolation,Matchers.empty()); } @Test @@ -256,7 +264,7 @@ public class HttpParserTest "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616); + HttpParser parser = new HttpParser(handler, HttpCompliance.RFC2616_LEGACY); parseAll(parser, buffer); Assert.assertThat(_bad, Matchers.nullValue()); @@ -265,7 +273,7 @@ public class HttpParserTest Assert.assertEquals("Name", _hdr[1]); Assert.assertEquals("value extra", _val[1]); Assert.assertEquals(1, _headers); - Assert.assertThat(_complianceViolation, Matchers.containsString("folding")); + Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.NO_FIELD_FOLDING)); } @Test @@ -279,12 +287,12 @@ public class HttpParserTest "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230); + HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230_LEGACY); parseAll(parser, buffer); Assert.assertThat(_bad, Matchers.notNullValue()); Assert.assertThat(_bad, Matchers.containsString("Header Folding")); - Assert.assertNull(_complianceViolation); + Assert.assertThat(_complianceViolation,Matchers.empty()); } @Test @@ -297,7 +305,7 @@ public class HttpParserTest "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230); + HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230_LEGACY); parseAll(parser, buffer); Assert.assertThat(_bad, Matchers.notNullValue()); @@ -314,7 +322,7 @@ public class HttpParserTest "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230); + HttpParser parser = new HttpParser(handler, 4096, HttpCompliance.RFC7230_LEGACY); parseAll(parser, buffer); Assert.assertThat(_bad, Matchers.notNullValue()); @@ -350,34 +358,92 @@ public class HttpParserTest } @Test - public void testNoColonLegacy() throws Exception + public void testSpaceinNameCustom0() throws Exception { ByteBuffer buffer = BufferUtil.toBuffer( "GET / HTTP/1.0\r\n" + "Host: localhost\r\n" + - "Name\r\n" + + "Name with space: value\r\n" + "Other: value\r\n" + "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler,HttpCompliance.LEGACY); + HttpParser parser = new HttpParser(handler,HttpCompliance.CUSTOM0); + parseAll(parser, buffer); + + Assert.assertThat(_bad, Matchers.containsString("Illegal character")); + Assert.assertThat(_complianceViolation,contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); + } + + @Test + public void testNoColonCustom0() throws Exception + { + ByteBuffer buffer = BufferUtil.toBuffer( + "GET / HTTP/1.0\r\n" + + "Host: localhost\r\n" + + "Name \r\n" + + "Other: value\r\n" + + "\r\n"); + + HttpParser.RequestHandler handler = new Handler(); + HttpParser parser = new HttpParser(handler,HttpCompliance.CUSTOM0); + parseAll(parser, buffer); + + Assert.assertThat(_bad, Matchers.containsString("Illegal character")); + Assert.assertThat(_complianceViolation,contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); + } + + @Test + public void testTrailingSpacesInHeaderNameInCustom0Mode() throws Exception + { + ByteBuffer buffer = BufferUtil.toBuffer( + "HTTP/1.1 204 No Content\r\n" + + "Access-Control-Allow-Headers : Origin\r\n" + + "Other: value\r\n" + + "\r\n"); + + HttpParser.ResponseHandler handler = new Handler(); + HttpParser parser = new HttpParser(handler, -1, HttpCompliance.CUSTOM0); parseAll(parser, buffer); Assert.assertTrue(_headerCompleted); Assert.assertTrue(_messageCompleted); - Assert.assertEquals("GET", _methodOrVersion); - Assert.assertEquals("/", _uriOrStatus); - Assert.assertEquals("HTTP/1.0", _versionOrReason); - Assert.assertEquals("Host", _hdr[0]); - Assert.assertEquals("localhost", _val[0]); - Assert.assertEquals("Name", _hdr[1]); - Assert.assertEquals("", _val[1]); - Assert.assertEquals("Other", _hdr[2]); - Assert.assertEquals("value", _val[2]); - Assert.assertEquals(2, _headers); - Assert.assertThat(_complianceViolation, Matchers.containsString("No colon")); + + Assert.assertEquals("HTTP/1.1", _methodOrVersion); + Assert.assertEquals("204", _uriOrStatus); + Assert.assertEquals("No Content", _versionOrReason); + Assert.assertEquals(null, _content); + + Assert.assertEquals(1, _headers); + System.out.println(Arrays.asList(_hdr)); + System.out.println(Arrays.asList(_val)); + Assert.assertEquals("Access-Control-Allow-Headers", _hdr[0]); + Assert.assertEquals("Origin", _val[0]); + Assert.assertEquals("Other", _hdr[1]); + Assert.assertEquals("value", _val[1]); + + Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.NO_WS_AFTER_FIELD_NAME)); } - + + @Test + public void testTrailingSpacesInHeaderNameNoCustom0() throws Exception + { + ByteBuffer buffer = BufferUtil.toBuffer( + "HTTP/1.1 204 No Content\r\n" + + "Access-Control-Allow-Headers : Origin\r\n" + + "Other: value\r\n" + + "\r\n"); + + HttpParser.ResponseHandler handler = new Handler(); + HttpParser parser = new HttpParser(handler); + parseAll(parser, buffer); + + Assert.assertEquals("HTTP/1.1", _methodOrVersion); + Assert.assertEquals("204", _uriOrStatus); + Assert.assertEquals("No Content", _versionOrReason); + Assert.assertThat(_bad, Matchers.containsString("Illegal character 0x20")); + } + @Test public void testNoColon7230() throws Exception { @@ -388,10 +454,10 @@ public class HttpParserTest "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler,HttpCompliance.RFC7230); + HttpParser parser = new HttpParser(handler,HttpCompliance.RFC7230_LEGACY); parseAll(parser, buffer); Assert.assertThat(_bad, Matchers.containsString("Illegal character")); - Assert.assertNull(_complianceViolation); + Assert.assertThat(_complianceViolation,Matchers.empty()); } @@ -682,11 +748,11 @@ public class HttpParserTest "Connection: close\r\n" + "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, -1, HttpCompliance.RFC7230); + HttpParser parser = new HttpParser(handler, -1, HttpCompliance.RFC7230_LEGACY); parseAll(parser, buffer); Assert.assertNull(_bad); Assert.assertEquals("GET", _methodOrVersion); - Assert.assertThat(_complianceViolation, Matchers.containsString("case insensitive method gEt")); + Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.METHOD_CASE_SENSITIVE)); } @Test @@ -702,7 +768,7 @@ public class HttpParserTest parseAll(parser, buffer); Assert.assertNull(_bad); Assert.assertEquals("gEt", _methodOrVersion); - Assert.assertNull(_complianceViolation); + Assert.assertThat(_complianceViolation,Matchers.empty()); } @Test @@ -714,7 +780,7 @@ public class HttpParserTest "cOnNeCtIoN: ClOsE\r\n" + "\r\n"); HttpParser.RequestHandler handler = new Handler(); - HttpParser parser = new HttpParser(handler, -1, HttpCompliance.RFC7230); + HttpParser parser = new HttpParser(handler, -1, HttpCompliance.RFC7230_LEGACY); parseAll(parser, buffer); Assert.assertNull(_bad); Assert.assertEquals("GET", _methodOrVersion); @@ -725,7 +791,7 @@ public class HttpParserTest Assert.assertEquals("Connection", _hdr[1]); Assert.assertEquals("close", _val[1]); Assert.assertEquals(1, _headers); - Assert.assertNull(_complianceViolation); + Assert.assertThat(_complianceViolation,Matchers.empty()); } @Test @@ -748,7 +814,7 @@ public class HttpParserTest Assert.assertEquals("cOnNeCtIoN", _hdr[1]); Assert.assertEquals("ClOsE", _val[1]); Assert.assertEquals(1, _headers); - Assert.assertThat(_complianceViolation, Matchers.containsString("case sensitive")); + Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE,HttpComplianceSection.FIELD_NAME_CASE_INSENSITIVE,HttpComplianceSection.CASE_INSENSITIVE_FIELD_VALUE_CACHE)); } @Test @@ -1366,10 +1432,10 @@ public class HttpParserTest @Test public void testResponseReasonIso8859_1() throws Exception - { + { ByteBuffer buffer = BufferUtil.toBuffer( "HTTP/1.1 302 déplacé temporairement\r\n" - + "Content-Length: 0\r\n" + + "Content-Length: 0\r\n" + "\r\n",StandardCharsets.ISO_8859_1); HttpParser.ResponseHandler handler = new Handler(); @@ -2041,7 +2107,7 @@ public class HttpParserTest _headers = 0; _headerCompleted = false; _messageCompleted = false; - _complianceViolation = null; + _complianceViolation.clear(); } private String _host; @@ -2059,8 +2125,8 @@ public class HttpParserTest private boolean _early; private boolean _headerCompleted; private boolean _messageCompleted; - private String _complianceViolation; - + private final List _complianceViolation = new ArrayList<>(); + private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler, HttpParser.ComplianceHandler { @Override @@ -2147,8 +2213,9 @@ public class HttpParserTest _methodOrVersion = version.asString(); _uriOrStatus = Integer.toString(status); _versionOrReason = reason; - _hdr = new String[9]; - _val = new String[9]; + _headers = -1; + _hdr = new String[10]; + _val = new String[10]; _messageCompleted = false; _headerCompleted = false; return false; @@ -2167,9 +2234,9 @@ public class HttpParserTest } @Override - public void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason) + public void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String reason) { - _complianceViolation=reason; + _complianceViolation.add(violation); } } } diff --git a/jetty-server/src/main/config/etc/jetty-http.xml b/jetty-server/src/main/config/etc/jetty-http.xml index 93ce0739193..f48e4863626 100644 --- a/jetty-server/src/main/config/etc/jetty-http.xml +++ b/jetty-server/src/main/config/etc/jetty-http.xml @@ -29,7 +29,7 @@ - + diff --git a/jetty-server/src/main/config/modules/http.mod b/jetty-server/src/main/config/modules/http.mod index 86a1ab96a4f..57ad1c82b28 100644 --- a/jetty-server/src/main/config/modules/http.mod +++ b/jetty-server/src/main/config/modules/http.mod @@ -46,5 +46,5 @@ etc/jetty-http.xml ## Connect Timeout in milliseconds # jetty.http.connectTimeout=15000 -## HTTP Compliance: RFC7230, RFC2616, LEGACY -# jetty.http.compliance=RFC7230 +## HTTP Compliance: RFC7230, RFC7230_LEGACY, RFC2616, RFC2616_LEGACY, LEGACY or CUSTOMn +# jetty.http.compliance=RFC7230_LEGACY diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java index 1fa66fbc4ac..bee4f951c92 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelOverHttp.java @@ -27,6 +27,7 @@ import java.util.List; import org.eclipse.jetty.http.BadMessageException; import org.eclipse.jetty.http.HostPortHttpField; import org.eclipse.jetty.http.HttpCompliance; +import org.eclipse.jetty.http.HttpComplianceSection; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpGenerator; @@ -516,7 +517,7 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque } @Override - public void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason) + public void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String reason) { if (_httpConnection.isRecordHttpComplianceViolations()) { @@ -524,10 +525,11 @@ public class HttpChannelOverHttp extends HttpChannel implements HttpParser.Reque { _complianceViolations = new ArrayList<>(); } - String violation = String.format("%s<%s: %s for %s", compliance, required, reason, getHttpTransport()); - _complianceViolations.add(violation); + String record = String.format("%s (see %s) in mode %s for %s in %s", + violation.getDescription(), violation.getURL(), compliance, reason, getHttpTransport()); + _complianceViolations.add(record); if (LOG.isDebugEnabled()) - LOG.debug(violation); + LOG.debug(record); } } } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java index fa1e3ac55bc..9577392af53 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConnection.java @@ -106,7 +106,7 @@ public class HttpConnection extends AbstractConnection implements Runnable, Http _channel = newHttpChannel(); _input = _channel.getRequest().getHttpInput(); _parser = newHttpParser(compliance); - _recordHttpComplianceViolations=recordComplianceViolations; + _recordHttpComplianceViolations = recordComplianceViolations; if (LOG.isDebugEnabled()) LOG.debug("New HTTP Connection {}", this); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java index d882bd80493..1632f522a4f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServerConnector.java @@ -342,13 +342,6 @@ public class ServerConnector extends AbstractNetworkConnector return serverChannel; } - - @Override - public Future shutdown() - { - // shutdown all the connections - return super.shutdown(); - } @Override public void close() diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java index 5262e61bfea..efd4989ccc5 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ExtendedServerTest.java @@ -104,7 +104,7 @@ public class ExtendedServerTest extends HttpServerTestBase { public ExtendedHttpConnection(HttpConfiguration config, Connector connector, EndPoint endPoint) { - super(config,connector,endPoint,HttpCompliance.RFC7230,false); + super(config,connector,endPoint,HttpCompliance.RFC7230_LEGACY,false); } @Override diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java index eb3534e2e81..0cb4ef52b10 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpConnectionTest.java @@ -245,7 +245,7 @@ public class HttpConnectionTest @Test public void test_0_9() throws Exception { - connector.getConnectionFactory(HttpConnectionFactory.class).setHttpCompliance(HttpCompliance.RFC2616); + connector.getConnectionFactory(HttpConnectionFactory.class).setHttpCompliance(HttpCompliance.RFC2616_LEGACY); LocalEndPoint endp = connector.executeRequest("GET /R1\n"); endp.waitUntilClosed(); String response=BufferUtil.toString(endp.takeOutput()); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ComplianceViolations2616Test.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ComplianceViolations2616Test.java index f26eb5da3d2..6442a09052e 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ComplianceViolations2616Test.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/ComplianceViolations2616Test.java @@ -110,7 +110,7 @@ public class ComplianceViolations2616Test HttpConfiguration config = new HttpConfiguration(); config.setSendServerVersion(false); - HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(config, HttpCompliance.RFC2616); + HttpConnectionFactory httpConnectionFactory = new HttpConnectionFactory(config, HttpCompliance.RFC2616_LEGACY); httpConnectionFactory.setRecordHttpComplianceViolations(true); connector = new LocalConnector(server, null, null, null, -1, httpConnectionFactory); @@ -147,7 +147,7 @@ public class ComplianceViolations2616Test String response = connector.getResponse(req1.toString()); assertThat("Response status", response, containsString("HTTP/1.1 200 OK")); - assertThat("Response headers", response, containsString("X-Http-Violation-0: RFC2616