mirror of
https://github.com/jetty/jetty.project.git
synced 2025-03-03 20:39:18 +00:00
Issue #2022 Fine Gramed Compliance Modes
Added HttpComplianceSection and an EnumSet within HttpCompliance Signed-off-by: Greg Wilkins <gregw@webtide.com>
This commit is contained in:
parent
c5fc35fa05
commit
d8dead35ae
@ -32,10 +32,10 @@ import org.eclipse.jetty.client.HttpExchange;
|
|||||||
import org.eclipse.jetty.client.HttpRequest;
|
import org.eclipse.jetty.client.HttpRequest;
|
||||||
import org.eclipse.jetty.client.HttpResponseException;
|
import org.eclipse.jetty.client.HttpResponseException;
|
||||||
import org.eclipse.jetty.client.Origin;
|
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.api.Response;
|
||||||
import org.eclipse.jetty.client.util.FutureResponseListener;
|
import org.eclipse.jetty.client.util.FutureResponseListener;
|
||||||
import org.eclipse.jetty.http.HttpCompliance;
|
import org.eclipse.jetty.http.HttpCompliance;
|
||||||
|
import org.eclipse.jetty.http.HttpComplianceSection;
|
||||||
import org.eclipse.jetty.http.HttpFields;
|
import org.eclipse.jetty.http.HttpFields;
|
||||||
import org.eclipse.jetty.http.HttpHeader;
|
import org.eclipse.jetty.http.HttpHeader;
|
||||||
import org.eclipse.jetty.http.HttpVersion;
|
import org.eclipse.jetty.http.HttpVersion;
|
||||||
@ -55,6 +55,11 @@ import org.junit.runners.Parameterized;
|
|||||||
@RunWith(Parameterized.class)
|
@RunWith(Parameterized.class)
|
||||||
public class HttpReceiverOverHTTPTest
|
public class HttpReceiverOverHTTPTest
|
||||||
{
|
{
|
||||||
|
static
|
||||||
|
{
|
||||||
|
HttpCompliance.CUSTOM0.sections().remove(HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final TestTracker tracker = new TestTracker();
|
public final TestTracker tracker = new TestTracker();
|
||||||
|
|
||||||
@ -71,7 +76,7 @@ public class HttpReceiverOverHTTPTest
|
|||||||
{
|
{
|
||||||
return Arrays.asList(
|
return Arrays.asList(
|
||||||
new Object[] { HttpCompliance.LEGACY },
|
new Object[] { HttpCompliance.LEGACY },
|
||||||
new Object[] { HttpCompliance.WEAK },
|
new Object[] { HttpCompliance.CUSTOM0 },
|
||||||
new Object[] { HttpCompliance.RFC2616 },
|
new Object[] { HttpCompliance.RFC2616 },
|
||||||
new Object[] { HttpCompliance.RFC7230 }
|
new Object[] { HttpCompliance.RFC7230 }
|
||||||
);
|
);
|
||||||
@ -245,7 +250,7 @@ public class HttpReceiverOverHTTPTest
|
|||||||
try {
|
try {
|
||||||
Response response = listener.get(5, TimeUnit.SECONDS);
|
Response response = listener.get(5, TimeUnit.SECONDS);
|
||||||
|
|
||||||
Assert.assertThat(compliance, Matchers.lessThanOrEqualTo(HttpCompliance.WEAK));
|
Assert.assertThat(compliance, Matchers.lessThanOrEqualTo(HttpCompliance.CUSTOM0));
|
||||||
Assert.assertNotNull(response);
|
Assert.assertNotNull(response);
|
||||||
Assert.assertEquals(200, response.getStatus());
|
Assert.assertEquals(200, response.getStatus());
|
||||||
Assert.assertEquals("OK", response.getReason());
|
Assert.assertEquals("OK", response.getReason());
|
||||||
@ -255,7 +260,7 @@ public class HttpReceiverOverHTTPTest
|
|||||||
Assert.assertEquals(1, headers.size());
|
Assert.assertEquals(1, headers.size());
|
||||||
Assert.assertEquals("0", headers.get(HttpHeader.CONTENT_LENGTH));
|
Assert.assertEquals("0", headers.get(HttpHeader.CONTENT_LENGTH));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Assert.assertThat(compliance, Matchers.greaterThan(HttpCompliance.WEAK));
|
Assert.assertThat(compliance, Matchers.greaterThan(HttpCompliance.CUSTOM0));
|
||||||
Throwable cause = e.getCause();
|
Throwable cause = e.getCause();
|
||||||
Assert.assertThat(cause, CoreMatchers.instanceOf(HttpResponseException.class));
|
Assert.assertThat(cause, CoreMatchers.instanceOf(HttpResponseException.class));
|
||||||
Assert.assertThat(cause.getMessage(), Matchers.containsString("HTTP protocol violation"));
|
Assert.assertThat(cause.getMessage(), Matchers.containsString("HTTP protocol violation"));
|
||||||
|
@ -19,6 +19,11 @@
|
|||||||
package org.eclipse.jetty.http;
|
package org.eclipse.jetty.http;
|
||||||
|
|
||||||
import java.util.EnumSet;
|
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:
|
* HTTP compliance modes:
|
||||||
@ -31,29 +36,122 @@ import java.util.EnumSet;
|
|||||||
*/
|
*/
|
||||||
public enum HttpCompliance
|
public enum HttpCompliance
|
||||||
{
|
{
|
||||||
LEGACY(EnumSet.noneOf(HttpRFC.class)),
|
// TODO in Jetty-10 convert this enum to a class so that extra custom modes can be defined dynamically
|
||||||
RFC2616(EnumSet.complementOf(EnumSet.of(
|
LEGACY(sectionsBySpec("LEGACY")),
|
||||||
HttpRFC.RFC7230_3_2_4_WS_AFTER_FIELD_NAME,
|
RFC2616(sectionsBySpec("RFC2616")),
|
||||||
HttpRFC.RFC7230_3_2_4_NO_FOLDING,
|
RFC7230(sectionsBySpec("RFC7230,-RFC7230_3_1_1_METHOD_CASE_SENSITIVE")), // TODO fix in Jetty-10
|
||||||
HttpRFC.RFC7230_A2_NO_HTTP_9))),
|
CUSTOM0(sectionsByProperty("CUSTOM0")),
|
||||||
RFC7230(EnumSet.allOf(HttpRFC.class)),
|
CUSTOM1(sectionsByProperty("CUSTOM1")),
|
||||||
;
|
CUSTOM2(sectionsByProperty("CUSTOM2")),
|
||||||
|
CUSTOM3(sectionsByProperty("CUSTOM3"));
|
||||||
|
|
||||||
|
private static final Logger LOG = Log.getLogger(HttpParser.class);
|
||||||
|
private static EnumSet<HttpComplianceSection> sectionsByProperty(String property)
|
||||||
|
{
|
||||||
|
String s = System.getProperty(HttpCompliance.class.getName()+property);
|
||||||
|
return sectionsBySpec(s==null?"*":s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static EnumSet<HttpComplianceSection> sectionsBySpec(String spec)
|
||||||
|
{
|
||||||
|
EnumSet<HttpComplianceSection> sections;
|
||||||
|
String[] elements = spec.split("\\s*,\\s*");
|
||||||
|
int i=0;
|
||||||
|
|
||||||
|
switch(elements[i])
|
||||||
|
{
|
||||||
|
case "RFC2616":
|
||||||
|
sections = EnumSet.complementOf(EnumSet.of(
|
||||||
|
HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME,
|
||||||
|
HttpComplianceSection.RFC7230_3_2_4_NO_FOLDING,
|
||||||
|
HttpComplianceSection.RFC7230_A2_NO_HTTP_9));
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "RFC7230":
|
||||||
|
case "*":
|
||||||
|
i++;
|
||||||
|
sections = EnumSet.allOf(HttpComplianceSection.class);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "LEGACY":
|
||||||
|
sections = EnumSet.of(HttpComplianceSection.RFC7230_3_1_1_METHOD_CASE_SENSITIVE);
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "0":
|
||||||
|
sections = EnumSet.noneOf(HttpComplianceSection.class);
|
||||||
|
i++;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sections = EnumSet.noneOf(HttpComplianceSection.class);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(i<elements.length)
|
||||||
|
{
|
||||||
|
String element = elements[i++];
|
||||||
|
boolean exclude = element.startsWith("-");
|
||||||
|
if (exclude)
|
||||||
|
element = element.substring(1);
|
||||||
|
HttpComplianceSection section = HttpComplianceSection.valueOf(element);
|
||||||
|
if (section==null)
|
||||||
|
{
|
||||||
|
LOG.warn("Unknown section '"+element+"' in HttpCompliance spec: "+spec);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (exclude)
|
||||||
|
sections.remove(section);
|
||||||
|
else
|
||||||
|
sections.add(section);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return sections;
|
||||||
|
}
|
||||||
|
|
||||||
final EnumSet<HttpRFC> _sections;
|
private final static Map<HttpComplianceSection,HttpCompliance> __required = new HashMap<>();
|
||||||
|
static
|
||||||
|
{
|
||||||
|
for (HttpComplianceSection section : HttpComplianceSection.values())
|
||||||
|
{
|
||||||
|
for (HttpCompliance compliance : HttpCompliance.values())
|
||||||
|
{
|
||||||
|
if (compliance.sections().contains(section))
|
||||||
|
{
|
||||||
|
__required.put(section,compliance);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
HttpCompliance(EnumSet<HttpRFC> sections)
|
/**
|
||||||
|
* @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<HttpComplianceSection> _sections;
|
||||||
|
|
||||||
|
private HttpCompliance(EnumSet<HttpComplianceSection> sections)
|
||||||
{
|
{
|
||||||
_sections = sections;
|
_sections = sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnumSet<HttpRFC> sections()
|
public EnumSet<HttpComplianceSection> sections()
|
||||||
{
|
{
|
||||||
return _sections;
|
return _sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
public EnumSet<HttpRFC> excluding(EnumSet<HttpRFC> exclusions)
|
public EnumSet<HttpComplianceSection> excluding(EnumSet<HttpComplianceSection> exclusions)
|
||||||
{
|
{
|
||||||
EnumSet<HttpRFC> sections = EnumSet.copyOf(_sections);
|
EnumSet<HttpComplianceSection> sections = EnumSet.copyOf(_sections);
|
||||||
sections.removeAll(exclusions);
|
sections.removeAll(exclusions);
|
||||||
return sections;
|
return sections;
|
||||||
}
|
}
|
||||||
|
@ -20,18 +20,18 @@ package org.eclipse.jetty.http;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*/
|
*/
|
||||||
public enum HttpRFC
|
public enum HttpComplianceSection
|
||||||
{
|
{
|
||||||
CASE_SENSITIVE_FIELD_VALUES("","case-sensitive field values"),
|
USE_CASE_INSENSITIVE_FIELD_VALUE_CACHE("","Use case insensitive field value cache"),
|
||||||
RFC7230_3_1_1_METHOD_CASE_SENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.1.1","Method is case-sensitive"),
|
RFC7230_3_1_1_METHOD_CASE_SENSITIVE("https://tools.ietf.org/html/rfc7230#section-3.1.1","Method is case-sensitive"),
|
||||||
RFC7230_3_2_FIELD_COLON("https://tools.ietf.org/html/rfc7230#section-3.2","Fields must have a Colon"),
|
RFC7230_3_2_FIELD_COLON("https://tools.ietf.org/html/rfc7230#section-3.2","Fields must have a Colon"),
|
||||||
RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2","Field name is case-insensitive"),
|
RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2","Field name is case-insensitive"),
|
||||||
RFC7230_3_2_4_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4","Whitespace not allowed after field name"),
|
RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME("https://tools.ietf.org/html/rfc7230#section-3.2.4","Whitespace not allowed after field name"),
|
||||||
RFC7230_3_2_4_NO_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4","No line Folding"),
|
RFC7230_3_2_4_NO_FOLDING("https://tools.ietf.org/html/rfc7230#section-3.2.4","No line Folding"),
|
||||||
RFC7230_A2_NO_HTTP_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9"),
|
RFC7230_A2_NO_HTTP_9("https://tools.ietf.org/html/rfc7230#appendix-A.2","No HTTP/0.9"),
|
||||||
;
|
;
|
||||||
|
|
||||||
HttpRFC(String url,String description)
|
HttpComplianceSection(String url,String description)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
@ -35,7 +35,6 @@ import org.eclipse.jetty.util.Utf8StringBuilder;
|
|||||||
import org.eclipse.jetty.util.log.Log;
|
import org.eclipse.jetty.util.log.Log;
|
||||||
import org.eclipse.jetty.util.log.Logger;
|
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.RFC2616;
|
||||||
import static org.eclipse.jetty.http.HttpCompliance.RFC7230;
|
import static org.eclipse.jetty.http.HttpCompliance.RFC7230;
|
||||||
import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN;
|
import static org.eclipse.jetty.http.HttpTokens.CARRIAGE_RETURN;
|
||||||
@ -117,7 +116,7 @@ public class HttpParser
|
|||||||
IN_NAME,
|
IN_NAME,
|
||||||
VALUE,
|
VALUE,
|
||||||
IN_VALUE,
|
IN_VALUE,
|
||||||
OWS_AFTER_NAME,
|
WS_AFTER_NAME,
|
||||||
}
|
}
|
||||||
|
|
||||||
// States
|
// States
|
||||||
@ -155,7 +154,8 @@ public class HttpParser
|
|||||||
private final ResponseHandler _responseHandler;
|
private final ResponseHandler _responseHandler;
|
||||||
private final ComplianceHandler _complianceHandler;
|
private final ComplianceHandler _complianceHandler;
|
||||||
private final int _maxHeaderBytes;
|
private final int _maxHeaderBytes;
|
||||||
private final EnumSet<HttpRFC> _compliances;
|
private final HttpCompliance _compliance;
|
||||||
|
private final EnumSet<HttpComplianceSection> _compliances;
|
||||||
private HttpField _field;
|
private HttpField _field;
|
||||||
private HttpHeader _header;
|
private HttpHeader _header;
|
||||||
private String _headerString;
|
private String _headerString;
|
||||||
@ -294,23 +294,24 @@ public class HttpParser
|
|||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
public HttpParser(RequestHandler handler,int maxHeaderBytes,HttpCompliance compliance)
|
public HttpParser(RequestHandler handler,int maxHeaderBytes,HttpCompliance compliance)
|
||||||
{
|
{
|
||||||
this(handler,null,maxHeaderBytes,(compliance==null?compliance():compliance).sections());
|
this(handler,null,maxHeaderBytes,compliance==null?compliance():compliance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
public HttpParser(ResponseHandler handler,int maxHeaderBytes,HttpCompliance compliance)
|
public HttpParser(ResponseHandler handler,int maxHeaderBytes,HttpCompliance compliance)
|
||||||
{
|
{
|
||||||
this(null,handler,maxHeaderBytes,(compliance==null?compliance():compliance).sections());
|
this(null,handler,maxHeaderBytes,compliance==null?compliance():compliance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
private HttpParser(RequestHandler requestHandler,ResponseHandler responseHandler,int maxHeaderBytes,EnumSet<HttpRFC> compliances)
|
private HttpParser(RequestHandler requestHandler,ResponseHandler responseHandler,int maxHeaderBytes,HttpCompliance compliance)
|
||||||
{
|
{
|
||||||
_handler=requestHandler!=null?requestHandler:responseHandler;
|
_handler=requestHandler!=null?requestHandler:responseHandler;
|
||||||
_requestHandler=requestHandler;
|
_requestHandler=requestHandler;
|
||||||
_responseHandler=responseHandler;
|
_responseHandler=responseHandler;
|
||||||
_maxHeaderBytes=maxHeaderBytes;
|
_maxHeaderBytes=maxHeaderBytes;
|
||||||
_compliances=compliances;
|
_compliance=compliance;
|
||||||
|
_compliances=compliance.sections();
|
||||||
_complianceHandler=(ComplianceHandler)(_handler instanceof ComplianceHandler?_handler:null);
|
_complianceHandler=(ComplianceHandler)(_handler instanceof ComplianceHandler?_handler:null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -322,36 +323,35 @@ public class HttpParser
|
|||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
/** Check RFC compliance violation
|
/** Check RFC compliance violation
|
||||||
* @param compliance The compliance level violated
|
* @param violation The compliance section violation
|
||||||
* @param reason The reason for the violation
|
* @param reason The reason for the violation
|
||||||
* @return True if the current compliance level is set so as to Not allow this 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)
|
if (_compliances.contains(violation))
|
||||||
return _compliance.ordinal()>=compliance.ordinal();
|
return true;
|
||||||
if (_compliance.ordinal()<compliance.ordinal())
|
|
||||||
{
|
if (_complianceHandler!=null)
|
||||||
_complianceHandler.onComplianceViolation(_compliance,compliance,reason);
|
_complianceHandler.onComplianceViolation(_compliance,violation,reason);
|
||||||
return false;
|
|
||||||
}
|
return false;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
protected void handleViolation(HttpRFC section,String reason)
|
protected void handleViolation(HttpComplianceSection section,String reason)
|
||||||
{
|
{
|
||||||
if (_complianceHandler!=null)
|
if (_complianceHandler!=null)
|
||||||
_complianceHandler.onComplianceViolation(section,reason);
|
_complianceHandler.onComplianceViolation(_compliance,section,reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------- */
|
/* ------------------------------------------------------------------------------- */
|
||||||
protected String caseInsensitiveHeader(String orig, String normative)
|
protected String caseInsensitiveHeader(String orig, String normative)
|
||||||
{
|
{
|
||||||
if (_compliances.contains(HttpRFC.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME))
|
if (_compliances.contains(HttpComplianceSection.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME))
|
||||||
return normative;
|
return normative;
|
||||||
if (orig.equals(normative))
|
if (!orig.equals(normative))
|
||||||
handleViolation(HttpRFC.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME,orig);
|
handleViolation(HttpComplianceSection.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME,orig);
|
||||||
return orig;
|
return orig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -666,7 +666,7 @@ public class HttpParser
|
|||||||
_length=_string.length();
|
_length=_string.length();
|
||||||
_methodString=takeString();
|
_methodString=takeString();
|
||||||
|
|
||||||
if (!_compliances.contains(HttpRFC.RFC7230_3_1_1_METHOD_CASE_SENSITIVE))
|
if (_compliances.contains(HttpComplianceSection.RFC7230_3_1_1_METHOD_CASE_SENSITIVE))
|
||||||
{
|
{
|
||||||
HttpMethod method=HttpMethod.CACHE.get(_methodString);
|
HttpMethod method=HttpMethod.CACHE.get(_methodString);
|
||||||
if (method!=null)
|
if (method!=null)
|
||||||
@ -679,7 +679,7 @@ public class HttpParser
|
|||||||
if (method!=null)
|
if (method!=null)
|
||||||
{
|
{
|
||||||
if (!method.asString().equals(_methodString))
|
if (!method.asString().equals(_methodString))
|
||||||
handleViolation(HttpRFC.RFC7230_3_1_1_METHOD_CASE_SENSITIVE,_methodString);
|
handleViolation(HttpComplianceSection.RFC7230_3_1_1_METHOD_CASE_SENSITIVE,_methodString);
|
||||||
_methodString = method.asString();
|
_methodString = method.asString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -784,7 +784,7 @@ public class HttpParser
|
|||||||
else if (b < HttpTokens.SPACE && b>=0)
|
else if (b < HttpTokens.SPACE && b>=0)
|
||||||
{
|
{
|
||||||
// HTTP/0.9
|
// HTTP/0.9
|
||||||
if (complianceViolation(RFC7230,"https://tools.ietf.org/html/rfc7230#appendix-A.2 HTTP/0.9"))
|
if (complianceViolation(HttpComplianceSection.RFC7230_A2_NO_HTTP_9,"No request version"))
|
||||||
throw new BadMessageException("HTTP/0.9 not supported");
|
throw new BadMessageException("HTTP/0.9 not supported");
|
||||||
handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9);
|
handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9);
|
||||||
setState(State.END);
|
setState(State.END);
|
||||||
@ -851,7 +851,7 @@ public class HttpParser
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// HTTP/0.9
|
// HTTP/0.9
|
||||||
if (complianceViolation(RFC7230,"https://tools.ietf.org/html/rfc7230#appendix-A.2 HTTP/0.9"))
|
if (complianceViolation(HttpComplianceSection.RFC7230_A2_NO_HTTP_9,"No request version"))
|
||||||
throw new BadMessageException("HTTP/0.9 not supported");
|
throw new BadMessageException("HTTP/0.9 not supported");
|
||||||
|
|
||||||
handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9);
|
handle=_requestHandler.startRequest(_methodString,_uri.toString(), HttpVersion.HTTP_0_9);
|
||||||
@ -969,7 +969,9 @@ public class HttpParser
|
|||||||
_host=true;
|
_host=true;
|
||||||
if (!(_field instanceof HostPortHttpField) && _valueString!=null && !_valueString.isEmpty())
|
if (!(_field instanceof HostPortHttpField) && _valueString!=null && !_valueString.isEmpty())
|
||||||
{
|
{
|
||||||
_field=new HostPortHttpField(_header,caseInsensitiveHeader(_headerString,_header.asString()),_valueString);
|
_field=new HostPortHttpField(_header,
|
||||||
|
_compliances.contains(HttpComplianceSection.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME)?_header.asString():_headerString,
|
||||||
|
_valueString);
|
||||||
add_to_connection_trie=_fieldCache!=null;
|
add_to_connection_trie=_fieldCache!=null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1066,7 +1068,7 @@ public class HttpParser
|
|||||||
case HttpTokens.SPACE:
|
case HttpTokens.SPACE:
|
||||||
case HttpTokens.TAB:
|
case HttpTokens.TAB:
|
||||||
{
|
{
|
||||||
if (complianceViolation(RFC7230,"https://tools.ietf.org/html/rfc7230#section-3.2.4 folding"))
|
if (complianceViolation(HttpComplianceSection.RFC7230_3_2_4_NO_FOLDING,"Folded "+_headerString))
|
||||||
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding");
|
throw new BadMessageException(HttpStatus.BAD_REQUEST_400,"Header Folding");
|
||||||
|
|
||||||
// header value without name - continuation?
|
// header value without name - continuation?
|
||||||
@ -1176,37 +1178,39 @@ public class HttpParser
|
|||||||
if (buffer.hasRemaining())
|
if (buffer.hasRemaining())
|
||||||
{
|
{
|
||||||
// Try a look ahead for the known header name and value.
|
// Try a look ahead for the known header name and value.
|
||||||
HttpField field=_fieldCache==null?null:_fieldCache.getBest(buffer,-1,buffer.remaining());
|
HttpField cached_field=_fieldCache==null?null:_fieldCache.getBest(buffer,-1,buffer.remaining());
|
||||||
if (field==null)
|
if (cached_field==null)
|
||||||
field=CACHE.getBest(buffer,-1,buffer.remaining());
|
cached_field=CACHE.getBest(buffer,-1,buffer.remaining());
|
||||||
|
|
||||||
if (field!=null)
|
if (cached_field!=null)
|
||||||
{
|
{
|
||||||
final String n;
|
String n = cached_field.getName();
|
||||||
final String v;
|
String v = cached_field.getValue();
|
||||||
|
|
||||||
if (!_compliances.contains(HttpRFC.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME))
|
if (!_compliances.contains(HttpComplianceSection.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME))
|
||||||
{
|
{
|
||||||
// Have to get the fields exactly from the buffer to match case
|
// Have to get the fields exactly from the buffer to match case
|
||||||
String fn=field.getName();
|
String en = BufferUtil.toString(buffer,buffer.position()-1,n.length(),StandardCharsets.US_ASCII);
|
||||||
n=caseInsensitiveHeader(BufferUtil.toString(buffer,buffer.position()-1,fn.length(),StandardCharsets.US_ASCII),fn);
|
if (!n.equals(en))
|
||||||
String fv=field.getValue();
|
|
||||||
if (fv==null)
|
|
||||||
v=null;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
XXX;
|
handleViolation(HttpComplianceSection.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME,en);
|
||||||
v=BufferUtil.toString(buffer,buffer.position()+fn.length()+1,fv.length(),StandardCharsets.ISO_8859_1);
|
n = en;
|
||||||
field=new HttpField(field.getHeader(),n,v);
|
cached_field = new HttpField(cached_field.getHeader(),n,v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (v!=null && !_compliances.contains(HttpComplianceSection.USE_CASE_INSENSITIVE_FIELD_VALUE_CACHE))
|
||||||
{
|
{
|
||||||
n=field.getName();
|
String ev = BufferUtil.toString(buffer,buffer.position()+n.length()+1,v.length(),StandardCharsets.ISO_8859_1);
|
||||||
v=field.getValue();
|
if (!v.equals(ev))
|
||||||
|
{
|
||||||
|
handleViolation(HttpComplianceSection.USE_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;
|
_headerString=n;
|
||||||
|
|
||||||
if (v==null)
|
if (v==null)
|
||||||
@ -1226,7 +1230,7 @@ public class HttpParser
|
|||||||
|
|
||||||
if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED)
|
if (peek==HttpTokens.CARRIAGE_RETURN || peek==HttpTokens.LINE_FEED)
|
||||||
{
|
{
|
||||||
_field=field;
|
_field=cached_field;
|
||||||
_valueString=v;
|
_valueString=v;
|
||||||
setState(FieldState.IN_VALUE);
|
setState(FieldState.IN_VALUE);
|
||||||
|
|
||||||
@ -1255,7 +1259,6 @@ public class HttpParser
|
|||||||
_string.setLength(0);
|
_string.setLength(0);
|
||||||
_string.append((char)b);
|
_string.append((char)b);
|
||||||
_length=1;
|
_length=1;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1276,7 +1279,7 @@ public class HttpParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fallthrough
|
// Fallthrough
|
||||||
case OWS_AFTER_NAME:
|
case WS_AFTER_NAME:
|
||||||
if (b==HttpTokens.COLON)
|
if (b==HttpTokens.COLON)
|
||||||
{
|
{
|
||||||
if (_headerString==null)
|
if (_headerString==null)
|
||||||
@ -1290,7 +1293,7 @@ public class HttpParser
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (b==HttpTokens.LINE_FEED && !complianceViolation(RFC2616,"https://tools.ietf.org/html/rfc2616#section-4.2 No colon"))
|
if (b==HttpTokens.LINE_FEED && !complianceViolation(HttpComplianceSection.RFC7230_3_2_FIELD_COLON,null))
|
||||||
{
|
{
|
||||||
if (_headerString==null)
|
if (_headerString==null)
|
||||||
{
|
{
|
||||||
@ -1306,9 +1309,9 @@ public class HttpParser
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Ignore trailing whitespaces
|
//Ignore trailing whitespaces
|
||||||
if (b==HttpTokens.SPACE && !complianceViolation(RFC2616,"https://tools.ietf.org/html/rfc2616#section-4.2 Invalid token in header name"))
|
if (b==HttpTokens.SPACE && !complianceViolation(HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME,null))
|
||||||
{
|
{
|
||||||
setState(FieldState.OWS_AFTER_NAME);
|
setState(FieldState.WS_AFTER_NAME);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1843,11 +1846,11 @@ public class HttpParser
|
|||||||
public interface ComplianceHandler extends HttpHandler
|
public interface ComplianceHandler extends HttpHandler
|
||||||
{
|
{
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public void onComplianceViolation(HttpCompliance compliance,HttpCompliance required,String reason);
|
public default void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason) {}
|
||||||
|
|
||||||
public default void onComplianceViolation(HttpRFC violation, String details)
|
public default void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String details)
|
||||||
{
|
{
|
||||||
|
onComplianceViolation(compliance,HttpCompliance.requiredCompliance(violation), details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
|
|
||||||
package org.eclipse.jetty.http;
|
package org.eclipse.jetty.http;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -34,6 +36,11 @@ import org.junit.Test;
|
|||||||
|
|
||||||
public class HttpParserTest
|
public class HttpParserTest
|
||||||
{
|
{
|
||||||
|
static
|
||||||
|
{
|
||||||
|
HttpCompliance.CUSTOM0.sections().remove(HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse until {@link State#END} state.
|
* Parse until {@link State#END} state.
|
||||||
* If the parser is already in the END state, then it is {@link HttpParser#reset()} and re-parsed.
|
* If the parser is already in the END state, then it is {@link HttpParser#reset()} and re-parsed.
|
||||||
@ -121,7 +128,7 @@ public class HttpParserTest
|
|||||||
Assert.assertEquals("/999", _uriOrStatus);
|
Assert.assertEquals("/999", _uriOrStatus);
|
||||||
Assert.assertEquals("HTTP/0.9", _versionOrReason);
|
Assert.assertEquals("HTTP/0.9", _versionOrReason);
|
||||||
Assert.assertEquals(-1, _headers);
|
Assert.assertEquals(-1, _headers);
|
||||||
Assert.assertThat(_complianceViolation, Matchers.containsString("0.9"));
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.RFC7230_A2_NO_HTTP_9));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -133,7 +140,7 @@ public class HttpParserTest
|
|||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
Assert.assertEquals("HTTP/0.9 not supported", _bad);
|
Assert.assertEquals("HTTP/0.9 not supported", _bad);
|
||||||
Assert.assertNull(_complianceViolation);
|
Assert.assertThat(_complianceViolation,Matchers.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -150,7 +157,7 @@ public class HttpParserTest
|
|||||||
Assert.assertEquals("/222", _uriOrStatus);
|
Assert.assertEquals("/222", _uriOrStatus);
|
||||||
Assert.assertEquals("HTTP/0.9", _versionOrReason);
|
Assert.assertEquals("HTTP/0.9", _versionOrReason);
|
||||||
Assert.assertEquals(-1, _headers);
|
Assert.assertEquals(-1, _headers);
|
||||||
Assert.assertThat(_complianceViolation, Matchers.containsString("0.9"));
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.RFC7230_A2_NO_HTTP_9));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -163,7 +170,7 @@ public class HttpParserTest
|
|||||||
HttpParser parser = new HttpParser(handler);
|
HttpParser parser = new HttpParser(handler);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
Assert.assertEquals("HTTP/0.9 not supported", _bad);
|
Assert.assertEquals("HTTP/0.9 not supported", _bad);
|
||||||
Assert.assertNull(_complianceViolation);
|
Assert.assertThat(_complianceViolation,Matchers.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -266,7 +273,7 @@ public class HttpParserTest
|
|||||||
Assert.assertEquals("Name", _hdr[1]);
|
Assert.assertEquals("Name", _hdr[1]);
|
||||||
Assert.assertEquals("value extra", _val[1]);
|
Assert.assertEquals("value extra", _val[1]);
|
||||||
Assert.assertEquals(1, _headers);
|
Assert.assertEquals(1, _headers);
|
||||||
Assert.assertThat(_complianceViolation, Matchers.containsString("folding"));
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.RFC7230_3_2_4_NO_FOLDING));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -285,7 +292,7 @@ public class HttpParserTest
|
|||||||
|
|
||||||
Assert.assertThat(_bad, Matchers.notNullValue());
|
Assert.assertThat(_bad, Matchers.notNullValue());
|
||||||
Assert.assertThat(_bad, Matchers.containsString("Header Folding"));
|
Assert.assertThat(_bad, Matchers.containsString("Header Folding"));
|
||||||
Assert.assertNull(_complianceViolation);
|
Assert.assertThat(_complianceViolation,Matchers.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -351,74 +358,52 @@ public class HttpParserTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoColonWeak() throws Exception
|
public void testSpaceinNameCustom0() throws Exception
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Name\r\n" +
|
"Name with space: value\r\n" +
|
||||||
"Other: value\r\n" +
|
"Other: value\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler,HttpCompliance.WEAK);
|
HttpParser parser = new HttpParser(handler,HttpCompliance.CUSTOM0);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
|
|
||||||
Assert.assertTrue(_headerCompleted);
|
Assert.assertThat(_bad, Matchers.containsString("Illegal character"));
|
||||||
Assert.assertTrue(_messageCompleted);
|
Assert.assertThat(_complianceViolation,contains(HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME));
|
||||||
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"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoColonWithWhitespaceWeak() throws Exception
|
public void testNoColonCustom0() throws Exception
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"GET / HTTP/1.0\r\n" +
|
"GET / HTTP/1.0\r\n" +
|
||||||
"Host: localhost\r\n" +
|
"Host: localhost\r\n" +
|
||||||
"Name \r\n" +
|
"Name \r\n" +
|
||||||
"Other: value\r\n" +
|
"Other: value\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
HttpParser.RequestHandler handler = new Handler();
|
HttpParser.RequestHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler,HttpCompliance.WEAK);
|
HttpParser parser = new HttpParser(handler,HttpCompliance.CUSTOM0);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
|
|
||||||
Assert.assertTrue(_headerCompleted);
|
Assert.assertThat(_bad, Matchers.containsString("Illegal character"));
|
||||||
Assert.assertTrue(_messageCompleted);
|
Assert.assertThat(_complianceViolation,contains(HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME));
|
||||||
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"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrailingSpacesInHeaderNameInWeakMode() throws Exception
|
public void testTrailingSpacesInHeaderNameInCustom0Mode() throws Exception
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 204 No Content\r\n" +
|
"HTTP/1.1 204 No Content\r\n" +
|
||||||
"Access-Control-Allow-Headers : Origin\r\n" +
|
"Access-Control-Allow-Headers : Origin\r\n" +
|
||||||
"Other: value\r\n" +
|
"Other: value\r\n" +
|
||||||
"\r\n");
|
"\r\n");
|
||||||
|
|
||||||
HttpParser.ResponseHandler handler = new Handler();
|
HttpParser.ResponseHandler handler = new Handler();
|
||||||
HttpParser parser = new HttpParser(handler, -1, HttpCompliance.WEAK);
|
HttpParser parser = new HttpParser(handler, -1, HttpCompliance.CUSTOM0);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
|
|
||||||
Assert.assertTrue(_headerCompleted);
|
Assert.assertTrue(_headerCompleted);
|
||||||
@ -437,11 +422,11 @@ public class HttpParserTest
|
|||||||
Assert.assertEquals("Other", _hdr[1]);
|
Assert.assertEquals("Other", _hdr[1]);
|
||||||
Assert.assertEquals("value", _val[1]);
|
Assert.assertEquals("value", _val[1]);
|
||||||
|
|
||||||
Assert.assertThat(_complianceViolation, Matchers.containsString("Invalid token in header name"));
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.RFC7230_3_2_4_NO_WS_AFTER_FIELD_NAME));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTrailingSpacesInHeaderNameNoWeak() throws Exception
|
public void testTrailingSpacesInHeaderNameNoCustom0() throws Exception
|
||||||
{
|
{
|
||||||
ByteBuffer buffer = BufferUtil.toBuffer(
|
ByteBuffer buffer = BufferUtil.toBuffer(
|
||||||
"HTTP/1.1 204 No Content\r\n" +
|
"HTTP/1.1 204 No Content\r\n" +
|
||||||
@ -472,7 +457,7 @@ public class HttpParserTest
|
|||||||
HttpParser parser = new HttpParser(handler,HttpCompliance.RFC7230);
|
HttpParser parser = new HttpParser(handler,HttpCompliance.RFC7230);
|
||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
Assert.assertThat(_bad, Matchers.containsString("Illegal character"));
|
Assert.assertThat(_bad, Matchers.containsString("Illegal character"));
|
||||||
Assert.assertNull(_complianceViolation);
|
Assert.assertThat(_complianceViolation,Matchers.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -767,7 +752,7 @@ public class HttpParserTest
|
|||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
Assert.assertNull(_bad);
|
Assert.assertNull(_bad);
|
||||||
Assert.assertEquals("GET", _methodOrVersion);
|
Assert.assertEquals("GET", _methodOrVersion);
|
||||||
Assert.assertThat(_complianceViolation, Matchers.containsString("case insensitive method gEt"));
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.RFC7230_3_1_1_METHOD_CASE_SENSITIVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -783,7 +768,7 @@ public class HttpParserTest
|
|||||||
parseAll(parser, buffer);
|
parseAll(parser, buffer);
|
||||||
Assert.assertNull(_bad);
|
Assert.assertNull(_bad);
|
||||||
Assert.assertEquals("gEt", _methodOrVersion);
|
Assert.assertEquals("gEt", _methodOrVersion);
|
||||||
Assert.assertNull(_complianceViolation);
|
Assert.assertThat(_complianceViolation,Matchers.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -806,7 +791,7 @@ public class HttpParserTest
|
|||||||
Assert.assertEquals("Connection", _hdr[1]);
|
Assert.assertEquals("Connection", _hdr[1]);
|
||||||
Assert.assertEquals("close", _val[1]);
|
Assert.assertEquals("close", _val[1]);
|
||||||
Assert.assertEquals(1, _headers);
|
Assert.assertEquals(1, _headers);
|
||||||
Assert.assertNull(_complianceViolation);
|
Assert.assertThat(_complianceViolation,Matchers.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -829,7 +814,7 @@ public class HttpParserTest
|
|||||||
Assert.assertEquals("cOnNeCtIoN", _hdr[1]);
|
Assert.assertEquals("cOnNeCtIoN", _hdr[1]);
|
||||||
Assert.assertEquals("ClOsE", _val[1]);
|
Assert.assertEquals("ClOsE", _val[1]);
|
||||||
Assert.assertEquals(1, _headers);
|
Assert.assertEquals(1, _headers);
|
||||||
Assert.assertThat(_complianceViolation, Matchers.containsString("case sensitive"));
|
Assert.assertThat(_complianceViolation, contains(HttpComplianceSection.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME,HttpComplianceSection.RFC7230_3_2_CASE_INSENSITIVE_FIELD_NAME,HttpComplianceSection.USE_CASE_INSENSITIVE_FIELD_VALUE_CACHE));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -2122,7 +2107,7 @@ public class HttpParserTest
|
|||||||
_headers = 0;
|
_headers = 0;
|
||||||
_headerCompleted = false;
|
_headerCompleted = false;
|
||||||
_messageCompleted = false;
|
_messageCompleted = false;
|
||||||
_complianceViolation = null;
|
_complianceViolation.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
private String _host;
|
private String _host;
|
||||||
@ -2140,8 +2125,8 @@ public class HttpParserTest
|
|||||||
private boolean _early;
|
private boolean _early;
|
||||||
private boolean _headerCompleted;
|
private boolean _headerCompleted;
|
||||||
private boolean _messageCompleted;
|
private boolean _messageCompleted;
|
||||||
private String _complianceViolation;
|
private final List<HttpComplianceSection> _complianceViolation = new ArrayList<>();
|
||||||
|
|
||||||
private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler, HttpParser.ComplianceHandler
|
private class Handler implements HttpParser.RequestHandler, HttpParser.ResponseHandler, HttpParser.ComplianceHandler
|
||||||
{
|
{
|
||||||
@Override
|
@Override
|
||||||
@ -2249,9 +2234,9 @@ public class HttpParserTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onComplianceViolation(HttpCompliance compliance, HttpCompliance required, String reason)
|
public void onComplianceViolation(HttpCompliance compliance, HttpComplianceSection violation, String reason)
|
||||||
{
|
{
|
||||||
_complianceViolation=reason;
|
_complianceViolation.add(violation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||||
#org.eclipse.jetty.LEVEL=DEBUG
|
#org.eclipse.jetty.LEVEL=DEBUG
|
||||||
#org.eclipse.jetty.server.LEVEL=DEBUG
|
org.eclipse.jetty.server.LEVEL=DEBUG
|
||||||
|
@ -336,13 +336,6 @@ public class ServerConnector extends AbstractNetworkConnector
|
|||||||
|
|
||||||
return serverChannel;
|
return serverChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Future<Void> shutdown()
|
|
||||||
{
|
|
||||||
// shutdown all the connections
|
|
||||||
return super.shutdown();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close()
|
public void close()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user